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
webscout/conversation.py CHANGED
@@ -1,565 +1,140 @@
1
- import os
2
- import json
3
- import logging
4
- from typing import Optional, Dict, List, Any, TypedDict, Callable, TypeVar, Union
5
-
6
- T = TypeVar('T')
7
-
8
-
9
- class FunctionCall(TypedDict):
10
- """Type for a function call."""
11
- name: str
12
- arguments: Dict[str, Any]
13
-
14
-
15
- class ToolDefinition(TypedDict):
16
- """Type for a tool definition."""
17
- type: str
18
- function: Dict[str, Any]
19
-
20
-
21
- class FunctionCallData(TypedDict, total=False):
22
- """Type for function call data"""
23
- tool_calls: List[FunctionCall]
24
- error: str
25
-
26
-
27
- class Fn:
28
- """
29
- Represents a function (tool) that the agent can call.
30
- """
31
- def __init__(self, name: str, description: str, parameters: Dict[str, str]) -> None:
32
- self.name: str = name
33
- self.description: str = description
34
- self.parameters: Dict[str, str] = parameters
35
-
36
-
37
- def tools(func: Callable[..., T]) -> Callable[..., T]:
38
- """Decorator to mark a function as a tool and automatically convert it."""
39
- func._is_tool = True # type: ignore
40
- return func
41
-
42
-
43
- class Conversation:
44
- """Handles prompt generation based on history and maintains chat context.
45
-
46
- This class is responsible for managing chat conversations, including:
47
- - Maintaining chat history
48
- - Loading/saving conversations from/to files
49
- - Generating prompts based on context
50
- - Managing token limits and history pruning
51
- - Supporting tool calling functionality
52
-
53
- Examples:
54
- >>> chat = Conversation(max_tokens=500)
55
- >>> chat.add_message("user", "Hello!")
56
- >>> chat.add_message("llm", "Hi there!")
57
- >>> prompt = chat.gen_complete_prompt("What's up?")
58
- """
59
-
60
- intro = (
61
- "You're a helpful Large Language Model assistant. "
62
- "Respond directly to the user's questions or use tools when appropriate."
63
- )
64
-
65
- def __init__(
66
- self,
67
- status: bool = True,
68
- max_tokens: int = 600,
69
- filepath: Optional[str] = None,
70
- update_file: bool = True,
71
- tools: Optional[List[Fn]] = None,
72
- ):
73
- """Initialize a new Conversation manager.
74
-
75
- Args:
76
- status (bool): Flag to control history tracking. Defaults to True.
77
- max_tokens (int): Maximum tokens for completion response. Defaults to 600.
78
- filepath (str, optional): Path to save/load conversation history. Defaults to None.
79
- update_file (bool): Whether to append new messages to file. Defaults to True.
80
- tools (List[Fn], optional): List of tools available for the conversation. Defaults to None.
81
-
82
- Examples:
83
- >>> chat = Conversation(max_tokens=500)
84
- >>> chat = Conversation(filepath="chat_history.txt")
85
- """
86
- self.status = status
87
- self.max_tokens_to_sample = max_tokens
88
- self.chat_history = "" # Initialize as empty string
89
- self.history_format = "\nUser : %(user)s\nLLM :%(llm)s"
90
- self.tool_history_format = "\nUser : %(user)s\nLLM : [Tool Call: %(tool)s]\nTool : %(result)s"
91
- self.file = filepath
92
- self.update_file = update_file
93
- self.history_offset = 10250
94
- self.prompt_allowance = 10
95
- self.tools = tools or []
96
-
97
- if filepath:
98
- self.load_conversation(filepath, False)
99
-
100
- def load_conversation(self, filepath: str, exists: bool = True) -> None:
101
- """Load conversation history from a text file.
102
-
103
- Args:
104
- filepath (str): Path to the history file
105
- exists (bool): Flag for file availability. Defaults to True.
106
-
107
- Raises:
108
- AssertionError: If filepath is not str or file doesn't exist
109
- """
110
- assert isinstance(
111
- filepath, str
112
- ), f"Filepath needs to be of str datatype not {type(filepath)}"
113
- assert (
114
- os.path.isfile(filepath) if exists else True
115
- ), f"File '{filepath}' does not exist"
116
-
117
- if not os.path.isfile(filepath):
118
- with open(filepath, "w", encoding="utf-8") as fh:
119
- fh.write(self.intro)
120
- else:
121
- with open(filepath, encoding="utf-8") as fh:
122
- file_contents = fh.readlines()
123
- if file_contents:
124
- self.intro = file_contents[0] # First line is intro
125
- self.chat_history = "\n".join(file_contents[1:])
126
-
127
- def __trim_chat_history(self, chat_history: str, intro: str) -> str:
128
- """Keep the chat history fresh by trimming it when it gets too long!
129
-
130
- This method makes sure we don't exceed our token limits by:
131
- - Calculating total length (intro + history)
132
- - Trimming older messages if needed
133
- - Keeping the convo smooth and within limits
134
-
135
- Args:
136
- chat_history (str): The current chat history to trim
137
- intro (str): The conversation's intro/system prompt
138
-
139
- Returns:
140
- str: The trimmed chat history, ready to use!
141
-
142
- Examples:
143
- >>> chat = Conversation(max_tokens=500)
144
- >>> trimmed = chat._Conversation__trim_chat_history("Hello! Hi!", "Intro")
145
- """
146
- len_of_intro = len(intro)
147
- len_of_chat_history = len(chat_history)
148
- total = self.max_tokens_to_sample + len_of_intro + len_of_chat_history
149
-
150
- if total > self.history_offset:
151
- truncate_at = (total - self.history_offset) + self.prompt_allowance
152
- trimmed_chat_history = chat_history[truncate_at:]
153
- return "... " + trimmed_chat_history
154
- return chat_history
155
-
156
- def gen_complete_prompt(self, prompt: str, intro: Optional[str] = None) -> str:
157
- """Generate a complete prompt that's ready to go!
158
-
159
- This method:
160
- - Combines the intro, history, and new prompt
161
- - Adds tools information if available
162
- - Trims history if needed
163
- - Keeps everything organized and flowing
164
-
165
- Args:
166
- prompt (str): Your message to add to the chat
167
- intro (str, optional): Custom intro to use. Default: None (uses class intro)
168
-
169
- Returns:
170
- str: The complete conversation prompt, ready for the LLM!
171
-
172
- Examples:
173
- >>> chat = Conversation()
174
- >>> prompt = chat.gen_complete_prompt("What's good?")
175
- """
176
- if not self.status:
177
- return prompt
178
-
179
- intro = intro or self.intro or (
180
- '''You are a helpful and versatile AI assistant. Your goal is to provide concise and informative responses directly to user queries. Use available tools in correct format to enhance responses or execute actions as needed.
181
- ''')
182
-
183
- # Add tool information if tools are available
184
- tools_description = self.get_tools_description()
185
- if tools_description:
186
- try:
187
- from datetime import datetime
188
- date_str = f"Current date: {datetime.now().strftime('%d %b %Y')}"
189
- except:
190
- date_str = ""
191
-
192
- intro = (f'''
193
- {intro}
194
-
195
- {date_str}
196
-
197
- **CORE PROTOCOL:**
198
-
199
- Your goal is to assist the user effectively. Analyze each query and choose one of two response modes:
200
-
201
- **1. Tool Mode:**
202
- - **When:** If the query requires external data, calculations, or functions listed under AVAILABLE TOOLS (e.g., web search, current info).
203
- - **Action:** Output *ONLY* the complete JSON tool call, exactly matching the TOOL FORMAT below, enclosed in `<tool_call>` and `</tool_call>` tags.
204
- - **CRITICAL:** Absolutely NO text, whitespace, or characters before `<tool_call>` or after `</tool_call>`. The output *must* start with `<tool_call>` and end with `</tool_call>`.
205
- - **Example (Output is *only* this block):**
206
- ```json
207
- <tool_call>
208
- {{
209
- "name": "search",
210
- "arguments": {{ "query": "latest population of Tokyo" }}
211
- }}
212
- </tool_call>
213
- ```
214
-
215
- **2. Conversational Mode:**
216
- - **When:** If the query can be answered using your internal knowledge, is creative, or conversational.
217
- - **Action:** Respond directly, clearly, and concisely.
218
- - **Example:** *User:* "Explain photosynthesis." *Assistant:* "Photosynthesis is how plants use sunlight, water, and carbon dioxide to create their food (glucose) and release oxygen."
219
-
220
- **ABSOLUTE PROHIBITIONS:**
221
- - **NEVER Explain Tool Use:** Don't say you're using a tool, which one, or why.
222
- - **NEVER Describe JSON/Tags:** Do not mention `tool_call`, JSON structure, or parameters.
223
- - **NEVER Apologize for Tools:** No need to say sorry for lacking direct info.
224
- - **NEVER Mix Text and Tool Calls:** Tool calls must be standalone.
225
-
226
- **Be concise and relevant in all responses.**
227
-
228
- **AVAILABLE TOOLS:**
229
- {tools_description}
230
-
231
- **TOOL FORMAT (Use Exactly):**
232
- <tool_call>
233
- {{
234
- "name": "tool_name",
235
- "arguments": {{
236
- "param": "value"
237
- /* Add other parameters as needed */
238
- }}
239
- }}
240
- </tool_call>
241
-
242
- **Summary Check:**
243
- 1. Tool needed? -> Output *only* the JSON in tags.
244
- 2. No tool needed? -> Respond directly and conversationally.
245
- 3. Avoid *all* prohibited explanations/text.
246
- ''')
247
-
248
- incomplete_chat_history = self.chat_history + self.history_format % {
249
- "user": prompt,
250
- "llm": ""
251
- }
252
- complete_prompt = intro + self.__trim_chat_history(incomplete_chat_history, intro)
253
- return complete_prompt
254
-
255
- def update_chat_history(
256
- self, prompt: str, response: str, force: bool = False
257
- ) -> None:
258
- """Keep the conversation flowing by updating the chat history!
259
-
260
- This method:
261
- - Adds new messages to the history
262
- - Updates the file if needed
263
- - Keeps everything organized
264
-
265
- Args:
266
- prompt (str): Your message to add
267
- response (str): The LLM's response
268
- force (bool): Force update even if history is off. Default: False
269
-
270
- Examples:
271
- >>> chat = Conversation()
272
- >>> chat.update_chat_history("Hi!", "Hello there!")
273
- """
274
- if not self.status and not force:
275
- return
276
-
277
- new_history = self.history_format % {"user": prompt, "llm": response}
278
-
279
- if self.file and self.update_file:
280
- # Create file if it doesn't exist
281
- if not os.path.exists(self.file):
282
- with open(self.file, "w", encoding="utf-8") as fh:
283
- fh.write(self.intro + "\n")
284
-
285
- # Append new history
286
- with open(self.file, "a", encoding="utf-8") as fh:
287
- fh.write(new_history)
288
-
289
- self.chat_history += new_history
290
- # logger.info(f"Chat history updated with prompt: {prompt}")
291
-
292
- def update_chat_history_with_tool(
293
- self, prompt: str, tool_name: str, tool_result: str, force: bool = False
294
- ) -> None:
295
- """Update chat history with a tool call and its result.
296
-
297
- This method:
298
- - Adds tool call interaction to the history
299
- - Updates the file if needed
300
- - Maintains the conversation flow with tools
301
-
302
- Args:
303
- prompt (str): The user's message that triggered the tool call
304
- tool_name (str): Name of the tool that was called
305
- tool_result (str): Result returned by the tool
306
- force (bool): Force update even if history is off. Default: False
307
-
308
- Examples:
309
- >>> chat = Conversation()
310
- >>> chat.update_chat_history_with_tool("What's the weather?", "weather_tool", "It's sunny, 75°F")
311
- """
312
- if not self.status and not force:
313
- return
314
-
315
- new_history = self.tool_history_format % {
316
- "user": prompt,
317
- "tool": tool_name,
318
- "result": tool_result
319
- }
320
-
321
- if self.file and self.update_file:
322
- # Create file if it doesn't exist
323
- if not os.path.exists(self.file):
324
- with open(self.file, "w", encoding="utf-8") as fh:
325
- fh.write(self.intro + "\n")
326
-
327
- # Append new history
328
- with open(self.file, "a", encoding="utf-8") as fh:
329
- fh.write(new_history)
330
-
331
- self.chat_history += new_history
332
-
333
- def add_message(self, role: str, content: str) -> None:
334
- """Add a new message to the chat - simple and clean!
335
-
336
- This method:
337
- - Validates the message role
338
- - Adds the message to history
339
- - Updates file if needed
340
-
341
- Args:
342
- role (str): Who's sending? ('user', 'llm', 'tool', or 'reasoning')
343
- content (str): What's the message?
344
-
345
- Examples:
346
- >>> chat = Conversation()
347
- >>> chat.add_message("user", "Hey there!")
348
- >>> chat.add_message("llm", "Hi! How can I help?")
349
- """
350
- if not self.validate_message(role, content):
351
- raise ValueError("Invalid message role or content")
352
-
353
- role_formats = {
354
- "user": "User",
355
- "llm": "LLM",
356
- "tool": "Tool",
357
- "reasoning": "Reasoning"
358
- }
359
-
360
- if role in role_formats:
361
- self.chat_history += f"\n{role_formats[role]} : {content}"
362
- else:
363
- raise ValueError(f"Invalid role: {role}. Must be one of {list(role_formats.keys())}")
364
-
365
- # # Enhanced logging for message addition
366
- # logger.info(f"Added message from {role}: {content}")
367
- # logging.info(f"Message added: {role}: {content}")
368
-
369
- def validate_message(self, role: str, content: str) -> bool:
370
- """Validate the message role and content."""
371
- valid_roles = { 'user', 'llm', 'tool', 'reasoning', 'function_call' }
372
- if role not in valid_roles:
373
- logging.error(f"Invalid role: {role}")
374
- return False
375
- if not content:
376
- logging.error("Content cannot be empty.")
377
- return False
378
- return True
379
-
380
- def _parse_function_call(self, response: str) -> FunctionCallData:
381
- """Parse a function call from the LLM's response.
382
-
383
- Args:
384
- response (str): The LLM's response containing a function call
385
-
386
- Returns:
387
- FunctionCallData: Parsed function call data or error
388
- """
389
- try:
390
- # First try the standard format with square brackets: <tool_call>[...]</tool_call>
391
- start_tag: str = "<tool_call>["
392
- end_tag: str = "]</tool_call>"
393
- start_idx: int = response.find(start_tag)
394
- end_idx: int = response.rfind(end_tag)
395
-
396
- # If not found, try the alternate format: <tool_call>\n{...}\n</tool_call>
397
- if start_idx == -1 or end_idx == -1 or end_idx <= start_idx:
398
- start_tag = "<tool_call>"
399
- end_tag = "</tool_call>"
400
- start_idx = response.find(start_tag)
401
- end_idx = response.rfind(end_tag)
402
-
403
- if start_idx == -1 or end_idx == -1 or end_idx <= start_idx:
404
- raise ValueError("No valid <tool_call> JSON structure found in the response.")
405
-
406
- # Extract JSON content - for the format without brackets
407
- json_str: str = response[start_idx + len(start_tag):end_idx].strip()
408
-
409
- # Try to parse the JSON directly
410
- try:
411
- parsed_response: Any = json.loads(json_str)
412
- if isinstance(parsed_response, dict):
413
- return {"tool_calls": [parsed_response]}
414
- else:
415
- raise ValueError("Invalid JSON structure in tool call.")
416
- except json.JSONDecodeError:
417
- # If direct parsing failed, try to extract just the JSON object
418
- import re
419
- json_pattern = re.search(r'\{[\s\S]*\}', json_str)
420
- if json_pattern:
421
- parsed_response = json.loads(json_pattern.group(0))
422
- return {"tool_calls": [parsed_response]}
423
- raise
424
- else:
425
- # Extract JSON content - for the format with brackets
426
- json_str: str = response[start_idx + len(start_tag):end_idx].strip()
427
- parsed_response: Any = json.loads(json_str)
428
-
429
- if isinstance(parsed_response, list):
430
- return {"tool_calls": parsed_response}
431
- elif isinstance(parsed_response, dict):
432
- return {"tool_calls": [parsed_response]}
433
- else:
434
- raise ValueError("<tool_call> should contain a list or a dictionary of tool calls.")
435
-
436
- except (ValueError, json.JSONDecodeError) as e:
437
- logging.error(f"Error parsing function call: %s", e)
438
- return {"error": str(e)}
439
-
440
- def execute_function(self, function_call_data: FunctionCallData) -> str:
441
- """Execute a function call and return the result.
442
-
443
- Args:
444
- function_call_data (FunctionCallData): The function call data
445
-
446
- Returns:
447
- str: Result of the function execution
448
- """
449
- tool_calls: Optional[List[FunctionCall]] = function_call_data.get("tool_calls")
450
-
451
- if not tool_calls or not isinstance(tool_calls, list):
452
- return "Invalid tool_calls format."
453
-
454
- results: List[str] = []
455
- for tool_call in tool_calls:
456
- function_name: str = tool_call.get("name")
457
- arguments: Dict[str, Any] = tool_call.get("arguments", {})
458
-
459
- if not function_name or not isinstance(arguments, dict):
460
- results.append(f"Invalid tool call: {tool_call}")
461
- continue
462
-
463
- # Here you would implement the actual execution logic for each tool
464
- # For demonstration, we'll return a placeholder response
465
- results.append(f"Executed {function_name} with arguments {arguments}")
466
-
467
- return "; ".join(results)
468
-
469
- def _convert_fns_to_tools(self, fns: Optional[List[Fn]]) -> List[ToolDefinition]:
470
- """Convert functions to tool definitions for the LLM.
471
-
472
- Args:
473
- fns (Optional[List[Fn]]): List of function definitions
474
-
475
- Returns:
476
- List[ToolDefinition]: List of tool definitions
477
- """
478
- if not fns:
479
- return []
480
-
481
- tools: List[ToolDefinition] = []
482
- for fn in fns:
483
- tool: ToolDefinition = {
484
- "type": "function",
485
- "function": {
486
- "name": fn.name,
487
- "description": fn.description,
488
- "parameters": {
489
- "type": "object",
490
- "properties": {
491
- param_name: {
492
- "type": param_type,
493
- "description": f"The {param_name} parameter"
494
- } for param_name, param_type in fn.parameters.items()
495
- },
496
- "required": list(fn.parameters.keys())
497
- }
498
- }
499
- }
500
- tools.append(tool)
501
- return tools
502
-
503
- def get_tools_description(self) -> str:
504
- """Get a formatted string of available tools for the intro prompt.
505
-
506
- Returns:
507
- str: Formatted tools description
508
- """
509
- if not self.tools:
510
- return ""
511
-
512
- tools_desc = []
513
- for fn in self.tools:
514
- params_desc = ", ".join([f"{name}: {typ}" for name, typ in fn.parameters.items()])
515
- tools_desc.append(f"- {fn.name}: {fn.description} (Parameters: {params_desc})")
516
-
517
- return "\n".join(tools_desc)
518
-
519
- def handle_tool_response(self, response: str) -> Dict[str, Any]:
520
- """Process a response that might contain a tool call.
521
-
522
- This method:
523
- - Checks if the response contains a tool call
524
- - Parses and executes the tool call if present
525
- - Returns the appropriate result
526
-
527
- Args:
528
- response (str): The LLM's response
529
-
530
- Returns:
531
- Dict[str, Any]: Result containing 'is_tool_call', 'result', and 'original_response'
532
- """
533
- # Check if response contains a tool call
534
- if "<tool_call>" in response:
535
- function_call_data = self._parse_function_call(response)
536
-
537
- if "error" in function_call_data:
538
- return {
539
- "is_tool_call": True,
540
- "success": False,
541
- "result": function_call_data["error"],
542
- "original_response": response
543
- }
544
-
545
- # Execute the function call
546
- result = self.execute_function(function_call_data)
547
-
548
- # Add the result to chat history as a tool message
549
- self.add_message("tool", result)
550
-
551
- return {
552
- "is_tool_call": True,
553
- "success": True,
554
- "result": result,
555
- "tool_calls": function_call_data.get("tool_calls", []),
556
- "original_response": response
557
- }
558
-
559
- return {
560
- "is_tool_call": False,
561
- "result": response,
562
- "original_response": response
563
- }
564
-
565
-
1
+ """
2
+ conversation.py
3
+
4
+ This module provides a modern conversation manager for handling chat-based interactions, message history, and robust error handling. It defines the Conversation class for managing conversational state.
5
+
6
+ Classes:
7
+ Conversation: Main conversation manager class.
8
+ """
9
+ import os
10
+ from typing import Optional
11
+
12
+ from litprinter import ic
13
+
14
+
15
+ class Conversation:
16
+ """Handles prompt generation based on history"""
17
+ intro: str
18
+ status: bool
19
+ max_tokens_to_sample: int
20
+ chat_history: str
21
+ history_format: str
22
+ file: Optional[str]
23
+ update_file: bool
24
+ history_offset: int
25
+ prompt_allowance: int
26
+
27
+ def __init__(
28
+ self,
29
+ status: bool = True,
30
+ max_tokens: int = 600,
31
+ filepath: Optional[str] = None,
32
+ update_file: bool = True,
33
+ ):
34
+ """Initializes Conversation
35
+
36
+ Args:
37
+ status (bool, optional): Flag to control history. Defaults to True.
38
+ max_tokens (int, optional): Maximum number of tokens to be generated upon completion. Defaults to 600.
39
+ filepath (str, optional): Path to file containing conversation history. Defaults to None.
40
+ update_file (bool, optional): Add new prompts and responses to the file. Defaults to True.
41
+ """
42
+ self.intro = (
43
+ "You're a Large Language Model for chatting with people. "
44
+ "Assume role of the LLM and give your response."
45
+ )
46
+ self.status = status
47
+ self.max_tokens_to_sample = max_tokens
48
+ self.chat_history = ""
49
+ self.history_format = "\nUser : %(user)s\nLLM :%(llm)s"
50
+ self.file = filepath
51
+ self.update_file = update_file
52
+ self.history_offset = 10250
53
+ self.prompt_allowance = 10
54
+ self.load_conversation(filepath, False) if filepath else None
55
+
56
+ def load_conversation(self, filepath: str, exists: bool = True) -> None:
57
+ """Load conversation into chat's history from .txt file
58
+
59
+ Args:
60
+ filepath (str): Path to .txt file
61
+ exists (bool, optional): Flag for file availability. Defaults to True.
62
+ """
63
+ assert isinstance(
64
+ filepath, str
65
+ ), f"Filepath needs to be of str datatype not {type(filepath)}"
66
+ assert (
67
+ os.path.isfile(filepath) if exists else True
68
+ ), f"File '{filepath}' does not exist"
69
+ if not os.path.isfile(filepath):
70
+ ic(f"Creating new chat-history file - '{filepath}'")
71
+ with open(filepath, "w") as fh: # Try creating new file
72
+ # lets add intro here
73
+ fh.write(self.intro)
74
+ else:
75
+ ic(f"Loading conversation from '{filepath}'")
76
+ with open(filepath) as fh:
77
+ file_contents = fh.readlines()
78
+ if file_contents:
79
+ self.intro = file_contents[0] # Presume first line is the intro.
80
+ self.chat_history = "\n".join(file_contents[1:])
81
+
82
+ def __trim_chat_history(self, chat_history: str, intro: str) -> str:
83
+ """Ensures the len(prompt) and max_tokens_to_sample is not > 4096"""
84
+ len_of_intro = len(intro)
85
+ len_of_chat_history = len(chat_history)
86
+ total = (
87
+ self.max_tokens_to_sample + len_of_intro + len_of_chat_history
88
+ ) # + self.max_tokens_to_sample
89
+ if total > self.history_offset:
90
+ truncate_at = (total - self.history_offset) + self.prompt_allowance
91
+ # Remove head of total (n) of chat_history
92
+ trimmed_chat_history = chat_history[truncate_at:]
93
+ return "... " + trimmed_chat_history
94
+ # print(len(self.chat_history))
95
+ else:
96
+ return chat_history
97
+
98
+ def gen_complete_prompt(self, prompt: str, intro: Optional[str] = None) -> str:
99
+ """Generates a kinda like incomplete conversation
100
+
101
+ Args:
102
+ prompt (str): Chat prompt
103
+ intro (str): Override class' intro. Defaults to None.
104
+
105
+ Returns:
106
+ str: Updated incomplete chat_history
107
+ """
108
+ if self.status:
109
+ intro = self.intro if intro is None else intro
110
+ incomplete_chat_history = self.chat_history + self.history_format % dict(
111
+ user=prompt, llm=""
112
+ )
113
+ return intro + self.__trim_chat_history(incomplete_chat_history, intro)
114
+
115
+ return prompt
116
+
117
+ def update_chat_history(
118
+ self, prompt: str, response: str, force: bool = False
119
+ ) -> None:
120
+ """Updates chat history
121
+
122
+ Args:
123
+ prompt (str): user prompt
124
+ response (str): LLM response
125
+ force (bool, optional): Force update
126
+ """
127
+ if not self.status and not force:
128
+ return
129
+ new_history = self.history_format % dict(user=prompt, llm=response)
130
+ if self.file and self.update_file:
131
+ if os.path.exists(self.file):
132
+ # Append new history to existing file
133
+ with open(self.file, "a") as fh:
134
+ fh.write(new_history)
135
+ else:
136
+ # Create new file with intro and new history
137
+ with open(self.file, "w") as fh:
138
+ fh.write(self.intro + "\n" + new_history)
139
+ self.chat_history += new_history
140
+