webscout 8.2.7__py3-none-any.whl → 8.2.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of webscout might be problematic. Click here for more details.

Files changed (323) hide show
  1. webscout/AIauto.py +1 -1
  2. webscout/AIutel.py +298 -249
  3. webscout/Extra/Act.md +309 -0
  4. webscout/Extra/GitToolkit/__init__.py +10 -0
  5. webscout/Extra/GitToolkit/gitapi/README.md +110 -0
  6. webscout/Extra/GitToolkit/gitapi/__init__.py +12 -0
  7. webscout/Extra/GitToolkit/gitapi/repository.py +195 -0
  8. webscout/Extra/GitToolkit/gitapi/user.py +96 -0
  9. webscout/Extra/GitToolkit/gitapi/utils.py +62 -0
  10. webscout/Extra/YTToolkit/README.md +375 -0
  11. webscout/Extra/YTToolkit/YTdownloader.py +957 -0
  12. webscout/Extra/YTToolkit/__init__.py +3 -0
  13. webscout/Extra/YTToolkit/transcriber.py +476 -0
  14. webscout/Extra/YTToolkit/ytapi/README.md +44 -0
  15. webscout/Extra/YTToolkit/ytapi/__init__.py +6 -0
  16. webscout/Extra/YTToolkit/ytapi/channel.py +307 -0
  17. webscout/Extra/YTToolkit/ytapi/errors.py +13 -0
  18. webscout/Extra/YTToolkit/ytapi/extras.py +118 -0
  19. webscout/Extra/YTToolkit/ytapi/https.py +88 -0
  20. webscout/Extra/YTToolkit/ytapi/patterns.py +61 -0
  21. webscout/Extra/YTToolkit/ytapi/playlist.py +59 -0
  22. webscout/Extra/YTToolkit/ytapi/pool.py +8 -0
  23. webscout/Extra/YTToolkit/ytapi/query.py +40 -0
  24. webscout/Extra/YTToolkit/ytapi/stream.py +63 -0
  25. webscout/Extra/YTToolkit/ytapi/utils.py +62 -0
  26. webscout/Extra/YTToolkit/ytapi/video.py +232 -0
  27. webscout/Extra/__init__.py +7 -0
  28. webscout/Extra/autocoder/__init__.py +9 -0
  29. webscout/Extra/autocoder/autocoder.py +1105 -0
  30. webscout/Extra/autocoder/autocoder_utiles.py +332 -0
  31. webscout/Extra/gguf.md +430 -0
  32. webscout/Extra/gguf.py +684 -0
  33. webscout/Extra/tempmail/README.md +488 -0
  34. webscout/Extra/tempmail/__init__.py +28 -0
  35. webscout/Extra/tempmail/async_utils.py +141 -0
  36. webscout/Extra/tempmail/base.py +161 -0
  37. webscout/Extra/tempmail/cli.py +187 -0
  38. webscout/Extra/tempmail/emailnator.py +84 -0
  39. webscout/Extra/tempmail/mail_tm.py +361 -0
  40. webscout/Extra/tempmail/temp_mail_io.py +292 -0
  41. webscout/Extra/weather.md +281 -0
  42. webscout/Extra/weather.py +194 -0
  43. webscout/Extra/weather_ascii.py +76 -0
  44. webscout/Litlogger/Readme.md +175 -0
  45. webscout/Litlogger/__init__.py +67 -0
  46. webscout/Litlogger/core/__init__.py +6 -0
  47. webscout/Litlogger/core/level.py +23 -0
  48. webscout/Litlogger/core/logger.py +165 -0
  49. webscout/Litlogger/handlers/__init__.py +12 -0
  50. webscout/Litlogger/handlers/console.py +33 -0
  51. webscout/Litlogger/handlers/file.py +143 -0
  52. webscout/Litlogger/handlers/network.py +173 -0
  53. webscout/Litlogger/styles/__init__.py +7 -0
  54. webscout/Litlogger/styles/colors.py +249 -0
  55. webscout/Litlogger/styles/formats.py +458 -0
  56. webscout/Litlogger/styles/text.py +87 -0
  57. webscout/Litlogger/utils/__init__.py +6 -0
  58. webscout/Litlogger/utils/detectors.py +153 -0
  59. webscout/Litlogger/utils/formatters.py +200 -0
  60. webscout/Provider/AI21.py +177 -0
  61. webscout/Provider/AISEARCH/DeepFind.py +254 -0
  62. webscout/Provider/AISEARCH/Perplexity.py +359 -0
  63. webscout/Provider/AISEARCH/README.md +279 -0
  64. webscout/Provider/AISEARCH/__init__.py +9 -0
  65. webscout/Provider/AISEARCH/felo_search.py +228 -0
  66. webscout/Provider/AISEARCH/genspark_search.py +350 -0
  67. webscout/Provider/AISEARCH/hika_search.py +198 -0
  68. webscout/Provider/AISEARCH/iask_search.py +436 -0
  69. webscout/Provider/AISEARCH/monica_search.py +246 -0
  70. webscout/Provider/AISEARCH/scira_search.py +324 -0
  71. webscout/Provider/AISEARCH/webpilotai_search.py +281 -0
  72. webscout/Provider/Aitopia.py +316 -0
  73. webscout/Provider/AllenAI.py +440 -0
  74. webscout/Provider/Andi.py +228 -0
  75. webscout/Provider/Blackboxai.py +673 -0
  76. webscout/Provider/ChatGPTClone.py +237 -0
  77. webscout/Provider/ChatGPTGratis.py +194 -0
  78. webscout/Provider/ChatSandbox.py +342 -0
  79. webscout/Provider/Cloudflare.py +324 -0
  80. webscout/Provider/Cohere.py +208 -0
  81. webscout/Provider/Deepinfra.py +340 -0
  82. webscout/Provider/ExaAI.py +261 -0
  83. webscout/Provider/ExaChat.py +358 -0
  84. webscout/Provider/Flowith.py +217 -0
  85. webscout/Provider/FreeGemini.py +250 -0
  86. webscout/Provider/Gemini.py +169 -0
  87. webscout/Provider/GithubChat.py +370 -0
  88. webscout/Provider/GizAI.py +295 -0
  89. webscout/Provider/Glider.py +225 -0
  90. webscout/Provider/Groq.py +801 -0
  91. webscout/Provider/HF_space/__init__.py +0 -0
  92. webscout/Provider/HF_space/qwen_qwen2.py +206 -0
  93. webscout/Provider/HeckAI.py +285 -0
  94. webscout/Provider/HuggingFaceChat.py +469 -0
  95. webscout/Provider/Hunyuan.py +283 -0
  96. webscout/Provider/Jadve.py +291 -0
  97. webscout/Provider/Koboldai.py +384 -0
  98. webscout/Provider/LambdaChat.py +411 -0
  99. webscout/Provider/Llama3.py +259 -0
  100. webscout/Provider/MCPCore.py +315 -0
  101. webscout/Provider/Marcus.py +198 -0
  102. webscout/Provider/Nemotron.py +218 -0
  103. webscout/Provider/Netwrck.py +270 -0
  104. webscout/Provider/OLLAMA.py +396 -0
  105. webscout/Provider/OPENAI/BLACKBOXAI.py +735 -0
  106. webscout/Provider/OPENAI/Cloudflare.py +378 -0
  107. webscout/Provider/OPENAI/FreeGemini.py +282 -0
  108. webscout/Provider/OPENAI/NEMOTRON.py +244 -0
  109. webscout/Provider/OPENAI/README.md +1253 -0
  110. webscout/Provider/OPENAI/__init__.py +36 -0
  111. webscout/Provider/OPENAI/ai4chat.py +293 -0
  112. webscout/Provider/OPENAI/api.py +810 -0
  113. webscout/Provider/OPENAI/base.py +249 -0
  114. webscout/Provider/OPENAI/c4ai.py +373 -0
  115. webscout/Provider/OPENAI/chatgpt.py +556 -0
  116. webscout/Provider/OPENAI/chatgptclone.py +488 -0
  117. webscout/Provider/OPENAI/chatsandbox.py +172 -0
  118. webscout/Provider/OPENAI/deepinfra.py +319 -0
  119. webscout/Provider/OPENAI/e2b.py +1356 -0
  120. webscout/Provider/OPENAI/exaai.py +411 -0
  121. webscout/Provider/OPENAI/exachat.py +443 -0
  122. webscout/Provider/OPENAI/flowith.py +162 -0
  123. webscout/Provider/OPENAI/freeaichat.py +359 -0
  124. webscout/Provider/OPENAI/glider.py +323 -0
  125. webscout/Provider/OPENAI/groq.py +361 -0
  126. webscout/Provider/OPENAI/heckai.py +307 -0
  127. webscout/Provider/OPENAI/llmchatco.py +335 -0
  128. webscout/Provider/OPENAI/mcpcore.py +383 -0
  129. webscout/Provider/OPENAI/multichat.py +376 -0
  130. webscout/Provider/OPENAI/netwrck.py +356 -0
  131. webscout/Provider/OPENAI/opkfc.py +496 -0
  132. webscout/Provider/OPENAI/scirachat.py +471 -0
  133. webscout/Provider/OPENAI/sonus.py +303 -0
  134. webscout/Provider/OPENAI/standardinput.py +433 -0
  135. webscout/Provider/OPENAI/textpollinations.py +339 -0
  136. webscout/Provider/OPENAI/toolbaz.py +413 -0
  137. webscout/Provider/OPENAI/typefully.py +355 -0
  138. webscout/Provider/OPENAI/typegpt.py +358 -0
  139. webscout/Provider/OPENAI/uncovrAI.py +462 -0
  140. webscout/Provider/OPENAI/utils.py +307 -0
  141. webscout/Provider/OPENAI/venice.py +425 -0
  142. webscout/Provider/OPENAI/wisecat.py +381 -0
  143. webscout/Provider/OPENAI/writecream.py +163 -0
  144. webscout/Provider/OPENAI/x0gpt.py +378 -0
  145. webscout/Provider/OPENAI/yep.py +356 -0
  146. webscout/Provider/OpenGPT.py +209 -0
  147. webscout/Provider/Openai.py +496 -0
  148. webscout/Provider/PI.py +429 -0
  149. webscout/Provider/Perplexitylabs.py +415 -0
  150. webscout/Provider/QwenLM.py +254 -0
  151. webscout/Provider/Reka.py +214 -0
  152. webscout/Provider/StandardInput.py +290 -0
  153. webscout/Provider/TTI/AiForce/README.md +159 -0
  154. webscout/Provider/TTI/AiForce/__init__.py +22 -0
  155. webscout/Provider/TTI/AiForce/async_aiforce.py +224 -0
  156. webscout/Provider/TTI/AiForce/sync_aiforce.py +245 -0
  157. webscout/Provider/TTI/FreeAIPlayground/README.md +99 -0
  158. webscout/Provider/TTI/FreeAIPlayground/__init__.py +9 -0
  159. webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +181 -0
  160. webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +180 -0
  161. webscout/Provider/TTI/ImgSys/README.md +174 -0
  162. webscout/Provider/TTI/ImgSys/__init__.py +23 -0
  163. webscout/Provider/TTI/ImgSys/async_imgsys.py +202 -0
  164. webscout/Provider/TTI/ImgSys/sync_imgsys.py +195 -0
  165. webscout/Provider/TTI/MagicStudio/README.md +101 -0
  166. webscout/Provider/TTI/MagicStudio/__init__.py +2 -0
  167. webscout/Provider/TTI/MagicStudio/async_magicstudio.py +111 -0
  168. webscout/Provider/TTI/MagicStudio/sync_magicstudio.py +109 -0
  169. webscout/Provider/TTI/Nexra/README.md +155 -0
  170. webscout/Provider/TTI/Nexra/__init__.py +22 -0
  171. webscout/Provider/TTI/Nexra/async_nexra.py +286 -0
  172. webscout/Provider/TTI/Nexra/sync_nexra.py +258 -0
  173. webscout/Provider/TTI/PollinationsAI/README.md +146 -0
  174. webscout/Provider/TTI/PollinationsAI/__init__.py +23 -0
  175. webscout/Provider/TTI/PollinationsAI/async_pollinations.py +311 -0
  176. webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +265 -0
  177. webscout/Provider/TTI/README.md +128 -0
  178. webscout/Provider/TTI/__init__.py +12 -0
  179. webscout/Provider/TTI/aiarta/README.md +134 -0
  180. webscout/Provider/TTI/aiarta/__init__.py +2 -0
  181. webscout/Provider/TTI/aiarta/async_aiarta.py +482 -0
  182. webscout/Provider/TTI/aiarta/sync_aiarta.py +440 -0
  183. webscout/Provider/TTI/artbit/README.md +100 -0
  184. webscout/Provider/TTI/artbit/__init__.py +22 -0
  185. webscout/Provider/TTI/artbit/async_artbit.py +155 -0
  186. webscout/Provider/TTI/artbit/sync_artbit.py +148 -0
  187. webscout/Provider/TTI/fastflux/README.md +129 -0
  188. webscout/Provider/TTI/fastflux/__init__.py +22 -0
  189. webscout/Provider/TTI/fastflux/async_fastflux.py +261 -0
  190. webscout/Provider/TTI/fastflux/sync_fastflux.py +252 -0
  191. webscout/Provider/TTI/huggingface/README.md +114 -0
  192. webscout/Provider/TTI/huggingface/__init__.py +22 -0
  193. webscout/Provider/TTI/huggingface/async_huggingface.py +199 -0
  194. webscout/Provider/TTI/huggingface/sync_huggingface.py +195 -0
  195. webscout/Provider/TTI/piclumen/README.md +161 -0
  196. webscout/Provider/TTI/piclumen/__init__.py +23 -0
  197. webscout/Provider/TTI/piclumen/async_piclumen.py +268 -0
  198. webscout/Provider/TTI/piclumen/sync_piclumen.py +233 -0
  199. webscout/Provider/TTI/pixelmuse/README.md +79 -0
  200. webscout/Provider/TTI/pixelmuse/__init__.py +4 -0
  201. webscout/Provider/TTI/pixelmuse/async_pixelmuse.py +249 -0
  202. webscout/Provider/TTI/pixelmuse/sync_pixelmuse.py +182 -0
  203. webscout/Provider/TTI/talkai/README.md +139 -0
  204. webscout/Provider/TTI/talkai/__init__.py +4 -0
  205. webscout/Provider/TTI/talkai/async_talkai.py +229 -0
  206. webscout/Provider/TTI/talkai/sync_talkai.py +207 -0
  207. webscout/Provider/TTS/README.md +192 -0
  208. webscout/Provider/TTS/__init__.py +9 -0
  209. webscout/Provider/TTS/base.py +159 -0
  210. webscout/Provider/TTS/deepgram.py +156 -0
  211. webscout/Provider/TTS/elevenlabs.py +111 -0
  212. webscout/Provider/TTS/gesserit.py +128 -0
  213. webscout/Provider/TTS/murfai.py +113 -0
  214. webscout/Provider/TTS/parler.py +111 -0
  215. webscout/Provider/TTS/speechma.py +580 -0
  216. webscout/Provider/TTS/sthir.py +94 -0
  217. webscout/Provider/TTS/streamElements.py +333 -0
  218. webscout/Provider/TTS/utils.py +280 -0
  219. webscout/Provider/TeachAnything.py +229 -0
  220. webscout/Provider/TextPollinationsAI.py +308 -0
  221. webscout/Provider/TwoAI.py +280 -0
  222. webscout/Provider/TypliAI.py +305 -0
  223. webscout/Provider/UNFINISHED/ChatHub.py +209 -0
  224. webscout/Provider/UNFINISHED/Youchat.py +330 -0
  225. webscout/Provider/UNFINISHED/liner_api_request.py +263 -0
  226. webscout/Provider/UNFINISHED/oivscode.py +351 -0
  227. webscout/Provider/UNFINISHED/test_lmarena.py +119 -0
  228. webscout/Provider/Venice.py +258 -0
  229. webscout/Provider/VercelAI.py +253 -0
  230. webscout/Provider/WiseCat.py +233 -0
  231. webscout/Provider/WrDoChat.py +370 -0
  232. webscout/Provider/Writecream.py +246 -0
  233. webscout/Provider/WritingMate.py +269 -0
  234. webscout/Provider/__init__.py +172 -0
  235. webscout/Provider/ai4chat.py +149 -0
  236. webscout/Provider/akashgpt.py +335 -0
  237. webscout/Provider/asksteve.py +220 -0
  238. webscout/Provider/cerebras.py +290 -0
  239. webscout/Provider/chatglm.py +215 -0
  240. webscout/Provider/cleeai.py +213 -0
  241. webscout/Provider/copilot.py +425 -0
  242. webscout/Provider/elmo.py +283 -0
  243. webscout/Provider/freeaichat.py +285 -0
  244. webscout/Provider/geminiapi.py +208 -0
  245. webscout/Provider/granite.py +235 -0
  246. webscout/Provider/hermes.py +266 -0
  247. webscout/Provider/julius.py +223 -0
  248. webscout/Provider/koala.py +170 -0
  249. webscout/Provider/learnfastai.py +325 -0
  250. webscout/Provider/llama3mitril.py +215 -0
  251. webscout/Provider/llmchat.py +258 -0
  252. webscout/Provider/llmchatco.py +306 -0
  253. webscout/Provider/lmarena.py +198 -0
  254. webscout/Provider/meta.py +801 -0
  255. webscout/Provider/multichat.py +364 -0
  256. webscout/Provider/samurai.py +223 -0
  257. webscout/Provider/scira_chat.py +299 -0
  258. webscout/Provider/scnet.py +243 -0
  259. webscout/Provider/searchchat.py +292 -0
  260. webscout/Provider/sonus.py +258 -0
  261. webscout/Provider/talkai.py +194 -0
  262. webscout/Provider/toolbaz.py +353 -0
  263. webscout/Provider/turboseek.py +266 -0
  264. webscout/Provider/typefully.py +202 -0
  265. webscout/Provider/typegpt.py +289 -0
  266. webscout/Provider/uncovr.py +368 -0
  267. webscout/Provider/x0gpt.py +299 -0
  268. webscout/Provider/yep.py +389 -0
  269. webscout/__init__.py +4 -2
  270. webscout/cli.py +3 -28
  271. webscout/conversation.py +35 -35
  272. webscout/litagent/Readme.md +276 -0
  273. webscout/litagent/__init__.py +29 -0
  274. webscout/litagent/agent.py +455 -0
  275. webscout/litagent/constants.py +60 -0
  276. webscout/litprinter/__init__.py +59 -0
  277. webscout/scout/README.md +402 -0
  278. webscout/scout/__init__.py +8 -0
  279. webscout/scout/core/__init__.py +7 -0
  280. webscout/scout/core/crawler.py +140 -0
  281. webscout/scout/core/scout.py +568 -0
  282. webscout/scout/core/search_result.py +96 -0
  283. webscout/scout/core/text_analyzer.py +63 -0
  284. webscout/scout/core/text_utils.py +277 -0
  285. webscout/scout/core/web_analyzer.py +52 -0
  286. webscout/scout/element.py +460 -0
  287. webscout/scout/parsers/__init__.py +69 -0
  288. webscout/scout/parsers/html5lib_parser.py +172 -0
  289. webscout/scout/parsers/html_parser.py +236 -0
  290. webscout/scout/parsers/lxml_parser.py +178 -0
  291. webscout/scout/utils.py +37 -0
  292. webscout/swiftcli/Readme.md +323 -0
  293. webscout/swiftcli/__init__.py +95 -0
  294. webscout/swiftcli/core/__init__.py +7 -0
  295. webscout/swiftcli/core/cli.py +297 -0
  296. webscout/swiftcli/core/context.py +104 -0
  297. webscout/swiftcli/core/group.py +241 -0
  298. webscout/swiftcli/decorators/__init__.py +28 -0
  299. webscout/swiftcli/decorators/command.py +221 -0
  300. webscout/swiftcli/decorators/options.py +220 -0
  301. webscout/swiftcli/decorators/output.py +252 -0
  302. webscout/swiftcli/exceptions.py +21 -0
  303. webscout/swiftcli/plugins/__init__.py +9 -0
  304. webscout/swiftcli/plugins/base.py +135 -0
  305. webscout/swiftcli/plugins/manager.py +262 -0
  306. webscout/swiftcli/utils/__init__.py +59 -0
  307. webscout/swiftcli/utils/formatting.py +252 -0
  308. webscout/swiftcli/utils/parsing.py +267 -0
  309. webscout/version.py +1 -1
  310. webscout/webscout_search.py +2 -182
  311. webscout/webscout_search_async.py +1 -179
  312. webscout/zeroart/README.md +89 -0
  313. webscout/zeroart/__init__.py +135 -0
  314. webscout/zeroart/base.py +66 -0
  315. webscout/zeroart/effects.py +101 -0
  316. webscout/zeroart/fonts.py +1239 -0
  317. {webscout-8.2.7.dist-info → webscout-8.2.8.dist-info}/METADATA +115 -60
  318. webscout-8.2.8.dist-info/RECORD +334 -0
  319. {webscout-8.2.7.dist-info → webscout-8.2.8.dist-info}/WHEEL +1 -1
  320. webscout-8.2.7.dist-info/RECORD +0 -26
  321. {webscout-8.2.7.dist-info → webscout-8.2.8.dist-info}/entry_points.txt +0 -0
  322. {webscout-8.2.7.dist-info → webscout-8.2.8.dist-info}/licenses/LICENSE.md +0 -0
  323. {webscout-8.2.7.dist-info → webscout-8.2.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,307 @@
1
+ from typing import List, Dict, Optional, Any, Union, Literal
2
+ from dataclasses import dataclass, asdict, is_dataclass, field
3
+ from enum import Enum
4
+ import time
5
+ import uuid
6
+
7
+ # --- OpenAI Response Structure Mimics ---
8
+ # Moved here for reusability across different OpenAI-compatible providers
9
+
10
+ class ToolCallType(str, Enum):
11
+ """Type of tool call."""
12
+ FUNCTION = "function"
13
+
14
+ @dataclass
15
+ class BaseModel:
16
+ """Base class for all models."""
17
+ def to_dict(self) -> Dict[str, Any]:
18
+ """Convert the model to a dictionary."""
19
+ def _convert(obj: Any) -> Any:
20
+ if is_dataclass(obj):
21
+ return {k: _convert(v) for k, v in asdict(obj).items() if v is not None}
22
+ elif isinstance(obj, list):
23
+ return [_convert(item) for item in obj]
24
+ elif isinstance(obj, dict):
25
+ return {k: _convert(v) for k, v in obj.items() if v is not None}
26
+ elif isinstance(obj, Enum):
27
+ return obj.value
28
+ return obj
29
+ return _convert(self)
30
+
31
+ def __getitem__(self, key):
32
+ """Support dictionary-style access."""
33
+ if hasattr(self, key):
34
+ return getattr(self, key)
35
+ raise KeyError(f"{key} not found in {self.__class__.__name__}")
36
+
37
+ def get(self, key, default=None):
38
+ """Dictionary-style get method with default value."""
39
+ try:
40
+ return self[key]
41
+ except KeyError:
42
+ return default
43
+
44
+ def __contains__(self, key):
45
+ """Support 'in' operator."""
46
+ return hasattr(self, key)
47
+
48
+ @dataclass
49
+ class FunctionCall(BaseModel):
50
+ """Function call specification."""
51
+ name: str
52
+ arguments: str
53
+
54
+ @dataclass
55
+ class ToolFunction(BaseModel):
56
+ """Function specification in a tool."""
57
+ name: str
58
+ arguments: str
59
+
60
+ @dataclass
61
+ class ToolCall(BaseModel):
62
+ """Tool call specification."""
63
+ id: str
64
+ type: str
65
+ function: ToolFunction
66
+
67
+ @dataclass
68
+ class CompletionUsage(BaseModel):
69
+ """Token usage information."""
70
+ prompt_tokens: int
71
+ completion_tokens: int
72
+ total_tokens: int
73
+ prompt_tokens_details: Optional[Dict[str, Any]] = None
74
+
75
+ @dataclass
76
+ class ChoiceDelta(BaseModel):
77
+ """Delta content in streaming response."""
78
+ content: Optional[str] = None
79
+ function_call: Optional[FunctionCall] = None
80
+ role: Optional[str] = None
81
+ tool_calls: Optional[List[ToolCall]] = None
82
+
83
+ @dataclass
84
+ class ChatCompletionMessage(BaseModel):
85
+ """Chat message in completion response."""
86
+ role: str
87
+ content: Optional[str] = None
88
+ function_call: Optional[FunctionCall] = None
89
+ tool_calls: Optional[List[ToolCall]] = None
90
+
91
+ @dataclass
92
+ class Choice(BaseModel):
93
+ """Choice in completion response."""
94
+ index: int
95
+ message: Optional[ChatCompletionMessage] = None
96
+ delta: Optional[ChoiceDelta] = None
97
+ finish_reason: Optional[str] = None
98
+ logprobs: Optional[Dict[str, Any]] = None
99
+
100
+ @dataclass
101
+ class ModelData(BaseModel):
102
+ """OpenAI model info response."""
103
+ id: str
104
+ object: str = "model"
105
+ created: int = int(time.time())
106
+ owned_by: str = "webscout"
107
+ permission: Optional[List[Dict[str, Any]]] = None
108
+ root: Optional[str] = None
109
+ parent: Optional[str] = None
110
+
111
+ @dataclass
112
+ class ModelList(BaseModel):
113
+ """OpenAI model list response."""
114
+ data: List[ModelData] # Moved before 'object'
115
+ object: str = "list"
116
+
117
+
118
+ # @dataclass
119
+ # class EmbeddingData(BaseModel):
120
+ # """Single embedding data."""
121
+ # embedding: List[float]
122
+ # index: int
123
+ # object: str = "embedding"
124
+
125
+ # @dataclass
126
+ # class EmbeddingResponse(BaseModel):
127
+ # """OpenAI embeddings response."""
128
+ # data: List[EmbeddingData]
129
+ # model: str
130
+ # usage: CompletionUsage
131
+ # object: str = "list"
132
+
133
+ # @dataclass
134
+ # class FineTuningJob(BaseModel):
135
+ # """OpenAI fine-tuning job."""
136
+ # id: str
137
+ # model: str
138
+ # created_at: int
139
+ # status: str
140
+ # training_file: str
141
+ # hyperparameters: Dict[str, Any]
142
+ # object: str = "fine_tuning.job"
143
+ # finished_at: Optional[int] = None
144
+ # validation_file: Optional[str] = None
145
+ # trained_tokens: Optional[int] = None
146
+ # result_files: Optional[List[str]] = None
147
+ # organization_id: Optional[str] = None
148
+
149
+ # @dataclass
150
+ # class FineTuningJobList(BaseModel):
151
+ # """OpenAI fine-tuning job list response."""
152
+ # data: List[FineTuningJob]
153
+ # object: str = "list"
154
+ # has_more: bool = False
155
+
156
+ # @dataclass
157
+ # class File(BaseModel):
158
+ # """OpenAI file."""
159
+ # id: str
160
+ # bytes: int
161
+ # created_at: int
162
+ # filename: str
163
+ # purpose: str
164
+ # object: str = "file"
165
+ # status: str = "uploaded"
166
+ # status_details: Optional[str] = None
167
+
168
+ # @dataclass
169
+ # class FileList(BaseModel):
170
+ # """OpenAI file list response."""
171
+ # data: List[File]
172
+ # object: str = "list"
173
+
174
+ # @dataclass
175
+ # class DeletedObject(BaseModel):
176
+ # """OpenAI deleted object response."""
177
+ # id: str
178
+ # object: str = "deleted_object"
179
+ # deleted: bool = True
180
+
181
+ # @dataclass
182
+ # class ImageData(BaseModel):
183
+ # """OpenAI generated image."""
184
+ # url: Optional[str] = None
185
+ # b64_json: Optional[str] = None
186
+ # revised_prompt: Optional[str] = None
187
+
188
+ # @dataclass
189
+ # class ImageResponse(BaseModel):
190
+ # """OpenAI image generation response."""
191
+ # data: List[ImageData]
192
+ # created: int = int(time.time())
193
+
194
+ @dataclass
195
+ class ChatCompletion(BaseModel):
196
+ """Chat completion response."""
197
+ model: str
198
+ choices: List[Choice]
199
+ id: str = field(default_factory=lambda: f"chatcmpl-{str(uuid.uuid4())}")
200
+ created: int = field(default_factory=lambda: int(time.time()))
201
+ object: str = "chat.completion"
202
+ system_fingerprint: Optional[str] = None
203
+ usage: Optional[CompletionUsage] = None
204
+
205
+ @dataclass
206
+ class ChatCompletionChunk(BaseModel):
207
+ """Streaming chat completion response chunk."""
208
+ model: str
209
+ choices: List[Choice]
210
+ id: str = field(default_factory=lambda: f"chatcmpl-{str(uuid.uuid4())}")
211
+ created: int = field(default_factory=lambda: int(time.time()))
212
+ object: str = "chat.completion.chunk"
213
+ system_fingerprint: Optional[str] = None
214
+
215
+
216
+ # --- Helper Functions ---
217
+
218
+ def format_prompt(messages: List[Dict[str, Any]], add_special_tokens: bool = False,
219
+ do_continue: bool = False, include_system: bool = True) -> str:
220
+ """
221
+ Format a series of messages into a single string, optionally adding special tokens.
222
+
223
+ Args:
224
+ messages: A list of message dictionaries, each containing 'role' and 'content'.
225
+ add_special_tokens: Whether to add special formatting tokens.
226
+ do_continue: If True, don't add the final "Assistant:" prompt.
227
+ include_system: Whether to include system messages in the formatted output.
228
+
229
+ Returns:
230
+ A formatted string containing all messages.
231
+ """
232
+ # Helper function to convert content to string
233
+ def to_string(value) -> str:
234
+ if isinstance(value, str):
235
+ return value
236
+ elif isinstance(value, dict):
237
+ if "text" in value:
238
+ return value.get("text", "")
239
+ return ""
240
+ elif isinstance(value, list):
241
+ return "".join([to_string(v) for v in value])
242
+ return str(value)
243
+
244
+ # If there's only one message and no special tokens needed, just return its content
245
+ if not add_special_tokens and len(messages) <= 1:
246
+ return to_string(messages[0]["content"])
247
+
248
+ # Filter and process messages
249
+ processed_messages = [
250
+ (message["role"], to_string(message["content"]))
251
+ for message in messages
252
+ if include_system or message.get("role") != "system"
253
+ ]
254
+
255
+ # Format each message as "Role: Content"
256
+ formatted = "\n".join([
257
+ f'{role.capitalize()}: {content}'
258
+ for role, content in processed_messages
259
+ if content.strip()
260
+ ])
261
+
262
+ # Add final prompt for assistant if needed
263
+ if do_continue:
264
+ return formatted
265
+
266
+ return f"{formatted}\nAssistant:"
267
+
268
+
269
+ def get_system_prompt(messages: List[Dict[str, Any]]) -> str:
270
+ """
271
+ Extract and concatenate all system messages.
272
+
273
+ Args:
274
+ messages: A list of message dictionaries.
275
+
276
+ Returns:
277
+ A string containing all system messages concatenated with newlines.
278
+ """
279
+ return "\n".join([m["content"] for m in messages if m["role"] == "system"])
280
+
281
+
282
+ def get_last_user_message(messages: List[Dict[str, Any]]) -> str:
283
+ """
284
+ Get the content of the last user message in the conversation.
285
+
286
+ Args:
287
+ messages: A list of message dictionaries.
288
+
289
+ Returns:
290
+ The content of the last user message as a string.
291
+ """
292
+ for message in reversed(messages):
293
+ if message["role"] == "user":
294
+ if isinstance(message["content"], str):
295
+ return message["content"]
296
+ # Handle complex content structures
297
+ if isinstance(message["content"], dict) and "text" in message["content"]:
298
+ return message["content"]["text"]
299
+ if isinstance(message["content"], list):
300
+ text_parts = []
301
+ for part in message["content"]:
302
+ if isinstance(part, dict) and part.get("type") == "text":
303
+ text_parts.append(part.get("text", ""))
304
+ elif isinstance(part, str):
305
+ text_parts.append(part)
306
+ return "".join(text_parts)
307
+ return ""