webscout 8.3.2__py3-none-any.whl → 8.3.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of webscout might be problematic. Click here for more details.

Files changed (117) hide show
  1. webscout/AIutel.py +367 -41
  2. webscout/Bard.py +2 -22
  3. webscout/Bing_search.py +1 -2
  4. webscout/Provider/AISEARCH/__init__.py +1 -0
  5. webscout/Provider/AISEARCH/scira_search.py +24 -11
  6. webscout/Provider/AISEARCH/stellar_search.py +132 -0
  7. webscout/Provider/Deepinfra.py +75 -57
  8. webscout/Provider/ExaChat.py +93 -63
  9. webscout/Provider/Flowith.py +1 -1
  10. webscout/Provider/FreeGemini.py +2 -2
  11. webscout/Provider/Gemini.py +3 -10
  12. webscout/Provider/GeminiProxy.py +31 -5
  13. webscout/Provider/HeckAI.py +85 -80
  14. webscout/Provider/Jadve.py +56 -50
  15. webscout/Provider/LambdaChat.py +39 -31
  16. webscout/Provider/MiniMax.py +207 -0
  17. webscout/Provider/Nemotron.py +41 -13
  18. webscout/Provider/Netwrck.py +39 -59
  19. webscout/Provider/OLLAMA.py +8 -9
  20. webscout/Provider/OPENAI/BLACKBOXAI.py +0 -1
  21. webscout/Provider/OPENAI/MiniMax.py +298 -0
  22. webscout/Provider/OPENAI/README.md +31 -30
  23. webscout/Provider/OPENAI/TogetherAI.py +4 -17
  24. webscout/Provider/OPENAI/__init__.py +4 -2
  25. webscout/Provider/OPENAI/autoproxy.py +753 -18
  26. webscout/Provider/OPENAI/base.py +7 -76
  27. webscout/Provider/OPENAI/copilot.py +73 -26
  28. webscout/Provider/OPENAI/deepinfra.py +96 -132
  29. webscout/Provider/OPENAI/exachat.py +9 -5
  30. webscout/Provider/OPENAI/flowith.py +179 -166
  31. webscout/Provider/OPENAI/friendli.py +233 -0
  32. webscout/Provider/OPENAI/monochat.py +329 -0
  33. webscout/Provider/OPENAI/netwrck.py +4 -7
  34. webscout/Provider/OPENAI/pydantic_imports.py +1 -172
  35. webscout/Provider/OPENAI/qodo.py +630 -0
  36. webscout/Provider/OPENAI/scirachat.py +82 -49
  37. webscout/Provider/OPENAI/textpollinations.py +13 -12
  38. webscout/Provider/OPENAI/toolbaz.py +1 -0
  39. webscout/Provider/OPENAI/typegpt.py +4 -4
  40. webscout/Provider/OPENAI/utils.py +19 -42
  41. webscout/Provider/OPENAI/x0gpt.py +14 -2
  42. webscout/Provider/OpenGPT.py +54 -32
  43. webscout/Provider/PI.py +58 -84
  44. webscout/Provider/Qodo.py +454 -0
  45. webscout/Provider/StandardInput.py +32 -13
  46. webscout/Provider/TTI/README.md +9 -9
  47. webscout/Provider/TTI/__init__.py +2 -1
  48. webscout/Provider/TTI/aiarta.py +92 -78
  49. webscout/Provider/TTI/infip.py +212 -0
  50. webscout/Provider/TTI/monochat.py +220 -0
  51. webscout/Provider/TeachAnything.py +11 -3
  52. webscout/Provider/TextPollinationsAI.py +91 -82
  53. webscout/Provider/TogetherAI.py +32 -48
  54. webscout/Provider/Venice.py +37 -46
  55. webscout/Provider/VercelAI.py +27 -24
  56. webscout/Provider/WiseCat.py +35 -35
  57. webscout/Provider/WrDoChat.py +22 -26
  58. webscout/Provider/WritingMate.py +26 -22
  59. webscout/Provider/__init__.py +6 -6
  60. webscout/Provider/copilot.py +58 -61
  61. webscout/Provider/freeaichat.py +64 -55
  62. webscout/Provider/granite.py +48 -57
  63. webscout/Provider/koala.py +51 -39
  64. webscout/Provider/learnfastai.py +49 -64
  65. webscout/Provider/llmchat.py +79 -93
  66. webscout/Provider/llmchatco.py +63 -78
  67. webscout/Provider/monochat.py +275 -0
  68. webscout/Provider/multichat.py +51 -40
  69. webscout/Provider/oivscode.py +1 -1
  70. webscout/Provider/scira_chat.py +257 -104
  71. webscout/Provider/scnet.py +13 -13
  72. webscout/Provider/searchchat.py +13 -13
  73. webscout/Provider/sonus.py +12 -11
  74. webscout/Provider/toolbaz.py +25 -8
  75. webscout/Provider/turboseek.py +41 -42
  76. webscout/Provider/typefully.py +27 -12
  77. webscout/Provider/typegpt.py +43 -48
  78. webscout/Provider/uncovr.py +55 -90
  79. webscout/Provider/x0gpt.py +325 -299
  80. webscout/Provider/yep.py +79 -96
  81. webscout/__init__.py +7 -2
  82. webscout/auth/__init__.py +12 -1
  83. webscout/auth/providers.py +27 -5
  84. webscout/auth/routes.py +146 -105
  85. webscout/auth/server.py +367 -312
  86. webscout/client.py +121 -116
  87. webscout/litagent/Readme.md +68 -55
  88. webscout/litagent/agent.py +99 -9
  89. webscout/version.py +1 -1
  90. {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/METADATA +102 -91
  91. {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/RECORD +95 -107
  92. webscout/Provider/AI21.py +0 -177
  93. webscout/Provider/HuggingFaceChat.py +0 -469
  94. webscout/Provider/OPENAI/freeaichat.py +0 -363
  95. webscout/Provider/TTI/fastflux.py +0 -233
  96. webscout/Provider/Writecream.py +0 -246
  97. webscout/auth/static/favicon.svg +0 -11
  98. webscout/auth/swagger_ui.py +0 -203
  99. webscout/auth/templates/components/authentication.html +0 -237
  100. webscout/auth/templates/components/base.html +0 -103
  101. webscout/auth/templates/components/endpoints.html +0 -750
  102. webscout/auth/templates/components/examples.html +0 -491
  103. webscout/auth/templates/components/footer.html +0 -75
  104. webscout/auth/templates/components/header.html +0 -27
  105. webscout/auth/templates/components/models.html +0 -286
  106. webscout/auth/templates/components/navigation.html +0 -70
  107. webscout/auth/templates/static/api.js +0 -455
  108. webscout/auth/templates/static/icons.js +0 -168
  109. webscout/auth/templates/static/main.js +0 -784
  110. webscout/auth/templates/static/particles.js +0 -201
  111. webscout/auth/templates/static/styles.css +0 -3353
  112. webscout/auth/templates/static/ui.js +0 -374
  113. webscout/auth/templates/swagger_ui.html +0 -170
  114. {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/WHEEL +0 -0
  115. {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/entry_points.txt +0 -0
  116. {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/licenses/LICENSE.md +0 -0
  117. {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/top_level.txt +0 -0
@@ -8,12 +8,11 @@ from webscout.Litlogger import Logger, LogLevel
8
8
 
9
9
  logger = Logger(name="OpenAIBase", level=LogLevel.INFO)
10
10
 
11
- # Import the ProxyAutoMeta metaclass
11
+ # Import the LitMeta metaclass from Litproxy
12
12
  try:
13
- from .autoproxy import ProxyAutoMeta
13
+ from litproxy import LitMeta
14
14
  except ImportError:
15
- # Fallback if autoproxy is not available
16
- ProxyAutoMeta = type
15
+ from .autoproxy import ProxyAutoMeta as LitMeta
17
16
 
18
17
 
19
18
  # Import the utils for response structures
@@ -183,81 +182,11 @@ class BaseChat(ABC):
183
182
  completions: BaseCompletions
184
183
 
185
184
 
186
- # class ProxyAutoMeta(ABCMeta):
187
- # """
188
- # Metaclass to ensure all OpenAICompatibleProvider subclasses automatically get proxy support.
189
- # This will inject proxies into any requests.Session, httpx.Client, or curl_cffi session attributes found on the instance.
190
-
191
- # To disable automatic proxy injection, set disable_auto_proxy=True in the constructor or
192
- # set the class attribute DISABLE_AUTO_PROXY = True.
193
- # """
194
- # def __call__(cls, *args, **kwargs):
195
- # instance = super().__call__(*args, **kwargs)
196
-
197
- # # Check if auto proxy is disabled
198
- # disable_auto_proxy = kwargs.get('disable_auto_proxy', False) or getattr(cls, 'DISABLE_AUTO_PROXY', False)
199
-
200
- # proxies = getattr(instance, 'proxies', None) or kwargs.get('proxies', None)
201
- # if proxies is None and not disable_auto_proxy:
202
- # try:
203
- # proxies = {"http": get_auto_proxy(), "https": get_auto_proxy()}
204
- # except Exception as e:
205
- # logger.warning(f"Failed to get auto proxy, disabling proxy support: {e}")
206
- # proxies = {}
207
- # elif proxies is None:
208
- # proxies = {}
209
- # instance.proxies = proxies
210
- # # Patch sessions if we have valid proxies
211
- # if proxies:
212
- # for attr in dir(instance):
213
- # obj = getattr(instance, attr)
214
- # if isinstance(obj, requests.Session):
215
- # obj.proxies.update(proxies)
216
- # if httpx and isinstance(obj, httpx.Client):
217
- # try:
218
- # obj._proxies = proxies
219
- # except Exception:
220
- # pass
221
- # # Patch curl_cffi sessions if present
222
- # if CurlSession and isinstance(obj, CurlSession):
223
- # try:
224
- # obj.proxies.update(proxies)
225
- # except Exception:
226
- # pass
227
- # if CurlAsyncSession and isinstance(obj, CurlAsyncSession):
228
- # try:
229
- # obj.proxies.update(proxies)
230
- # except Exception:
231
- # pass
232
- # # Provide helpers for proxied sessions
233
- # def get_proxied_session():
234
- # s = requests.Session()
235
- # s.proxies.update(proxies)
236
- # return s
237
- # instance.get_proxied_session = get_proxied_session
238
-
239
- # def get_proxied_curl_session(impersonate="chrome120", **kwargs):
240
- # """Get a curl_cffi Session with proxies configured"""
241
- # if CurlSession:
242
- # return CurlSession(proxies=proxies, impersonate=impersonate, **kwargs)
243
- # else:
244
- # raise ImportError("curl_cffi is not installed")
245
- # instance.get_proxied_curl_session = get_proxied_curl_session
246
-
247
- # def get_proxied_curl_async_session(impersonate="chrome120", **kwargs):
248
- # """Get a curl_cffi AsyncSession with proxies configured"""
249
- # if CurlAsyncSession:
250
- # return CurlAsyncSession(proxies=proxies, impersonate=impersonate, **kwargs)
251
- # else:
252
- # raise ImportError("curl_cffi is not installed")
253
- # instance.get_proxied_curl_async_session = get_proxied_curl_async_session
254
-
255
- # return instance
256
- class OpenAICompatibleProvider(ABC, metaclass=ProxyAutoMeta):
185
+ class OpenAICompatibleProvider(ABC, metaclass=LitMeta):
257
186
  """
258
187
  Abstract Base Class for providers mimicking the OpenAI Python client structure.
259
188
  Requires a nested 'chat.completions' structure with tool support.
260
- All subclasses automatically get proxy support via ProxyAutoMeta.
189
+ All subclasses automatically get proxy support via LitMeta.
261
190
 
262
191
  # Available proxy helpers:
263
192
  # - self.get_proxied_session() - returns a requests.Session with proxies
@@ -269,6 +198,8 @@ class OpenAICompatibleProvider(ABC, metaclass=ProxyAutoMeta):
269
198
  # - httpx.Client objects
270
199
  # - curl_cffi.requests.Session objects
271
200
  # - curl_cffi.requests.AsyncSession objects
201
+ #
202
+ # Inbuilt auto-retry is also enabled for all requests.Session and curl_cffi.Session objects.
272
203
  """
273
204
  chat: BaseChat
274
205
  available_tools: Dict[str, Tool] = {} # Dictionary of available tools
@@ -86,14 +86,8 @@ class Completions(BaseCompletions):
86
86
  raise RuntimeError(f"Image upload failed: {r.text}")
87
87
  images.append({"type": "image", "url": r.json().get("url")})
88
88
 
89
- # Connect to websocket
90
- # Note: ws_connect might not use timeout in the same way as POST/GET
91
89
  ws = s.ws_connect(self._client.websocket_url)
92
-
93
- # Use model to set mode ("reasoning" for Think Deeper)
94
90
  mode = "reasoning" if "Think" in model else "chat"
95
-
96
- # Send the message to Copilot
97
91
  ws.send(json.dumps({
98
92
  "event": "send",
99
93
  "conversationId": conv_id,
@@ -101,79 +95,132 @@ class Completions(BaseCompletions):
101
95
  "mode": mode
102
96
  }).encode(), CurlWsFlag.TEXT)
103
97
 
104
- # Track token usage using count_tokens
105
98
  prompt_tokens = count_tokens(prompt_text)
106
99
  completion_tokens = 0
107
100
  total_tokens = prompt_tokens
108
-
109
101
  started = False
102
+ image_prompt = None
110
103
  while True:
111
104
  try:
112
105
  msg = json.loads(ws.recv()[0])
113
106
  except Exception:
114
107
  break
115
108
 
116
- if msg.get("event") == "appendText":
109
+ event = msg.get("event")
110
+ if event not in ["appendText", "done", "error", "generatingImage", "imageGenerated", "suggestedFollowups", "replaceText"]:
111
+ print(f"[Copilot] Unhandled event: {event} | msg: {msg}")
112
+
113
+ if event == "appendText":
117
114
  started = True
118
115
  content = msg.get("text", "")
119
-
120
- # Update token counts using count_tokens
121
116
  content_tokens = count_tokens(content)
122
117
  completion_tokens += content_tokens
123
118
  total_tokens = prompt_tokens + completion_tokens
124
-
125
- # Create the delta object
126
119
  delta = ChoiceDelta(
127
120
  content=content,
128
121
  role="assistant"
129
122
  )
130
-
131
- # Create the choice object
132
123
  choice = Choice(
133
124
  index=0,
134
125
  delta=delta,
135
126
  finish_reason=None
136
127
  )
137
-
138
- # Create the chunk object
139
128
  chunk = ChatCompletionChunk(
140
129
  id=request_id,
141
130
  choices=[choice],
142
131
  created=created_time,
143
132
  model=model
144
133
  )
145
-
146
134
  yield chunk
147
- elif msg.get("event") == "done":
148
- # Final chunk with finish_reason
135
+ elif event == "replaceText":
136
+ # treat as appendText for OpenAI compatibility
137
+ content = msg.get("text", "")
138
+ content_tokens = count_tokens(content)
139
+ completion_tokens += content_tokens
140
+ total_tokens = prompt_tokens + completion_tokens
141
+ delta = ChoiceDelta(
142
+ content=content,
143
+ role="assistant"
144
+ )
145
+ choice = Choice(
146
+ index=0,
147
+ delta=delta,
148
+ finish_reason=None
149
+ )
150
+ chunk = ChatCompletionChunk(
151
+ id=request_id,
152
+ choices=[choice],
153
+ created=created_time,
154
+ model=model
155
+ )
156
+ yield chunk
157
+ elif event == "generatingImage":
158
+ image_prompt = msg.get("prompt")
159
+ elif event == "imageGenerated":
160
+ # Yield a chunk with image metadata in the delta (custom extension)
161
+ delta = ChoiceDelta(
162
+ content=None,
163
+ role=None
164
+ )
165
+ choice = Choice(
166
+ index=0,
167
+ delta=delta,
168
+ finish_reason=None
169
+ )
170
+ chunk = ChatCompletionChunk(
171
+ id=request_id,
172
+ choices=[choice],
173
+ created=created_time,
174
+ model=model
175
+ )
176
+ chunk.image_url = msg.get("url")
177
+ chunk.image_prompt = image_prompt
178
+ chunk.image_preview = msg.get("thumbnailUrl")
179
+ yield chunk
180
+ elif event == "suggestedFollowups":
181
+ # Yield a chunk with followups in the delta (custom extension)
182
+ delta = ChoiceDelta(
183
+ content=None,
184
+ role=None
185
+ )
186
+ choice = Choice(
187
+ index=0,
188
+ delta=delta,
189
+ finish_reason=None
190
+ )
191
+ chunk = ChatCompletionChunk(
192
+ id=request_id,
193
+ choices=[choice],
194
+ created=created_time,
195
+ model=model
196
+ )
197
+ chunk.suggested_followups = msg.get("suggestions")
198
+ yield chunk
199
+ elif event == "done":
149
200
  delta = ChoiceDelta(
150
201
  content=None,
151
202
  role=None
152
203
  )
153
-
154
204
  choice = Choice(
155
205
  index=0,
156
206
  delta=delta,
157
207
  finish_reason="stop"
158
208
  )
159
-
160
209
  chunk = ChatCompletionChunk(
161
210
  id=request_id,
162
211
  choices=[choice],
163
212
  created=created_time,
164
213
  model=model
165
214
  )
166
-
167
215
  yield chunk
168
216
  break
169
- elif msg.get("event") == "error":
217
+ elif event == "error":
218
+ print(f"[Copilot] Error event: {msg}")
170
219
  raise RuntimeError(f"Copilot error: {msg}")
171
220
 
172
221
  ws.close()
173
-
174
222
  if not started:
175
223
  raise RuntimeError("No response received from Copilot")
176
-
177
224
  except Exception as e:
178
225
  raise RuntimeError(f"Stream error: {e}") from e
179
226
  finally:
@@ -2,23 +2,20 @@ import requests
2
2
  import json
3
3
  import time
4
4
  import uuid
5
+ import collections
5
6
  from typing import List, Dict, Optional, Union, Generator, Any
6
7
 
7
- # Import base classes and utility structures
8
8
  from webscout.Provider.OPENAI.base import OpenAICompatibleProvider, BaseChat, BaseCompletions
9
9
  from webscout.Provider.OPENAI.utils import (
10
10
  ChatCompletionChunk, ChatCompletion, Choice, ChoiceDelta,
11
11
  ChatCompletionMessage, CompletionUsage
12
12
  )
13
13
 
14
- # Attempt to import LitAgent, fallback if not available
15
14
  try:
16
15
  from webscout.litagent import LitAgent
17
16
  except ImportError:
18
17
  pass
19
18
 
20
- # --- DeepInfra Client ---
21
-
22
19
  class Completions(BaseCompletions):
23
20
  def __init__(self, client: 'DeepInfra'):
24
21
  self._client = client
@@ -36,10 +33,6 @@ class Completions(BaseCompletions):
36
33
  proxies: Optional[Dict[str, str]] = None,
37
34
  **kwargs: Any
38
35
  ) -> Union[ChatCompletion, Generator[ChatCompletionChunk, None, None]]:
39
- """
40
- Creates a model response for the given chat conversation.
41
- Mimics openai.chat.completions.create
42
- """
43
36
  payload = {
44
37
  "model": model,
45
38
  "messages": messages,
@@ -50,12 +43,9 @@ class Completions(BaseCompletions):
50
43
  payload["temperature"] = temperature
51
44
  if top_p is not None:
52
45
  payload["top_p"] = top_p
53
-
54
46
  payload.update(kwargs)
55
-
56
47
  request_id = f"chatcmpl-{uuid.uuid4()}"
57
48
  created_time = int(time.time())
58
-
59
49
  if stream:
60
50
  return self._create_stream(request_id, created_time, model, payload, timeout, proxies)
61
51
  else:
@@ -75,52 +65,39 @@ class Completions(BaseCompletions):
75
65
  proxies=proxies
76
66
  )
77
67
  response.raise_for_status()
78
-
79
- # Track token usage across chunks
80
68
  prompt_tokens = 0
81
69
  completion_tokens = 0
82
70
  total_tokens = 0
83
-
84
- for line in response.iter_lines():
71
+ for line in response.iter_lines(decode_unicode=True):
85
72
  if line:
86
- decoded_line = line.decode('utf-8').strip()
87
-
88
- if decoded_line.startswith("data: "):
89
- json_str = decoded_line[6:]
73
+ if line.startswith("data: "):
74
+ json_str = line[6:]
90
75
  if json_str == "[DONE]":
91
- # Format the final [DONE] marker in OpenAI format
92
- # print("data: [DONE]")
93
76
  break
94
-
95
77
  try:
96
78
  data = json.loads(json_str)
97
79
  choice_data = data.get('choices', [{}])[0]
98
80
  delta_data = choice_data.get('delta', {})
99
81
  finish_reason = choice_data.get('finish_reason')
100
-
101
- # Update token counts if available
102
82
  usage_data = data.get('usage', {})
103
83
  if usage_data:
104
84
  prompt_tokens = usage_data.get('prompt_tokens', prompt_tokens)
105
85
  completion_tokens = usage_data.get('completion_tokens', completion_tokens)
106
86
  total_tokens = usage_data.get('total_tokens', total_tokens)
107
-
108
- # Create the delta object
87
+ if delta_data.get('content'):
88
+ completion_tokens += 1
89
+ total_tokens = prompt_tokens + completion_tokens
109
90
  delta = ChoiceDelta(
110
91
  content=delta_data.get('content'),
111
92
  role=delta_data.get('role'),
112
93
  tool_calls=delta_data.get('tool_calls')
113
94
  )
114
-
115
- # Create the choice object
116
95
  choice = Choice(
117
96
  index=choice_data.get('index', 0),
118
97
  delta=delta,
119
98
  finish_reason=finish_reason,
120
99
  logprobs=choice_data.get('logprobs')
121
100
  )
122
-
123
- # Create the chunk object
124
101
  chunk = ChatCompletionChunk(
125
102
  id=request_id,
126
103
  choices=[choice],
@@ -128,48 +105,35 @@ class Completions(BaseCompletions):
128
105
  model=model,
129
106
  system_fingerprint=data.get('system_fingerprint')
130
107
  )
131
-
132
- # Convert chunk to dict using Pydantic's API
133
- if hasattr(chunk, "model_dump"):
134
- chunk_dict = chunk.model_dump(exclude_none=True)
135
- else:
136
- chunk_dict = chunk.dict(exclude_none=True)
137
-
138
- # Add usage information to match OpenAI format
139
- # Even if we don't have real token counts, include estimated usage
140
- # This matches the format in the examples
141
- usage_dict = {
142
- "prompt_tokens": prompt_tokens or 10,
143
- "completion_tokens": completion_tokens or (len(delta_data.get('content', '')) if delta_data.get('content') else 0),
144
- "total_tokens": total_tokens or (10 + (len(delta_data.get('content', '')) if delta_data.get('content') else 0)),
108
+ chunk.usage = {
109
+ "prompt_tokens": prompt_tokens,
110
+ "completion_tokens": completion_tokens,
111
+ "total_tokens": total_tokens,
145
112
  "estimated_cost": None
146
113
  }
147
-
148
- # Update completion_tokens and total_tokens as we receive more content
149
- if delta_data.get('content'):
150
- completion_tokens += 1
151
- total_tokens = prompt_tokens + completion_tokens
152
- usage_dict["completion_tokens"] = completion_tokens
153
- usage_dict["total_tokens"] = total_tokens
154
-
155
- chunk_dict["usage"] = usage_dict
156
-
157
- # Format the response in OpenAI format exactly as requested
158
- # We need to print the raw string and also yield the chunk object
159
- # This ensures both the console output and the returned object are correct
160
- # print(f"data: {json.dumps(chunk_dict)}")
161
-
162
- # Return the chunk object for internal processing
163
114
  yield chunk
164
115
  except json.JSONDecodeError:
165
- print(f"Warning: Could not decode JSON line: {json_str}")
166
116
  continue
167
- except requests.exceptions.RequestException as e:
117
+ # Final chunk with finish_reason="stop"
118
+ delta = ChoiceDelta(content=None, role=None, tool_calls=None)
119
+ choice = Choice(index=0, delta=delta, finish_reason="stop", logprobs=None)
120
+ chunk = ChatCompletionChunk(
121
+ id=request_id,
122
+ choices=[choice],
123
+ created=created_time,
124
+ model=model,
125
+ system_fingerprint=None
126
+ )
127
+ chunk.usage = {
128
+ "prompt_tokens": prompt_tokens,
129
+ "completion_tokens": completion_tokens,
130
+ "total_tokens": total_tokens,
131
+ "estimated_cost": None
132
+ }
133
+ yield chunk
134
+ except Exception as e:
168
135
  print(f"Error during DeepInfra stream request: {e}")
169
136
  raise IOError(f"DeepInfra request failed: {e}") from e
170
- except Exception as e:
171
- print(f"Error processing DeepInfra stream: {e}")
172
- raise
173
137
 
174
138
  def _create_non_stream(
175
139
  self, request_id: str, created_time: int, model: str, payload: Dict[str, Any],
@@ -185,13 +149,19 @@ class Completions(BaseCompletions):
185
149
  )
186
150
  response.raise_for_status()
187
151
  data = response.json()
188
-
189
152
  choices_data = data.get('choices', [])
190
153
  usage_data = data.get('usage', {})
191
-
192
154
  choices = []
193
155
  for choice_d in choices_data:
194
- message_d = choice_d.get('message', {})
156
+ message_d = choice_d.get('message')
157
+ if not message_d and 'delta' in choice_d:
158
+ delta = choice_d['delta']
159
+ message_d = {
160
+ 'role': delta.get('role', 'assistant'),
161
+ 'content': delta.get('content', '')
162
+ }
163
+ if not message_d:
164
+ message_d = {'role': 'assistant', 'content': ''}
195
165
  message = ChatCompletionMessage(
196
166
  role=message_d.get('role', 'assistant'),
197
167
  content=message_d.get('content', '')
@@ -202,13 +172,11 @@ class Completions(BaseCompletions):
202
172
  finish_reason=choice_d.get('finish_reason', 'stop')
203
173
  )
204
174
  choices.append(choice)
205
-
206
175
  usage = CompletionUsage(
207
176
  prompt_tokens=usage_data.get('prompt_tokens', 0),
208
177
  completion_tokens=usage_data.get('completion_tokens', 0),
209
178
  total_tokens=usage_data.get('total_tokens', 0)
210
179
  )
211
-
212
180
  completion = ChatCompletion(
213
181
  id=request_id,
214
182
  choices=choices,
@@ -217,87 +185,83 @@ class Completions(BaseCompletions):
217
185
  usage=usage,
218
186
  )
219
187
  return completion
220
-
221
- except requests.exceptions.RequestException as e:
188
+ except Exception as e:
222
189
  print(f"Error during DeepInfra non-stream request: {e}")
223
190
  raise IOError(f"DeepInfra request failed: {e}") from e
224
- except Exception as e:
225
- print(f"Error processing DeepInfra response: {e}")
226
- raise
227
191
 
228
192
  class Chat(BaseChat):
229
193
  def __init__(self, client: 'DeepInfra'):
230
194
  self.completions = Completions(client)
231
195
 
232
196
  class DeepInfra(OpenAICompatibleProvider):
233
-
234
197
  AVAILABLE_MODELS = [
235
- # "anthropic/claude-3-7-sonnet-latest", # >>>> NOT WORKING
236
- "deepseek-ai/DeepSeek-R1-0528",
237
- "deepseek-ai/DeepSeek-R1",
238
- "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
239
- "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
240
- "deepseek-ai/DeepSeek-R1-Turbo",
241
- "deepseek-ai/DeepSeek-V3",
198
+ "anthropic/claude-4-opus",
199
+ "anthropic/claude-4-sonnet",
200
+ "deepseek-ai/DeepSeek-R1-0528-Turbo",
201
+ "Qwen/Qwen3-235B-A22B",
202
+ "Qwen/Qwen3-30B-A3B",
203
+ "Qwen/Qwen3-32B",
204
+ "Qwen/Qwen3-14B",
205
+ "deepseek-ai/DeepSeek-V3-0324-Turbo",
242
206
  "deepseek-ai/DeepSeek-Prover-V2-671B",
243
- "google/gemma-2-27b-it",
244
- "google/gemma-2-9b-it",
245
- "google/gemma-3-12b-it",
207
+ "meta-llama/Llama-4-Maverick-17B-128E-Instruct-Turbo",
208
+ "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8",
209
+ "meta-llama/Llama-4-Scout-17B-16E-Instruct",
210
+ "deepseek-ai/DeepSeek-R1-0528",
211
+ "deepseek-ai/DeepSeek-V3-0324",
212
+ "mistralai/Mistral-Small-3.1-24B-Instruct-2503",
213
+ "microsoft/phi-4-reasoning-plus",
214
+ "Qwen/QwQ-32B",
215
+ "google/gemini-2.5-flash",
216
+ "google/gemini-2.5-pro",
246
217
  "google/gemma-3-27b-it",
218
+ "google/gemma-3-12b-it",
247
219
  "google/gemma-3-4b-it",
248
- "meta-llama/Llama-3.3-70B-Instruct",
220
+ "microsoft/Phi-4-multimodal-instruct",
221
+ "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
222
+ "deepseek-ai/DeepSeek-V3",
249
223
  "meta-llama/Llama-3.3-70B-Instruct-Turbo",
250
- "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8",
251
- "meta-llama/Llama-4-Scout-17B-16E-Instruct",
252
- "meta-llama/Llama-Guard-4-12B",
224
+ "meta-llama/Llama-3.3-70B-Instruct",
225
+ "microsoft/phi-4",
226
+ "Gryphe/MythoMax-L2-13b",
227
+ "NousResearch/Hermes-3-Llama-3.1-405B",
228
+ "NousResearch/Hermes-3-Llama-3.1-70B",
229
+ "NovaSky-AI/Sky-T1-32B-Preview",
230
+ "Qwen/Qwen2.5-72B-Instruct",
231
+ "Qwen/Qwen2.5-7B-Instruct",
232
+ "Qwen/Qwen2.5-Coder-32B-Instruct",
233
+ "Sao10K/L3-8B-Lunaris-v1-Turbo",
234
+ "Sao10K/L3.1-70B-Euryale-v2.2",
235
+ "Sao10K/L3.3-70B-Euryale-v2.3",
236
+ "anthropic/claude-3-7-sonnet-latest",
237
+ "deepseek-ai/DeepSeek-R1",
238
+ "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
239
+ "deepseek-ai/DeepSeek-R1-Turbo",
240
+ "google/gemini-2.0-flash-001",
241
+ "meta-llama/Llama-3.2-11B-Vision-Instruct",
242
+ "meta-llama/Llama-3.2-1B-Instruct",
243
+ "meta-llama/Llama-3.2-3B-Instruct",
244
+ "meta-llama/Llama-3.2-90B-Vision-Instruct",
245
+ "meta-llama/Meta-Llama-3-70B-Instruct",
246
+ "meta-llama/Meta-Llama-3-8B-Instruct",
247
+ "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
253
248
  "meta-llama/Meta-Llama-3.1-8B-Instruct",
254
249
  "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
255
- "microsoft/Phi-4-multimodal-instruct",
256
250
  "microsoft/WizardLM-2-8x22B",
257
- "microsoft/phi-4",
258
- "microsoft/phi-4-reasoning-plus",
251
+ "mistralai/Devstral-Small-2505",
252
+ "mistralai/Mistral-7B-Instruct-v0.3",
253
+ "mistralai/Mistral-Nemo-Instruct-2407",
259
254
  "mistralai/Mistral-Small-24B-Instruct-2501",
255
+ "mistralai/Mistral-Small-3.2-24B-Instruct-2506",
256
+ "mistralai/Mixtral-8x7B-Instruct-v0.1",
260
257
  "nvidia/Llama-3.1-Nemotron-70B-Instruct",
261
- "Qwen/QwQ-32B",
262
- "Qwen/Qwen2.5-72B-Instruct",
263
- "Qwen/Qwen2.5-Coder-32B-Instruct",
264
- "Qwen/Qwen3-14B",
265
- "Qwen/Qwen3-30B-A3B",
266
- "Qwen/Qwen3-32B",
267
- "Qwen/Qwen3-235B-A22B",
268
- # "google/gemini-1.5-flash", # >>>> NOT WORKING
269
- # "google/gemini-1.5-flash-8b", # >>>> NOT WORKING
270
- # "google/gemini-2.0-flash-001", # >>>> NOT WORKING
271
-
272
- # "Gryphe/MythoMax-L2-13b", # >>>> NOT WORKING
273
-
274
- # "meta-llama/Llama-3.2-1B-Instruct", # >>>> NOT WORKING
275
- # "meta-llama/Llama-3.2-3B-Instruct", # >>>> NOT WORKING
276
- # "meta-llama/Llama-3.2-90B-Vision-Instruct", # >>>> NOT WORKING
277
- # "meta-llama/Llama-3.2-11B-Vision-Instruct", # >>>> NOT WORKING
278
- # "meta-llama/Meta-Llama-3-70B-Instruct", # >>>> NOT WORKING
279
- # "meta-llama/Meta-Llama-3-8B-Instruct", # >>>> NOT WORKING
280
- # "meta-llama/Meta-Llama-3.1-70B-Instruct", # >>>> NOT WORKING
281
- # "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo", # >>>> NOT WORKING
282
- # "meta-llama/Meta-Llama-3.1-405B-Instruct", # >>>> NOT WORKING
283
- # "mistralai/Mixtral-8x7B-Instruct-v0.1", # >>>> NOT WORKING
284
- # "mistralai/Mistral-7B-Instruct-v0.3", # >>>> NOT WORKING
285
- # "mistralai/Mistral-Nemo-Instruct-2407", # >>>> NOT WORKING
286
- # "NousResearch/Hermes-3-Llama-3.1-405B", # >>>> NOT WORKING
287
- # "NovaSky-AI/Sky-T1-32B-Preview", # >>>> NOT WORKING
288
- # "Qwen/Qwen2.5-7B-Instruct", # >>>> NOT WORKING
289
- # "Sao10K/L3.1-70B-Euryale-v2.2", # >>>> NOT WORKING
290
- # "Sao10K/L3.3-70B-Euryale-v2.3", # >>>> NOT WORKING
291
258
  ]
292
-
293
- def __init__(self, browser: str = "chrome"):
294
- self.timeout = None # Default timeout
259
+ def __init__(self, browser: str = "chrome", api_key: str = None):
260
+ self.timeout = None
295
261
  self.base_url = "https://api.deepinfra.com/v1/openai/chat/completions"
296
262
  self.session = requests.Session()
297
-
298
263
  agent = LitAgent()
299
264
  fingerprint = agent.generate_fingerprint(browser)
300
-
301
265
  self.headers = {
302
266
  "Accept": fingerprint["accept"],
303
267
  "Accept-Encoding": "gzip, deflate, br, zstd",
@@ -317,23 +281,23 @@ class DeepInfra(OpenAICompatibleProvider):
317
281
  "Sec-CH-UA-Platform": f'"{fingerprint["platform"]}"',
318
282
  "User-Agent": fingerprint["user_agent"],
319
283
  }
284
+ if api_key is not None:
285
+ self.headers["Authorization"] = f"Bearer {api_key}"
320
286
  self.session.headers.update(self.headers)
321
287
  self.chat = Chat(self)
322
-
323
288
  @property
324
289
  def models(self):
325
290
  class _ModelList:
326
291
  def list(inner_self):
327
292
  return type(self).AVAILABLE_MODELS
328
293
  return _ModelList()
329
-
294
+
330
295
  if __name__ == "__main__":
331
- # Example usage
332
296
  client = DeepInfra()
333
297
  response = client.chat.completions.create(
334
298
  model="deepseek-ai/DeepSeek-R1-0528",
335
299
  messages=[{"role": "user", "content": "Hello, how are you?"}],
336
- max_tokens=100,
300
+ max_tokens=10000,
337
301
  stream=False
338
302
  )
339
303
  print(response)