webscout 8.3__py3-none-any.whl → 8.3.2__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/AIauto.py +4 -4
- webscout/AIbase.py +61 -1
- webscout/AIutel.py +46 -53
- webscout/Bing_search.py +418 -0
- webscout/Extra/YTToolkit/ytapi/patterns.py +45 -45
- webscout/Extra/YTToolkit/ytapi/stream.py +1 -1
- webscout/Extra/YTToolkit/ytapi/video.py +10 -10
- webscout/Extra/autocoder/autocoder_utiles.py +1 -1
- webscout/Extra/gguf.py +706 -177
- webscout/Litlogger/formats.py +9 -0
- webscout/Litlogger/handlers.py +18 -0
- webscout/Litlogger/logger.py +43 -1
- webscout/Provider/AISEARCH/genspark_search.py +7 -7
- webscout/Provider/AISEARCH/scira_search.py +3 -2
- webscout/Provider/GeminiProxy.py +140 -0
- webscout/Provider/LambdaChat.py +7 -1
- webscout/Provider/MCPCore.py +78 -75
- webscout/Provider/OPENAI/BLACKBOXAI.py +1046 -1017
- webscout/Provider/OPENAI/GeminiProxy.py +328 -0
- webscout/Provider/OPENAI/Qwen3.py +303 -303
- webscout/Provider/OPENAI/README.md +5 -0
- webscout/Provider/OPENAI/README_AUTOPROXY.md +238 -0
- webscout/Provider/OPENAI/TogetherAI.py +355 -0
- webscout/Provider/OPENAI/__init__.py +16 -1
- webscout/Provider/OPENAI/autoproxy.py +332 -0
- webscout/Provider/OPENAI/base.py +101 -14
- webscout/Provider/OPENAI/chatgpt.py +15 -2
- webscout/Provider/OPENAI/chatgptclone.py +14 -3
- webscout/Provider/OPENAI/deepinfra.py +339 -328
- webscout/Provider/OPENAI/e2b.py +295 -74
- webscout/Provider/OPENAI/mcpcore.py +109 -70
- webscout/Provider/OPENAI/opkfc.py +18 -6
- webscout/Provider/OPENAI/scirachat.py +59 -50
- webscout/Provider/OPENAI/toolbaz.py +2 -10
- webscout/Provider/OPENAI/writecream.py +166 -166
- webscout/Provider/OPENAI/x0gpt.py +367 -367
- webscout/Provider/OPENAI/xenai.py +514 -0
- webscout/Provider/OPENAI/yep.py +389 -383
- webscout/Provider/STT/__init__.py +3 -0
- webscout/Provider/STT/base.py +281 -0
- webscout/Provider/STT/elevenlabs.py +265 -0
- webscout/Provider/TTI/__init__.py +4 -1
- webscout/Provider/TTI/aiarta.py +399 -365
- webscout/Provider/TTI/base.py +74 -2
- webscout/Provider/TTI/bing.py +231 -0
- webscout/Provider/TTI/fastflux.py +63 -30
- webscout/Provider/TTI/gpt1image.py +149 -0
- webscout/Provider/TTI/imagen.py +196 -0
- webscout/Provider/TTI/magicstudio.py +60 -29
- webscout/Provider/TTI/piclumen.py +43 -32
- webscout/Provider/TTI/pixelmuse.py +232 -225
- webscout/Provider/TTI/pollinations.py +43 -32
- webscout/Provider/TTI/together.py +287 -0
- webscout/Provider/TTI/utils.py +2 -1
- webscout/Provider/TTS/README.md +1 -0
- webscout/Provider/TTS/__init__.py +2 -1
- webscout/Provider/TTS/freetts.py +140 -0
- webscout/Provider/TTS/speechma.py +45 -39
- webscout/Provider/TogetherAI.py +366 -0
- webscout/Provider/UNFINISHED/ChutesAI.py +314 -0
- webscout/Provider/UNFINISHED/fetch_together_models.py +95 -0
- webscout/Provider/XenAI.py +324 -0
- webscout/Provider/__init__.py +8 -0
- webscout/Provider/deepseek_assistant.py +378 -0
- webscout/Provider/scira_chat.py +3 -2
- webscout/Provider/toolbaz.py +0 -1
- webscout/auth/__init__.py +44 -0
- webscout/auth/api_key_manager.py +189 -0
- webscout/auth/auth_system.py +100 -0
- webscout/auth/config.py +76 -0
- webscout/auth/database.py +400 -0
- webscout/auth/exceptions.py +67 -0
- webscout/auth/middleware.py +248 -0
- webscout/auth/models.py +130 -0
- webscout/auth/providers.py +257 -0
- webscout/auth/rate_limiter.py +254 -0
- webscout/auth/request_models.py +127 -0
- webscout/auth/request_processing.py +226 -0
- webscout/auth/routes.py +526 -0
- webscout/auth/schemas.py +103 -0
- webscout/auth/server.py +312 -0
- webscout/auth/static/favicon.svg +11 -0
- webscout/auth/swagger_ui.py +203 -0
- webscout/auth/templates/components/authentication.html +237 -0
- webscout/auth/templates/components/base.html +103 -0
- webscout/auth/templates/components/endpoints.html +750 -0
- webscout/auth/templates/components/examples.html +491 -0
- webscout/auth/templates/components/footer.html +75 -0
- webscout/auth/templates/components/header.html +27 -0
- webscout/auth/templates/components/models.html +286 -0
- webscout/auth/templates/components/navigation.html +70 -0
- webscout/auth/templates/static/api.js +455 -0
- webscout/auth/templates/static/icons.js +168 -0
- webscout/auth/templates/static/main.js +784 -0
- webscout/auth/templates/static/particles.js +201 -0
- webscout/auth/templates/static/styles.css +3353 -0
- webscout/auth/templates/static/ui.js +374 -0
- webscout/auth/templates/swagger_ui.html +170 -0
- webscout/client.py +49 -3
- webscout/litagent/Readme.md +12 -3
- webscout/litagent/agent.py +99 -62
- webscout/scout/core/scout.py +104 -26
- webscout/scout/element.py +139 -18
- webscout/swiftcli/core/cli.py +14 -3
- webscout/swiftcli/decorators/output.py +59 -9
- webscout/update_checker.py +31 -49
- webscout/version.py +1 -1
- webscout/webscout_search.py +4 -12
- webscout/webscout_search_async.py +3 -10
- webscout/yep_search.py +2 -11
- {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/METADATA +41 -11
- {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/RECORD +116 -68
- {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/entry_points.txt +1 -1
- webscout/Provider/HF_space/__init__.py +0 -0
- webscout/Provider/HF_space/qwen_qwen2.py +0 -206
- webscout/Provider/OPENAI/api.py +0 -1035
- webscout/Provider/TTI/artbit.py +0 -0
- {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/WHEEL +0 -0
- {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/top_level.txt +0 -0
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
##################################################################################
|
|
2
2
|
## Modified version of code written by t.me/infip1217 ##
|
|
3
3
|
##################################################################################
|
|
4
|
-
import time
|
|
5
4
|
import requests
|
|
6
5
|
import pathlib
|
|
7
6
|
import tempfile
|
|
8
|
-
from io import BytesIO
|
|
9
7
|
from webscout import exceptions
|
|
10
8
|
from webscout.litagent import LitAgent
|
|
11
|
-
from
|
|
12
|
-
from webscout.Provider.TTS import utils
|
|
9
|
+
from webscout.Litlogger import Logger, LogLevel
|
|
13
10
|
from webscout.Provider.TTS.base import BaseTTSProvider
|
|
14
11
|
|
|
15
12
|
class SpeechMaTTS(BaseTTSProvider):
|
|
@@ -18,12 +15,11 @@ class SpeechMaTTS(BaseTTSProvider):
|
|
|
18
15
|
"""
|
|
19
16
|
# Request headers
|
|
20
17
|
headers = {
|
|
21
|
-
"
|
|
22
|
-
"accept-language": "en-IN,en-GB;q=0.9,en-US;q=0.8,en;q=0.7,en-AU;q=0.6",
|
|
23
|
-
"content-type": "application/json",
|
|
18
|
+
"authority": "speechma.com",
|
|
24
19
|
"origin": "https://speechma.com",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
20
|
+
"referer": "https://speechma.com/",
|
|
21
|
+
"content-type": "application/json",
|
|
22
|
+
**LitAgent().generate_fingerprint()
|
|
27
23
|
}
|
|
28
24
|
|
|
29
25
|
# Available voices with their IDs
|
|
@@ -496,8 +492,9 @@ class SpeechMaTTS(BaseTTSProvider):
|
|
|
496
492
|
if proxies:
|
|
497
493
|
self.session.proxies.update(proxies)
|
|
498
494
|
self.timeout = timeout
|
|
495
|
+
self.logger = Logger(name="SpeechMaTTS", level=LogLevel.INFO)
|
|
499
496
|
|
|
500
|
-
def tts(self, text: str, voice: str = "Emma", pitch: int = 0, rate: int = 0) -> str:
|
|
497
|
+
def tts(self, text: str, voice: str = "Emma", pitch: int = 0, rate: int = 0, verbose: bool = False) -> str:
|
|
501
498
|
"""
|
|
502
499
|
Converts text to speech using the SpeechMa API and saves it to a file.
|
|
503
500
|
|
|
@@ -506,6 +503,7 @@ class SpeechMaTTS(BaseTTSProvider):
|
|
|
506
503
|
voice (str): The voice to use for TTS (default: "Emma")
|
|
507
504
|
pitch (int): Voice pitch adjustment (-10 to 10, default: 0)
|
|
508
505
|
rate (int): Voice rate/speed adjustment (-10 to 10, default: 0)
|
|
506
|
+
verbose (bool): Whether to print debug information (default: False)
|
|
509
507
|
|
|
510
508
|
Returns:
|
|
511
509
|
str: Path to the generated audio file
|
|
@@ -517,10 +515,13 @@ class SpeechMaTTS(BaseTTSProvider):
|
|
|
517
515
|
voice in self.all_voices
|
|
518
516
|
), f"Voice '{voice}' not one of [{', '.join(self.all_voices.keys())}]"
|
|
519
517
|
|
|
518
|
+
if not text or text.strip() == '':
|
|
519
|
+
raise exceptions.FailedToGenerateResponseError("Text is empty")
|
|
520
|
+
|
|
520
521
|
filename = pathlib.Path(tempfile.mktemp(suffix=".mp3", dir=self.temp_dir))
|
|
521
522
|
voice_id = self.all_voices[voice]
|
|
522
523
|
|
|
523
|
-
# Prepare payload for the
|
|
524
|
+
# Prepare payload for the API
|
|
524
525
|
payload = {
|
|
525
526
|
"text": text,
|
|
526
527
|
"voice": voice_id,
|
|
@@ -530,44 +531,49 @@ class SpeechMaTTS(BaseTTSProvider):
|
|
|
530
531
|
}
|
|
531
532
|
|
|
532
533
|
try:
|
|
534
|
+
# Set logger level based on verbose flag
|
|
535
|
+
if verbose:
|
|
536
|
+
self.logger.level = LogLevel.DEBUG
|
|
537
|
+
self.logger.debug(f"Generating audio for voice: {voice} ({voice_id})")
|
|
538
|
+
self.logger.debug(f"Text length: {len(text)} characters")
|
|
539
|
+
else:
|
|
540
|
+
self.logger.level = LogLevel.INFO
|
|
541
|
+
|
|
542
|
+
# Make the request to the SpeechMa API
|
|
533
543
|
response = self.session.post(
|
|
534
544
|
self.api_url,
|
|
535
545
|
headers=self.headers,
|
|
536
546
|
json=payload,
|
|
537
547
|
timeout=self.timeout
|
|
538
548
|
)
|
|
539
|
-
response.raise_for_status()
|
|
540
|
-
resp_json = response.json()
|
|
541
|
-
if not resp_json.get("success") or "data" not in resp_json or "job_id" not in resp_json["data"]:
|
|
542
|
-
raise exceptions.FailedToGenerateResponseError(f"SpeechMa API error: {resp_json}")
|
|
543
|
-
job_id = resp_json["data"]["job_id"]
|
|
544
549
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
status_url,
|
|
550
|
-
headers=self.headers,
|
|
551
|
-
timeout=self.timeout
|
|
552
|
-
)
|
|
553
|
-
status_resp.raise_for_status()
|
|
554
|
-
status_json = status_resp.json()
|
|
555
|
-
if status_json.get("success") and status_json.get("data", {}).get("status") == "completed":
|
|
556
|
-
break
|
|
557
|
-
time.sleep(1)
|
|
558
|
-
else:
|
|
559
|
-
raise exceptions.FailedToGenerateResponseError("TTS job did not complete in time.")
|
|
550
|
+
if response.status_code != 200:
|
|
551
|
+
if verbose:
|
|
552
|
+
self.logger.error(f"API error: Status {response.status_code}")
|
|
553
|
+
raise exceptions.FailedToGenerateResponseError(f"API returned status {response.status_code}: {response.text[:500]}")
|
|
560
554
|
|
|
561
|
-
#
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
555
|
+
# Check if response is audio data (content-type should be audio/mpeg)
|
|
556
|
+
content_type = response.headers.get('content-type', '').lower()
|
|
557
|
+
if verbose:
|
|
558
|
+
self.logger.debug(f"Response content type: {content_type}")
|
|
559
|
+
self.logger.debug(f"Response size: {len(response.content)} bytes")
|
|
560
|
+
|
|
561
|
+
if 'audio' in content_type or response.content.startswith(b'\xff\xfb') or response.content.startswith(b'ID3') or b'LAME' in response.content[:100]:
|
|
562
|
+
# This is audio data, save it directly
|
|
563
|
+
with open(filename, 'wb') as f:
|
|
564
|
+
f.write(response.content)
|
|
565
|
+
if verbose:
|
|
566
|
+
self.logger.debug(f"Audio saved to: {filename}")
|
|
567
|
+
return filename.as_posix()
|
|
568
|
+
else:
|
|
569
|
+
# Unexpected response format
|
|
570
|
+
if verbose:
|
|
571
|
+
self.logger.error(f"Unexpected response format: {content_type}")
|
|
572
|
+
raise exceptions.FailedToGenerateResponseError(f"Unexpected response format. Content-Type: {content_type}, Content: {response.text[:200]}")
|
|
569
573
|
|
|
570
574
|
except requests.exceptions.RequestException as e:
|
|
575
|
+
if verbose:
|
|
576
|
+
self.logger.error(f"Request failed: {e}")
|
|
571
577
|
raise exceptions.FailedToGenerateResponseError(
|
|
572
578
|
f"Failed to perform the operation: {e}"
|
|
573
579
|
)
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
from curl_cffi.requests import Session
|
|
2
|
+
from curl_cffi import CurlError
|
|
3
|
+
from typing import Any, Dict, Optional, Generator, Union
|
|
4
|
+
|
|
5
|
+
from webscout.AIutel import Optimizers
|
|
6
|
+
from webscout.AIutel import Conversation
|
|
7
|
+
from webscout.AIutel import AwesomePrompts, sanitize_stream
|
|
8
|
+
from webscout.AIbase import Provider
|
|
9
|
+
from webscout import exceptions
|
|
10
|
+
from webscout.litagent import LitAgent
|
|
11
|
+
|
|
12
|
+
class TogetherAI(Provider):
|
|
13
|
+
"""
|
|
14
|
+
A class to interact with the TogetherAI API.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
AVAILABLE_MODELS = [
|
|
18
|
+
"Gryphe/MythoMax-L2-13b",
|
|
19
|
+
"Gryphe/MythoMax-L2-13b-Lite",
|
|
20
|
+
"NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
|
|
21
|
+
"Qwen/QwQ-32B",
|
|
22
|
+
"Qwen/Qwen2-72B-Instruct",
|
|
23
|
+
"Qwen/Qwen2-VL-72B-Instruct",
|
|
24
|
+
"Qwen/Qwen2.5-72B-Instruct-Turbo",
|
|
25
|
+
"Qwen/Qwen2.5-7B-Instruct-Turbo",
|
|
26
|
+
"Qwen/Qwen2.5-Coder-32B-Instruct",
|
|
27
|
+
"Qwen/Qwen2.5-VL-72B-Instruct",
|
|
28
|
+
"Qwen/Qwen3-235B-A22B-fp8",
|
|
29
|
+
"Qwen/Qwen3-235B-A22B-fp8-tput",
|
|
30
|
+
"Rrrr/meta-llama/Llama-3-70b-chat-hf-6f9ad551",
|
|
31
|
+
"Rrrr/meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo-03dc18e1",
|
|
32
|
+
"Rrrr/meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo-6c92f39d",
|
|
33
|
+
"arcee-ai/arcee-blitz",
|
|
34
|
+
"arcee-ai/caller",
|
|
35
|
+
"arcee-ai/coder-large",
|
|
36
|
+
"arcee-ai/maestro-reasoning",
|
|
37
|
+
"arcee-ai/virtuoso-large",
|
|
38
|
+
"arcee-ai/virtuoso-medium-v2",
|
|
39
|
+
"arcee_ai/arcee-spotlight",
|
|
40
|
+
"blackbox/meta-llama-3-1-8b",
|
|
41
|
+
"deepseek-ai/DeepSeek-R1",
|
|
42
|
+
"deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
|
|
43
|
+
"deepseek-ai/DeepSeek-R1-Distill-Llama-70B-free",
|
|
44
|
+
"deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B",
|
|
45
|
+
"deepseek-ai/DeepSeek-R1-Distill-Qwen-14B",
|
|
46
|
+
"deepseek-ai/DeepSeek-V3",
|
|
47
|
+
"deepseek-ai/DeepSeek-V3-p-dp",
|
|
48
|
+
"google/gemma-2-27b-it",
|
|
49
|
+
"google/gemma-2b-it",
|
|
50
|
+
"lgai/exaone-3-5-32b-instruct",
|
|
51
|
+
"lgai/exaone-deep-32b",
|
|
52
|
+
"marin-community/marin-8b-instruct",
|
|
53
|
+
"meta-llama/Llama-3-70b-chat-hf",
|
|
54
|
+
"meta-llama/Llama-3-8b-chat-hf",
|
|
55
|
+
"meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo",
|
|
56
|
+
"meta-llama/Llama-3.2-3B-Instruct-Turbo",
|
|
57
|
+
"meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo",
|
|
58
|
+
"meta-llama/Llama-3.3-70B-Instruct-Turbo",
|
|
59
|
+
"meta-llama/Llama-3.3-70B-Instruct-Turbo-Free",
|
|
60
|
+
"meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8",
|
|
61
|
+
"meta-llama/Llama-4-Scout-17B-16E-Instruct",
|
|
62
|
+
"meta-llama/Llama-Vision-Free",
|
|
63
|
+
"meta-llama/Meta-Llama-3-70B-Instruct-Turbo",
|
|
64
|
+
"meta-llama/Meta-Llama-3-8B-Instruct-Lite",
|
|
65
|
+
"meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo",
|
|
66
|
+
"meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo",
|
|
67
|
+
"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
|
|
68
|
+
"mistralai/Mistral-7B-Instruct-v0.1",
|
|
69
|
+
"mistralai/Mistral-7B-Instruct-v0.2",
|
|
70
|
+
"mistralai/Mistral-7B-Instruct-v0.3",
|
|
71
|
+
"mistralai/Mistral-Small-24B-Instruct-2501",
|
|
72
|
+
"mistralai/Mixtral-8x7B-Instruct-v0.1",
|
|
73
|
+
"nvidia/Llama-3.1-Nemotron-70B-Instruct-HF",
|
|
74
|
+
"perplexity-ai/r1-1776",
|
|
75
|
+
"roberizk@gmail.com/meta-llama/Llama-3-70b-chat-hf-26ee936b",
|
|
76
|
+
"roberizk@gmail.com/meta-llama/Meta-Llama-3-70B-Instruct-6feb41f7",
|
|
77
|
+
"roberizk@gmail.com/meta-llama/Meta-Llama-3-8B-Instruct-8ced8839",
|
|
78
|
+
"scb10x/scb10x-llama3-1-typhoon2-70b-instruct",
|
|
79
|
+
"scb10x/scb10x-llama3-1-typhoon2-8b-instruct",
|
|
80
|
+
"togethercomputer/MoA-1",
|
|
81
|
+
"togethercomputer/MoA-1-Turbo",
|
|
82
|
+
"togethercomputer/Refuel-Llm-V2",
|
|
83
|
+
"togethercomputer/Refuel-Llm-V2-Small",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def _togetherai_extractor(chunk: Union[str, Dict[str, Any]]) -> Optional[str]:
|
|
88
|
+
"""Extracts content from TogetherAI stream JSON objects."""
|
|
89
|
+
if isinstance(chunk, dict):
|
|
90
|
+
return chunk.get("choices", [{}])[0].get("delta", {}).get("content")
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
def __init__(
|
|
94
|
+
self,
|
|
95
|
+
is_conversation: bool = True,
|
|
96
|
+
max_tokens: int = 2049,
|
|
97
|
+
timeout: int = 30,
|
|
98
|
+
intro: str = None,
|
|
99
|
+
filepath: str = None,
|
|
100
|
+
update_file: bool = True,
|
|
101
|
+
proxies: dict = {},
|
|
102
|
+
history_offset: int = 10250,
|
|
103
|
+
act: str = None,
|
|
104
|
+
model: str = "meta-llama/Llama-3.1-8B-Instruct-Turbo",
|
|
105
|
+
system_prompt: str = "You are a helpful assistant.",
|
|
106
|
+
browser: str = "chrome"
|
|
107
|
+
):
|
|
108
|
+
"""Initializes the TogetherAI API client."""
|
|
109
|
+
if model not in self.AVAILABLE_MODELS:
|
|
110
|
+
raise ValueError(f"Invalid model: {model}. Choose from: {self.AVAILABLE_MODELS}")
|
|
111
|
+
|
|
112
|
+
self.api_endpoint = "https://api.together.xyz/v1/chat/completions"
|
|
113
|
+
self.activation_endpoint = "https://www.codegeneration.ai/activate-v2"
|
|
114
|
+
|
|
115
|
+
# Initialize LitAgent
|
|
116
|
+
self.agent = LitAgent()
|
|
117
|
+
self.fingerprint = self.agent.generate_fingerprint(browser)
|
|
118
|
+
|
|
119
|
+
# Use the fingerprint for headers
|
|
120
|
+
self.headers = {
|
|
121
|
+
"Accept": self.fingerprint["accept"],
|
|
122
|
+
"Accept-Language": self.fingerprint["accept_language"],
|
|
123
|
+
"Content-Type": "application/json",
|
|
124
|
+
"Cache-Control": "no-cache",
|
|
125
|
+
"Origin": "https://www.codegeneration.ai",
|
|
126
|
+
"Pragma": "no-cache",
|
|
127
|
+
"Referer": "https://www.codegeneration.ai/",
|
|
128
|
+
"Sec-Fetch-Dest": "empty",
|
|
129
|
+
"Sec-Fetch-Mode": "cors",
|
|
130
|
+
"Sec-Fetch-Site": "same-site",
|
|
131
|
+
"User-Agent": self.fingerprint["user_agent"],
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# Initialize curl_cffi Session
|
|
135
|
+
self.session = Session()
|
|
136
|
+
self.session.headers.update(self.headers)
|
|
137
|
+
self.session.proxies = proxies
|
|
138
|
+
self.system_prompt = system_prompt
|
|
139
|
+
self.is_conversation = is_conversation
|
|
140
|
+
self.max_tokens_to_sample = max_tokens
|
|
141
|
+
self.timeout = timeout
|
|
142
|
+
self.last_response = {}
|
|
143
|
+
self.model = model
|
|
144
|
+
self._api_key_cache = None
|
|
145
|
+
|
|
146
|
+
self.__available_optimizers = (
|
|
147
|
+
method
|
|
148
|
+
for method in dir(Optimizers)
|
|
149
|
+
if callable(getattr(Optimizers, method)) and not method.startswith("__")
|
|
150
|
+
)
|
|
151
|
+
Conversation.intro = (
|
|
152
|
+
AwesomePrompts().get_act(
|
|
153
|
+
act, raise_not_found=True, default=None, case_insensitive=True
|
|
154
|
+
)
|
|
155
|
+
if act
|
|
156
|
+
else intro or Conversation.intro
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
self.conversation = Conversation(
|
|
160
|
+
is_conversation, self.max_tokens_to_sample, filepath, update_file
|
|
161
|
+
)
|
|
162
|
+
self.conversation.history_offset = history_offset
|
|
163
|
+
|
|
164
|
+
def refresh_identity(self, browser: str = None):
|
|
165
|
+
"""
|
|
166
|
+
Refreshes the browser identity fingerprint.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
browser: Specific browser to use for the new fingerprint
|
|
170
|
+
"""
|
|
171
|
+
browser = browser or self.fingerprint.get("browser_type", "chrome")
|
|
172
|
+
self.fingerprint = self.agent.generate_fingerprint(browser)
|
|
173
|
+
|
|
174
|
+
# Update headers with new fingerprint
|
|
175
|
+
self.headers.update({
|
|
176
|
+
"Accept": self.fingerprint["accept"],
|
|
177
|
+
"Accept-Language": self.fingerprint["accept_language"],
|
|
178
|
+
"User-Agent": self.fingerprint["user_agent"],
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
# Update session headers
|
|
182
|
+
self.session.headers.update(self.headers)
|
|
183
|
+
|
|
184
|
+
return self.fingerprint
|
|
185
|
+
|
|
186
|
+
def get_activation_key(self) -> str:
|
|
187
|
+
"""Get API key from activation endpoint"""
|
|
188
|
+
if self._api_key_cache:
|
|
189
|
+
return self._api_key_cache
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
response = self.session.get(
|
|
193
|
+
self.activation_endpoint,
|
|
194
|
+
headers={"Accept": "application/json"},
|
|
195
|
+
timeout=30
|
|
196
|
+
)
|
|
197
|
+
response.raise_for_status()
|
|
198
|
+
activation_data = response.json()
|
|
199
|
+
self._api_key_cache = activation_data["openAIParams"]["apiKey"]
|
|
200
|
+
return self._api_key_cache
|
|
201
|
+
except Exception as e:
|
|
202
|
+
raise exceptions.FailedToGenerateResponseError(f"Failed to get activation key: {e}")
|
|
203
|
+
|
|
204
|
+
def ask(
|
|
205
|
+
self,
|
|
206
|
+
prompt: str,
|
|
207
|
+
stream: bool = False,
|
|
208
|
+
raw: bool = False,
|
|
209
|
+
optimizer: str = None,
|
|
210
|
+
conversationally: bool = False,
|
|
211
|
+
) -> Union[Dict[str, Any], Generator]:
|
|
212
|
+
"""
|
|
213
|
+
Sends a prompt to the TogetherAI API and returns the response.
|
|
214
|
+
"""
|
|
215
|
+
conversation_prompt = self.conversation.gen_complete_prompt(prompt)
|
|
216
|
+
if optimizer:
|
|
217
|
+
if optimizer in self.__available_optimizers:
|
|
218
|
+
conversation_prompt = getattr(Optimizers, optimizer)(
|
|
219
|
+
conversation_prompt if conversationally else prompt
|
|
220
|
+
)
|
|
221
|
+
else:
|
|
222
|
+
raise Exception(f"Optimizer is not one of {self.__available_optimizers}")
|
|
223
|
+
|
|
224
|
+
# Get API key if not already set
|
|
225
|
+
if not self.headers.get("Authorization"):
|
|
226
|
+
api_key = self.get_activation_key()
|
|
227
|
+
self.headers["Authorization"] = f"Bearer {api_key}"
|
|
228
|
+
self.session.headers.update(self.headers)
|
|
229
|
+
|
|
230
|
+
# Payload construction
|
|
231
|
+
payload = {
|
|
232
|
+
"model": self.model,
|
|
233
|
+
"messages": [
|
|
234
|
+
{"role": "system", "content": self.system_prompt},
|
|
235
|
+
{"role": "user", "content": conversation_prompt},
|
|
236
|
+
],
|
|
237
|
+
"stream": stream
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
def for_stream():
|
|
241
|
+
streaming_text = ""
|
|
242
|
+
try:
|
|
243
|
+
response = self.session.post(
|
|
244
|
+
self.api_endpoint,
|
|
245
|
+
json=payload,
|
|
246
|
+
stream=True,
|
|
247
|
+
timeout=self.timeout,
|
|
248
|
+
impersonate="chrome110"
|
|
249
|
+
)
|
|
250
|
+
response.raise_for_status()
|
|
251
|
+
|
|
252
|
+
# Use sanitize_stream
|
|
253
|
+
processed_stream = sanitize_stream(
|
|
254
|
+
data=response.iter_content(chunk_size=None),
|
|
255
|
+
intro_value="data:",
|
|
256
|
+
to_json=True,
|
|
257
|
+
skip_markers=["[DONE]"],
|
|
258
|
+
content_extractor=self._togetherai_extractor,
|
|
259
|
+
yield_raw_on_error=False
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
for content_chunk in processed_stream:
|
|
263
|
+
if content_chunk and isinstance(content_chunk, str):
|
|
264
|
+
streaming_text += content_chunk
|
|
265
|
+
resp = dict(text=content_chunk)
|
|
266
|
+
yield resp if not raw else content_chunk
|
|
267
|
+
|
|
268
|
+
except CurlError as e:
|
|
269
|
+
raise exceptions.FailedToGenerateResponseError(f"Request failed (CurlError): {str(e)}") from e
|
|
270
|
+
except Exception as e:
|
|
271
|
+
raise exceptions.FailedToGenerateResponseError(f"Request failed ({type(e).__name__}): {str(e)}") from e
|
|
272
|
+
finally:
|
|
273
|
+
if streaming_text:
|
|
274
|
+
self.last_response = {"text": streaming_text}
|
|
275
|
+
self.conversation.update_chat_history(prompt, streaming_text)
|
|
276
|
+
|
|
277
|
+
def for_non_stream():
|
|
278
|
+
try:
|
|
279
|
+
response = self.session.post(
|
|
280
|
+
self.api_endpoint,
|
|
281
|
+
json=payload,
|
|
282
|
+
timeout=self.timeout,
|
|
283
|
+
impersonate="chrome110"
|
|
284
|
+
)
|
|
285
|
+
response.raise_for_status()
|
|
286
|
+
|
|
287
|
+
response_text = response.text
|
|
288
|
+
|
|
289
|
+
# Use sanitize_stream to parse the non-streaming JSON response
|
|
290
|
+
processed_stream = sanitize_stream(
|
|
291
|
+
data=response_text,
|
|
292
|
+
to_json=True,
|
|
293
|
+
intro_value=None,
|
|
294
|
+
content_extractor=lambda chunk: chunk.get("choices", [{}])[0].get("message", {}).get("content") if isinstance(chunk, dict) else None,
|
|
295
|
+
yield_raw_on_error=False
|
|
296
|
+
)
|
|
297
|
+
content = next(processed_stream, None)
|
|
298
|
+
content = content if isinstance(content, str) else ""
|
|
299
|
+
|
|
300
|
+
self.last_response = {"text": content}
|
|
301
|
+
self.conversation.update_chat_history(prompt, content)
|
|
302
|
+
return self.last_response if not raw else content
|
|
303
|
+
|
|
304
|
+
except CurlError as e:
|
|
305
|
+
raise exceptions.FailedToGenerateResponseError(f"Request failed (CurlError): {e}") from e
|
|
306
|
+
except Exception as e:
|
|
307
|
+
err_text = getattr(e, 'response', None) and getattr(e.response, 'text', '')
|
|
308
|
+
raise exceptions.FailedToGenerateResponseError(f"Request failed ({type(e).__name__}): {e} - {err_text}") from e
|
|
309
|
+
|
|
310
|
+
return for_stream() if stream else for_non_stream()
|
|
311
|
+
|
|
312
|
+
def chat(
|
|
313
|
+
self,
|
|
314
|
+
prompt: str,
|
|
315
|
+
stream: bool = False,
|
|
316
|
+
optimizer: str = None,
|
|
317
|
+
conversationally: bool = False,
|
|
318
|
+
) -> Union[str, Generator[str, None, None]]:
|
|
319
|
+
"""Generate response `str`"""
|
|
320
|
+
def for_stream_chat():
|
|
321
|
+
gen = self.ask(
|
|
322
|
+
prompt, stream=True, raw=False,
|
|
323
|
+
optimizer=optimizer, conversationally=conversationally
|
|
324
|
+
)
|
|
325
|
+
for response_dict in gen:
|
|
326
|
+
yield self.get_message(response_dict)
|
|
327
|
+
|
|
328
|
+
def for_non_stream_chat():
|
|
329
|
+
response_data = self.ask(
|
|
330
|
+
prompt, stream=False, raw=False,
|
|
331
|
+
optimizer=optimizer, conversationally=conversationally
|
|
332
|
+
)
|
|
333
|
+
return self.get_message(response_data)
|
|
334
|
+
|
|
335
|
+
return for_stream_chat() if stream else for_non_stream_chat()
|
|
336
|
+
|
|
337
|
+
def get_message(self, response: dict) -> str:
|
|
338
|
+
"""Retrieves message only from response"""
|
|
339
|
+
assert isinstance(response, dict), "Response should be of dict data-type only"
|
|
340
|
+
return response["text"]
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
if __name__ == "__main__":
|
|
344
|
+
print("-" * 80)
|
|
345
|
+
print(f"{'Model':<50} {'Status':<10} {'Response'}")
|
|
346
|
+
print("-" * 80)
|
|
347
|
+
|
|
348
|
+
for model in TogetherAI.AVAILABLE_MODELS:
|
|
349
|
+
try:
|
|
350
|
+
test_ai = TogetherAI(model=model, timeout=60)
|
|
351
|
+
response = test_ai.chat("Say 'Hello' in one word", stream=True)
|
|
352
|
+
response_text = ""
|
|
353
|
+
for chunk in response:
|
|
354
|
+
response_text += chunk
|
|
355
|
+
|
|
356
|
+
if response_text and len(response_text.strip()) > 0:
|
|
357
|
+
status = "✓"
|
|
358
|
+
# Clean and truncate response
|
|
359
|
+
clean_text = response_text.strip().encode('utf-8', errors='ignore').decode('utf-8')
|
|
360
|
+
display_text = clean_text[:50] + "..." if len(clean_text) > 50 else clean_text
|
|
361
|
+
else:
|
|
362
|
+
status = "✗"
|
|
363
|
+
display_text = "Empty or invalid response"
|
|
364
|
+
print(f"\r{model:<50} {status:<10} {display_text}")
|
|
365
|
+
except Exception as e:
|
|
366
|
+
print(f"\r{model:<50} {'✗':<10} {str(e)}")
|