webscout 8.2.2__py3-none-any.whl → 2026.1.19__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.
Files changed (483) hide show
  1. webscout/AIauto.py +524 -143
  2. webscout/AIbase.py +247 -123
  3. webscout/AIutel.py +68 -132
  4. webscout/Bard.py +1072 -535
  5. webscout/Extra/GitToolkit/__init__.py +2 -2
  6. webscout/Extra/GitToolkit/gitapi/__init__.py +20 -12
  7. webscout/Extra/GitToolkit/gitapi/gist.py +142 -0
  8. webscout/Extra/GitToolkit/gitapi/organization.py +91 -0
  9. webscout/Extra/GitToolkit/gitapi/repository.py +308 -195
  10. webscout/Extra/GitToolkit/gitapi/search.py +162 -0
  11. webscout/Extra/GitToolkit/gitapi/trending.py +236 -0
  12. webscout/Extra/GitToolkit/gitapi/user.py +128 -96
  13. webscout/Extra/GitToolkit/gitapi/utils.py +82 -62
  14. webscout/Extra/YTToolkit/README.md +443 -0
  15. webscout/Extra/YTToolkit/YTdownloader.py +953 -957
  16. webscout/Extra/YTToolkit/__init__.py +3 -3
  17. webscout/Extra/YTToolkit/transcriber.py +595 -476
  18. webscout/Extra/YTToolkit/ytapi/README.md +230 -0
  19. webscout/Extra/YTToolkit/ytapi/__init__.py +22 -6
  20. webscout/Extra/YTToolkit/ytapi/captions.py +190 -0
  21. webscout/Extra/YTToolkit/ytapi/channel.py +302 -307
  22. webscout/Extra/YTToolkit/ytapi/errors.py +13 -13
  23. webscout/Extra/YTToolkit/ytapi/extras.py +178 -45
  24. webscout/Extra/YTToolkit/ytapi/hashtag.py +120 -0
  25. webscout/Extra/YTToolkit/ytapi/https.py +89 -88
  26. webscout/Extra/YTToolkit/ytapi/patterns.py +61 -61
  27. webscout/Extra/YTToolkit/ytapi/playlist.py +59 -59
  28. webscout/Extra/YTToolkit/ytapi/pool.py +8 -8
  29. webscout/Extra/YTToolkit/ytapi/query.py +143 -40
  30. webscout/Extra/YTToolkit/ytapi/shorts.py +122 -0
  31. webscout/Extra/YTToolkit/ytapi/stream.py +68 -63
  32. webscout/Extra/YTToolkit/ytapi/suggestions.py +97 -0
  33. webscout/Extra/YTToolkit/ytapi/utils.py +66 -62
  34. webscout/Extra/YTToolkit/ytapi/video.py +189 -18
  35. webscout/Extra/__init__.py +2 -3
  36. webscout/Extra/gguf.py +1298 -682
  37. webscout/Extra/tempmail/README.md +488 -0
  38. webscout/Extra/tempmail/__init__.py +28 -28
  39. webscout/Extra/tempmail/async_utils.py +143 -141
  40. webscout/Extra/tempmail/base.py +172 -161
  41. webscout/Extra/tempmail/cli.py +191 -187
  42. webscout/Extra/tempmail/emailnator.py +88 -84
  43. webscout/Extra/tempmail/mail_tm.py +378 -361
  44. webscout/Extra/tempmail/temp_mail_io.py +304 -292
  45. webscout/Extra/weather.py +196 -194
  46. webscout/Extra/weather_ascii.py +17 -15
  47. webscout/Provider/AISEARCH/PERPLEXED_search.py +175 -0
  48. webscout/Provider/AISEARCH/Perplexity.py +237 -304
  49. webscout/Provider/AISEARCH/README.md +106 -0
  50. webscout/Provider/AISEARCH/__init__.py +16 -10
  51. webscout/Provider/AISEARCH/brave_search.py +298 -0
  52. webscout/Provider/AISEARCH/iask_search.py +130 -209
  53. webscout/Provider/AISEARCH/monica_search.py +200 -246
  54. webscout/Provider/AISEARCH/webpilotai_search.py +242 -281
  55. webscout/Provider/Algion.py +413 -0
  56. webscout/Provider/Andi.py +74 -69
  57. webscout/Provider/Apriel.py +313 -0
  58. webscout/Provider/Ayle.py +323 -0
  59. webscout/Provider/ChatSandbox.py +329 -0
  60. webscout/Provider/ClaudeOnline.py +365 -0
  61. webscout/Provider/Cohere.py +232 -208
  62. webscout/Provider/DeepAI.py +367 -0
  63. webscout/Provider/Deepinfra.py +343 -173
  64. webscout/Provider/EssentialAI.py +217 -0
  65. webscout/Provider/ExaAI.py +274 -261
  66. webscout/Provider/Gemini.py +60 -54
  67. webscout/Provider/GithubChat.py +385 -367
  68. webscout/Provider/Gradient.py +286 -0
  69. webscout/Provider/Groq.py +556 -670
  70. webscout/Provider/HadadXYZ.py +323 -0
  71. webscout/Provider/HeckAI.py +392 -233
  72. webscout/Provider/HuggingFace.py +387 -0
  73. webscout/Provider/IBM.py +340 -0
  74. webscout/Provider/Jadve.py +317 -266
  75. webscout/Provider/K2Think.py +306 -0
  76. webscout/Provider/Koboldai.py +221 -381
  77. webscout/Provider/Netwrck.py +273 -228
  78. webscout/Provider/Nvidia.py +310 -0
  79. webscout/Provider/OPENAI/DeepAI.py +489 -0
  80. webscout/Provider/OPENAI/K2Think.py +423 -0
  81. webscout/Provider/OPENAI/PI.py +463 -0
  82. webscout/Provider/OPENAI/README.md +890 -0
  83. webscout/Provider/OPENAI/TogetherAI.py +405 -0
  84. webscout/Provider/OPENAI/TwoAI.py +255 -0
  85. webscout/Provider/OPENAI/__init__.py +148 -25
  86. webscout/Provider/OPENAI/ai4chat.py +348 -0
  87. webscout/Provider/OPENAI/akashgpt.py +436 -0
  88. webscout/Provider/OPENAI/algion.py +303 -0
  89. webscout/Provider/OPENAI/ayle.py +365 -0
  90. webscout/Provider/OPENAI/base.py +253 -46
  91. webscout/Provider/OPENAI/cerebras.py +296 -0
  92. webscout/Provider/OPENAI/chatgpt.py +514 -193
  93. webscout/Provider/OPENAI/chatsandbox.py +233 -0
  94. webscout/Provider/OPENAI/deepinfra.py +403 -272
  95. webscout/Provider/OPENAI/e2b.py +2370 -1350
  96. webscout/Provider/OPENAI/elmo.py +278 -0
  97. webscout/Provider/OPENAI/exaai.py +186 -138
  98. webscout/Provider/OPENAI/freeassist.py +446 -0
  99. webscout/Provider/OPENAI/gradient.py +448 -0
  100. webscout/Provider/OPENAI/groq.py +380 -0
  101. webscout/Provider/OPENAI/hadadxyz.py +292 -0
  102. webscout/Provider/OPENAI/heckai.py +100 -104
  103. webscout/Provider/OPENAI/huggingface.py +321 -0
  104. webscout/Provider/OPENAI/ibm.py +425 -0
  105. webscout/Provider/OPENAI/llmchat.py +253 -0
  106. webscout/Provider/OPENAI/llmchatco.py +378 -327
  107. webscout/Provider/OPENAI/meta.py +541 -0
  108. webscout/Provider/OPENAI/netwrck.py +110 -84
  109. webscout/Provider/OPENAI/nvidia.py +317 -0
  110. webscout/Provider/OPENAI/oivscode.py +348 -0
  111. webscout/Provider/OPENAI/openrouter.py +328 -0
  112. webscout/Provider/OPENAI/pydantic_imports.py +1 -0
  113. webscout/Provider/OPENAI/sambanova.py +397 -0
  114. webscout/Provider/OPENAI/sonus.py +126 -115
  115. webscout/Provider/OPENAI/textpollinations.py +218 -133
  116. webscout/Provider/OPENAI/toolbaz.py +136 -166
  117. webscout/Provider/OPENAI/typefully.py +419 -0
  118. webscout/Provider/OPENAI/typliai.py +279 -0
  119. webscout/Provider/OPENAI/utils.py +314 -211
  120. webscout/Provider/OPENAI/wisecat.py +103 -125
  121. webscout/Provider/OPENAI/writecream.py +185 -156
  122. webscout/Provider/OPENAI/x0gpt.py +227 -136
  123. webscout/Provider/OPENAI/zenmux.py +380 -0
  124. webscout/Provider/OpenRouter.py +386 -0
  125. webscout/Provider/Openai.py +337 -496
  126. webscout/Provider/PI.py +443 -344
  127. webscout/Provider/QwenLM.py +346 -254
  128. webscout/Provider/STT/__init__.py +28 -0
  129. webscout/Provider/STT/base.py +303 -0
  130. webscout/Provider/STT/elevenlabs.py +264 -0
  131. webscout/Provider/Sambanova.py +317 -0
  132. webscout/Provider/TTI/README.md +69 -0
  133. webscout/Provider/TTI/__init__.py +37 -12
  134. webscout/Provider/TTI/base.py +147 -0
  135. webscout/Provider/TTI/claudeonline.py +393 -0
  136. webscout/Provider/TTI/magicstudio.py +292 -0
  137. webscout/Provider/TTI/miragic.py +180 -0
  138. webscout/Provider/TTI/pollinations.py +331 -0
  139. webscout/Provider/TTI/together.py +334 -0
  140. webscout/Provider/TTI/utils.py +14 -0
  141. webscout/Provider/TTS/README.md +186 -0
  142. webscout/Provider/TTS/__init__.py +43 -7
  143. webscout/Provider/TTS/base.py +523 -0
  144. webscout/Provider/TTS/deepgram.py +286 -156
  145. webscout/Provider/TTS/elevenlabs.py +189 -111
  146. webscout/Provider/TTS/freetts.py +218 -0
  147. webscout/Provider/TTS/murfai.py +288 -113
  148. webscout/Provider/TTS/openai_fm.py +364 -0
  149. webscout/Provider/TTS/parler.py +203 -111
  150. webscout/Provider/TTS/qwen.py +334 -0
  151. webscout/Provider/TTS/sherpa.py +286 -0
  152. webscout/Provider/TTS/speechma.py +693 -180
  153. webscout/Provider/TTS/streamElements.py +275 -333
  154. webscout/Provider/TTS/utils.py +280 -280
  155. webscout/Provider/TextPollinationsAI.py +221 -121
  156. webscout/Provider/TogetherAI.py +450 -0
  157. webscout/Provider/TwoAI.py +309 -199
  158. webscout/Provider/TypliAI.py +311 -0
  159. webscout/Provider/UNFINISHED/ChatHub.py +219 -0
  160. webscout/Provider/{OPENAI/glider.py → UNFINISHED/ChutesAI.py} +160 -145
  161. webscout/Provider/UNFINISHED/GizAI.py +300 -0
  162. webscout/Provider/UNFINISHED/Marcus.py +218 -0
  163. webscout/Provider/UNFINISHED/Qodo.py +481 -0
  164. webscout/Provider/UNFINISHED/XenAI.py +330 -0
  165. webscout/Provider/{Youchat.py → UNFINISHED/Youchat.py} +64 -47
  166. webscout/Provider/UNFINISHED/aihumanizer.py +41 -0
  167. webscout/Provider/UNFINISHED/grammerchecker.py +37 -0
  168. webscout/Provider/UNFINISHED/liner.py +342 -0
  169. webscout/Provider/UNFINISHED/liner_api_request.py +246 -0
  170. webscout/Provider/UNFINISHED/samurai.py +231 -0
  171. webscout/Provider/WiseCat.py +256 -196
  172. webscout/Provider/WrDoChat.py +390 -0
  173. webscout/Provider/__init__.py +115 -198
  174. webscout/Provider/ai4chat.py +181 -202
  175. webscout/Provider/akashgpt.py +330 -342
  176. webscout/Provider/cerebras.py +397 -242
  177. webscout/Provider/cleeai.py +236 -213
  178. webscout/Provider/elmo.py +291 -234
  179. webscout/Provider/geminiapi.py +343 -208
  180. webscout/Provider/julius.py +245 -223
  181. webscout/Provider/learnfastai.py +333 -266
  182. webscout/Provider/llama3mitril.py +230 -180
  183. webscout/Provider/llmchat.py +308 -213
  184. webscout/Provider/llmchatco.py +321 -311
  185. webscout/Provider/meta.py +996 -794
  186. webscout/Provider/oivscode.py +332 -0
  187. webscout/Provider/searchchat.py +316 -293
  188. webscout/Provider/sonus.py +264 -208
  189. webscout/Provider/toolbaz.py +359 -320
  190. webscout/Provider/turboseek.py +332 -219
  191. webscout/Provider/typefully.py +262 -280
  192. webscout/Provider/x0gpt.py +332 -256
  193. webscout/__init__.py +31 -38
  194. webscout/__main__.py +5 -5
  195. webscout/cli.py +585 -293
  196. webscout/client.py +1497 -0
  197. webscout/conversation.py +140 -565
  198. webscout/exceptions.py +383 -339
  199. webscout/litagent/__init__.py +29 -29
  200. webscout/litagent/agent.py +492 -455
  201. webscout/litagent/constants.py +60 -60
  202. webscout/models.py +505 -181
  203. webscout/optimizers.py +32 -378
  204. webscout/prompt_manager.py +376 -274
  205. webscout/sanitize.py +1514 -0
  206. webscout/scout/README.md +452 -0
  207. webscout/scout/__init__.py +8 -8
  208. webscout/scout/core/__init__.py +7 -7
  209. webscout/scout/core/crawler.py +330 -140
  210. webscout/scout/core/scout.py +800 -568
  211. webscout/scout/core/search_result.py +51 -96
  212. webscout/scout/core/text_analyzer.py +64 -63
  213. webscout/scout/core/text_utils.py +412 -277
  214. webscout/scout/core/web_analyzer.py +54 -52
  215. webscout/scout/element.py +872 -460
  216. webscout/scout/parsers/__init__.py +70 -69
  217. webscout/scout/parsers/html5lib_parser.py +182 -172
  218. webscout/scout/parsers/html_parser.py +238 -236
  219. webscout/scout/parsers/lxml_parser.py +203 -178
  220. webscout/scout/utils.py +38 -37
  221. webscout/search/__init__.py +47 -0
  222. webscout/search/base.py +201 -0
  223. webscout/search/bing_main.py +45 -0
  224. webscout/search/brave_main.py +92 -0
  225. webscout/search/duckduckgo_main.py +57 -0
  226. webscout/search/engines/__init__.py +127 -0
  227. webscout/search/engines/bing/__init__.py +15 -0
  228. webscout/search/engines/bing/base.py +35 -0
  229. webscout/search/engines/bing/images.py +114 -0
  230. webscout/search/engines/bing/news.py +96 -0
  231. webscout/search/engines/bing/suggestions.py +36 -0
  232. webscout/search/engines/bing/text.py +109 -0
  233. webscout/search/engines/brave/__init__.py +19 -0
  234. webscout/search/engines/brave/base.py +47 -0
  235. webscout/search/engines/brave/images.py +213 -0
  236. webscout/search/engines/brave/news.py +353 -0
  237. webscout/search/engines/brave/suggestions.py +318 -0
  238. webscout/search/engines/brave/text.py +167 -0
  239. webscout/search/engines/brave/videos.py +364 -0
  240. webscout/search/engines/duckduckgo/__init__.py +25 -0
  241. webscout/search/engines/duckduckgo/answers.py +80 -0
  242. webscout/search/engines/duckduckgo/base.py +189 -0
  243. webscout/search/engines/duckduckgo/images.py +100 -0
  244. webscout/search/engines/duckduckgo/maps.py +183 -0
  245. webscout/search/engines/duckduckgo/news.py +70 -0
  246. webscout/search/engines/duckduckgo/suggestions.py +22 -0
  247. webscout/search/engines/duckduckgo/text.py +221 -0
  248. webscout/search/engines/duckduckgo/translate.py +48 -0
  249. webscout/search/engines/duckduckgo/videos.py +80 -0
  250. webscout/search/engines/duckduckgo/weather.py +84 -0
  251. webscout/search/engines/mojeek.py +61 -0
  252. webscout/search/engines/wikipedia.py +77 -0
  253. webscout/search/engines/yahoo/__init__.py +41 -0
  254. webscout/search/engines/yahoo/answers.py +19 -0
  255. webscout/search/engines/yahoo/base.py +34 -0
  256. webscout/search/engines/yahoo/images.py +323 -0
  257. webscout/search/engines/yahoo/maps.py +19 -0
  258. webscout/search/engines/yahoo/news.py +258 -0
  259. webscout/search/engines/yahoo/suggestions.py +140 -0
  260. webscout/search/engines/yahoo/text.py +273 -0
  261. webscout/search/engines/yahoo/translate.py +19 -0
  262. webscout/search/engines/yahoo/videos.py +302 -0
  263. webscout/search/engines/yahoo/weather.py +220 -0
  264. webscout/search/engines/yandex.py +67 -0
  265. webscout/search/engines/yep/__init__.py +13 -0
  266. webscout/search/engines/yep/base.py +34 -0
  267. webscout/search/engines/yep/images.py +101 -0
  268. webscout/search/engines/yep/suggestions.py +38 -0
  269. webscout/search/engines/yep/text.py +99 -0
  270. webscout/search/http_client.py +172 -0
  271. webscout/search/results.py +141 -0
  272. webscout/search/yahoo_main.py +57 -0
  273. webscout/search/yep_main.py +48 -0
  274. webscout/server/__init__.py +48 -0
  275. webscout/server/config.py +78 -0
  276. webscout/server/exceptions.py +69 -0
  277. webscout/server/providers.py +286 -0
  278. webscout/server/request_models.py +131 -0
  279. webscout/server/request_processing.py +404 -0
  280. webscout/server/routes.py +642 -0
  281. webscout/server/server.py +351 -0
  282. webscout/server/ui_templates.py +1171 -0
  283. webscout/swiftcli/__init__.py +79 -809
  284. webscout/swiftcli/core/__init__.py +7 -0
  285. webscout/swiftcli/core/cli.py +574 -0
  286. webscout/swiftcli/core/context.py +98 -0
  287. webscout/swiftcli/core/group.py +268 -0
  288. webscout/swiftcli/decorators/__init__.py +28 -0
  289. webscout/swiftcli/decorators/command.py +243 -0
  290. webscout/swiftcli/decorators/options.py +247 -0
  291. webscout/swiftcli/decorators/output.py +392 -0
  292. webscout/swiftcli/exceptions.py +21 -0
  293. webscout/swiftcli/plugins/__init__.py +9 -0
  294. webscout/swiftcli/plugins/base.py +134 -0
  295. webscout/swiftcli/plugins/manager.py +269 -0
  296. webscout/swiftcli/utils/__init__.py +58 -0
  297. webscout/swiftcli/utils/formatting.py +251 -0
  298. webscout/swiftcli/utils/parsing.py +368 -0
  299. webscout/update_checker.py +280 -136
  300. webscout/utils.py +28 -14
  301. webscout/version.py +2 -1
  302. webscout/version.py.bak +3 -0
  303. webscout/zeroart/__init__.py +218 -55
  304. webscout/zeroart/base.py +70 -60
  305. webscout/zeroart/effects.py +155 -99
  306. webscout/zeroart/fonts.py +1799 -816
  307. webscout-2026.1.19.dist-info/METADATA +638 -0
  308. webscout-2026.1.19.dist-info/RECORD +312 -0
  309. {webscout-8.2.2.dist-info → webscout-2026.1.19.dist-info}/WHEEL +1 -1
  310. webscout-2026.1.19.dist-info/entry_points.txt +4 -0
  311. webscout-2026.1.19.dist-info/top_level.txt +1 -0
  312. inferno/__init__.py +0 -6
  313. inferno/__main__.py +0 -9
  314. inferno/cli.py +0 -6
  315. webscout/DWEBS.py +0 -477
  316. webscout/Extra/autocoder/__init__.py +0 -9
  317. webscout/Extra/autocoder/autocoder.py +0 -849
  318. webscout/Extra/autocoder/autocoder_utiles.py +0 -332
  319. webscout/LLM.py +0 -442
  320. webscout/Litlogger/__init__.py +0 -67
  321. webscout/Litlogger/core/__init__.py +0 -6
  322. webscout/Litlogger/core/level.py +0 -23
  323. webscout/Litlogger/core/logger.py +0 -165
  324. webscout/Litlogger/handlers/__init__.py +0 -12
  325. webscout/Litlogger/handlers/console.py +0 -33
  326. webscout/Litlogger/handlers/file.py +0 -143
  327. webscout/Litlogger/handlers/network.py +0 -173
  328. webscout/Litlogger/styles/__init__.py +0 -7
  329. webscout/Litlogger/styles/colors.py +0 -249
  330. webscout/Litlogger/styles/formats.py +0 -458
  331. webscout/Litlogger/styles/text.py +0 -87
  332. webscout/Litlogger/utils/__init__.py +0 -6
  333. webscout/Litlogger/utils/detectors.py +0 -153
  334. webscout/Litlogger/utils/formatters.py +0 -200
  335. webscout/Local/__init__.py +0 -12
  336. webscout/Local/__main__.py +0 -9
  337. webscout/Local/api.py +0 -576
  338. webscout/Local/cli.py +0 -516
  339. webscout/Local/config.py +0 -75
  340. webscout/Local/llm.py +0 -287
  341. webscout/Local/model_manager.py +0 -253
  342. webscout/Local/server.py +0 -721
  343. webscout/Local/utils.py +0 -93
  344. webscout/Provider/AI21.py +0 -177
  345. webscout/Provider/AISEARCH/DeepFind.py +0 -250
  346. webscout/Provider/AISEARCH/ISou.py +0 -256
  347. webscout/Provider/AISEARCH/felo_search.py +0 -228
  348. webscout/Provider/AISEARCH/genspark_search.py +0 -208
  349. webscout/Provider/AISEARCH/hika_search.py +0 -194
  350. webscout/Provider/AISEARCH/scira_search.py +0 -324
  351. webscout/Provider/Aitopia.py +0 -292
  352. webscout/Provider/AllenAI.py +0 -413
  353. webscout/Provider/Blackboxai.py +0 -229
  354. webscout/Provider/C4ai.py +0 -432
  355. webscout/Provider/ChatGPTClone.py +0 -226
  356. webscout/Provider/ChatGPTES.py +0 -237
  357. webscout/Provider/ChatGPTGratis.py +0 -194
  358. webscout/Provider/Chatify.py +0 -175
  359. webscout/Provider/Cloudflare.py +0 -273
  360. webscout/Provider/DeepSeek.py +0 -196
  361. webscout/Provider/ElectronHub.py +0 -709
  362. webscout/Provider/ExaChat.py +0 -342
  363. webscout/Provider/Free2GPT.py +0 -241
  364. webscout/Provider/GPTWeb.py +0 -193
  365. webscout/Provider/Glider.py +0 -211
  366. webscout/Provider/HF_space/__init__.py +0 -0
  367. webscout/Provider/HF_space/qwen_qwen2.py +0 -206
  368. webscout/Provider/HuggingFaceChat.py +0 -462
  369. webscout/Provider/Hunyuan.py +0 -272
  370. webscout/Provider/LambdaChat.py +0 -392
  371. webscout/Provider/Llama.py +0 -200
  372. webscout/Provider/Llama3.py +0 -204
  373. webscout/Provider/Marcus.py +0 -148
  374. webscout/Provider/OLLAMA.py +0 -396
  375. webscout/Provider/OPENAI/c4ai.py +0 -367
  376. webscout/Provider/OPENAI/chatgptclone.py +0 -460
  377. webscout/Provider/OPENAI/exachat.py +0 -433
  378. webscout/Provider/OPENAI/freeaichat.py +0 -352
  379. webscout/Provider/OPENAI/opkfc.py +0 -488
  380. webscout/Provider/OPENAI/scirachat.py +0 -463
  381. webscout/Provider/OPENAI/standardinput.py +0 -425
  382. webscout/Provider/OPENAI/typegpt.py +0 -346
  383. webscout/Provider/OPENAI/uncovrAI.py +0 -455
  384. webscout/Provider/OPENAI/venice.py +0 -413
  385. webscout/Provider/OPENAI/yep.py +0 -327
  386. webscout/Provider/OpenGPT.py +0 -199
  387. webscout/Provider/Perplexitylabs.py +0 -415
  388. webscout/Provider/Phind.py +0 -535
  389. webscout/Provider/PizzaGPT.py +0 -198
  390. webscout/Provider/Reka.py +0 -214
  391. webscout/Provider/StandardInput.py +0 -278
  392. webscout/Provider/TTI/AiForce/__init__.py +0 -22
  393. webscout/Provider/TTI/AiForce/async_aiforce.py +0 -224
  394. webscout/Provider/TTI/AiForce/sync_aiforce.py +0 -245
  395. webscout/Provider/TTI/FreeAIPlayground/__init__.py +0 -9
  396. webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +0 -181
  397. webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +0 -180
  398. webscout/Provider/TTI/ImgSys/__init__.py +0 -23
  399. webscout/Provider/TTI/ImgSys/async_imgsys.py +0 -202
  400. webscout/Provider/TTI/ImgSys/sync_imgsys.py +0 -195
  401. webscout/Provider/TTI/MagicStudio/__init__.py +0 -2
  402. webscout/Provider/TTI/MagicStudio/async_magicstudio.py +0 -111
  403. webscout/Provider/TTI/MagicStudio/sync_magicstudio.py +0 -109
  404. webscout/Provider/TTI/Nexra/__init__.py +0 -22
  405. webscout/Provider/TTI/Nexra/async_nexra.py +0 -286
  406. webscout/Provider/TTI/Nexra/sync_nexra.py +0 -258
  407. webscout/Provider/TTI/PollinationsAI/__init__.py +0 -23
  408. webscout/Provider/TTI/PollinationsAI/async_pollinations.py +0 -311
  409. webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +0 -265
  410. webscout/Provider/TTI/aiarta/__init__.py +0 -2
  411. webscout/Provider/TTI/aiarta/async_aiarta.py +0 -482
  412. webscout/Provider/TTI/aiarta/sync_aiarta.py +0 -440
  413. webscout/Provider/TTI/artbit/__init__.py +0 -22
  414. webscout/Provider/TTI/artbit/async_artbit.py +0 -155
  415. webscout/Provider/TTI/artbit/sync_artbit.py +0 -148
  416. webscout/Provider/TTI/fastflux/__init__.py +0 -22
  417. webscout/Provider/TTI/fastflux/async_fastflux.py +0 -261
  418. webscout/Provider/TTI/fastflux/sync_fastflux.py +0 -252
  419. webscout/Provider/TTI/huggingface/__init__.py +0 -22
  420. webscout/Provider/TTI/huggingface/async_huggingface.py +0 -199
  421. webscout/Provider/TTI/huggingface/sync_huggingface.py +0 -195
  422. webscout/Provider/TTI/piclumen/__init__.py +0 -23
  423. webscout/Provider/TTI/piclumen/async_piclumen.py +0 -268
  424. webscout/Provider/TTI/piclumen/sync_piclumen.py +0 -233
  425. webscout/Provider/TTI/pixelmuse/__init__.py +0 -4
  426. webscout/Provider/TTI/pixelmuse/async_pixelmuse.py +0 -249
  427. webscout/Provider/TTI/pixelmuse/sync_pixelmuse.py +0 -182
  428. webscout/Provider/TTI/talkai/__init__.py +0 -4
  429. webscout/Provider/TTI/talkai/async_talkai.py +0 -229
  430. webscout/Provider/TTI/talkai/sync_talkai.py +0 -207
  431. webscout/Provider/TTS/gesserit.py +0 -127
  432. webscout/Provider/TeachAnything.py +0 -187
  433. webscout/Provider/Venice.py +0 -219
  434. webscout/Provider/VercelAI.py +0 -234
  435. webscout/Provider/WebSim.py +0 -228
  436. webscout/Provider/Writecream.py +0 -211
  437. webscout/Provider/WritingMate.py +0 -197
  438. webscout/Provider/aimathgpt.py +0 -189
  439. webscout/Provider/askmyai.py +0 -158
  440. webscout/Provider/asksteve.py +0 -203
  441. webscout/Provider/bagoodex.py +0 -145
  442. webscout/Provider/chatglm.py +0 -205
  443. webscout/Provider/copilot.py +0 -428
  444. webscout/Provider/freeaichat.py +0 -271
  445. webscout/Provider/gaurish.py +0 -244
  446. webscout/Provider/geminiprorealtime.py +0 -160
  447. webscout/Provider/granite.py +0 -187
  448. webscout/Provider/hermes.py +0 -219
  449. webscout/Provider/koala.py +0 -268
  450. webscout/Provider/labyrinth.py +0 -340
  451. webscout/Provider/lepton.py +0 -194
  452. webscout/Provider/llamatutor.py +0 -192
  453. webscout/Provider/multichat.py +0 -325
  454. webscout/Provider/promptrefine.py +0 -193
  455. webscout/Provider/scira_chat.py +0 -277
  456. webscout/Provider/scnet.py +0 -187
  457. webscout/Provider/talkai.py +0 -194
  458. webscout/Provider/tutorai.py +0 -252
  459. webscout/Provider/typegpt.py +0 -232
  460. webscout/Provider/uncovr.py +0 -312
  461. webscout/Provider/yep.py +0 -376
  462. webscout/litprinter/__init__.py +0 -59
  463. webscout/scout/core.py +0 -881
  464. webscout/tempid.py +0 -128
  465. webscout/webscout_search.py +0 -1346
  466. webscout/webscout_search_async.py +0 -877
  467. webscout/yep_search.py +0 -297
  468. webscout-8.2.2.dist-info/METADATA +0 -734
  469. webscout-8.2.2.dist-info/RECORD +0 -309
  470. webscout-8.2.2.dist-info/entry_points.txt +0 -5
  471. webscout-8.2.2.dist-info/top_level.txt +0 -3
  472. webstoken/__init__.py +0 -30
  473. webstoken/classifier.py +0 -189
  474. webstoken/keywords.py +0 -216
  475. webstoken/language.py +0 -128
  476. webstoken/ner.py +0 -164
  477. webstoken/normalizer.py +0 -35
  478. webstoken/processor.py +0 -77
  479. webstoken/sentiment.py +0 -206
  480. webstoken/stemmer.py +0 -73
  481. webstoken/tagger.py +0 -60
  482. webstoken/tokenizer.py +0 -158
  483. {webscout-8.2.2.dist-info → webscout-2026.1.19.dist-info/licenses}/LICENSE.md +0 -0
@@ -1,242 +1,397 @@
1
-
2
- import re
3
- import requests
4
- import json
5
- import os
6
- from typing import Any, Dict, Optional, Generator, List, Union
7
- from webscout.AIutel import Optimizers, Conversation, AwesomePrompts
8
- from webscout.AIbase import Provider
9
- from webscout import exceptions
10
- from webscout.litagent import LitAgent as UserAgent
11
-
12
- class Cerebras(Provider):
13
- """
14
- A class to interact with the Cerebras API using a cookie for authentication.
15
- """
16
-
17
- AVAILABLE_MODELS = [
18
- "llama3.1-8b",
19
- "llama-3.3-70b",
20
- "deepseek-r1-distill-llama-70b"
21
- ]
22
-
23
- def __init__(
24
- self,
25
- is_conversation: bool = True,
26
- max_tokens: int = 2049,
27
- timeout: int = 30,
28
- intro: str = None,
29
- filepath: str = None,
30
- update_file: bool = True,
31
- proxies: dict = {},
32
- history_offset: int = 10250,
33
- act: str = None,
34
- cookie_path: str = "cookie.json",
35
- model: str = "llama3.1-8b",
36
- system_prompt: str = "You are a helpful assistant.",
37
- ):
38
- # Validate model choice
39
- if model not in self.AVAILABLE_MODELS:
40
- raise ValueError(
41
- f"Invalid model: {model}. Choose from: {self.AVAILABLE_MODELS}"
42
- )
43
-
44
- # Initialize basic settings first
45
- self.timeout = timeout
46
- self.model = model
47
- self.system_prompt = system_prompt
48
- self.is_conversation = is_conversation
49
- self.max_tokens_to_sample = max_tokens
50
- self.last_response = {}
51
-
52
- # Get API key first
53
- try:
54
- self.api_key = self.get_demo_api_key(cookie_path)
55
- except Exception as e:
56
- raise exceptions.APIConnectionError(f"Failed to initialize Cerebras client: {e}")
57
-
58
- # Initialize optimizers
59
- self.__available_optimizers = (
60
- method
61
- for method in dir(Optimizers)
62
- if callable(getattr(Optimizers, method)) and not method.startswith("__")
63
- )
64
-
65
- # Initialize conversation settings
66
- Conversation.intro = (
67
- AwesomePrompts().get_act(
68
- act, raise_not_found=True, default=None, case_insensitive=True
69
- )
70
- if act
71
- else None
72
- )
73
- self.conversation = Conversation(
74
- is_conversation, self.max_tokens_to_sample, filepath, update_file
75
- )
76
- self.conversation.history_offset = history_offset
77
-
78
- # Rest of the class implementation remains the same...
79
- @staticmethod
80
- def extract_query(text: str) -> str:
81
- """Extracts the first code block from the given text."""
82
- pattern = r"```(.*?)```"
83
- matches = re.findall(pattern, text, re.DOTALL)
84
- return matches[0].strip() if matches else text.strip()
85
-
86
- @staticmethod
87
- def refiner(text: str) -> str:
88
- """Refines the input text by removing surrounding quotes."""
89
- return text.strip('"')
90
-
91
- def get_demo_api_key(self, cookie_path: str) -> str:
92
- """Retrieves the demo API key using the provided cookie."""
93
- try:
94
- with open(cookie_path, "r") as file:
95
- cookies = {item["name"]: item["value"] for item in json.load(file)}
96
- except FileNotFoundError:
97
- raise FileNotFoundError(f"Cookie file not found at path: {cookie_path}")
98
- except json.JSONDecodeError:
99
- raise json.JSONDecodeError("Invalid JSON format in the cookie file.", "", 0)
100
-
101
- headers = {
102
- "Accept": "*/*",
103
- "Accept-Language": "en-US,en;q=0.9",
104
- "Content-Type": "application/json",
105
- "Origin": "https://inference.cerebras.ai",
106
- "Referer": "https://inference.cerebras.ai/",
107
- "user-agent": UserAgent().random(),
108
- }
109
-
110
- json_data = {
111
- "operationName": "GetMyDemoApiKey",
112
- "variables": {},
113
- "query": "query GetMyDemoApiKey {\n GetMyDemoApiKey\n}",
114
- }
115
-
116
- try:
117
- response = requests.post(
118
- "https://inference.cerebras.ai/api/graphql",
119
- cookies=cookies,
120
- headers=headers,
121
- json=json_data,
122
- timeout=self.timeout,
123
- )
124
- response.raise_for_status()
125
- api_key = response.json()["data"]["GetMyDemoApiKey"]
126
- return api_key
127
- except requests.exceptions.RequestException as e:
128
- raise exceptions.APIConnectionError(f"Failed to retrieve API key: {e}")
129
- except KeyError:
130
- raise exceptions.InvalidResponseError("API key not found in response.")
131
-
132
- def _make_request(self, messages: List[Dict], stream: bool = False) -> Union[Dict, Generator]:
133
- """Make a request to the Cerebras API."""
134
- headers = {
135
- "Authorization": f"Bearer {self.api_key}",
136
- "Content-Type": "application/json",
137
- "User-Agent": UserAgent().random(),
138
- }
139
-
140
- payload = {
141
- "model": self.model,
142
- "messages": messages,
143
- "stream": stream
144
- }
145
-
146
- try:
147
- response = requests.post(
148
- "https://api.cerebras.ai/v1/chat/completions",
149
- headers=headers,
150
- json=payload,
151
- stream=stream,
152
- timeout=self.timeout
153
- )
154
- response.raise_for_status()
155
-
156
- if stream:
157
- def generate_stream():
158
- for line in response.iter_lines():
159
- if line:
160
- line = line.decode('utf-8')
161
- if line.startswith('data:'):
162
- try:
163
- data = json.loads(line[6:])
164
- if data.get('choices') and data['choices'][0].get('delta', {}).get('content'):
165
- content = data['choices'][0]['delta']['content']
166
- yield content
167
- except json.JSONDecodeError:
168
- continue
169
-
170
- return generate_stream()
171
- else:
172
- response_json = response.json()
173
- return response_json['choices'][0]['message']['content']
174
-
175
- except requests.exceptions.RequestException as e:
176
- raise exceptions.APIConnectionError(f"Request failed: {e}")
177
-
178
- def ask(
179
- self,
180
- prompt: str,
181
- stream: bool = False,
182
- optimizer: str = None,
183
- conversationally: bool = False,
184
- ) -> Union[Dict, Generator]:
185
- """Send a prompt to the model and get a response."""
186
- conversation_prompt = self.conversation.gen_complete_prompt(prompt)
187
- if optimizer:
188
- if optimizer in self.__available_optimizers:
189
- conversation_prompt = getattr(Optimizers, optimizer)(
190
- conversation_prompt if conversationally else prompt
191
- )
192
- else:
193
- raise Exception(f"Optimizer is not one of {self.__available_optimizers}")
194
-
195
- messages = [
196
- {"role": "system", "content": self.system_prompt},
197
- {"role": "user", "content": conversation_prompt}
198
- ]
199
-
200
- try:
201
- response = self._make_request(messages, stream)
202
- if stream:
203
- return response
204
-
205
- self.last_response = response
206
- return response
207
-
208
- except Exception as e:
209
- raise exceptions.FailedToGenerateResponseError(f"Error during request: {e}")
210
-
211
- def chat(
212
- self,
213
- prompt: str,
214
- stream: bool = False,
215
- optimizer: str = None,
216
- conversationally: bool = False,
217
- ) -> Union[str, Generator]:
218
- """Chat with the model."""
219
- response = self.ask(prompt, stream, optimizer, conversationally)
220
- if stream:
221
- return response
222
- return response
223
-
224
- def get_message(self, response: str) -> str:
225
- """Retrieves message from response."""
226
- return response
227
-
228
-
229
- if __name__ == "__main__":
230
- from rich import print
231
-
232
- # Example usage
233
- cerebras = Cerebras(
234
- cookie_path='cookie.json',
235
- model='llama3.1-8b',
236
- system_prompt="You are a helpful AI assistant."
237
- )
238
-
239
- # Test with streaming
240
- response = cerebras.chat("Hello!", stream=True)
241
- for chunk in response:
242
- print(chunk, end="", flush=True)
1
+ import re
2
+
3
+ # Import trio before curl_cffi to prevent eventlet socket monkey-patching conflicts
4
+ # See: https://github.com/python-trio/trio/issues/3015
5
+ try:
6
+ import trio # noqa: F401 # type: ignore
7
+ except ImportError:
8
+ pass # trio is optional, ignore if not available
9
+ import json
10
+ from typing import Any, Dict, Generator, List, Optional, Union, cast
11
+
12
+ import curl_cffi
13
+ from curl_cffi.requests import Session
14
+
15
+ from webscout import exceptions
16
+ from webscout.AIbase import Provider, Response
17
+ from webscout.AIutel import ( # Import sanitize_stream
18
+ AwesomePrompts,
19
+ Conversation,
20
+ Optimizers,
21
+ sanitize_stream,
22
+ )
23
+ from webscout.litagent import LitAgent as UserAgent
24
+
25
+
26
+ class Cerebras(Provider):
27
+ """
28
+ A class to interact with the Cerebras API using a cookie for authentication.
29
+ """
30
+ required_auth = True
31
+ AVAILABLE_MODELS = [
32
+ "qwen-3-coder-480b",
33
+ "qwen-3-235b-a22b-instruct-2507",
34
+ "qwen-3-235b-a22b-thinking-2507",
35
+ "qwen-3-32b",
36
+ "llama-3.3-70b",
37
+ "llama-4-maverick-17b-128e-instruct",
38
+ "gpt-oss-120b",
39
+ "llama-4-scout-17b-16e-instruct",
40
+ "llama3.1-8b"
41
+ ]
42
+
43
+ @classmethod
44
+ def get_models(cls, api_key: Optional[str] = None):
45
+ """Fetch available models from Cerebras API.
46
+
47
+ Args:
48
+ api_key (str, optional): Cerebras API key. If not provided, returns default models.
49
+
50
+ Returns:
51
+ list: List of available model IDs
52
+ """
53
+ if not api_key:
54
+ raise Exception("API key required to fetch models")
55
+
56
+ try:
57
+ # Use a temporary curl_cffi session for this class method
58
+ temp_session = Session()
59
+ headers = {
60
+ "Content-Type": "application/json",
61
+ "Authorization": f"Bearer {api_key}",
62
+ }
63
+
64
+ response = temp_session.get(
65
+ "https://api.cerebras.ai/v1/models",
66
+ headers=headers,
67
+ impersonate="chrome120"
68
+ )
69
+
70
+ if response.status_code != 200:
71
+ raise Exception(f"Failed to fetch models: HTTP {response.status_code}")
72
+
73
+ data = response.json()
74
+ if "data" in data and isinstance(data["data"], list):
75
+ return [model['id'] for model in data['data']]
76
+ raise Exception("Invalid response format from API")
77
+
78
+ except (curl_cffi.CurlError, Exception) as e:
79
+ raise Exception(f"Failed to fetch models: {str(e)}")
80
+
81
+ def __init__(
82
+ self,
83
+ cookie_path: Optional[str] = None,
84
+ is_conversation: bool = True,
85
+ max_tokens: int = 40000,
86
+ timeout: int = 30,
87
+ intro: Optional[str] = None,
88
+ filepath: Optional[str] = None,
89
+ update_file: bool = True,
90
+ proxies: dict = {},
91
+ history_offset: int = 10250,
92
+ act: Optional[str] = None,
93
+ api_key: Optional[str] = None,
94
+ model: str = "qwen-3-coder-480b",
95
+ system_prompt: str = "You are a helpful assistant.",
96
+ temperature: float = 0.7,
97
+ top_p: float = 0.8,
98
+ ):
99
+ # Initialize basic settings first
100
+ self.timeout = timeout
101
+ self.model = model
102
+ self.system_prompt = system_prompt
103
+ self.is_conversation = is_conversation
104
+ self.max_tokens_to_sample = max_tokens
105
+ self.temperature = temperature
106
+ self.top_p = top_p
107
+ self.last_response = {}
108
+
109
+ self.session = Session() # Initialize curl_cffi session
110
+
111
+ # Handle API key - either provided directly or retrieved from cookies
112
+ if api_key:
113
+ self.api_key = api_key.strip()
114
+ # Basic validation for API key format
115
+ if not self.api_key or len(self.api_key) < 10:
116
+ raise ValueError("Invalid API key format. API key must be at least 10 characters long.")
117
+ elif cookie_path:
118
+ # Get API key from cookies
119
+ try:
120
+ self.api_key = self.get_demo_api_key(cookie_path)
121
+ except Exception as e:
122
+ raise exceptions.APIConnectionError(f"Failed to initialize Cerebras client: {e}")
123
+ else:
124
+ raise ValueError("Either api_key must be provided or cookie_path must be specified")
125
+
126
+ # Validate model choice after updating models
127
+ if model not in self.AVAILABLE_MODELS:
128
+ raise ValueError(
129
+ f"Invalid model: {model}. Choose from: {self.AVAILABLE_MODELS}"
130
+ )
131
+
132
+ # Initialize optimizers
133
+ self.__available_optimizers = (
134
+ method
135
+ for method in dir(Optimizers)
136
+ if callable(getattr(Optimizers, method)) and not method.startswith("__")
137
+ )
138
+
139
+ # Initialize conversation settings
140
+ self.conversation = Conversation(
141
+ is_conversation, self.max_tokens_to_sample, filepath, update_file
142
+ )
143
+ self.conversation.history_offset = history_offset
144
+
145
+ if act:
146
+ self.conversation.intro = AwesomePrompts().get_act(cast(Union[str, int], act), default=self.conversation.intro, case_insensitive=True
147
+ ) or self.conversation.intro
148
+ elif intro:
149
+ self.conversation.intro = intro
150
+
151
+ # Set headers for the session
152
+ self.headers = {
153
+ "Accept": "application/json",
154
+ "Content-Type": "application/json",
155
+ "User-Agent": UserAgent().random(),
156
+ }
157
+
158
+ # Apply proxies to the session
159
+ self.session.headers.update(self.headers)
160
+ if proxies:
161
+ self.session.proxies.update(cast(Any, proxies))
162
+ self.last_response = {}
163
+
164
+ # Rest of the class implementation remains the same...
165
+ @staticmethod
166
+ def extract_query(text: str) -> str:
167
+ """Extracts the first code block from the given text."""
168
+ pattern = r"```(.*?)```"
169
+ matches = re.findall(pattern, text, re.DOTALL)
170
+ return matches[0].strip() if matches else text.strip()
171
+
172
+ @staticmethod
173
+ def refiner(text: str) -> str:
174
+ """Refines the input text by removing surrounding quotes."""
175
+ return text.strip('"')
176
+
177
+ @staticmethod
178
+ def _cerebras_extractor(chunk: Union[str, Dict[str, Any]]) -> Optional[str]:
179
+ """Extracts content from Cerebras stream JSON objects."""
180
+ if isinstance(chunk, dict):
181
+ return chunk.get("choices", [{}])[0].get("delta", {}).get("content")
182
+ return None
183
+
184
+ def get_demo_api_key(self, cookie_path: Optional[str] = None) -> str: # Keep this using requests or switch to curl_cffi
185
+ """Retrieves the demo API key using the provided cookie."""
186
+ if not cookie_path:
187
+ raise ValueError("cookie_path must be provided when using cookie-based authentication")
188
+ try:
189
+ with open(cookie_path, "r") as file:
190
+ cookies = {item["name"]: item["value"] for item in json.load(file)}
191
+ except FileNotFoundError:
192
+ raise FileNotFoundError(f"Cookie file not found at path: {cookie_path}")
193
+ except json.JSONDecodeError:
194
+ raise json.JSONDecodeError("Invalid JSON format in the cookie file.", "", 0)
195
+
196
+ headers = {
197
+ "Accept": "*/*",
198
+ "Accept-Language": "en-US,en;q=0.9",
199
+ "Content-Type": "application/json",
200
+ "Origin": "https://inference.cerebras.ai",
201
+ "Referer": "https://inference.cerebras.ai/",
202
+ "user-agent": UserAgent().random(),
203
+ }
204
+
205
+ json_data = {
206
+ "operationName": "GetMyDemoApiKey",
207
+ "variables": {},
208
+ "query": "query GetMyDemoApiKey {\n GetMyDemoApiKey\n}",
209
+ }
210
+
211
+ try:
212
+ # Use the initialized curl_cffi session
213
+ response = self.session.post(
214
+ "https://inference.cerebras.ai/api/graphql",
215
+ cookies=cookies,
216
+ headers=headers,
217
+ json=json_data,
218
+ timeout=self.timeout,
219
+ impersonate="chrome120" # Add impersonate
220
+ )
221
+ response.raise_for_status()
222
+ api_key = response.json().get("data", {}).get("GetMyDemoApiKey")
223
+ return api_key
224
+ except curl_cffi.CurlError as e:
225
+ raise exceptions.APIConnectionError(f"Failed to retrieve API key: {e}")
226
+ except KeyError:
227
+ raise exceptions.InvalidResponseError("API key not found in response.")
228
+
229
+ def _make_request(self, messages: List[Dict], stream: bool = False) -> Union[Dict, Generator, str]:
230
+ """Make a request to the Cerebras API."""
231
+ headers = {
232
+ "Authorization": f"Bearer {self.api_key}",
233
+ "Content-Type": "application/json",
234
+ "User-Agent": UserAgent().random(),
235
+ }
236
+
237
+ payload = {
238
+ "model": self.model,
239
+ "messages": messages,
240
+ "stream": stream,
241
+ "max_tokens": self.max_tokens_to_sample,
242
+ "temperature": self.temperature,
243
+ "top_p": self.top_p
244
+ }
245
+
246
+ try:
247
+ # Use the initialized curl_cffi session
248
+ response = self.session.post(
249
+ "https://api.cerebras.ai/v1/chat/completions",
250
+ headers=headers,
251
+ json=payload,
252
+ stream=stream,
253
+ timeout=self.timeout,
254
+ impersonate="chrome120" # Add impersonate
255
+ )
256
+ response.raise_for_status()
257
+
258
+ if stream:
259
+ def generate_stream() -> Generator[str, None, None]:
260
+ # Use sanitize_stream
261
+ processed_stream = sanitize_stream(
262
+ data=response.iter_content(chunk_size=None), # Pass byte iterator
263
+ intro_value="data:",
264
+ to_json=True, # Stream sends JSON
265
+ content_extractor=self._cerebras_extractor, # Use the specific extractor
266
+ yield_raw_on_error=False # Skip non-JSON lines or lines where extractor fails
267
+ )
268
+ for content_chunk in processed_stream:
269
+ if content_chunk and isinstance(content_chunk, str):
270
+ yield content_chunk # Yield the extracted text chunk
271
+
272
+ return generate_stream()
273
+ else:
274
+ response_json = response.json()
275
+ # Extract content for non-streaming response
276
+ content = response_json.get("choices", [{}])[0].get("message", {}).get("content")
277
+ return content if content else "" # Return empty string if not found
278
+
279
+ except curl_cffi.CurlError as e:
280
+ raise exceptions.APIConnectionError(f"Request failed (CurlError): {e}") from e
281
+ except Exception as e:
282
+ # Check if it's an HTTP error with status code
283
+ if hasattr(e, 'response') and hasattr(e.response, 'status_code'):
284
+ status_code = e.response.status_code
285
+ if status_code == 401:
286
+ raise exceptions.APIConnectionError(
287
+ "Authentication failed (401): Invalid API key. Please check your API key and try again."
288
+ ) from e
289
+ elif status_code == 403:
290
+ raise exceptions.APIConnectionError(
291
+ "Access forbidden (403): Your API key may not have permission to access this resource."
292
+ ) from e
293
+ elif status_code == 429:
294
+ raise exceptions.APIConnectionError(
295
+ "Rate limit exceeded (429): Too many requests. Please wait and try again."
296
+ ) from e
297
+ else:
298
+ raise exceptions.APIConnectionError(f"HTTP {status_code} error: {e}") from e
299
+ else:
300
+ raise exceptions.APIConnectionError(f"Request failed: {e}") from e
301
+
302
+ def ask(
303
+ self,
304
+ prompt: str,
305
+ stream: bool = False,
306
+ raw: bool = False, # Add raw parameter for consistency
307
+ optimizer: Optional[str] = None,
308
+ conversationally: bool = False,
309
+ **kwargs: Any,
310
+ ) -> Response:
311
+ """Send a prompt to the model and get a response."""
312
+ conversation_prompt = self.conversation.gen_complete_prompt(prompt)
313
+ if optimizer:
314
+ if optimizer in self.__available_optimizers:
315
+ conversation_prompt = getattr(Optimizers, optimizer)(
316
+ conversation_prompt if conversationally else prompt
317
+ )
318
+ else:
319
+ raise Exception(f"Optimizer is not one of {self.__available_optimizers}")
320
+
321
+ messages = [
322
+ {"role": "system", "content": self.system_prompt},
323
+ {"role": "user", "content": conversation_prompt}
324
+ ]
325
+
326
+ try:
327
+ response = self._make_request(messages, stream)
328
+
329
+ if stream:
330
+ # Wrap the generator to yield dicts or raw strings
331
+ def stream_wrapper() -> Generator[Union[str, Dict[str, str]], None, None]:
332
+ full_text = ""
333
+ for chunk in response:
334
+ full_text += chunk
335
+ yield chunk if raw else {"text": chunk}
336
+ # Update history after stream finishes
337
+ self.last_response = {"text": full_text}
338
+ self.conversation.update_chat_history(prompt, full_text)
339
+ return stream_wrapper()
340
+ else:
341
+ # Non-streaming response is already the full text string
342
+ self.last_response = {"text": response}
343
+ self.conversation.update_chat_history(prompt, response)
344
+ return self.last_response if not raw else json.dumps(self.last_response)
345
+
346
+ except Exception as e:
347
+ raise exceptions.FailedToGenerateResponseError(f"Error during request: {e}")
348
+
349
+ def chat(
350
+ self,
351
+ prompt: str,
352
+ stream: bool = False,
353
+ optimizer: Optional[str] = None,
354
+ conversationally: bool = False,
355
+ **kwargs: Any,
356
+ ) -> Union[str, Generator[str, None, None]]:
357
+ """Chat with the model."""
358
+ raw = kwargs.get("raw", False)
359
+ # Ask returns a generator for stream=True, dict/str for stream=False
360
+ response_gen_or_dict = self.ask(prompt, stream, raw=raw, optimizer=optimizer, conversationally=conversationally, **kwargs)
361
+
362
+ if stream:
363
+ # Wrap the generator from ask() to get message text
364
+ def stream_wrapper() -> Generator[str, None, None]:
365
+ for chunk in response_gen_or_dict:
366
+ if raw:
367
+ yield chunk
368
+ else:
369
+ yield self.get_message(cast(Response, chunk))
370
+ return stream_wrapper()
371
+ else:
372
+ # Non-streaming response
373
+ if raw:
374
+ return str(response_gen_or_dict)
375
+ return self.get_message(response_gen_or_dict)
376
+
377
+ def get_message(self, response: Response) -> str:
378
+ """Retrieves message from response."""
379
+ # Updated to handle dict input from ask()
380
+ if not isinstance(response, dict):
381
+ return str(response)
382
+ return cast(Dict[str, Any], response).get("text", "")
383
+
384
+ if __name__ == "__main__":
385
+ from rich import print
386
+
387
+ # Example usage
388
+ cerebras = Cerebras(
389
+ api_key='csk-**********************', # Replace with your actual API key
390
+ model='qwen-3-235b-a22b-instruct-2507',
391
+ system_prompt="You are a helpful AI assistant."
392
+ )
393
+
394
+ # Test with streaming
395
+ response = cerebras.chat("Hello!", stream=True)
396
+ for chunk in response:
397
+ print(chunk, end="", flush=True)