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.
- webscout/AIutel.py +367 -41
- webscout/Bard.py +2 -22
- webscout/Bing_search.py +1 -2
- webscout/Provider/AISEARCH/__init__.py +1 -0
- webscout/Provider/AISEARCH/scira_search.py +24 -11
- webscout/Provider/AISEARCH/stellar_search.py +132 -0
- webscout/Provider/Deepinfra.py +75 -57
- webscout/Provider/ExaChat.py +93 -63
- webscout/Provider/Flowith.py +1 -1
- webscout/Provider/FreeGemini.py +2 -2
- webscout/Provider/Gemini.py +3 -10
- webscout/Provider/GeminiProxy.py +31 -5
- webscout/Provider/HeckAI.py +85 -80
- webscout/Provider/Jadve.py +56 -50
- webscout/Provider/LambdaChat.py +39 -31
- webscout/Provider/MiniMax.py +207 -0
- webscout/Provider/Nemotron.py +41 -13
- webscout/Provider/Netwrck.py +39 -59
- webscout/Provider/OLLAMA.py +8 -9
- webscout/Provider/OPENAI/BLACKBOXAI.py +0 -1
- webscout/Provider/OPENAI/MiniMax.py +298 -0
- webscout/Provider/OPENAI/README.md +31 -30
- webscout/Provider/OPENAI/TogetherAI.py +4 -17
- webscout/Provider/OPENAI/__init__.py +4 -2
- webscout/Provider/OPENAI/autoproxy.py +753 -18
- webscout/Provider/OPENAI/base.py +7 -76
- webscout/Provider/OPENAI/copilot.py +73 -26
- webscout/Provider/OPENAI/deepinfra.py +96 -132
- webscout/Provider/OPENAI/exachat.py +9 -5
- webscout/Provider/OPENAI/flowith.py +179 -166
- webscout/Provider/OPENAI/friendli.py +233 -0
- webscout/Provider/OPENAI/monochat.py +329 -0
- webscout/Provider/OPENAI/netwrck.py +4 -7
- webscout/Provider/OPENAI/pydantic_imports.py +1 -172
- webscout/Provider/OPENAI/qodo.py +630 -0
- webscout/Provider/OPENAI/scirachat.py +82 -49
- webscout/Provider/OPENAI/textpollinations.py +13 -12
- webscout/Provider/OPENAI/toolbaz.py +1 -0
- webscout/Provider/OPENAI/typegpt.py +4 -4
- webscout/Provider/OPENAI/utils.py +19 -42
- webscout/Provider/OPENAI/x0gpt.py +14 -2
- webscout/Provider/OpenGPT.py +54 -32
- webscout/Provider/PI.py +58 -84
- webscout/Provider/Qodo.py +454 -0
- webscout/Provider/StandardInput.py +32 -13
- webscout/Provider/TTI/README.md +9 -9
- webscout/Provider/TTI/__init__.py +2 -1
- webscout/Provider/TTI/aiarta.py +92 -78
- webscout/Provider/TTI/infip.py +212 -0
- webscout/Provider/TTI/monochat.py +220 -0
- webscout/Provider/TeachAnything.py +11 -3
- webscout/Provider/TextPollinationsAI.py +91 -82
- webscout/Provider/TogetherAI.py +32 -48
- webscout/Provider/Venice.py +37 -46
- webscout/Provider/VercelAI.py +27 -24
- webscout/Provider/WiseCat.py +35 -35
- webscout/Provider/WrDoChat.py +22 -26
- webscout/Provider/WritingMate.py +26 -22
- webscout/Provider/__init__.py +6 -6
- webscout/Provider/copilot.py +58 -61
- webscout/Provider/freeaichat.py +64 -55
- webscout/Provider/granite.py +48 -57
- webscout/Provider/koala.py +51 -39
- webscout/Provider/learnfastai.py +49 -64
- webscout/Provider/llmchat.py +79 -93
- webscout/Provider/llmchatco.py +63 -78
- webscout/Provider/monochat.py +275 -0
- webscout/Provider/multichat.py +51 -40
- webscout/Provider/oivscode.py +1 -1
- webscout/Provider/scira_chat.py +257 -104
- webscout/Provider/scnet.py +13 -13
- webscout/Provider/searchchat.py +13 -13
- webscout/Provider/sonus.py +12 -11
- webscout/Provider/toolbaz.py +25 -8
- webscout/Provider/turboseek.py +41 -42
- webscout/Provider/typefully.py +27 -12
- webscout/Provider/typegpt.py +43 -48
- webscout/Provider/uncovr.py +55 -90
- webscout/Provider/x0gpt.py +325 -299
- webscout/Provider/yep.py +79 -96
- webscout/__init__.py +7 -2
- webscout/auth/__init__.py +12 -1
- webscout/auth/providers.py +27 -5
- webscout/auth/routes.py +146 -105
- webscout/auth/server.py +367 -312
- webscout/client.py +121 -116
- webscout/litagent/Readme.md +68 -55
- webscout/litagent/agent.py +99 -9
- webscout/version.py +1 -1
- {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/METADATA +102 -91
- {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/RECORD +95 -107
- webscout/Provider/AI21.py +0 -177
- webscout/Provider/HuggingFaceChat.py +0 -469
- webscout/Provider/OPENAI/freeaichat.py +0 -363
- webscout/Provider/TTI/fastflux.py +0 -233
- webscout/Provider/Writecream.py +0 -246
- webscout/auth/static/favicon.svg +0 -11
- webscout/auth/swagger_ui.py +0 -203
- webscout/auth/templates/components/authentication.html +0 -237
- webscout/auth/templates/components/base.html +0 -103
- webscout/auth/templates/components/endpoints.html +0 -750
- webscout/auth/templates/components/examples.html +0 -491
- webscout/auth/templates/components/footer.html +0 -75
- webscout/auth/templates/components/header.html +0 -27
- webscout/auth/templates/components/models.html +0 -286
- webscout/auth/templates/components/navigation.html +0 -70
- webscout/auth/templates/static/api.js +0 -455
- webscout/auth/templates/static/icons.js +0 -168
- webscout/auth/templates/static/main.js +0 -784
- webscout/auth/templates/static/particles.js +0 -201
- webscout/auth/templates/static/styles.css +0 -3353
- webscout/auth/templates/static/ui.js +0 -374
- webscout/auth/templates/swagger_ui.html +0 -170
- {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/WHEEL +0 -0
- {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/entry_points.txt +0 -0
- {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.3.2.dist-info → webscout-8.3.4.dist-info}/top_level.txt +0 -0
webscout/Provider/yep.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import uuid
|
|
2
|
-
import json
|
|
3
2
|
from curl_cffi import CurlError
|
|
4
3
|
from curl_cffi.requests import Session
|
|
5
4
|
|
|
6
5
|
from typing import Any, Dict, Optional, Generator, Union, List, TypeVar
|
|
7
|
-
|
|
8
6
|
from webscout.AIutel import Optimizers
|
|
9
7
|
from webscout.AIutel import AwesomePrompts, sanitize_stream # Import sanitize_stream
|
|
10
8
|
from webscout.AIbase import Provider
|
|
@@ -192,81 +190,63 @@ class YEPCHAT(Provider):
|
|
|
192
190
|
|
|
193
191
|
def for_stream():
|
|
194
192
|
try:
|
|
195
|
-
# buffer = b"" # No longer needed here
|
|
196
|
-
# Use curl_cffi session post, pass cookies explicitly
|
|
197
193
|
response = self.session.post(self.chat_endpoint, headers=self.headers, cookies=self.cookies, json=data, stream=True, timeout=self.timeout, impersonate=self.fingerprint.get("browser_type", "chrome110"))
|
|
198
|
-
|
|
199
194
|
if not response.ok:
|
|
200
|
-
# If we get a non-200 response, try refreshing our identity once
|
|
201
195
|
if response.status_code in [403, 429]:
|
|
202
196
|
self.refresh_identity()
|
|
203
|
-
# Retry with new identity
|
|
204
|
-
# Use curl_cffi session post, pass cookies explicitly
|
|
205
197
|
retry_response = self.session.post(self.chat_endpoint, headers=self.headers, cookies=self.cookies, json=data, stream=True, timeout=self.timeout, impersonate=self.fingerprint.get("browser_type", "chrome110"))
|
|
206
198
|
if not retry_response.ok:
|
|
207
199
|
raise exceptions.FailedToGenerateResponseError(
|
|
208
200
|
f"Failed to generate response after identity refresh - ({retry_response.status_code}, {retry_response.reason}) - {retry_response.text}"
|
|
209
201
|
)
|
|
210
|
-
response = retry_response
|
|
202
|
+
response = retry_response
|
|
211
203
|
else:
|
|
212
204
|
raise exceptions.FailedToGenerateResponseError(
|
|
213
205
|
f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}"
|
|
214
206
|
)
|
|
215
|
-
|
|
216
|
-
# --- Start of stream processing block (should be outside the 'if not response.ok' block) ---
|
|
217
207
|
streaming_text = ""
|
|
218
|
-
|
|
219
|
-
# Use sanitize_stream to process the lines
|
|
220
208
|
processed_stream = sanitize_stream(
|
|
221
|
-
data=response.iter_content(chunk_size=None),
|
|
209
|
+
data=response.iter_content(chunk_size=None),
|
|
222
210
|
intro_value="data:",
|
|
223
|
-
to_json=True,
|
|
224
|
-
skip_markers=["[DONE]"],
|
|
225
|
-
yield_raw_on_error=False,
|
|
226
|
-
|
|
227
|
-
|
|
211
|
+
to_json=True,
|
|
212
|
+
skip_markers=["[DONE]"],
|
|
213
|
+
yield_raw_on_error=False,
|
|
214
|
+
content_extractor=lambda chunk: chunk.get('choices', [{}])[0].get('delta', {}).get('content') if isinstance(chunk, dict) else None,
|
|
215
|
+
raw=raw
|
|
228
216
|
)
|
|
229
|
-
# The loop now yields the final extracted string content directly
|
|
230
217
|
for content_chunk in processed_stream:
|
|
231
|
-
#
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
yield dict(text=content_chunk) if not raw else content_chunk
|
|
237
|
-
# --- End of stream processing block ---
|
|
238
|
-
|
|
239
|
-
# Check if the response contains a tool call (This should happen *after* processing the stream)
|
|
240
|
-
response_data = self.conversation.handle_tool_response(streaming_text)
|
|
241
|
-
|
|
242
|
-
if response_data["is_tool_call"]:
|
|
243
|
-
# Handle tool call results
|
|
244
|
-
if response_data["success"]:
|
|
245
|
-
for tool_call in response_data.get("tool_calls", []):
|
|
246
|
-
tool_name = tool_call.get("name", "unknown_tool")
|
|
247
|
-
result = response_data["result"]
|
|
248
|
-
self.conversation.update_chat_history_with_tool(prompt, tool_name, result)
|
|
218
|
+
# Always yield as string, even in raw mode
|
|
219
|
+
if isinstance(content_chunk, bytes):
|
|
220
|
+
content_chunk = content_chunk.decode('utf-8', errors='ignore')
|
|
221
|
+
if raw:
|
|
222
|
+
yield content_chunk
|
|
249
223
|
else:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
224
|
+
if content_chunk and isinstance(content_chunk, str):
|
|
225
|
+
streaming_text += content_chunk
|
|
226
|
+
yield dict(text=content_chunk)
|
|
227
|
+
if not raw:
|
|
228
|
+
response_data = self.conversation.handle_tool_response(streaming_text)
|
|
229
|
+
if response_data["is_tool_call"]:
|
|
230
|
+
if response_data["success"]:
|
|
231
|
+
for tool_call in response_data.get("tool_calls", []):
|
|
232
|
+
tool_name = tool_call.get("name", "unknown_tool")
|
|
233
|
+
result = response_data["result"]
|
|
234
|
+
self.conversation.update_chat_history_with_tool(prompt, tool_name, result)
|
|
235
|
+
else:
|
|
236
|
+
self.conversation.update_chat_history(prompt, f"Error executing tool call: {response_data['result']}")
|
|
237
|
+
else:
|
|
238
|
+
self.conversation.update_chat_history(prompt, streaming_text)
|
|
239
|
+
except CurlError as e:
|
|
240
|
+
raise exceptions.FailedToGenerateResponseError(f"Request failed (CurlError): {e}")
|
|
259
241
|
except Exception as e:
|
|
260
242
|
raise exceptions.FailedToGenerateResponseError(f"Request failed: {e}")
|
|
261
243
|
|
|
262
244
|
def for_non_stream():
|
|
263
245
|
try:
|
|
264
|
-
# Use curl_cffi session post, pass cookies explicitly
|
|
265
246
|
response = self.session.post(self.chat_endpoint, headers=self.headers, cookies=self.cookies, json=data, timeout=self.timeout, impersonate=self.fingerprint.get("browser_type", "chrome110"))
|
|
266
247
|
if not response.ok:
|
|
267
248
|
if response.status_code in [403, 429]:
|
|
268
249
|
self.refresh_identity()
|
|
269
|
-
# Use curl_cffi session post, pass cookies explicitly
|
|
270
250
|
response = self.session.post(self.chat_endpoint, headers=self.headers, cookies=self.cookies, json=data, timeout=self.timeout, impersonate=self.fingerprint.get("browser_type", "chrome110"))
|
|
271
251
|
if not response.ok:
|
|
272
252
|
raise exceptions.FailedToGenerateResponseError(
|
|
@@ -276,40 +256,28 @@ class YEPCHAT(Provider):
|
|
|
276
256
|
raise exceptions.FailedToGenerateResponseError(
|
|
277
257
|
f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}"
|
|
278
258
|
)
|
|
279
|
-
|
|
280
|
-
|
|
259
|
+
if raw:
|
|
260
|
+
return response.text
|
|
281
261
|
response_data = response.json()
|
|
282
262
|
if 'choices' in response_data and len(response_data['choices']) > 0:
|
|
283
263
|
content = response_data['choices'][0].get('message', {}).get('content', '')
|
|
284
|
-
|
|
285
|
-
# Check if the response contains a tool call
|
|
286
264
|
tool_response = self.conversation.handle_tool_response(content)
|
|
287
|
-
|
|
288
265
|
if tool_response["is_tool_call"]:
|
|
289
|
-
# Process tool call
|
|
290
266
|
if tool_response["success"]:
|
|
291
|
-
# Get the first tool call for simplicity
|
|
292
267
|
if "tool_calls" in tool_response and len(tool_response["tool_calls"]) > 0:
|
|
293
268
|
tool_call = tool_response["tool_calls"][0]
|
|
294
269
|
tool_name = tool_call.get("name", "unknown_tool")
|
|
295
270
|
tool_result = tool_response["result"]
|
|
296
|
-
|
|
297
|
-
# Update chat history with tool call
|
|
298
271
|
self.conversation.update_chat_history_with_tool(prompt, tool_name, tool_result)
|
|
299
|
-
|
|
300
|
-
# Return tool result
|
|
301
272
|
return {"text": tool_result, "is_tool_call": True, "tool_name": tool_name}
|
|
302
|
-
|
|
303
|
-
# If tool call processing failed
|
|
304
273
|
return {"text": tool_response["result"], "is_tool_call": True, "error": True}
|
|
305
274
|
else:
|
|
306
|
-
# Normal response handling
|
|
307
275
|
self.conversation.update_chat_history(prompt, content)
|
|
308
276
|
return {"text": content}
|
|
309
277
|
else:
|
|
310
278
|
raise exceptions.FailedToGenerateResponseError("No response content found")
|
|
311
|
-
except CurlError as e:
|
|
312
|
-
|
|
279
|
+
except CurlError as e:
|
|
280
|
+
raise exceptions.FailedToGenerateResponseError(f"Request failed (CurlError): {e}")
|
|
313
281
|
except Exception as e:
|
|
314
282
|
raise exceptions.FailedToGenerateResponseError(f"Request failed: {e}")
|
|
315
283
|
|
|
@@ -321,6 +289,7 @@ class YEPCHAT(Provider):
|
|
|
321
289
|
stream: bool = False,
|
|
322
290
|
optimizer: str = None,
|
|
323
291
|
conversationally: bool = False,
|
|
292
|
+
raw: bool = False, # Added raw parameter
|
|
324
293
|
) -> Union[str, Generator[str, None, None]]:
|
|
325
294
|
"""
|
|
326
295
|
Initiates a chat with the Yep API using the provided prompt.
|
|
@@ -335,19 +304,25 @@ class YEPCHAT(Provider):
|
|
|
335
304
|
"""
|
|
336
305
|
def for_stream():
|
|
337
306
|
for response in self.ask(
|
|
338
|
-
prompt, True, optimizer=optimizer, conversationally=conversationally
|
|
307
|
+
prompt, True, raw=raw, optimizer=optimizer, conversationally=conversationally
|
|
339
308
|
):
|
|
340
|
-
|
|
309
|
+
if raw:
|
|
310
|
+
yield response
|
|
311
|
+
else:
|
|
312
|
+
yield self.get_message(response)
|
|
341
313
|
|
|
342
314
|
def for_non_stream():
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
)
|
|
315
|
+
result = self.ask(
|
|
316
|
+
prompt,
|
|
317
|
+
False,
|
|
318
|
+
raw=raw,
|
|
319
|
+
optimizer=optimizer,
|
|
320
|
+
conversationally=conversationally,
|
|
350
321
|
)
|
|
322
|
+
if raw:
|
|
323
|
+
return result
|
|
324
|
+
else:
|
|
325
|
+
return self.get_message(result)
|
|
351
326
|
|
|
352
327
|
return for_stream() if stream else for_non_stream()
|
|
353
328
|
|
|
@@ -361,29 +336,37 @@ class YEPCHAT(Provider):
|
|
|
361
336
|
>>> ai.get_message(response)
|
|
362
337
|
Extracts and returns the message content from the response.
|
|
363
338
|
"""
|
|
364
|
-
|
|
365
|
-
|
|
339
|
+
if isinstance(response, dict):
|
|
340
|
+
return response["text"]
|
|
341
|
+
elif isinstance(response, (str, bytes)):
|
|
342
|
+
return response
|
|
343
|
+
else:
|
|
344
|
+
raise TypeError(f"Unexpected response type: {type(response)}")
|
|
366
345
|
|
|
367
346
|
|
|
368
347
|
if __name__ == "__main__":
|
|
369
|
-
print("-" * 80)
|
|
370
|
-
print(f"{'Model':<50} {'Status':<10} {'Response'}")
|
|
371
|
-
print("-" * 80)
|
|
372
|
-
|
|
373
|
-
for model in YEPCHAT.AVAILABLE_MODELS:
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
348
|
+
# print("-" * 80)
|
|
349
|
+
# print(f"{'Model':<50} {'Status':<10} {'Response'}")
|
|
350
|
+
# print("-" * 80)
|
|
351
|
+
|
|
352
|
+
# for model in YEPCHAT.AVAILABLE_MODELS:
|
|
353
|
+
# try:
|
|
354
|
+
# test_ai = YEPCHAT(model=model, timeout=60)
|
|
355
|
+
# response = test_ai.chat("Say 'Hello' in one word")
|
|
356
|
+
# response_text = response
|
|
378
357
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
358
|
+
# if response_text and len(response_text.strip()) > 0:
|
|
359
|
+
# status = "✓"
|
|
360
|
+
# # Truncate response if too long
|
|
361
|
+
# display_text = response_text.strip()[:50] + "..." if len(response_text.strip()) > 50 else response_text.strip()
|
|
362
|
+
# else:
|
|
363
|
+
# status = "✗"
|
|
364
|
+
# display_text = "Empty or invalid response"
|
|
365
|
+
# print(f"{model:<50} {status:<10} {display_text}")
|
|
366
|
+
# except Exception as e:
|
|
367
|
+
# print(f"{model:<50} {'✗':<10} {str(e)}")
|
|
368
|
+
ai = YEPCHAT(model="DeepSeek-R1-Distill-Qwen-32B", timeout=60)
|
|
369
|
+
response = ai.chat("Say 'Hello' in one word", raw=True, stream=True)
|
|
370
|
+
for chunk in response:
|
|
371
|
+
|
|
372
|
+
print(chunk, end='', flush=True)
|
webscout/__init__.py
CHANGED
|
@@ -17,8 +17,13 @@ from .litagent import LitAgent
|
|
|
17
17
|
from .scout import *
|
|
18
18
|
from .zeroart import *
|
|
19
19
|
from .yep_search import *
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
# Import litprinter components for direct access from webscout (uncomment if needed)
|
|
21
22
|
# from .litprinter import lit, litprint, ic, install, uninstall
|
|
23
|
+
|
|
24
|
+
# Import sanitize_stream and lit_streamer for easy access
|
|
25
|
+
from .AIutel import sanitize_stream, lit_streamer, LITSTREAM
|
|
26
|
+
|
|
22
27
|
agent = LitAgent()
|
|
23
28
|
|
|
24
29
|
__repo__ = "https://github.com/OE-LUCIFER/Webscout"
|
|
@@ -30,7 +35,7 @@ try:
|
|
|
30
35
|
if update_message:
|
|
31
36
|
print(update_message)
|
|
32
37
|
except Exception:
|
|
33
|
-
pass # Silently handle any update check
|
|
38
|
+
pass # Silently handle any update check errors
|
|
34
39
|
|
|
35
40
|
import logging
|
|
36
41
|
logging.getLogger("webscout").addHandler(logging.NullHandler())
|
webscout/auth/__init__.py
CHANGED
|
@@ -13,7 +13,18 @@ from .schemas import (
|
|
|
13
13
|
UserResponse,
|
|
14
14
|
HealthCheckResponse
|
|
15
15
|
)
|
|
16
|
-
|
|
16
|
+
# Import server functions lazily to avoid module execution issues
|
|
17
|
+
def create_app():
|
|
18
|
+
from .server import create_app as _create_app
|
|
19
|
+
return _create_app()
|
|
20
|
+
|
|
21
|
+
def run_api(*args, **kwargs):
|
|
22
|
+
from .server import run_api as _run_api
|
|
23
|
+
return _run_api(*args, **kwargs)
|
|
24
|
+
|
|
25
|
+
def start_server(*args, **kwargs):
|
|
26
|
+
from .server import start_server as _start_server
|
|
27
|
+
return _start_server(*args, **kwargs)
|
|
17
28
|
from .routes import Api
|
|
18
29
|
from .config import ServerConfig, AppConfig
|
|
19
30
|
from .exceptions import APIError
|
webscout/auth/providers.py
CHANGED
|
@@ -87,13 +87,13 @@ def initialize_tti_provider_map() -> None:
|
|
|
87
87
|
logger.info("Initializing TTI provider map...")
|
|
88
88
|
|
|
89
89
|
try:
|
|
90
|
-
import webscout.Provider.TTI as tti_module
|
|
91
90
|
from webscout.Provider.TTI.base import TTICompatibleProvider
|
|
92
|
-
|
|
91
|
+
module = sys.modules["webscout.Provider.TTI"]
|
|
92
|
+
|
|
93
93
|
provider_count = 0
|
|
94
94
|
model_count = 0
|
|
95
95
|
|
|
96
|
-
for name, obj in inspect.getmembers(
|
|
96
|
+
for name, obj in inspect.getmembers(module):
|
|
97
97
|
if (
|
|
98
98
|
inspect.isclass(obj)
|
|
99
99
|
and issubclass(obj, TTICompatibleProvider)
|
|
@@ -242,7 +242,18 @@ def get_provider_instance(provider_class: Any):
|
|
|
242
242
|
key = provider_class.__name__
|
|
243
243
|
instance = provider_instances.get(key)
|
|
244
244
|
if instance is None:
|
|
245
|
-
|
|
245
|
+
try:
|
|
246
|
+
instance = provider_class()
|
|
247
|
+
except TypeError as e:
|
|
248
|
+
# Handle abstract class instantiation error
|
|
249
|
+
if "abstract class" in str(e):
|
|
250
|
+
from .exceptions import APIError
|
|
251
|
+
raise APIError(
|
|
252
|
+
f"Provider misconfiguration: Cannot instantiate abstract class '{provider_class.__name__}'. Please check the provider implementation.",
|
|
253
|
+
HTTP_500_INTERNAL_SERVER_ERROR,
|
|
254
|
+
"provider_error"
|
|
255
|
+
)
|
|
256
|
+
raise
|
|
246
257
|
provider_instances[key] = instance
|
|
247
258
|
return instance
|
|
248
259
|
|
|
@@ -252,6 +263,17 @@ def get_tti_provider_instance(provider_class: Any):
|
|
|
252
263
|
key = provider_class.__name__
|
|
253
264
|
instance = tti_provider_instances.get(key)
|
|
254
265
|
if instance is None:
|
|
255
|
-
|
|
266
|
+
try:
|
|
267
|
+
instance = provider_class()
|
|
268
|
+
except TypeError as e:
|
|
269
|
+
# Handle abstract class instantiation error
|
|
270
|
+
if "abstract class" in str(e):
|
|
271
|
+
from .exceptions import APIError
|
|
272
|
+
raise APIError(
|
|
273
|
+
f"Provider misconfiguration: Cannot instantiate abstract class '{provider_class.__name__}'. Please check the provider implementation.",
|
|
274
|
+
HTTP_500_INTERNAL_SERVER_ERROR,
|
|
275
|
+
"provider_error",
|
|
276
|
+
)
|
|
277
|
+
raise
|
|
256
278
|
tti_provider_instances[key] = instance
|
|
257
279
|
return instance
|