webscout 8.2.6__py3-none-any.whl → 8.2.8__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 +1 -1
- webscout/AIutel.py +298 -239
- webscout/Extra/Act.md +309 -0
- webscout/Extra/GitToolkit/gitapi/README.md +110 -0
- webscout/Extra/YTToolkit/README.md +375 -0
- webscout/Extra/YTToolkit/ytapi/README.md +44 -0
- webscout/Extra/YTToolkit/ytapi/extras.py +92 -19
- webscout/Extra/autocoder/autocoder.py +309 -114
- webscout/Extra/autocoder/autocoder_utiles.py +15 -15
- webscout/Extra/gguf.md +430 -0
- webscout/Extra/tempmail/README.md +488 -0
- webscout/Extra/weather.md +281 -0
- webscout/Litlogger/Readme.md +175 -0
- webscout/Provider/AISEARCH/DeepFind.py +41 -37
- webscout/Provider/AISEARCH/README.md +279 -0
- webscout/Provider/AISEARCH/__init__.py +0 -1
- webscout/Provider/AISEARCH/genspark_search.py +228 -86
- webscout/Provider/AISEARCH/hika_search.py +11 -11
- webscout/Provider/AISEARCH/scira_search.py +324 -322
- webscout/Provider/AllenAI.py +7 -14
- webscout/Provider/Blackboxai.py +518 -74
- webscout/Provider/Cloudflare.py +0 -1
- webscout/Provider/Deepinfra.py +23 -21
- webscout/Provider/Flowith.py +217 -0
- webscout/Provider/FreeGemini.py +250 -0
- webscout/Provider/GizAI.py +15 -5
- webscout/Provider/Glider.py +11 -8
- webscout/Provider/HeckAI.py +80 -52
- webscout/Provider/Koboldai.py +7 -4
- webscout/Provider/LambdaChat.py +2 -2
- webscout/Provider/Marcus.py +10 -18
- webscout/Provider/OPENAI/BLACKBOXAI.py +735 -0
- webscout/Provider/OPENAI/Cloudflare.py +378 -0
- webscout/Provider/OPENAI/FreeGemini.py +282 -0
- webscout/Provider/OPENAI/NEMOTRON.py +244 -0
- webscout/Provider/OPENAI/README.md +1253 -0
- webscout/Provider/OPENAI/__init__.py +8 -0
- webscout/Provider/OPENAI/ai4chat.py +293 -286
- webscout/Provider/OPENAI/api.py +810 -0
- webscout/Provider/OPENAI/base.py +217 -14
- webscout/Provider/OPENAI/c4ai.py +373 -367
- webscout/Provider/OPENAI/chatgpt.py +7 -0
- webscout/Provider/OPENAI/chatgptclone.py +7 -0
- webscout/Provider/OPENAI/chatsandbox.py +172 -0
- webscout/Provider/OPENAI/deepinfra.py +30 -20
- webscout/Provider/OPENAI/e2b.py +6 -0
- webscout/Provider/OPENAI/exaai.py +7 -0
- webscout/Provider/OPENAI/exachat.py +6 -0
- webscout/Provider/OPENAI/flowith.py +162 -0
- webscout/Provider/OPENAI/freeaichat.py +359 -352
- webscout/Provider/OPENAI/glider.py +323 -316
- webscout/Provider/OPENAI/groq.py +361 -354
- webscout/Provider/OPENAI/heckai.py +30 -64
- webscout/Provider/OPENAI/llmchatco.py +8 -0
- webscout/Provider/OPENAI/mcpcore.py +7 -0
- webscout/Provider/OPENAI/multichat.py +8 -0
- webscout/Provider/OPENAI/netwrck.py +356 -350
- webscout/Provider/OPENAI/opkfc.py +8 -0
- webscout/Provider/OPENAI/scirachat.py +471 -462
- webscout/Provider/OPENAI/sonus.py +9 -0
- webscout/Provider/OPENAI/standardinput.py +9 -1
- webscout/Provider/OPENAI/textpollinations.py +339 -329
- webscout/Provider/OPENAI/toolbaz.py +7 -0
- webscout/Provider/OPENAI/typefully.py +355 -0
- webscout/Provider/OPENAI/typegpt.py +358 -346
- webscout/Provider/OPENAI/uncovrAI.py +7 -0
- webscout/Provider/OPENAI/utils.py +103 -7
- webscout/Provider/OPENAI/venice.py +12 -0
- webscout/Provider/OPENAI/wisecat.py +19 -19
- webscout/Provider/OPENAI/writecream.py +7 -0
- webscout/Provider/OPENAI/x0gpt.py +7 -0
- webscout/Provider/OPENAI/yep.py +50 -21
- webscout/Provider/OpenGPT.py +1 -1
- webscout/Provider/TTI/AiForce/README.md +159 -0
- webscout/Provider/TTI/FreeAIPlayground/README.md +99 -0
- webscout/Provider/TTI/ImgSys/README.md +174 -0
- webscout/Provider/TTI/MagicStudio/README.md +101 -0
- webscout/Provider/TTI/Nexra/README.md +155 -0
- webscout/Provider/TTI/PollinationsAI/README.md +146 -0
- webscout/Provider/TTI/README.md +128 -0
- webscout/Provider/TTI/aiarta/README.md +134 -0
- webscout/Provider/TTI/artbit/README.md +100 -0
- webscout/Provider/TTI/fastflux/README.md +129 -0
- webscout/Provider/TTI/huggingface/README.md +114 -0
- webscout/Provider/TTI/piclumen/README.md +161 -0
- webscout/Provider/TTI/pixelmuse/README.md +79 -0
- webscout/Provider/TTI/talkai/README.md +139 -0
- webscout/Provider/TTS/README.md +192 -0
- webscout/Provider/TTS/__init__.py +2 -1
- webscout/Provider/TTS/speechma.py +500 -100
- webscout/Provider/TTS/sthir.py +94 -0
- webscout/Provider/TeachAnything.py +3 -7
- webscout/Provider/TextPollinationsAI.py +4 -2
- webscout/Provider/{aimathgpt.py → UNFINISHED/ChatHub.py} +88 -68
- webscout/Provider/UNFINISHED/liner_api_request.py +263 -0
- webscout/Provider/UNFINISHED/oivscode.py +351 -0
- webscout/Provider/UNFINISHED/test_lmarena.py +119 -0
- webscout/Provider/Writecream.py +11 -2
- webscout/Provider/__init__.py +8 -14
- webscout/Provider/ai4chat.py +4 -58
- webscout/Provider/asksteve.py +17 -9
- webscout/Provider/cerebras.py +3 -1
- webscout/Provider/koala.py +170 -268
- webscout/Provider/llmchat.py +3 -0
- webscout/Provider/lmarena.py +198 -0
- webscout/Provider/meta.py +7 -4
- webscout/Provider/samurai.py +223 -0
- webscout/Provider/scira_chat.py +4 -2
- webscout/Provider/typefully.py +23 -151
- webscout/__init__.py +4 -2
- webscout/cli.py +3 -28
- webscout/conversation.py +35 -35
- webscout/litagent/Readme.md +276 -0
- webscout/scout/README.md +402 -0
- webscout/swiftcli/Readme.md +323 -0
- webscout/version.py +1 -1
- webscout/webscout_search.py +2 -182
- webscout/webscout_search_async.py +1 -179
- webscout/zeroart/README.md +89 -0
- webscout/zeroart/__init__.py +134 -54
- webscout/zeroart/base.py +19 -13
- webscout/zeroart/effects.py +101 -99
- webscout/zeroart/fonts.py +1239 -816
- {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/METADATA +116 -74
- {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/RECORD +130 -103
- {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/WHEEL +1 -1
- webscout-8.2.8.dist-info/entry_points.txt +3 -0
- webscout-8.2.8.dist-info/top_level.txt +1 -0
- webscout/Provider/AISEARCH/ISou.py +0 -256
- webscout/Provider/ElectronHub.py +0 -773
- webscout/Provider/Free2GPT.py +0 -241
- webscout/Provider/GPTWeb.py +0 -249
- webscout/Provider/bagoodex.py +0 -145
- webscout/Provider/geminiprorealtime.py +0 -160
- webscout/scout/core.py +0 -881
- webscout-8.2.6.dist-info/entry_points.txt +0 -3
- webscout-8.2.6.dist-info/top_level.txt +0 -2
- webstoken/__init__.py +0 -30
- webstoken/classifier.py +0 -189
- webstoken/keywords.py +0 -216
- webstoken/language.py +0 -128
- webstoken/ner.py +0 -164
- webstoken/normalizer.py +0 -35
- webstoken/processor.py +0 -77
- webstoken/sentiment.py +0 -206
- webstoken/stemmer.py +0 -73
- webstoken/tagger.py +0 -60
- webstoken/tokenizer.py +0 -158
- /webscout/Provider/{Youchat.py → UNFINISHED/Youchat.py} +0 -0
- {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -103,11 +103,6 @@ class AsyncWEBS:
|
|
|
103
103
|
self.sleep_timestamp = 0.0
|
|
104
104
|
|
|
105
105
|
self._exception_event = asyncio.Event()
|
|
106
|
-
self._chat_messages: List[Dict[str, str]] = []
|
|
107
|
-
self._chat_tokens_count = 0
|
|
108
|
-
self._chat_vqd: str = ""
|
|
109
|
-
self._chat_vqd_hash: str = ""
|
|
110
|
-
self._chat_xfe: str = ""
|
|
111
106
|
|
|
112
107
|
async def __aenter__(self) -> AsyncWEBS:
|
|
113
108
|
return self
|
|
@@ -189,179 +184,6 @@ class AsyncWEBS:
|
|
|
189
184
|
resp_content = (await self._get_url("GET", "https://duckduckgo.com", params={"q": keywords})).content
|
|
190
185
|
return _extract_vqd(resp_content, keywords)
|
|
191
186
|
|
|
192
|
-
async def achat_yield(self, keywords: str, model: str = "gpt-4o-mini", timeout: int = 30, max_retries: int = 3) -> AsyncIterator[str]:
|
|
193
|
-
"""Initiates an async chat session with webscout AI.
|
|
194
|
-
|
|
195
|
-
Args:
|
|
196
|
-
keywords (str): The initial message or question to send to the AI.
|
|
197
|
-
model (str): The model to use: "gpt-4o-mini", "llama-3.3-70b", "claude-3-haiku",
|
|
198
|
-
"o3-mini", "mistral-small-3". Defaults to "gpt-4o-mini".
|
|
199
|
-
timeout (int): Timeout value for the HTTP client. Defaults to 30.
|
|
200
|
-
max_retries (int): Maximum number of retry attempts for rate limited requests. Defaults to 3.
|
|
201
|
-
|
|
202
|
-
Yields:
|
|
203
|
-
str: Chunks of the response from the AI.
|
|
204
|
-
"""
|
|
205
|
-
# Get Cloudflare Turnstile token
|
|
206
|
-
async def get_turnstile_token():
|
|
207
|
-
try:
|
|
208
|
-
# Visit the DuckDuckGo chat page to get the Turnstile token
|
|
209
|
-
resp_content = (await self._get_url(
|
|
210
|
-
method="GET",
|
|
211
|
-
url="https://duckduckgo.com/?q=DuckDuckGo+AI+Chat&ia=chat&duckai=1",
|
|
212
|
-
)).content
|
|
213
|
-
|
|
214
|
-
# Extract the Turnstile token if available
|
|
215
|
-
if b'cf-turnstile-response' in resp_content:
|
|
216
|
-
token = resp_content.split(b'cf-turnstile-response="', maxsplit=1)[1].split(b'"', maxsplit=1)[0].decode()
|
|
217
|
-
return token
|
|
218
|
-
return ""
|
|
219
|
-
except Exception:
|
|
220
|
-
return ""
|
|
221
|
-
|
|
222
|
-
# x-fe-version
|
|
223
|
-
if not self._chat_xfe:
|
|
224
|
-
resp_content = (await self._get_url(
|
|
225
|
-
method="GET",
|
|
226
|
-
url="https://duckduckgo.com/?q=DuckDuckGo+AI+Chat&ia=chat&duckai=1",
|
|
227
|
-
)).content
|
|
228
|
-
try:
|
|
229
|
-
xfe1 = resp_content.split(b'__DDG_BE_VERSION__="', maxsplit=1)[1].split(b'"', maxsplit=1)[0].decode()
|
|
230
|
-
xfe2 = resp_content.split(b'__DDG_FE_CHAT_HASH__="', maxsplit=1)[1].split(b'"', maxsplit=1)[0].decode()
|
|
231
|
-
self._chat_xfe = f"{xfe1}-{xfe2}"
|
|
232
|
-
except Exception as ex:
|
|
233
|
-
raise WebscoutE(
|
|
234
|
-
f"achat_yield() Error to get _chat_xfe: {type(ex).__name__}: {ex}"
|
|
235
|
-
) from ex
|
|
236
|
-
# vqd
|
|
237
|
-
if not self._chat_vqd:
|
|
238
|
-
resp = await self._get_url(
|
|
239
|
-
method="GET", url="https://duckduckgo.com/duckchat/v1/status", headers={"x-vqd-accept": "1"}
|
|
240
|
-
)
|
|
241
|
-
self._chat_vqd = resp.headers.get("x-vqd-4", "")
|
|
242
|
-
self._chat_vqd_hash = resp.headers.get("x-vqd-hash-1", "")
|
|
243
|
-
|
|
244
|
-
self._chat_messages.append({"role": "user", "content": keywords})
|
|
245
|
-
self._chat_tokens_count += max(len(keywords) // 4, 1) # approximate number of tokens
|
|
246
|
-
if model not in self._chat_models:
|
|
247
|
-
warnings.warn(f"{model=} is unavailable. Using 'gpt-4o-mini'", stacklevel=1)
|
|
248
|
-
model = "gpt-4o-mini"
|
|
249
|
-
|
|
250
|
-
# Get Cloudflare Turnstile token
|
|
251
|
-
turnstile_token = await get_turnstile_token()
|
|
252
|
-
|
|
253
|
-
json_data = {
|
|
254
|
-
"model": self._chat_models[model],
|
|
255
|
-
"messages": self._chat_messages,
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
# Add Turnstile token if available
|
|
259
|
-
if turnstile_token:
|
|
260
|
-
json_data["cf-turnstile-response"] = turnstile_token
|
|
261
|
-
|
|
262
|
-
# Enhanced headers to better mimic a real browser
|
|
263
|
-
chat_headers = {
|
|
264
|
-
"x-fe-version": self._chat_xfe,
|
|
265
|
-
"x-vqd-4": self._chat_vqd,
|
|
266
|
-
"x-vqd-hash-1": "",
|
|
267
|
-
"Accept": "text/event-stream",
|
|
268
|
-
"Accept-Language": "en-US,en;q=0.9",
|
|
269
|
-
"Cache-Control": "no-cache",
|
|
270
|
-
"Content-Type": "application/json",
|
|
271
|
-
"DNT": "1",
|
|
272
|
-
"Origin": "https://duckduckgo.com",
|
|
273
|
-
"Referer": "https://duckduckgo.com/",
|
|
274
|
-
"Sec-Fetch-Dest": "empty",
|
|
275
|
-
"Sec-Fetch-Mode": "cors",
|
|
276
|
-
"Sec-Fetch-Site": "same-origin",
|
|
277
|
-
"User-Agent": self.client.headers.get("User-Agent", "")
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
# Retry logic for rate limited requests
|
|
281
|
-
retry_count = 0
|
|
282
|
-
while retry_count <= max_retries:
|
|
283
|
-
try:
|
|
284
|
-
resp = await self._get_url(
|
|
285
|
-
method="POST",
|
|
286
|
-
url="https://duckduckgo.com/duckchat/v1/chat",
|
|
287
|
-
headers=chat_headers,
|
|
288
|
-
json=json_data,
|
|
289
|
-
timeout=timeout,
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
self._chat_vqd = resp.headers.get("x-vqd-4", "")
|
|
293
|
-
self._chat_vqd_hash = resp.headers.get("x-vqd-hash-1", "")
|
|
294
|
-
chunks = []
|
|
295
|
-
|
|
296
|
-
# curl_cffi uses aiter_content instead of aiter_bytes
|
|
297
|
-
async for chunk in resp.aiter_content(chunk_size=1024):
|
|
298
|
-
lines = chunk.split(b"data:")
|
|
299
|
-
for line in lines:
|
|
300
|
-
if line := line.strip():
|
|
301
|
-
if line == b"[DONE]":
|
|
302
|
-
break
|
|
303
|
-
if line == b"[DONE][LIMIT_CONVERSATION]":
|
|
304
|
-
raise ConversationLimitException("ERR_CONVERSATION_LIMIT")
|
|
305
|
-
try:
|
|
306
|
-
x = json_loads(line)
|
|
307
|
-
if isinstance(x, dict):
|
|
308
|
-
if x.get("action") == "error":
|
|
309
|
-
err_message = x.get("type", "")
|
|
310
|
-
if x.get("status") == 429:
|
|
311
|
-
raise (
|
|
312
|
-
ConversationLimitException(err_message)
|
|
313
|
-
if err_message == "ERR_CONVERSATION_LIMIT"
|
|
314
|
-
else RatelimitE(err_message)
|
|
315
|
-
)
|
|
316
|
-
raise WebscoutE(err_message)
|
|
317
|
-
elif message := x.get("message"):
|
|
318
|
-
chunks.append(message)
|
|
319
|
-
yield message
|
|
320
|
-
except Exception:
|
|
321
|
-
# Skip invalid JSON data
|
|
322
|
-
continue
|
|
323
|
-
|
|
324
|
-
# If we get here, the request was successful
|
|
325
|
-
result = "".join(chunks)
|
|
326
|
-
self._chat_messages.append({"role": "assistant", "content": result})
|
|
327
|
-
self._chat_tokens_count += len(result)
|
|
328
|
-
return
|
|
329
|
-
|
|
330
|
-
except RatelimitE as ex:
|
|
331
|
-
retry_count += 1
|
|
332
|
-
if retry_count > max_retries:
|
|
333
|
-
raise WebscoutE(f"achat_yield() Rate limit exceeded after {max_retries} retries: {ex}") from ex
|
|
334
|
-
|
|
335
|
-
# Get a fresh Turnstile token for the retry
|
|
336
|
-
turnstile_token = await get_turnstile_token()
|
|
337
|
-
if turnstile_token:
|
|
338
|
-
json_data["cf-turnstile-response"] = turnstile_token
|
|
339
|
-
|
|
340
|
-
# Exponential backoff
|
|
341
|
-
sleep_time = 2 ** retry_count
|
|
342
|
-
await asyncio.sleep(sleep_time)
|
|
343
|
-
|
|
344
|
-
except Exception as ex:
|
|
345
|
-
raise WebscoutE(f"achat_yield() {type(ex).__name__}: {ex}") from ex
|
|
346
|
-
|
|
347
|
-
async def achat(self, keywords: str, model: str = "gpt-4o-mini", timeout: int = 30, max_retries: int = 3) -> str:
|
|
348
|
-
"""Initiates an async chat session with webscout AI.
|
|
349
|
-
|
|
350
|
-
Args:
|
|
351
|
-
keywords (str): The initial message or question to send to the AI.
|
|
352
|
-
model (str): The model to use: "gpt-4o-mini", "llama-3.3-70b", "claude-3-haiku",
|
|
353
|
-
"o3-mini", "mistral-small-3". Defaults to "gpt-4o-mini".
|
|
354
|
-
timeout (int): Timeout value for the HTTP client. Defaults to 30.
|
|
355
|
-
max_retries (int): Maximum number of retry attempts for rate limited requests. Defaults to 3.
|
|
356
|
-
|
|
357
|
-
Returns:
|
|
358
|
-
str: The response from the AI.
|
|
359
|
-
"""
|
|
360
|
-
chunks = []
|
|
361
|
-
async for chunk in self.achat_yield(keywords, model, timeout, max_retries):
|
|
362
|
-
chunks.append(chunk)
|
|
363
|
-
return "".join(chunks)
|
|
364
|
-
|
|
365
187
|
async def atext(
|
|
366
188
|
self,
|
|
367
189
|
keywords: str,
|
|
@@ -829,4 +651,4 @@ class AsyncWEBS:
|
|
|
829
651
|
TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
|
|
830
652
|
"""
|
|
831
653
|
# These methods are not implemented in the async version yet
|
|
832
|
-
raise NotImplementedError("aweather method is not implemented yet")
|
|
654
|
+
raise NotImplementedError("aweather method is not implemented yet")
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# 🎨 ZeroArt: Zero-Dependency ASCII Art Generator
|
|
2
|
+
|
|
3
|
+
## 🚀 Overview
|
|
4
|
+
|
|
5
|
+
ZeroArt is a powerful, lightweight Python library for generating stunning ASCII art text with zero external dependencies. Transform your plain text into eye-catching, stylized art with just a few lines of code!
|
|
6
|
+
|
|
7
|
+
## ✨ Features
|
|
8
|
+
|
|
9
|
+
- **Multiple Font Styles**
|
|
10
|
+
- Block Font
|
|
11
|
+
- Slant Font
|
|
12
|
+
- Neon Font
|
|
13
|
+
- Cyber Font
|
|
14
|
+
|
|
15
|
+
- **Zero Dependencies**
|
|
16
|
+
- Completely standalone library
|
|
17
|
+
- No external package requirements
|
|
18
|
+
|
|
19
|
+
- **Easy to Use**
|
|
20
|
+
- Simple, intuitive API
|
|
21
|
+
- Minimal setup needed
|
|
22
|
+
|
|
23
|
+
- **Text Effects**
|
|
24
|
+
- Rainbow coloring
|
|
25
|
+
- Glitch effect
|
|
26
|
+
- Text wrapping
|
|
27
|
+
- Outline generation
|
|
28
|
+
|
|
29
|
+
## 🛠 Installation
|
|
30
|
+
|
|
31
|
+
No installation required! Just copy the `zeroart` directory into your project.
|
|
32
|
+
|
|
33
|
+
## 💻 Usage Examples
|
|
34
|
+
|
|
35
|
+
### Basic ASCII Art
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from webscout import zeroart
|
|
39
|
+
|
|
40
|
+
# Generate ASCII art
|
|
41
|
+
art = zeroart.figlet_format("PYTHON", font='block')
|
|
42
|
+
print(art)
|
|
43
|
+
|
|
44
|
+
# Directly print ASCII art
|
|
45
|
+
zeroart.print_figlet("CODING", font='slant')
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Font Styles
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from webscout import zeroart
|
|
52
|
+
|
|
53
|
+
# Different font styles
|
|
54
|
+
print(zeroart.figlet_format("AWESOME", font='block')) # Block style
|
|
55
|
+
print(zeroart.figlet_format("CODING", font='slant')) # Slant style
|
|
56
|
+
print(zeroart.figlet_format("NEON", font='neon')) # Neon style
|
|
57
|
+
print(zeroart.figlet_format("CYBER", font='cyber')) # Cyber style
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Text Effects
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from webscout import zeroart
|
|
64
|
+
|
|
65
|
+
# Rainbow effect
|
|
66
|
+
print(zeroart.rainbow("COLORFUL", font='neon'))
|
|
67
|
+
|
|
68
|
+
# Glitch effect
|
|
69
|
+
print(zeroart.glitch("GLITCH", font='cyber'))
|
|
70
|
+
|
|
71
|
+
# Outline effect
|
|
72
|
+
print(zeroart.outline("BORDER", font='block'))
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 🎨 Available Fonts
|
|
76
|
+
|
|
77
|
+
1. **Block Font**: Classic, bold block-style letters
|
|
78
|
+
2. **Slant Font**: Elegant, slanted text
|
|
79
|
+
3. **Neon Font**: Glowing, pixel-style art
|
|
80
|
+
4. **Cyber Font**: Cyberpunk-inspired rendering
|
|
81
|
+
|
|
82
|
+
## 🤝 Contributing
|
|
83
|
+
|
|
84
|
+
Contributions are welcome!
|
|
85
|
+
|
|
86
|
+
- Fork the repository
|
|
87
|
+
- Create a new font
|
|
88
|
+
- Add text effects
|
|
89
|
+
- Improve existing code
|
webscout/zeroart/__init__.py
CHANGED
|
@@ -1,55 +1,135 @@
|
|
|
1
|
-
"""
|
|
2
|
-
ZeroArt: A zero-dependency ASCII art text generator
|
|
3
|
-
|
|
4
|
-
Create awesome ASCII art text without external dependencies!
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from
|
|
8
|
-
from .
|
|
9
|
-
from .
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
'
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
'
|
|
53
|
-
|
|
54
|
-
|
|
1
|
+
"""
|
|
2
|
+
ZeroArt: A zero-dependency ASCII art text generator
|
|
3
|
+
|
|
4
|
+
Create awesome ASCII art text without external dependencies!
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, List, Literal, Optional, Union
|
|
8
|
+
from .base import ZeroArtFont
|
|
9
|
+
from .fonts import BlockFont, SlantFont, NeonFont, CyberFont, DottedFont, ShadowFont
|
|
10
|
+
from .effects import AsciiArtEffects
|
|
11
|
+
|
|
12
|
+
FontType = Literal['block', 'slant', 'neon', 'cyber', 'dotted', 'shadow']
|
|
13
|
+
|
|
14
|
+
def figlet_format(text: str, font: Union[str, ZeroArtFont] = 'block') -> str:
|
|
15
|
+
"""
|
|
16
|
+
Generate ASCII art text
|
|
17
|
+
|
|
18
|
+
:param text: Text to convert
|
|
19
|
+
:param font: Font style (default: 'block')
|
|
20
|
+
:return: ASCII art representation of text
|
|
21
|
+
"""
|
|
22
|
+
font_map: Dict[str, ZeroArtFont] = {
|
|
23
|
+
'block': BlockFont(),
|
|
24
|
+
'slant': SlantFont(),
|
|
25
|
+
'neon': NeonFont(),
|
|
26
|
+
'cyber': CyberFont(),
|
|
27
|
+
'dotted': DottedFont(),
|
|
28
|
+
'shadow': ShadowFont()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if isinstance(font, str):
|
|
32
|
+
selected_font: ZeroArtFont = font_map.get(font.lower(), BlockFont())
|
|
33
|
+
else:
|
|
34
|
+
selected_font = font
|
|
35
|
+
return selected_font.render(text)
|
|
36
|
+
|
|
37
|
+
def print_figlet(text: str, font: Union[str, ZeroArtFont] = 'block') -> None:
|
|
38
|
+
"""
|
|
39
|
+
Print ASCII art text directly
|
|
40
|
+
|
|
41
|
+
:param text: Text to convert and print
|
|
42
|
+
:param font: Font style (default: 'block')
|
|
43
|
+
"""
|
|
44
|
+
print(figlet_format(text, font))
|
|
45
|
+
|
|
46
|
+
# Expose additional effects with font handling
|
|
47
|
+
def rainbow(text: str, font: Union[str, ZeroArtFont] = 'block') -> str:
|
|
48
|
+
"""
|
|
49
|
+
Apply a rainbow-like color effect to ASCII art
|
|
50
|
+
|
|
51
|
+
:param text: Text to render
|
|
52
|
+
:param font: Font style (default: 'block')
|
|
53
|
+
:return: Rainbow-styled ASCII art
|
|
54
|
+
"""
|
|
55
|
+
font_map: Dict[str, ZeroArtFont] = {
|
|
56
|
+
'block': BlockFont(),
|
|
57
|
+
'slant': SlantFont(),
|
|
58
|
+
'neon': NeonFont(),
|
|
59
|
+
'cyber': CyberFont(),
|
|
60
|
+
'dotted': DottedFont(),
|
|
61
|
+
'shadow': ShadowFont()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if isinstance(font, str):
|
|
65
|
+
selected_font: ZeroArtFont = font_map.get(font.lower(), BlockFont())
|
|
66
|
+
else:
|
|
67
|
+
selected_font = font
|
|
68
|
+
return AsciiArtEffects.rainbow_effect(text, selected_font)
|
|
69
|
+
|
|
70
|
+
def glitch(text: str, font: Union[str, ZeroArtFont] = 'block', glitch_intensity: float = 0.1) -> str:
|
|
71
|
+
"""
|
|
72
|
+
Apply a glitch-like distortion to ASCII art
|
|
73
|
+
|
|
74
|
+
:param text: Text to render
|
|
75
|
+
:param font: Font style (default: 'block')
|
|
76
|
+
:param glitch_intensity: Probability of character distortion
|
|
77
|
+
:return: Glitched ASCII art
|
|
78
|
+
"""
|
|
79
|
+
font_map: Dict[str, ZeroArtFont] = {
|
|
80
|
+
'block': BlockFont(),
|
|
81
|
+
'slant': SlantFont(),
|
|
82
|
+
'neon': NeonFont(),
|
|
83
|
+
'cyber': CyberFont(),
|
|
84
|
+
'dotted': DottedFont(),
|
|
85
|
+
'shadow': ShadowFont()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if isinstance(font, str):
|
|
89
|
+
selected_font: ZeroArtFont = font_map.get(font.lower(), BlockFont())
|
|
90
|
+
else:
|
|
91
|
+
selected_font = font
|
|
92
|
+
return AsciiArtEffects.glitch_effect(text, selected_font, glitch_intensity)
|
|
93
|
+
|
|
94
|
+
wrap_text = AsciiArtEffects.wrap_text
|
|
95
|
+
|
|
96
|
+
def outline(text: str, font: Union[str, ZeroArtFont] = 'block', outline_char: str = '*') -> str:
|
|
97
|
+
"""
|
|
98
|
+
Add an outline effect to ASCII art
|
|
99
|
+
|
|
100
|
+
:param text: Text to render
|
|
101
|
+
:param font: Font style (default: 'block')
|
|
102
|
+
:param outline_char: Character to use for outline
|
|
103
|
+
:return: ASCII art with outline
|
|
104
|
+
"""
|
|
105
|
+
font_map: Dict[str, ZeroArtFont] = {
|
|
106
|
+
'block': BlockFont(),
|
|
107
|
+
'slant': SlantFont(),
|
|
108
|
+
'neon': NeonFont(),
|
|
109
|
+
'cyber': CyberFont(),
|
|
110
|
+
'dotted': DottedFont(),
|
|
111
|
+
'shadow': ShadowFont()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if isinstance(font, str):
|
|
115
|
+
selected_font: ZeroArtFont = font_map.get(font.lower(), BlockFont())
|
|
116
|
+
else:
|
|
117
|
+
selected_font = font
|
|
118
|
+
return AsciiArtEffects.outline_effect(text, selected_font, outline_char)
|
|
119
|
+
|
|
120
|
+
__all__ = [
|
|
121
|
+
'figlet_format',
|
|
122
|
+
'print_figlet',
|
|
123
|
+
'rainbow',
|
|
124
|
+
'glitch',
|
|
125
|
+
'wrap_text',
|
|
126
|
+
'outline',
|
|
127
|
+
'BlockFont',
|
|
128
|
+
'SlantFont',
|
|
129
|
+
'NeonFont',
|
|
130
|
+
'CyberFont',
|
|
131
|
+
'DottedFont',
|
|
132
|
+
'ShadowFont',
|
|
133
|
+
'ZeroArtFont',
|
|
134
|
+
'FontType'
|
|
55
135
|
]
|
webscout/zeroart/base.py
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"""
|
|
2
2
|
ZeroArt Base: Core classes and utilities for ASCII art generation
|
|
3
3
|
"""
|
|
4
|
+
from typing import Dict, List, Optional, Union
|
|
4
5
|
|
|
5
6
|
class ZeroArtFont:
|
|
6
7
|
"""Base class for ASCII art fonts"""
|
|
7
|
-
def __init__(self, name):
|
|
8
|
-
self.name = name
|
|
9
|
-
self.letters = {}
|
|
10
|
-
self.special_chars = {}
|
|
8
|
+
def __init__(self, name: str) -> None:
|
|
9
|
+
self.name: str = name
|
|
10
|
+
self.letters: Dict[str, List[str]] = {}
|
|
11
|
+
self.special_chars: Dict[str, List[str]] = {}
|
|
11
12
|
|
|
12
|
-
def add_letter(self, char, art_lines):
|
|
13
|
+
def add_letter(self, char: str, art_lines: List[str]) -> None:
|
|
13
14
|
"""
|
|
14
15
|
Add a custom letter to the font
|
|
15
16
|
|
|
@@ -18,7 +19,7 @@ class ZeroArtFont:
|
|
|
18
19
|
"""
|
|
19
20
|
self.letters[char.upper()] = art_lines
|
|
20
21
|
|
|
21
|
-
def add_special_char(self, name, art_lines):
|
|
22
|
+
def add_special_char(self, name: str, art_lines: List[str]) -> None:
|
|
22
23
|
"""
|
|
23
24
|
Add a special ASCII art character or design
|
|
24
25
|
|
|
@@ -27,7 +28,7 @@ class ZeroArtFont:
|
|
|
27
28
|
"""
|
|
28
29
|
self.special_chars[name] = art_lines
|
|
29
30
|
|
|
30
|
-
def get_letter(self, char):
|
|
31
|
+
def get_letter(self, char: str) -> List[str]:
|
|
31
32
|
"""
|
|
32
33
|
Get ASCII art for a specific character
|
|
33
34
|
|
|
@@ -36,19 +37,24 @@ class ZeroArtFont:
|
|
|
36
37
|
"""
|
|
37
38
|
return self.letters.get(char.upper(), self.letters.get(' ', [' ']))
|
|
38
39
|
|
|
39
|
-
def render(self, text):
|
|
40
|
+
def render(self, text: str) -> str:
|
|
41
|
+
"""
|
|
42
|
+
Render text as ASCII art
|
|
43
|
+
|
|
44
|
+
:param text: Text to render as ASCII art
|
|
45
|
+
:return: ASCII art representation of the text
|
|
46
|
+
"""
|
|
40
47
|
if not text:
|
|
41
48
|
return ""
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
max_height = max(len(self.get_letter(c)) for c in text)
|
|
49
|
+
# Get the maximum height of any character in the font
|
|
50
|
+
max_height: int = max(len(self.get_letter(c)) for c in text)
|
|
45
51
|
|
|
46
52
|
# Initialize art_lines with empty strings
|
|
47
|
-
art_lines = ["" for _ in range(max_height)]
|
|
53
|
+
art_lines: List[str] = ["" for _ in range(max_height)]
|
|
48
54
|
|
|
49
55
|
# Process each character
|
|
50
56
|
for char in text:
|
|
51
|
-
char_art = self.get_letter(char)
|
|
57
|
+
char_art: List[str] = self.get_letter(char)
|
|
52
58
|
# Pad shorter characters with empty lines to match max_height
|
|
53
59
|
while len(char_art) < max_height:
|
|
54
60
|
char_art.append(" " * len(char_art[0]))
|