webscout 6.2__py3-none-any.whl → 6.3__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/AIbase.py CHANGED
@@ -1,240 +1,310 @@
1
- from abc import ABC
2
- from abc import abstractmethod
3
- from typing import AsyncGenerator, List, Union, Generator
4
-
5
- class Provider(ABC):
6
- """Base class for text-based AI providers"""
7
-
8
- @abstractmethod
9
- def ask(
10
- self,
11
- prompt: str,
12
- stream: bool = False,
13
- raw: bool = False,
14
- optimizer: str = None,
15
- conversationally: bool = False,
16
- ) -> dict:
17
- """Chat with AI
18
-
19
- Args:
20
- prompt (str): Prompt to be sent
21
- stream (bool, optional): Flag for streaming response. Defaults to False.
22
- raw (bool, optional): Stream back raw response as received
23
- optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`
24
- conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
25
- Returns:
26
- dict : {}
27
- ```json
28
- {
29
- "completion": "\nNext: domestic cat breeds with short hair >>",
30
- "stop_reason": null,
31
- "truncated": false,
32
- "stop": null,
33
- "model": "llama-2-13b-chat",
34
- "log_id": "cmpl-3kYiYxSNDvgMShSzFooz6t",
35
- "exception": null
36
- }
37
- ```
38
- """
39
- raise NotImplementedError("Method needs to be implemented in subclass")
40
-
41
- @abstractmethod
42
- def chat(
43
- self,
44
- prompt: str,
45
- stream: bool = False,
46
- optimizer: str = None,
47
- conversationally: bool = False,
48
- ) -> str:
49
- """Generate response `str`
50
- Args:
51
- prompt (str): Prompt to be sent
52
- stream (bool, optional): Flag for streaming response. Defaults to False.
53
- optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`
54
- conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
55
- Returns:
56
- str: Response generated
57
- """
58
- raise NotImplementedError("Method needs to be implemented in subclass")
59
-
60
- @abstractmethod
61
- def get_message(self, response: dict) -> str:
62
- """Retrieves message only from response
63
-
64
- Args:
65
- response (dict): Response generated by `self.ask`
66
-
67
- Returns:
68
- str: Message extracted
69
- """
70
- raise NotImplementedError("Method needs to be implemented in subclass")
71
-
72
- class AsyncProvider(ABC):
73
- """Asynchronous base class for text-based AI providers"""
74
-
75
- @abstractmethod
76
- async def ask(
77
- self,
78
- prompt: str,
79
- stream: bool = False,
80
- raw: bool = False,
81
- optimizer: str = None,
82
- conversationally: bool = False,
83
- ) -> dict:
84
- """Asynchronously chat with AI
85
-
86
- Args:
87
- prompt (str): Prompt to be sent
88
- stream (bool, optional): Flag for streaming response. Defaults to False.
89
- raw (bool, optional): Stream back raw response as received
90
- optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`
91
- conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
92
- Returns:
93
- dict : {}
94
- ```json
95
- {
96
- "completion": "\nNext: domestic cat breeds with short hair >>",
97
- "stop_reason": null,
98
- "truncated": false,
99
- "stop": null,
100
- "model": "llama-2-13b-chat",
101
- "log_id": "cmpl-3kYiYxSNDvgMShSzFooz6t",
102
- "exception": null
103
- }
104
- ```
105
- """
106
- raise NotImplementedError("Method needs to be implemented in subclass")
107
-
108
- @abstractmethod
109
- async def chat(
110
- self,
111
- prompt: str,
112
- stream: bool = False,
113
- optimizer: str = None,
114
- conversationally: bool = False,
115
- ) -> str:
116
- """Asynchronously generate response `str`
117
- Args:
118
- prompt (str): Prompt to be sent
119
- stream (bool, optional): Flag for streaming response. Defaults to False.
120
- optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`
121
- conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
122
- Returns:
123
- str: Response generated
124
- """
125
- raise NotImplementedError("Method needs to be implemented in subclass")
126
-
127
- @abstractmethod
128
- async def get_message(self, response: dict) -> str:
129
- """Asynchronously retrieves message only from response
130
-
131
- Args:
132
- response (dict): Response generated by `self.ask`
133
-
134
- Returns:
135
- str: Message extracted
136
- """
137
- raise NotImplementedError("Method needs to be implemented in subclass")
138
-
139
- class TTSProvider(ABC):
140
- """Base class for text-to-speech providers"""
141
-
142
- @abstractmethod
143
- def tts(self, text: str) -> Union[bytes, str, Generator[bytes, None, None]]:
144
- """
145
- Converts text to speech.
146
-
147
- Args:
148
- text (str): The text to be converted to speech.
149
-
150
- Returns:
151
- Union[bytes, str, Generator[bytes, None, None]]:
152
- - The raw audio bytes if the provider supports returning audio directly.
153
- - The filename of the saved audio file if the provider saves the audio to a file.
154
- - A generator yielding chunks of audio bytes if the provider supports streaming audio.
155
- """
156
- raise NotImplementedError("Method needs to be implemented in subclass")
157
-
158
- class AsyncTTSProvider(ABC):
159
- """Asynchronous base class for text-to-speech providers"""
160
-
161
- @abstractmethod
162
- async def tts(self, text: str) -> Union[bytes, str, AsyncGenerator[bytes, None]]:
163
- """
164
- Asynchronously converts text to speech.
165
-
166
- Args:
167
- text (str): The text to be converted to speech.
168
-
169
- Returns:
170
- Union[bytes, str, AsyncGenerator[bytes, None]]:
171
- - The raw audio bytes if the provider supports returning audio directly.
172
- - The filename of the saved audio file if the provider saves the audio to a file.
173
- - An asynchronous generator yielding chunks of audio bytes if the provider supports streaming audio.
174
- """
175
- raise NotImplementedError("Method needs to be implemented in subclass")
176
-
177
- class ImageProvider(ABC):
178
- """Base class for text-to-image providers"""
179
-
180
- @abstractmethod
181
- def generate(self, prompt: str, amount: int = 1) -> List[bytes]:
182
- """Generates images from a text prompt.
183
-
184
- Args:
185
- prompt (str): The text prompt describing the desired image.
186
- amount (int, optional): The number of images to generate. Defaults to 1.
187
-
188
- Returns:
189
- List[bytes]: A list of generated images in bytes format.
190
- """
191
- raise NotImplementedError("Method needs to be implemented in subclass")
192
-
193
- @abstractmethod
194
- def save(self, response: List[bytes], name: str = None, dir: str = None) -> List[str]:
195
- """Saves the generated images to files.
196
-
197
- Args:
198
- response (List[bytes]): The list of generated images in bytes format.
199
- name (str, optional): The base filename for the images. Defaults to None.
200
- dir (str, optional): The directory to save the images. Defaults to None.
201
-
202
- Returns:
203
- List[str]: A list of the saved filenames.
204
- """
205
- raise NotImplementedError("Method needs to be implemented in subclass")
206
-
207
- class AsyncImageProvider(ABC):
208
- """Base class for asynchronous text-to-image providers"""
209
-
210
- @abstractmethod
211
- async def generate(self, prompt: str, amount: int = 1) -> Union[AsyncGenerator[bytes, None], List[bytes]]:
212
- """Asynchronously generates images from a text prompt.
213
-
214
- Args:
215
- prompt (str): The text prompt describing the desired image.
216
- amount (int, optional): The number of images to generate. Defaults to 1.
217
-
218
- Returns:
219
- Union[AsyncGenerator[bytes, None], List[bytes]]:
220
- - An asynchronous generator yielding image bytes.
221
- - A list of image bytes if not streaming.
222
- """
223
- raise NotImplementedError("Method needs to be implemented in subclass")
224
-
225
- @abstractmethod
226
- async def save(self, response: Union[AsyncGenerator[bytes, None], List[bytes]],
227
- name: str = None, dir: str = None) -> List[str]:
228
- """Asynchronously saves the generated images to files.
229
-
230
- Args:
231
- response (Union[AsyncGenerator[bytes, None], List[bytes]]):
232
- - The asynchronous generator yielding images in bytes format (if streaming).
233
- - The list of generated images in bytes format (if not streaming).
234
- name (str, optional): The base filename for the images. Defaults to None.
235
- dir (str, optional): The directory to save the images. Defaults to None.
236
-
237
- Returns:
238
- List[str]: A list of the saved filenames.
239
- """
1
+ from abc import ABC
2
+ from abc import abstractmethod
3
+ from pathlib import Path
4
+ from typing import AsyncGenerator, List, Union, Generator, Optional
5
+ from typing_extensions import TypeAlias
6
+
7
+ # Type aliases for better readability
8
+ Response: TypeAlias = dict[str, Union[str, bool, None]]
9
+ ImageData: TypeAlias = Union[bytes, str, Generator[bytes, None, None]]
10
+ AsyncImageData: TypeAlias = Union[bytes, str, AsyncGenerator[bytes, None]]
11
+
12
+ class AIProviderError(Exception):
13
+ """Base exception for AI provider errors"""
14
+ pass
15
+
16
+ class Provider(ABC):
17
+ """Base class for text-based AI providers.
18
+
19
+ This class defines the interface for synchronous AI text generation providers.
20
+ All text-based AI providers should inherit from this class and implement
21
+ its abstract methods.
22
+ """
23
+
24
+ @abstractmethod
25
+ def ask(
26
+ self,
27
+ prompt: str,
28
+ stream: bool = False,
29
+ raw: bool = False,
30
+ optimizer: Optional[str] = None,
31
+ conversationally: bool = False,
32
+ ) -> Response:
33
+ """Chat with AI and get detailed response.
34
+
35
+ Args:
36
+ prompt: The input text to send to the AI
37
+ stream: Whether to stream the response. Defaults to False
38
+ raw: Whether to return raw response as received. Defaults to False
39
+ optimizer: Optional prompt optimizer - choices: ['code', 'shell_command']
40
+ conversationally: Whether to maintain conversation context. Defaults to False
41
+
42
+ Returns:
43
+ A dictionary containing response details:
44
+ {
45
+ "completion": str, # The AI's response
46
+ "stop_reason": str|None, # Reason for response termination
47
+ "truncated": bool, # Whether response was truncated
48
+ "stop": str|None, # Stop token if any
49
+ "model": str, # Model used for generation
50
+ "log_id": str, # Unique log identifier
51
+ "exception": str|None # Error message if any
52
+ }
53
+
54
+ Raises:
55
+ AIProviderError: If there's an error communicating with the AI provider
56
+ """
57
+ raise NotImplementedError("Method needs to be implemented in subclass")
58
+
59
+ @abstractmethod
60
+ def chat(
61
+ self,
62
+ prompt: str,
63
+ stream: bool = False,
64
+ optimizer: Optional[str] = None,
65
+ conversationally: bool = False,
66
+ ) -> str:
67
+ """Generate a simple text response from the AI.
68
+
69
+ Args:
70
+ prompt: The input text to send to the AI
71
+ stream: Whether to stream the response. Defaults to False
72
+ optimizer: Optional prompt optimizer - choices: ['code', 'shell_command']
73
+ conversationally: Whether to maintain conversation context. Defaults to False
74
+
75
+ Returns:
76
+ The AI's text response
77
+
78
+ Raises:
79
+ AIProviderError: If there's an error communicating with the AI provider
80
+ """
81
+ raise NotImplementedError("Method needs to be implemented in subclass")
82
+
83
+ @abstractmethod
84
+ def get_message(self, response: Response) -> str:
85
+ """Extract the message content from a response dictionary.
86
+
87
+ Args:
88
+ response: Response dictionary from ask() method
89
+
90
+ Returns:
91
+ The extracted message text
92
+
93
+ Raises:
94
+ AIProviderError: If message cannot be extracted from response
95
+ """
96
+ raise NotImplementedError("Method needs to be implemented in subclass")
97
+
98
+ class AsyncProvider(ABC):
99
+ """Asynchronous base class for text-based AI providers"""
100
+
101
+ @abstractmethod
102
+ async def ask(
103
+ self,
104
+ prompt: str,
105
+ stream: bool = False,
106
+ raw: bool = False,
107
+ optimizer: Optional[str] = None,
108
+ conversationally: bool = False,
109
+ ) -> Response:
110
+ """Asynchronously chat with AI and get detailed response.
111
+
112
+ Args:
113
+ prompt: The input text to send to the AI
114
+ stream: Whether to stream the response. Defaults to False
115
+ raw: Whether to return raw response as received. Defaults to False
116
+ optimizer: Optional prompt optimizer - choices: ['code', 'shell_command']
117
+ conversationally: Whether to maintain conversation context. Defaults to False
118
+
119
+ Returns:
120
+ A dictionary containing response details:
121
+ {
122
+ "completion": str, # The AI's response
123
+ "stop_reason": str|None, # Reason for response termination
124
+ "truncated": bool, # Whether response was truncated
125
+ "stop": str|None, # Stop token if any
126
+ "model": str, # Model used for generation
127
+ "log_id": str, # Unique log identifier
128
+ "exception": str|None # Error message if any
129
+ }
130
+
131
+ Raises:
132
+ AIProviderError: If there's an error communicating with the AI provider
133
+ """
134
+ raise NotImplementedError("Method needs to be implemented in subclass")
135
+
136
+ @abstractmethod
137
+ async def chat(
138
+ self,
139
+ prompt: str,
140
+ stream: bool = False,
141
+ optimizer: Optional[str] = None,
142
+ conversationally: bool = False,
143
+ ) -> str:
144
+ """Asynchronously generate a simple text response from the AI.
145
+
146
+ Args:
147
+ prompt: The input text to send to the AI
148
+ stream: Whether to stream the response. Defaults to False
149
+ optimizer: Optional prompt optimizer - choices: ['code', 'shell_command']
150
+ conversationally: Whether to maintain conversation context. Defaults to False
151
+
152
+ Returns:
153
+ The AI's text response
154
+
155
+ Raises:
156
+ AIProviderError: If there's an error communicating with the AI provider
157
+ """
158
+ raise NotImplementedError("Method needs to be implemented in subclass")
159
+
160
+ @abstractmethod
161
+ async def get_message(self, response: Response) -> str:
162
+ """Asynchronously extract the message content from a response dictionary.
163
+
164
+ Args:
165
+ response: Response dictionary from ask() method
166
+
167
+ Returns:
168
+ The extracted message text
169
+
170
+ Raises:
171
+ AIProviderError: If message cannot be extracted from response
172
+ """
173
+ raise NotImplementedError("Method needs to be implemented in subclass")
174
+
175
+ class TTSProvider(ABC):
176
+ """Base class for text-to-speech providers.
177
+
178
+ This class defines the interface for synchronous text-to-speech providers.
179
+ """
180
+
181
+ @abstractmethod
182
+ def tts(self, text: str) -> ImageData:
183
+ """Convert text to speech.
184
+
185
+ Args:
186
+ text: The text to convert to speech
187
+
188
+ Returns:
189
+ One of:
190
+ - Raw audio bytes
191
+ - Path to saved audio file
192
+ - Generator yielding audio chunks
193
+
194
+ Raises:
195
+ AIProviderError: If text-to-speech conversion fails
196
+ """
197
+ raise NotImplementedError("Method needs to be implemented in subclass")
198
+
199
+ class AsyncTTSProvider(ABC):
200
+ """Base class for asynchronous text-to-speech providers."""
201
+
202
+ @abstractmethod
203
+ async def tts(self, text: str) -> AsyncImageData:
204
+ """Asynchronously convert text to speech.
205
+
206
+ Args:
207
+ text: The text to convert to speech
208
+
209
+ Returns:
210
+ One of:
211
+ - Raw audio bytes
212
+ - Path to saved audio file
213
+ - AsyncGenerator yielding audio chunks
214
+
215
+ Raises:
216
+ AIProviderError: If text-to-speech conversion fails
217
+ """
218
+ raise NotImplementedError("Method needs to be implemented in subclass")
219
+
220
+ class ImageProvider(ABC):
221
+ """Base class for text-to-image generation providers."""
222
+
223
+ @abstractmethod
224
+ def generate(self, prompt: str, amount: int = 1) -> List[bytes]:
225
+ """Generate images from a text description.
226
+
227
+ Args:
228
+ prompt: Text description of desired image
229
+ amount: Number of images to generate (default: 1)
230
+
231
+ Returns:
232
+ List of generated images as bytes
233
+
234
+ Raises:
235
+ AIProviderError: If image generation fails
236
+ ValueError: If amount is less than 1
237
+ """
238
+ raise NotImplementedError("Method needs to be implemented in subclass")
239
+
240
+ @abstractmethod
241
+ def save(
242
+ self,
243
+ response: List[bytes],
244
+ name: Optional[str] = None,
245
+ dir: Optional[Union[str, Path]] = None
246
+ ) -> List[str]:
247
+ """Save generated images to disk.
248
+
249
+ Args:
250
+ response: List of image data in bytes
251
+ name: Base filename for saved images (default: auto-generated)
252
+ dir: Directory to save images (default: current directory)
253
+
254
+ Returns:
255
+ List of paths to saved image files
256
+
257
+ Raises:
258
+ AIProviderError: If saving images fails
259
+ ValueError: If response is empty
260
+ """
261
+ raise NotImplementedError("Method needs to be implemented in subclass")
262
+
263
+ class AsyncImageProvider(ABC):
264
+ """Base class for asynchronous text-to-image generation providers."""
265
+
266
+ @abstractmethod
267
+ async def generate(
268
+ self,
269
+ prompt: str,
270
+ amount: int = 1
271
+ ) -> Union[AsyncGenerator[bytes, None], List[bytes]]:
272
+ """Asynchronously generate images from text.
273
+
274
+ Args:
275
+ prompt: Text description of desired image
276
+ amount: Number of images to generate (default: 1)
277
+
278
+ Returns:
279
+ Either:
280
+ - AsyncGenerator yielding image bytes for streaming
281
+ - List of image bytes if not streaming
282
+
283
+ Raises:
284
+ AIProviderError: If image generation fails
285
+ ValueError: If amount is less than 1
286
+ """
287
+ raise NotImplementedError("Method needs to be implemented in subclass")
288
+
289
+ @abstractmethod
290
+ async def save(
291
+ self,
292
+ response: Union[AsyncGenerator[bytes, None], List[bytes]],
293
+ name: Optional[str] = None,
294
+ dir: Optional[Union[str, Path]] = None
295
+ ) -> List[str]:
296
+ """Asynchronously save generated images.
297
+
298
+ Args:
299
+ response: Either AsyncGenerator yielding images or List of image bytes
300
+ name: Base filename for saved images (default: auto-generated)
301
+ dir: Directory to save images (default: current directory)
302
+
303
+ Returns:
304
+ List of paths to saved image files
305
+
306
+ Raises:
307
+ AIProviderError: If saving images fails
308
+ ValueError: If response is empty
309
+ """
240
310
  raise NotImplementedError("Method needs to be implemented in subclass")