File size: 6,232 Bytes
ed4d993
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import http.client
import json
import ssl
from typing import Any, List, Mapping, Optional

from langchain_core.callbacks import CallbackManagerForLLMRun
from langchain_core.language_models.llms import LLM


class NIBittensorLLM(LLM):
    """NIBittensor LLMs

    NIBittensorLLM is created by Neural Internet (https://neuralinternet.ai/),
    powered by Bittensor, a decentralized network full of different AI models.

    To analyze API_KEYS and logs of your usage visit
        https://api.neuralinternet.ai/api-keys
        https://api.neuralinternet.ai/logs

    Example:
        .. code-block:: python

            from langchain_community.llms import NIBittensorLLM
            llm = NIBittensorLLM()
    """

    system_prompt: Optional[str]
    """Provide system prompt that you want to supply it to model before every prompt"""

    top_responses: Optional[int] = 0
    """Provide top_responses to get Top N miner responses on one request.May get delayed
        Don't use in Production"""

    @property
    def _llm_type(self) -> str:
        return "NIBittensorLLM"

    def _call(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> str:
        """
        Wrapper around the bittensor top miner models. Its built by Neural Internet.

        Call the Neural Internet's BTVEP Server and return the output.

        Parameters (optional):
            system_prompt(str): A system prompt defining how your model should respond.
            top_responses(int): Total top miner responses to retrieve from Bittensor
                protocol.

        Return:
            The generated response(s).

        Example:
            .. code-block:: python

                from langchain_community.llms import NIBittensorLLM
                llm = NIBittensorLLM(system_prompt="Act like you are programmer with \
                5+ years of experience.")
        """

        # Creating HTTPS connection with SSL
        context = ssl.create_default_context()
        context.check_hostname = True
        conn = http.client.HTTPSConnection("test.neuralinternet.ai", context=context)

        # Sanitizing User Input before passing to API.
        if isinstance(self.top_responses, int):
            top_n = min(100, self.top_responses)
        else:
            top_n = 0

        default_prompt = "You are an assistant which is created by Neural Internet(NI) \
            in decentralized network named as a Bittensor."
        if self.system_prompt is None:
            system_prompt = (
                default_prompt
                + " Your task is to provide accurate response based on user prompt"
            )
        else:
            system_prompt = default_prompt + str(self.system_prompt)

        # Retrieving API KEY to pass into header of each request
        conn.request("GET", "/admin/api-keys/")
        api_key_response = conn.getresponse()
        api_keys_data = (
            api_key_response.read().decode("utf-8").replace("\n", "").replace("\t", "")
        )
        api_keys_json = json.loads(api_keys_data)
        api_key = api_keys_json[0]["api_key"]

        # Creating Header and getting top benchmark miner uids
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}",
            "Endpoint-Version": "2023-05-19",
        }
        conn.request("GET", "/top_miner_uids", headers=headers)
        miner_response = conn.getresponse()
        miner_data = (
            miner_response.read().decode("utf-8").replace("\n", "").replace("\t", "")
        )
        uids = json.loads(miner_data)

        # Condition for benchmark miner response
        if isinstance(uids, list) and uids and not top_n:
            for uid in uids:
                try:
                    payload = json.dumps(
                        {
                            "uids": [uid],
                            "messages": [
                                {"role": "system", "content": system_prompt},
                                {"role": "user", "content": prompt},
                            ],
                        }
                    )

                    conn.request("POST", "/chat", payload, headers)
                    init_response = conn.getresponse()
                    init_data = (
                        init_response.read()
                        .decode("utf-8")
                        .replace("\n", "")
                        .replace("\t", "")
                    )
                    init_json = json.loads(init_data)
                    if "choices" not in init_json:
                        continue
                    reply = init_json["choices"][0]["message"]["content"]
                    conn.close()
                    return reply
                except Exception:
                    continue

        # For top miner based on bittensor response
        try:
            payload = json.dumps(
                {
                    "top_n": top_n,
                    "messages": [
                        {"role": "system", "content": system_prompt},
                        {"role": "user", "content": prompt},
                    ],
                }
            )

            conn.request("POST", "/chat", payload, headers)
            response = conn.getresponse()
            utf_string = (
                response.read().decode("utf-8").replace("\n", "").replace("\t", "")
            )
            if top_n:
                conn.close()
                return utf_string
            json_resp = json.loads(utf_string)
            reply = json_resp["choices"][0]["message"]["content"]
            conn.close()
            return reply
        except Exception as e:
            conn.request("GET", f"/error_msg?e={e}&p={prompt}", headers=headers)
            return "Sorry I am unable to provide response now, Please try again later."

    @property
    def _identifying_params(self) -> Mapping[str, Any]:
        """Get the identifying parameters."""
        return {
            "system_prompt": self.system_prompt,
            "top_responses": self.top_responses,
        }