mirror of
https://github.com/xtekky/gpt4free.git
synced 2025-12-06 02:30:41 -08:00
Update models and providers with improved documentation and code structure (#2786)
* docs(docs/providers-and-models.md): update documentation structure and model listings * refactor(g4f/debug.py): add type hints and docstrings * refactor(g4f/tools/run_tools.py): Restructure tool handling and improve modularity * refactor(g4f/providers/response.py): enhance type hints and code documentation * feat(g4f/models.py): Update model providers and add new models * feat(g4f/Provider/Blackbox.py): add encrypted session handling and model updates * fix(g4f/Provider/ChatGptEs.py): migrate to curl_cffi for request handling and improve error resilience * feat(g4f/Provider/DeepInfraChat.py): Update default model and add new DeepSeek variants * feat(g4f/Provider/Free2GPT.py): add Gemini models and streamline headers * feat(g4f/Provider/FreeGpt.py): Add support for Gemini 1.5 Flash model * feat(g4f/Provider/Liaobots.py): Add Claude 3.7 models and update default GPT-4o * fix(g4f/Provider/PollinationsAI.py): Correct model mappings and generation parameters * feat(g4f/Provider/PollinationsImage.py): Add class identifier label * chore(g4f/Provider/TeachAnything.py): Update default model and simplify model handling * (g4f/Provider/Mhystical.py): Remove class implementation * chore(g4f/Provider/Prodia.py > g4f/Provider/not_working/Prodia.py): mark Prodia provider as non-working * feat(g4f/Provider/Blackbox.py): Add Claude 3.7 Sonnet model alias * chore(g4f/models.py): Update model configurations * fix(g4f/Provider/ChatGptEs.py): improve request reliability and nonce detection --------- Co-authored-by: kqlio67 <>
This commit is contained in:
parent
17a99b684a
commit
c79635aaeb
18 changed files with 778 additions and 548 deletions
|
|
@ -11,7 +11,10 @@ This document provides an overview of various AI providers and models, including
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
- [Providers](#providers)
|
- [Providers](#providers)
|
||||||
- [No auth required](#providers-not-needs-auth)
|
- [No auth required](#providers-not-needs-auth)
|
||||||
|
- [HuggingFace](#providers-huggingface)
|
||||||
- [HuggingSpace](#providers-huggingspace)
|
- [HuggingSpace](#providers-huggingspace)
|
||||||
|
- [Local](#providers-local)
|
||||||
|
- [MiniMax](#providers-minimax)
|
||||||
- [Needs auth](#providers-needs-auth)
|
- [Needs auth](#providers-needs-auth)
|
||||||
- [Models](#models)
|
- [Models](#models)
|
||||||
- [Text Models](#text-models)
|
- [Text Models](#text-models)
|
||||||
|
|
@ -38,7 +41,7 @@ This document provides an overview of various AI providers and models, including
|
||||||
| Website | API Credentials | Provider | Text Models | Image Models | Vision (Image Upload) | Stream | Status |
|
| Website | API Credentials | Provider | Text Models | Image Models | Vision (Image Upload) | Stream | Status |
|
||||||
|----------|-------------|--------------|---------------|--------|--------|------|------|
|
|----------|-------------|--------------|---------------|--------|--------|------|------|
|
||||||
|[playground.allenai.org](https://playground.allenai.org)|No auth required|`g4f.Provider.AllenAI`|`tulu-3-405b, olmo-2-13b, tulu-3-1-8b, tulu-3-70b, olmoe-0125`|❌|❌|✔||
|
|[playground.allenai.org](https://playground.allenai.org)|No auth required|`g4f.Provider.AllenAI`|`tulu-3-405b, olmo-2-13b, tulu-3-1-8b, tulu-3-70b, olmoe-0125`|❌|❌|✔||
|
||||||
|[blackbox.ai](https://www.blackbox.ai)|No auth required|`g4f.Provider.Blackbox`|`blackboxai, gemini-1.5-flash, blackboxai-pro, llama-3.1-8b, llama-3.1-70b, llama-3-1-405b, llama-3.3-70b, mixtral-small-28b, deepseek-chat, dbrx-instruct, qwq-32b, hermes-2-dpo, deepseek-v3, deepseek-r1, gemini-2.0-flash` _**(+35)**_|`flux`|`blackboxai, gpt-4o, o3-mini, gemini-1.5-pro, gemini-1.5-flash, llama-3.1-8b, llama-3.1-70b, llama-3.1-405b, gemini-2.0-flash`|✔||
|
|[blackbox.ai](https://www.blackbox.ai)|No auth required|`g4f.Provider.Blackbox`|`blackboxai, gemini-1.5-flash, blackboxai-pro, llama-3.1-8b, llama-3.1-70b, llama-3-1-405b, llama-3.3-70b, mixtral-small-28b, deepseek-chat, dbrx-instruct, qwq-32b, hermes-2-dpo, deepseek-v3, deepseek-r1, gemini-2.0-flash, gpt-4o, o1, o3-mini, gemini-1.5-pro, claude-3.7-sonnet` _**(+29)**_|`flux`|`blackboxai, gpt-4o, o1, o3-mini, gemini-1.5-pro, gemini-1.5-flash, llama-3.1-8b, llama-3.1-70b, llama-3.1-405b, gemini-2.0-flash, deepseek-v3`|✔||
|
||||||
|[chatglm.cn](https://chatglm.cn)|No auth required|`g4f.Provider.ChatGLM`|`glm-4`|❌|❌|✔||
|
|[chatglm.cn](https://chatglm.cn)|No auth required|`g4f.Provider.ChatGLM`|`glm-4`|❌|❌|✔||
|
||||||
|[chatgpt.com](https://chatgpt.com)|No auth required|`g4f.Provider.ChatGpt`|✔ _**(+7)**_|❌|❌|✔||
|
|[chatgpt.com](https://chatgpt.com)|No auth required|`g4f.Provider.ChatGpt`|✔ _**(+7)**_|❌|❌|✔||
|
||||||
|[chatgpt.es](https://chatgpt.es)|No auth required|`g4f.Provider.ChatGptEs`|`gpt-4, gpt-4o, gpt-4o-mini`|❌|❌|✔||
|
|[chatgpt.es](https://chatgpt.es)|No auth required|`g4f.Provider.ChatGptEs`|`gpt-4, gpt-4o, gpt-4o-mini`|❌|❌|✔||
|
||||||
|
|
@ -46,27 +49,34 @@ This document provides an overview of various AI providers and models, including
|
||||||
|[copilot.microsoft.com](https://copilot.microsoft.com)|Optional API key|`g4f.Provider.Copilot`|`gpt-4, gpt-4o`|❌|❌|✔||
|
|[copilot.microsoft.com](https://copilot.microsoft.com)|Optional API key|`g4f.Provider.Copilot`|`gpt-4, gpt-4o`|❌|❌|✔||
|
||||||
|[duckduckgo.com/aichat](https://duckduckgo.com/aichat)|No auth required|`g4f.Provider.DDG`|`gpt-4, gpt-4o-mini, llama-3.3-70b, claude-3-haiku, o3-mini, mixtral-small-24b`|❌|❌|✔||
|
|[duckduckgo.com/aichat](https://duckduckgo.com/aichat)|No auth required|`g4f.Provider.DDG`|`gpt-4, gpt-4o-mini, llama-3.3-70b, claude-3-haiku, o3-mini, mixtral-small-24b`|❌|❌|✔||
|
||||||
|[deepinfra.com/chat](https://deepinfra.com/chat)|No auth required|`g4f.Provider.DeepInfraChat`|`llama-3.1-8b, llama-3.2-90b, llama-3.3-70b, deepseek-v3, mixtral-small-28b, deepseek-r1, phi-4, wizardlm-2-8x22b, qwen-2.5-72b, yi-34b, qwen-2-72b, dolphin-2.6, dolphin-2.9, dbrx-instruct, airoboros-70b, lzlv-70b, wizardlm-2-7b, mixtral-8x22b, minicpm-2.5`|❌|`llama-3.2-90b, minicpm-2.5`|✔||
|
|[deepinfra.com/chat](https://deepinfra.com/chat)|No auth required|`g4f.Provider.DeepInfraChat`|`llama-3.1-8b, llama-3.2-90b, llama-3.3-70b, deepseek-v3, mixtral-small-28b, deepseek-r1, phi-4, wizardlm-2-8x22b, qwen-2.5-72b, yi-34b, qwen-2-72b, dolphin-2.6, dolphin-2.9, dbrx-instruct, airoboros-70b, lzlv-70b, wizardlm-2-7b, mixtral-8x22b, minicpm-2.5`|❌|`llama-3.2-90b, minicpm-2.5`|✔||
|
||||||
|[chat10.free2gpt.xyz](https://chat10.free2gpt.xyz)|No auth required|`g4f.Provider.Free2GPT`|`mistral-7b`|❌|❌|✔||
|
|[chat10.free2gpt.xyz](https://chat10.free2gpt.xyz)|No auth required|`g4f.Provider.Free2GPT`|`gemini-1.5-pro, gemini-1.5-flash`|❌|❌|✔||
|
||||||
|[freegptsnav.aifree.site](https://freegptsnav.aifree.site)|No auth required|`g4f.Provider.FreeGpt`|`gemini-1.5-pro`|❌|❌|✔||
|
|[freegptsnav.aifree.site](https://freegptsnav.aifree.site)|No auth required|`g4f.Provider.FreeGpt`|`gemini-1.5-pro, gemini-1.5-flash`|❌|❌|✔||
|
||||||
|[app.giz.ai/assistant](https://app.giz.ai/assistant)|No auth required|`g4f.Provider.GizAI`|`gemini-1.5-flash`|❌|❌|✔||
|
|[app.giz.ai/assistant](https://app.giz.ai/assistant)|No auth required|`g4f.Provider.GizAI`|`gemini-1.5-flash`|❌|❌|✔||
|
||||||
|[glider.so](https://glider.so)|No auth required|`g4f.Provider.Glider`|`llama-3.1-70b, llama-3.1-8b, llama-3.2-3b, deepseek-r1`|❌|❌|✔||
|
|[glider.so](https://glider.so)|No auth required|`g4f.Provider.Glider`|`llama-3.1-70b, llama-3.1-8b, llama-3.2-3b, deepseek-r1`|❌|❌|✔||
|
||||||
|[hailuo.ai](https://www.hailuo.ai)|No auth required|`g4f.Provider.HailuoAI`|`MiniMax` _**(1)**_|❌|❌|✔||
|
|[hailuo.ai](https://www.hailuo.ai)|No auth required|`g4f.Provider.HailuoAI`|`MiniMax` _**(1)**_|❌|❌|✔||
|
||||||
|[editor.imagelabs.net](https://editor.imagelabs.net)|No auth required|`g4f.Provider.ImageLabs`|`gemini-1.5-pro`|❌|❌|✔||
|
|
||||||
|[editor.imagelabs.net](editor.imagelabs.net)|No auth required|`g4f.Provider.ImageLabs`|❌|`sdxl-turbo`|❌|✔||
|
|[editor.imagelabs.net](editor.imagelabs.net)|No auth required|`g4f.Provider.ImageLabs`|❌|`sdxl-turbo`|❌|✔||
|
||||||
|[huggingface.co/spaces](https://huggingface.co/spaces)|Optional API key|`g4f.Provider.HuggingSpace`|`qvq-72b, qwen-2-72b, command-r, command-r-plus, command-r7b`|`flux-dev, flux-schnell, sd-3.5`|❌|✔||
|
|[huggingface.co/spaces](https://huggingface.co/spaces)|Optional API key|`g4f.Provider.HuggingSpace`|`qvq-72b, qwen-2-72b, command-r, command-r-plus, command-r7b`|`flux-dev, flux-schnell, sd-3.5`|❌|✔||
|
||||||
|[jmuz.me](https://jmuz.me)|Optional API key|`g4f.Provider.Jmuz`|`claude-3-haiku, claude-3-opus, claude-3-haiku, claude-3.5-sonnet, deepseek-r1, deepseek-chat, gemini-exp, gemini-1.5-flash, gemini-1.5-pro, gemini-2.0-flash-thinking, gpt-4, gpt-4o, gpt-4o-mini, llama-3-70b, llama-3-8b, llama-3.1-405b, llama-3.1-70b, llama-3.1-8b, llama-3.2-11b, llama-3.2-90b, llama-3.3-70b, mixtral-8x7b, qwen-2.5-72b, qwen-2.5-coder-32b, qwq-32b, wizardlm-2-8x22b`|❌|❌|✔||
|
|[jmuz.me](https://jmuz.me)|Optional API key|`g4f.Provider.Jmuz`|`claude-3-haiku, claude-3-opus, claude-3-haiku, claude-3.5-sonnet, deepseek-r1, deepseek-chat, gemini-exp, gemini-1.5-flash, gemini-1.5-pro, gemini-2.0-flash-thinking, gpt-4, gpt-4o, gpt-4o-mini, llama-3-70b, llama-3-8b, llama-3.1-405b, llama-3.1-70b, llama-3.1-8b, llama-3.2-11b, llama-3.2-90b, llama-3.3-70b, mixtral-8x7b, qwen-2.5-72b, qwen-2.5-coder-32b, qwq-32b, wizardlm-2-8x22b`|❌|❌|✔||
|
||||||
|[liaobots.work](https://liaobots.work)|[Automatic cookies](https://liaobots.work)|`g4f.Provider.Liaobots`|`gpt-4o-mini, gpt-4o, gpt-4, o1-preview, deepseek-r1, deepseek-v3, claude-3-opus, claude-3.5-sonnet, claude-3-sonnet, gemini-2.0-flash, gemini-2.0-flash-thinking, grok-3, grok-3-r1, o3-mini`|❌|❌|✔||
|
|[liaobots.work](https://liaobots.work)|[Automatic cookies](https://liaobots.work)|`g4f.Provider.Liaobots`|`claude-3.5-sonnet, claude-3.7-sonnet, claude-3.7-sonnet-thinking, claude-3-opus, claude-3-sonnet, deepseek-r1, deepseek-v3, gemini-2.0-flash, gemini-2.0-flash-thinking, gemini-2.0-pro, gpt-4, gpt-4o, gpt-4o-mini, grok-3, grok-3-r1, o3-mini`|❌|❌|✔||
|
||||||
|[mhystical.cc](https://mhystical.cc)|[Optional API key](https://mhystical.cc/dashboard)|`g4f.Provider.Mhystical`|`gpt-4`|❌|❌|✔||
|
|
||||||
|[oi-vscode-server.onrender.com](https://oi-vscode-server.onrender.com)|No auth required|`g4f.Provider.OIVSCode`|`gpt-4o-mini, deepseek-v3`|❌|`gpt-4o-mini`|✔||
|
|[oi-vscode-server.onrender.com](https://oi-vscode-server.onrender.com)|No auth required|`g4f.Provider.OIVSCode`|`gpt-4o-mini, deepseek-v3`|❌|`gpt-4o-mini`|✔||
|
||||||
|[labs.perplexity.ai](https://labs.perplexity.ai)|No auth required|`g4f.Provider.PerplexityLabs`|`sonar, sonar-pro, sonar-reasoning, sonar-reasoning-pro`|❌|❌|✔||
|
|[labs.perplexity.ai](https://labs.perplexity.ai)|No auth required|`g4f.Provider.PerplexityLabs`|`sonar, sonar-pro, sonar-reasoning, sonar-reasoning-pro`|❌|❌|✔||
|
||||||
|[pi.ai/talk](https://pi.ai/talk)|[Manual cookies](https://pi.ai/talk)|`g4f.Provider.Pi`|`pi`|❌|❌|✔||
|
|[pi.ai/talk](https://pi.ai/talk)|[Manual cookies](https://pi.ai/talk)|`g4f.Provider.Pi`|`pi`|❌|❌|✔||
|
||||||
|[pizzagpt.it](https://www.pizzagpt.it)|No auth required|`g4f.Provider.Pizzagpt`|`gpt-4o-mini`|❌|❌|✔||
|
|[pizzagpt.it](https://www.pizzagpt.it)|No auth required|`g4f.Provider.Pizzagpt`|`gpt-4o-mini`|❌|❌|✔||
|
||||||
|[pollinations.ai](https://pollinations.ai)|No auth required|`g4f.Provider.PollinationsAI`|`gpt-4o-mini, gpt-4o, qwen-2.5-coder-32b, llama-3.3-70b, mistral-nemo, deepseek-chat, llama-3.1-8b, deepseek-r1, gemini-2.0-flash, gemini-2.0-flash-thinking` _**(3+)**_|`flux, flux-pro, flux-dev, flux-schnell, dall-e-3, sdxl-turbo`|gpt-4o, gpt-4o-mini|✔||
|
|[pollinations.ai](https://pollinations.ai)|No auth required|`g4f.Provider.PollinationsAI`|`gpt-4o-mini, gpt-4o, o1-mini, qwen-2.5-coder-32b, llama-3.3-70b, mistral-nemo, llama-3.1-8b, deepseek-r1, phi-4` _**(6+)**_|`flux, flux-pro, flux-dev, flux-schnell, dall-e-3, sdxl-turbo`|gpt-4o, gpt-4o-mini, o1-mini|✔||
|
||||||
|
|[pollinations.ai](https://pollinations.ai)|No auth required|`g4f.Provider.PollinationsImage`|❌|`flux, flux-pro, flux-dev, flux-schnell, dall-e-3, sdxl-turbo`|❌|✔||
|
||||||
|[app.prodia.com](https://app.prodia.com)|No auth required|`g4f.Provider.Prodia`|❌|✔ _**(46)**_|❌|❌||
|
|[app.prodia.com](https://app.prodia.com)|No auth required|`g4f.Provider.Prodia`|❌|✔ _**(46)**_|❌|❌||
|
||||||
|[teach-anything.com](https://www.teach-anything.com)|No auth required|`g4f.Provider.TeachAnything`|`llama-3.1-70b`|❌|❌|✔||
|
|[teach-anything.com](https://www.teach-anything.com)|No auth required|`g4f.Provider.TeachAnything`|`gemini-1.5-pro, gemini-1.5-flash`|❌|❌|✔||
|
||||||
|[you.com](https://you.com)|[Manual cookies](https://you.com)|`g4f.Provider.You`|✔|✔|✔|✔||
|
|[you.com](https://you.com)|[Manual cookies](https://you.com)|`g4f.Provider.You`|✔|✔|✔|✔||
|
||||||
|[chat9.yqcloud.top](https://chat9.yqcloud.top)|No auth required|`g4f.Provider.Yqcloud`|`gpt-4`|✔|✔|✔||
|
|[chat9.yqcloud.top](https://chat9.yqcloud.top)|No auth required|`g4f.Provider.Yqcloud`|`gpt-4`|✔|✔|✔||
|
||||||
|
|
||||||
|
---
|
||||||
|
### Providers HuggingFace
|
||||||
|
| Website | API Credentials | Provider | Text Models | Image Models | Vision (Image Upload) | Stream | Status |
|
||||||
|
|----------|-------------|--------------|---------------|--------|--------|------|------|
|
||||||
|
|[huggingface.co/chat](https://huggingface.co/chat)|[Manual cookies](https://huggingface.co/chat)|`g4f.Provider.HuggingChat`|`qwen-2.5-72b, llama-3.3-70b, command-r-plus, deepseek-r1, qwq-32b, nemotron-70b, llama-3.2-11b, mistral-nemo, phi-3.5-mini`|`flux-dev, flux-schnell`|❌|✔||
|
||||||
|
|[huggingface.co/chat](https://huggingface.co/chat)|[API key / Cookies](https://huggingface.co/settings/tokens)|`g4f.Provider.HuggingFace`|✔ _**(47+)**_|✔ _**(9+)**_|❌|✔||
|
||||||
|
|[api-inference.huggingface.co](https://api-inference.huggingface.co)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.HuggingFaceAPI`|✔ _**(9+)**_|✔ _**(2+)**_|✔ _**(1+)**_|❌||✔|
|
||||||
|
|
||||||
---
|
---
|
||||||
### Providers HuggingSpace
|
### Providers HuggingSpace
|
||||||
| Website | API Credentials | Provider | Text Models | Image Models | Vision (Image Upload) | Stream | Status | Auth |
|
| Website | API Credentials | Provider | Text Models | Image Models | Vision (Image Upload) | Stream | Status | Auth |
|
||||||
|
|
@ -74,6 +84,7 @@ This document provides an overview of various AI providers and models, including
|
||||||
|[black-forest-labs-flux-1-dev.hf.space](https://black-forest-labs-flux-1-dev.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.BlackForestLabsFlux1Dev`|❌|`flux-dev`|❌|✔||
|
|[black-forest-labs-flux-1-dev.hf.space](https://black-forest-labs-flux-1-dev.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.BlackForestLabsFlux1Dev`|❌|`flux-dev`|❌|✔||
|
||||||
|[black-forest-labs-flux-1-schnell.hf.space](https://black-forest-labs-flux-1-schnell.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.BlackForestLabsFlux1Schnell`|❌|`flux-schnell`|❌|✔||
|
|[black-forest-labs-flux-1-schnell.hf.space](https://black-forest-labs-flux-1-schnell.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.BlackForestLabsFlux1Schnell`|❌|`flux-schnell`|❌|✔||
|
||||||
|[cohereforai-c4ai-command.hf.space](https://cohereforai-c4ai-command.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.CohereForAI`|`command-r, command-r-plus, command-r7b`|❌|❌|✔||
|
|[cohereforai-c4ai-command.hf.space](https://cohereforai-c4ai-command.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.CohereForAI`|`command-r, command-r-plus, command-r7b`|❌|❌|✔||
|
||||||
|
|[roxky-flux-1-dev.hf.space](https://roxky-flux-1-dev.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|❌|❌|✔ _**(3)**_|✔||
|
||||||
|[huggingface.co/spaces/deepseek-ai/Janus-Pro-7B](https://huggingface.co/spaces/deepseek-ai/Janus-Pro-7B)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Janus_Pro_7B`|✔|✔|❌|✔||
|
|[huggingface.co/spaces/deepseek-ai/Janus-Pro-7B](https://huggingface.co/spaces/deepseek-ai/Janus-Pro-7B)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Janus_Pro_7B`|✔|✔|❌|✔||
|
||||||
|[qwen-qvq-72b-preview.hf.space](https://qwen-qvq-72b-preview.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_QVQ_72B`|`qvq-72b`|❌|❌|✔||
|
|[qwen-qvq-72b-preview.hf.space](https://qwen-qvq-72b-preview.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_QVQ_72B`|`qvq-72b`|❌|❌|✔||
|
||||||
|[qwen-qwen2-5-1m-demo.hf.space](https://qwen-qwen2-5-1m-demo.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_Qwen_2_5M_Demo`|`qwen-2.5-1m-demo`|❌|❌|✔||
|
|[qwen-qwen2-5-1m-demo.hf.space](https://qwen-qwen2-5-1m-demo.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_Qwen_2_5M_Demo`|`qwen-2.5-1m-demo`|❌|❌|✔||
|
||||||
|
|
@ -81,6 +92,19 @@ This document provides an overview of various AI providers and models, including
|
||||||
|[stabilityai-stable-diffusion-3-5-large.hf.space](https://stabilityai-stable-diffusion-3-5-large.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.StableDiffusion35Large`|❌|`sd-3.5`|❌|✔||
|
|[stabilityai-stable-diffusion-3-5-large.hf.space](https://stabilityai-stable-diffusion-3-5-large.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.StableDiffusion35Large`|❌|`sd-3.5`|❌|✔||
|
||||||
|[voodoohop-flux-1-schnell.hf.space](https://voodoohop-flux-1-schnell.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.VoodoohopFlux1Schnell`|❌|`flux-schnell`|❌|✔||
|
|[voodoohop-flux-1-schnell.hf.space](https://voodoohop-flux-1-schnell.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.VoodoohopFlux1Schnell`|❌|`flux-schnell`|❌|✔||
|
||||||
|
|
||||||
|
### Providers Local
|
||||||
|
| Website | API Credentials | Provider | Text Models | Image Models | Vision (Image Upload) | Stream | Status |
|
||||||
|
|----------|-------------|--------------|---------------|--------|--------|------|------|
|
||||||
|
|[]( )|No auth required|`g4f.Provider.Local`|✔|❌|❌|✔||
|
||||||
|
|[ollama.com](https://ollama.com)|No auth required|`g4f.Provider.Ollama`|✔|❌|❌|✔||
|
||||||
|
|
||||||
|
---
|
||||||
|
### Providers MiniMax
|
||||||
|
| Website | API Credentials | Provider | Text Models | Image Models | Vision (Image Upload) | Stream | Status |
|
||||||
|
|----------|-------------|--------------|---------------|--------|--------|------|------|
|
||||||
|
|[hailuo.ai/chat](https://www.hailuo.ai/chat)|[Get API key](https://intl.minimaxi.com/user-center/basic-information/interface-key)|`g4f.Provider.MiniMax`|`MiniMax` _**(1)**_|❌|❌|✔||
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
### Providers Needs Auth
|
### Providers Needs Auth
|
||||||
| Website | API Credentials | Provider | Text Models | Image Models | Vision (Image Upload) | Stream | Status |
|
| Website | API Credentials | Provider | Text Models | Image Models | Vision (Image Upload) | Stream | Status |
|
||||||
|
|
@ -98,13 +122,9 @@ This document provides an overview of various AI providers and models, including
|
||||||
|[github.com/copilot](https://github.com/copilot)|[Manual cookies](https://github.com/copilot)|`g4f.Provider.GithubCopilot`|✔ _**(4+)**_|❌|❌|❌||
|
|[github.com/copilot](https://github.com/copilot)|[Manual cookies](https://github.com/copilot)|`g4f.Provider.GithubCopilot`|✔ _**(4+)**_|❌|❌|❌||
|
||||||
|[glhf.chat](https://glhf.chat)|[Get API key](https://glhf.chat/user-settings/api)|`g4f.Provider.GlhfChat`|✔ _**(22+)**_|❌|❌|❌||
|
|[glhf.chat](https://glhf.chat)|[Get API key](https://glhf.chat/user-settings/api)|`g4f.Provider.GlhfChat`|✔ _**(22+)**_|❌|❌|❌||
|
||||||
|[console.groq.com/playground](https://console.groq.com/playground)|[Get API key](https://console.groq.com/keys)|`g4f.Provider.Groq`|✔ _**(18+)**_|❌|✔|❌||
|
|[console.groq.com/playground](https://console.groq.com/playground)|[Get API key](https://console.groq.com/keys)|`g4f.Provider.Groq`|✔ _**(18+)**_|❌|✔|❌||
|
||||||
|[huggingface.co/chat](https://huggingface.co/chat)|[Manual cookies](https://huggingface.co/chat)|`g4f.Provider.HuggingChat`|`qwen-2.5-72b, llama-3.3-70b, command-r-plus, deepseek-r1, qwq-32b, nemotron-70b, llama-3.2-11b, mistral-nemo, phi-3.5-mini`|`flux-dev, flux-schnell`|❌|✔||
|
|
||||||
|[huggingface.co/chat](https://huggingface.co/chat)|[API key / Cookies](https://huggingface.co/settings/tokens)|`g4f.Provider.HuggingFace`|✔ _**(47+)**_|✔ _**(9+)**_|❌|✔||
|
|
||||||
|[api-inference.huggingface.co](https://api-inference.huggingface.co)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.HuggingFaceAPI`|✔ _**(9+)**_|✔ _**(2+)**_|✔ _**(1+)**_|❌||✔|
|
|
||||||
|[meta.ai](https://www.meta.ai)|[Manual cookies](https://www.meta.ai)|`g4f.Provider.MetaAI`|`meta-ai`|❌|❌|✔||✔|
|
|[meta.ai](https://www.meta.ai)|[Manual cookies](https://www.meta.ai)|`g4f.Provider.MetaAI`|`meta-ai`|❌|❌|✔||✔|
|
||||||
|[meta.ai](https://www.meta.ai)|[Manual cookies](https://www.meta.ai)|`g4f.Provider.MetaAIAccount`|❌|`meta-ai`|❌|✔||
|
|[meta.ai](https://www.meta.ai)|[Manual cookies](https://www.meta.ai)|`g4f.Provider.MetaAIAccount`|❌|`meta-ai`|❌|✔||
|
||||||
|[designer.microsoft.com](https://designer.microsoft.com)|[Manual cookies](https://designer.microsoft.com)|`g4f.Provider.MicrosoftDesigner`|❌|`dall-e-3`|❌|❌||
|
|[designer.microsoft.com](https://designer.microsoft.com)|[Manual cookies](https://designer.microsoft.com)|`g4f.Provider.MicrosoftDesigner`|❌|`dall-e-3`|❌|❌||
|
||||||
|[hailuo.ai/chat](https://www.hailuo.ai/chat)|[Get API key](https://intl.minimaxi.com/user-center/basic-information/interface-key)|`g4f.Provider.MiniMax`|`MiniMax` _**(1)**_|❌|❌|✔||
|
|
||||||
|[platform.openai.com](https://platform.openai.com)|[Get API key](https://platform.openai.com/settings/organization/api-keys)|`g4f.Provider.OpenaiAPI`|✔|❌|❌|✔||
|
|[platform.openai.com](https://platform.openai.com)|[Get API key](https://platform.openai.com/settings/organization/api-keys)|`g4f.Provider.OpenaiAPI`|✔|❌|❌|✔||
|
||||||
|[chatgpt.com](https://chatgpt.com)|[Manual cookies](https://chatgpt.com)|`g4f.Provider.OpenaiChat`|`gpt-4o, gpt-4o-mini, gpt-4` _**(8+)**_|✔_**(1)**_|✔_**(8+)**_|✔||
|
|[chatgpt.com](https://chatgpt.com)|[Manual cookies](https://chatgpt.com)|`g4f.Provider.OpenaiChat`|`gpt-4o, gpt-4o-mini, gpt-4` _**(8+)**_|✔_**(1)**_|✔_**(8+)**_|✔||
|
||||||
|[perplexity.ai](https://www.perplexity.ai)|[Get API key](https://www.perplexity.ai/settings/api)|`g4f.Provider.PerplexityApi`|✔ _**(6+)**_|❌|❌|✔||
|
|[perplexity.ai](https://www.perplexity.ai)|[Get API key](https://www.perplexity.ai/settings/api)|`g4f.Provider.PerplexityApi`|✔ _**(6+)**_|❌|❌|✔||
|
||||||
|
|
@ -121,44 +141,47 @@ This document provides an overview of various AI providers and models, including
|
||||||
| Model | Base Provider | Providers | Website |
|
| Model | Base Provider | Providers | Website |
|
||||||
|-------|---------------|-----------|---------|
|
|-------|---------------|-----------|---------|
|
||||||
|gpt-4|OpenAI|8+ Providers|[platform.openai.com](https://platform.openai.com/docs/models/gpt-4-turbo-and-gpt-4)|
|
|gpt-4|OpenAI|8+ Providers|[platform.openai.com](https://platform.openai.com/docs/models/gpt-4-turbo-and-gpt-4)|
|
||||||
|gpt-4o|OpenAI|6+ Providers|[platform.openai.com](https://platform.openai.com/docs/models/gpt-4o)|
|
|gpt-4o|OpenAI|7+ Providers|[platform.openai.com](https://platform.openai.com/docs/models/gpt-4o)|
|
||||||
|gpt-4o-mini|OpenAI|7+ Providers|[platform.openai.com](https://platform.openai.com/docs/models/gpt-4o-mini)|
|
|gpt-4o-mini|OpenAI|7+ Providers|[platform.openai.com](https://platform.openai.com/docs/models/gpt-4o-mini)|
|
||||||
|o1|OpenAI|1+ Providers|[openai.com](https://openai.com/index/introducing-openai-o1-preview/)|
|
|o1|OpenAI|2+ Providers|[openai.com](https://openai.com/index/introducing-openai-o1-preview/)|
|
||||||
|o1-preview|OpenAI|1+ Providers|[openai.com](https://openai.com/index/introducing-openai-o1-preview/)|
|
|o1-mini|OpenAI|1+ Providers|[openai.com](https://openai.com/index/openai-o1-mini-advancing-cost-efficient-reasoning/)|
|
||||||
|o3-mini|OpenAI|2+ Providers|[openai.com](https://openai.com/index/openai-o3-mini/)|
|
|o3-mini|OpenAI|3+ Providers|[openai.com](https://openai.com/index/openai-o3-mini/)|
|
||||||
|gigachat|GigaChat|1+ Providers|[developers.sber.ru/gigachat](https://developers.sber.ru/gigachat)|
|
|gigachat|GigaChat|1+ Providers|[developers.sber.ru/gigachat](https://developers.sber.ru/gigachat)|
|
||||||
|meta-ai|Meta|1+ Providers|[ai.meta.com](https://ai.meta.com/)|
|
|meta-ai|Meta|1+ Providers|[ai.meta.com](https://ai.meta.com/)|
|
||||||
|llama-2-7b|Meta Llama|1+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-2-7b)|
|
|llama-2-7b|Meta Llama|1+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-2-7b)|
|
||||||
|llama-3-8b|Meta Llama|2+ Providers|[ai.meta.com](https://ai.meta.com/blog/meta-llama-3/)|
|
|llama-3-8b|Meta Llama|2+ Providers|[ai.meta.com](https://ai.meta.com/blog/meta-llama-3/)|
|
||||||
|llama-3-70b|Meta Llama|1+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Meta-Llama-3-70B)|
|
|llama-3-70b|Meta Llama|1+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Meta-Llama-3-70B)|
|
||||||
|llama-3.1-8b|Meta Llama|6+ Providers|[ai.meta.com](https://ai.meta.com/blog/meta-llama-3-1/)|
|
|llama-3.1-8b|Meta Llama|6+ Providers|[ai.meta.com](https://ai.meta.com/blog/meta-llama-3-1/)|
|
||||||
|llama-3.1-70b|Meta Llama|5+ Providers|[ai.meta.com](https://ai.meta.com/blog/meta-llama-3-1/)|
|
|llama-3.1-70b|Meta Llama|3+ Providers|[ai.meta.com](https://ai.meta.com/blog/meta-llama-3-1/)|
|
||||||
|llama-3.1-405b|Meta Llama|2+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-3.1-405B)|
|
|llama-3.1-405b|Meta Llama|2+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-3.1-405B)|
|
||||||
|llama-3.2-1b|Meta Llama|1+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-3.2-1B)|
|
|llama-3.2-1b|Meta Llama|1+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-3.2-1B)|
|
||||||
|llama-3.2-3b|Meta Llama|1+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-3.2-3B)|
|
|llama-3.2-3b|Meta Llama|1+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-3.2-3B)|
|
||||||
|llama-3.2-11b|Meta Llama|3+ Providers|[ai.meta.com](https://ai.meta.com/blog/llama-3-2-connect-2024-vision-edge-mobile-devices/)|
|
|llama-3.2-11b|Meta Llama|3+ Providers|[ai.meta.com](https://ai.meta.com/blog/llama-3-2-connect-2024-vision-edge-mobile-devices/)|
|
||||||
|llama-3.2-90b|Meta Llama|1+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-3.2-90B-Vision)|
|
|llama-3.2-90b|Meta Llama|2+ Providers|[huggingface.co](https://huggingface.co/meta-llama/Llama-3.2-90B-Vision)|
|
||||||
|llama-3.3-70b|Meta Llama|6+ Providers|[ai.meta.com](https://ai.meta.com/blog/llama-3-3/)|
|
|llama-3.3-70b|Meta Llama|7+ Providers|[ai.meta.com](https://ai.meta.com/blog/llama-3-3/)|
|
||||||
|mixtral-8x7b|Mistral|1+ Providers|[mistral.ai](https://mistral.ai/news/mixtral-of-experts/)|
|
|mixtral-8x7b|Mistral|1+ Providers|[mistral.ai](https://mistral.ai/news/mixtral-of-experts/)|
|
||||||
|mixtral-8x22b|Mistral|1+ Providers|[huggingface.co](https://huggingface.co/mistralai/Mixtral-8x22B-Instruct-v0.1)|
|
|mixtral-8x22b|Mistral|1+ Providers|[huggingface.co](https://huggingface.co/mistralai/Mixtral-8x22B-Instruct-v0.1)|
|
||||||
|mistral-nemo|Mistral|3+ Providers|[huggingface.co](https://huggingface.co/mistralai/Mistral-Nemo-Instruct-2407)|
|
|mistral-nemo|Mistral|3+ Providers|[huggingface.co](https://huggingface.co/mistralai/Mistral-Nemo-Instruct-2407)|
|
||||||
|mixtral-small-24b|Mistral|1+ Providers|[huggingface.co](https://huggingface.co/mistralai/Mistral-Small-24B-Instruct-2501)|
|
|mixtral-small-24b|Mistral|1+ Providers|[huggingface.co](https://huggingface.co/mistralai/Mistral-Small-24B-Instruct-2501)|
|
||||||
|mixtral-small-28b|Mistral|3+ Providers|[mistral.ai](https://mistral.ai/news/mixtral-small-28b/)|
|
|mixtral-small-28b|Mistral|2+ Providers|[mistral.ai](https://mistral.ai/news/mixtral-small-28b/)|
|
||||||
|hermes-2-dpo|NousResearch|1+ Providers|[huggingface.co](https://huggingface.co/NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO)|
|
|hermes-2-dpo|NousResearch|1+ Providers|[huggingface.co](https://huggingface.co/NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO)|
|
||||||
|phi-3.5-mini|Microsoft|1+ Providers|[huggingface.co](https://huggingface.co/microsoft/Phi-3.5-mini-instruct)|
|
|phi-3.5-mini|Microsoft|1+ Providers|[huggingface.co](https://huggingface.co/microsoft/Phi-3.5-mini-instruct)|
|
||||||
|phi-4|Microsoft|1+ Providers|[techcommunity.microsoft.com](https://techcommunity.microsoft.com/blog/aiplatformblog/introducing-phi-4-microsoft%E2%80%99s-newest-small-language-model-specializing-in-comple/4357090)|
|
|phi-4|Microsoft|2+ Providers|[techcommunity.microsoft.com](https://techcommunity.microsoft.com/blog/aiplatformblog/introducing-phi-4-microsoft%E2%80%99s-newest-small-language-model-specializing-in-comple/4357090)|
|
||||||
|wizardlm-2-7b|Microsoft|1+ Providers|[wizardlm.github.io](https://wizardlm.github.io/WizardLM2/)|
|
|wizardlm-2-7b|Microsoft|1+ Providers|[wizardlm.github.io](https://wizardlm.github.io/WizardLM2/)|
|
||||||
|wizardlm-2-8x22b|Microsoft|2+ Providers|[wizardlm.github.io](https://wizardlm.github.io/WizardLM2/)|
|
|wizardlm-2-8x22b|Microsoft|2+ Providers|[wizardlm.github.io](https://wizardlm.github.io/WizardLM2/)|
|
||||||
|gemini-2.0|Google DeepMind|1+|[deepmind.google](http://deepmind.google/technologies/gemini/)|
|
|gemini-2.0|Google DeepMind|1+ Providers|[deepmind.google](http://deepmind.google/technologies/gemini/)|
|
||||||
|gemini-exp|Google DeepMind|1+ Providers|[blog.google](https://blog.google/feed/gemini-exp-1206/)|
|
|gemini-exp|Google DeepMind|1+ Providers|[blog.google](https://blog.google/feed/gemini-exp-1206/)|
|
||||||
|gemini-1.5-flash|Google DeepMind|3+ Providers|[deepmind.google](https://deepmind.google/technologies/gemini/flash/)|
|
|gemini-1.5-flash|Google DeepMind|6+ Providers|[deepmind.google](https://deepmind.google/technologies/gemini/flash/)|
|
||||||
|gemini-1.5-pro|Google DeepMind|2+ Providers|[deepmind.google](https://deepmind.google/technologies/gemini/pro/)|
|
|gemini-1.5-pro|Google DeepMind|6+ Providers|[deepmind.google](https://deepmind.google/technologies/gemini/pro/)|
|
||||||
|gemini-2.0-flash|Google DeepMind|4+ Providers|[deepmind.google](https://deepmind.google/technologies/gemini/flash/)|
|
|gemini-2.0-flash|Google DeepMind|3+ Providers|[deepmind.google](https://deepmind.google/technologies/gemini/flash/)|
|
||||||
|gemini-2.0-flash-thinking|Google DeepMind|1+ Providers|[ai.google.dev](https://ai.google.dev/gemini-api/docs/thinking-mode)|
|
|gemini-2.0-flash-thinking|Google DeepMind|1+ Providers|[ai.google.dev](https://ai.google.dev/gemini-api/docs/thinking-mode)|
|
||||||
|
|gemini-2.0-pro|Google DeepMind|1+ Providers|[deepmind.google](https://deepmind.google/technologies/gemini/flash-thinking/)|
|
||||||
|claude-3-haiku|Anthropic|2+ Providers|[anthropic.com](https://www.anthropic.com/news/claude-3-haiku)|
|
|claude-3-haiku|Anthropic|2+ Providers|[anthropic.com](https://www.anthropic.com/news/claude-3-haiku)|
|
||||||
|claude-3-sonnet|Anthropic|1+ Providers|[anthropic.com](https://www.anthropic.com/news/claude-3-family)|
|
|claude-3-sonnet|Anthropic|1+ Providers|[anthropic.com](https://www.anthropic.com/news/claude-3-family)|
|
||||||
|claude-3-opus|Anthropic|2+ Providers|[anthropic.com](https://www.anthropic.com/news/claude-3-family)|
|
|claude-3-opus|Anthropic|2+ Providers|[anthropic.com](https://www.anthropic.com/news/claude-3-family)|
|
||||||
|claude-3.5-sonnet|Anthropic|2+ Providers|[anthropic.com](https://www.anthropic.com/news/claude-3-5-sonnet)|
|
|claude-3.5-sonnet|Anthropic|2+ Providers|[anthropic.com](https://www.anthropic.com/news/claude-3-5-sonnet)|
|
||||||
|
|claude-3.7-sonnet|Anthropic|2+ Providers|[anthropic.com](https://www.anthropic.com/claude/sonnet)|
|
||||||
|
|claude-3.7-sonnet-thinking|Anthropic|1+ Providers|[anthropic.com](https://www.anthropic.com/claude/sonnet)|
|
||||||
|reka-core|Reka AI|1+ Providers|[reka.ai](https://www.reka.ai/ourmodels)|
|
|reka-core|Reka AI|1+ Providers|[reka.ai](https://www.reka.ai/ourmodels)|
|
||||||
|blackboxai|Blackbox AI|1+ Providers|[docs.blackbox.chat](https://docs.blackbox.chat/blackbox-ai-1)|
|
|blackboxai|Blackbox AI|1+ Providers|[docs.blackbox.chat](https://docs.blackbox.chat/blackbox-ai-1)|
|
||||||
|blackboxai-pro|Blackbox AI|1+ Providers|[docs.blackbox.chat](https://docs.blackbox.chat/blackbox-ai-1)|
|
|blackboxai-pro|Blackbox AI|1+ Providers|[docs.blackbox.chat](https://docs.blackbox.chat/blackbox-ai-1)|
|
||||||
|
|
@ -168,17 +191,18 @@ This document provides an overview of various AI providers and models, including
|
||||||
|qwen-1.5-7b|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen1.5-7B)|
|
|qwen-1.5-7b|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen1.5-7B)|
|
||||||
|qwen-2-72b|Qwen|2+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2-72B)|
|
|qwen-2-72b|Qwen|2+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2-72B)|
|
||||||
|qwen-2-vl-7b|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2-VL-7B)|
|
|qwen-2-vl-7b|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2-VL-7B)|
|
||||||
|qwen-2.5-72b|Qwen|2+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2.5-72B-Instruct)|
|
|qwen-2.5-72b|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2.5-72B-Instruct)|
|
||||||
|qwen-2.5-coder-32b|Qwen|3+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2.5-Coder-32B)|
|
|qwen-2.5-coder-32b|Qwen|3+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2.5-Coder-32B)|
|
||||||
|qwen-2.5-1m-demo|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2.5-1M-Demo)|
|
|qwen-2.5-1m-demo|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2.5-1M-Demo)|
|
||||||
|qwq-32b|Qwen|3+ Providers|[huggingface.co](https://huggingface.co/Qwen/QwQ-32B-Preview)|
|
|qwq-32b|Qwen|3+ Providers|[huggingface.co](https://huggingface.co/Qwen/QwQ-32B-Preview)|
|
||||||
|qvq-72b|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/QVQ-72B-Preview)|
|
|qvq-72b|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/QVQ-72B-Preview)|
|
||||||
|pi|Inflection|1+ Providers|[inflection.ai](https://inflection.ai/blog/inflection-2-5)|
|
|pi|Inflection|1+ Providers|[inflection.ai](https://inflection.ai/blog/inflection-2-5)|
|
||||||
|deepseek-chat|DeepSeek|3+ Providers|[huggingface.co](https://huggingface.co/deepseek-ai/deepseek-llm-67b-chat)|
|
|deepseek-chat|DeepSeek|2+ Providers|[huggingface.co](https://huggingface.co/deepseek-ai/deepseek-llm-67b-chat)|
|
||||||
|deepseek-v3|DeepSeek|4+ Providers|[api-docs.deepseek.com](https://api-docs.deepseek.com/news/news250120)|
|
|deepseek-v3|DeepSeek|4+ Providers|[api-docs.deepseek.com](https://api-docs.deepseek.com/news/news250120)|
|
||||||
|deepseek-r1|DeepSeek|8+ Providers|[api-docs.deepseek.com](https://api-docs.deepseek.com/news/news250120)|
|
|deepseek-r1|DeepSeek|8+ Providers|[api-docs.deepseek.com](https://api-docs.deepseek.com/news/news250120)|
|
||||||
|grok-3|x.ai|1+|[x.ai](https://x.ai/blog/grok-3)|
|
|janus-pro-7b|DeepSeek|2+ Providers|[api-docs.deepseek.com](https://api-docs.deepseek.com/docs/janus-pro-7b)|
|
||||||
|grok-3-r1|x.ai|1+|[x.ai](https://x.ai/blog/grok-3)|
|
|grok-3|x.ai|1+ Providers|[x.ai](https://x.ai/blog/grok-3)|
|
||||||
|
|grok-3-r1|x.ai|1+ Providers|[x.ai](https://x.ai/blog/grok-3)|
|
||||||
|sonar|Perplexity AI|1+ Providers|[sonar.perplexity.ai](https://sonar.perplexity.ai/)|
|
|sonar|Perplexity AI|1+ Providers|[sonar.perplexity.ai](https://sonar.perplexity.ai/)|
|
||||||
|sonar-pro|Perplexity AI|1+ Providers|[sonar.perplexity.ai](https://sonar.perplexity.ai/)|
|
|sonar-pro|Perplexity AI|1+ Providers|[sonar.perplexity.ai](https://sonar.perplexity.ai/)|
|
||||||
|sonar-reasoning|Perplexity AI|1+ Providers|[sonar.perplexity.ai](https://sonar.perplexity.ai/)|
|
|sonar-reasoning|Perplexity AI|1+ Providers|[sonar.perplexity.ai](https://sonar.perplexity.ai/)|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import re
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
import base64
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
@ -35,32 +36,28 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
supports_system_message = True
|
supports_system_message = True
|
||||||
supports_message_history = True
|
supports_message_history = True
|
||||||
|
|
||||||
default_model = "BLACKBOXAI"
|
default_model = "blackboxai"
|
||||||
default_vision_model = default_model
|
default_vision_model = default_model
|
||||||
default_image_model = 'ImageGeneration'
|
default_image_model = 'ImageGeneration'
|
||||||
|
|
||||||
image_models = [default_image_model]
|
image_models = [default_image_model]
|
||||||
vision_models = [default_vision_model, 'GPT-4o', 'o3-mini', 'Gemini-PRO', 'gemini-1.5-flash', 'llama-3.1-8b', 'llama-3.1-70b', 'llama-3.1-405b', 'Gemini-Flash-2.0']
|
vision_models = [default_vision_model, 'gpt-4o', 'o1', 'o3-mini', 'gemini-pro', 'gemini-1.5-flash', 'llama-3.1-8b', 'llama-3.1-70b', 'llama-3.1-405b', 'gemini-2.0-flash', 'deepseek-v3']
|
||||||
|
|
||||||
premium_models = ['GPT-4o', 'o1', 'o3-mini', 'Gemini-PRO', 'Claude-Sonnet-3.5']
|
|
||||||
|
|
||||||
userSelectedModel = ['DeepSeek-V3', 'DeepSeek-R1', 'BLACKBOXAI-PRO', 'Meta-Llama-3.3-70B-Instruct-Turbo', 'Mistral-Small-24B-Instruct-2501', 'DeepSeek-LLM-Chat-(67B)', 'DBRX-Instruct', 'Qwen-QwQ-32B-Preview', 'Nous-Hermes-2-Mixtral-8x7B-DPO', 'Gemini-Flash-2.0'] + premium_models
|
userSelectedModel = ['gpt-4o', 'o1', 'o3-mini', 'gemini-pro', 'claude-sonnet-3.7', 'deepseek-v3', 'deepseek-r1', 'blackboxai-pro', 'Meta-Llama-3.3-70B-Instruct-Turbo', 'Mistral-Small-24B-Instruct-2501', 'DeepSeek-LLM-Chat-(67B)', 'dbrx-instruct', 'Qwen-QwQ-32B-Preview', 'Nous-Hermes-2-Mixtral-8x7B-DPO', 'gemini-2.0-flash']
|
||||||
|
|
||||||
agentMode = {
|
agentMode = {
|
||||||
'DeepSeek-V3': {'mode': True, 'id': "deepseek-chat", 'name': "DeepSeek-V3"},
|
'deepseek-v3': {'mode': True, 'id': "deepseek-chat", 'name': "DeepSeek-V3"},
|
||||||
'DeepSeek-R1': {'mode': True, 'id': "deepseek-reasoner", 'name': "DeepSeek-R1"},
|
'deepseek-r1': {'mode': True, 'id': "deepseek-reasoner", 'name': "DeepSeek-R1"},
|
||||||
'Meta-Llama-3.3-70B-Instruct-Turbo': {'mode': True, 'id': "meta-llama/Llama-3.3-70B-Instruct-Turbo", 'name': "Meta-Llama-3.3-70B-Instruct-Turbo"},
|
'Meta-Llama-3.3-70B-Instruct-Turbo': {'mode': True, 'id': "meta-llama/Llama-3.3-70B-Instruct-Turbo", 'name': "Meta-Llama-3.3-70B-Instruct-Turbo"},
|
||||||
'Mistral-Small-24B-Instruct-2501': {'mode': True, 'id': "mistralai/Mistral-Small-24B-Instruct-2501", 'name': "Mistral-Small-24B-Instruct-2501"},
|
'Mistral-Small-24B-Instruct-2501': {'mode': True, 'id': "mistralai/Mistral-Small-24B-Instruct-2501", 'name': "Mistral-Small-24B-Instruct-2501"},
|
||||||
'DeepSeek-LLM-Chat-(67B)': {'mode': True, 'id': "deepseek-ai/deepseek-llm-67b-chat", 'name': "DeepSeek-LLM-Chat-(67B)"},
|
'DeepSeek-LLM-Chat-(67B)': {'mode': True, 'id': "deepseek-ai/deepseek-llm-67b-chat", 'name': "DeepSeek-LLM-Chat-(67B)"},
|
||||||
'DBRX-Instruct': {'mode': True, 'id': "databricks/dbrx-instruct", 'name': "DBRX-Instruct"},
|
'dbrx-instruct': {'mode': True, 'id': "databricks/dbrx-instruct", 'name': "DBRX-Instruct"},
|
||||||
'Qwen-QwQ-32B-Preview': {'mode': True, 'id': "Qwen/QwQ-32B-Preview", 'name': "Qwen-QwQ-32B-Preview"},
|
'Qwen-QwQ-32B-Preview': {'mode': True, 'id': "Qwen/QwQ-32B-Preview", 'name': "Qwen-QwQ-32B-Preview"},
|
||||||
'Nous-Hermes-2-Mixtral-8x7B-DPO': {'mode': True, 'id': "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO", 'name': "Nous-Hermes-2-Mixtral-8x7B-DPO"},
|
'Nous-Hermes-2-Mixtral-8x7B-DPO': {'mode': True, 'id': "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO", 'name': "Nous-Hermes-2-Mixtral-8x7B-DPO"},
|
||||||
'Gemini-Flash-2.0': {'mode': True, 'id': "Gemini/Gemini-Flash-2.0", 'name': "Gemini-Flash-2.0"},
|
'gemini-2.0-flash': {'mode': True, 'id': "Gemini/Gemini-Flash-2.0", 'name': "Gemini-Flash-2.0"},
|
||||||
}
|
}
|
||||||
|
|
||||||
trendingAgentMode = {
|
trendingAgentMode = {
|
||||||
"o1": {'mode': True, 'id': 'o1'},
|
|
||||||
"o3-mini": {'mode': True, 'id': 'o3-mini'},
|
|
||||||
"gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
|
"gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
|
||||||
"llama-3.1-8b": {'mode': True, 'id': "llama-3.1-8b"},
|
"llama-3.1-8b": {'mode': True, 'id': "llama-3.1-8b"},
|
||||||
'llama-3.1-70b': {'mode': True, 'id': "llama-3.1-70b"},
|
'llama-3.1-70b': {'mode': True, 'id': "llama-3.1-70b"},
|
||||||
|
|
@ -77,7 +74,7 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
'PyTorch Agent': {'mode': True, 'id': "PyTorch Agent"},
|
'PyTorch Agent': {'mode': True, 'id': "PyTorch Agent"},
|
||||||
'React Agent': {'mode': True, 'id': "React Agent"},
|
'React Agent': {'mode': True, 'id': "React Agent"},
|
||||||
'Xcode Agent': {'mode': True, 'id': "Xcode Agent"},
|
'Xcode Agent': {'mode': True, 'id': "Xcode Agent"},
|
||||||
'BLACKBOXAI-PRO': {'mode': True, 'id': "BLACKBOXAI-PRO"},
|
'blackboxai-pro': {'mode': True, 'id': "BLACKBOXAI-PRO"},
|
||||||
'Heroku Agent': {'mode': True, 'id': "Heroku Agent"},
|
'Heroku Agent': {'mode': True, 'id': "Heroku Agent"},
|
||||||
'Godot Agent': {'mode': True, 'id': "Godot Agent"},
|
'Godot Agent': {'mode': True, 'id': "Godot Agent"},
|
||||||
'Go Agent': {'mode': True, 'id': "Go Agent"},
|
'Go Agent': {'mode': True, 'id': "Go Agent"},
|
||||||
|
|
@ -100,38 +97,20 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
models = list(dict.fromkeys([default_model, *userSelectedModel, *image_models, *list(agentMode.keys()), *list(trendingAgentMode.keys())]))
|
models = list(dict.fromkeys([default_model, *userSelectedModel, *image_models, *list(agentMode.keys()), *list(trendingAgentMode.keys())]))
|
||||||
|
|
||||||
model_aliases = {
|
model_aliases = {
|
||||||
"blackboxai": "BLACKBOXAI",
|
|
||||||
"gemini-1.5-flash": "gemini-1.5-flash",
|
"gemini-1.5-flash": "gemini-1.5-flash",
|
||||||
"deepseek-v3": "DeepSeek-V3",
|
"gemini-1.5-pro": "gemini-pro",
|
||||||
"deepseek-r1": "DeepSeek-R1",
|
|
||||||
"llama-3.3-70b": "Meta-Llama-3.3-70B-Instruct-Turbo",
|
"llama-3.3-70b": "Meta-Llama-3.3-70B-Instruct-Turbo",
|
||||||
"mixtral-small-28b": "Mistral-Small-24B-Instruct-2501",
|
"mixtral-small-28b": "Mistral-Small-24B-Instruct-2501",
|
||||||
"deepseek-chat": "DeepSeek-LLM-Chat-(67B)",
|
"deepseek-chat": "DeepSeek-LLM-Chat-(67B)",
|
||||||
"dbrx-instruct": "DBRX-Instruct",
|
|
||||||
"qwq-32b": "Qwen-QwQ-32B-Preview",
|
"qwq-32b": "Qwen-QwQ-32B-Preview",
|
||||||
"hermes-2-dpo": "Nous-Hermes-2-Mixtral-8x7B-DPO",
|
"hermes-2-dpo": "Nous-Hermes-2-Mixtral-8x7B-DPO",
|
||||||
"gemini-2.0-flash": "Gemini-Flash-2.0",
|
"claude-3.7-sonnet": "claude-sonnet-3.7",
|
||||||
"blackboxai-pro": "BLACKBOXAI-PRO",
|
|
||||||
"flux": "ImageGeneration",
|
"flux": "ImageGeneration",
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
ENCRYPTED_SESSION = "eyJ1c2VyIjogeyJuYW1lIjogIkJMQUNLQk9YIEFJIiwgImVtYWlsIjogImdpc2VsZUBibGFja2JveC5haSIsICJpbWFnZSI6ICJodHRwczovL3l0My5nb29nbGV1c2VyY29udGVudC5jb20vQjd6RVlVSzUxWnNQYmFSUFVhMF9ZbnQ1WV9URFZoTE4tVjAzdndRSHM0eF96a2g4a1psLXkxcXFxb3hoeFFzcS1wUVBHS0R0WFE9czE2MC1jLWstYzB4MDBmZmZmZmYtbm8tcmoifSwgImV4cGlyZXMiOiBudWxsfQ=="
|
||||||
def get_models(cls) -> list[str]:
|
ENCRYPTED_SUBSCRIPTION_CACHE = "eyJzdGF0dXMiOiAiUFJFTUlVTSIsICJleHBpcnlUaW1lc3RhbXAiOiBudWxsLCAibGFzdENoZWNrZWQiOiBudWxsLCAiaXNUcmlhbFN1YnNjcmlwdGlvbiI6IHRydWV9"
|
||||||
models = super().get_models()
|
ENCRYPTED_IS_PREMIUM = "dHJ1ZQ=="
|
||||||
filtered = [m for m in models if m not in cls.premium_models]
|
|
||||||
filtered += [f"{m} (Premium)" for m in cls.premium_models]
|
|
||||||
return filtered
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_model(cls, model: str, **kwargs) -> str:
|
|
||||||
try:
|
|
||||||
model = super().get_model(model, **kwargs)
|
|
||||||
return model.split(" (Premium)")[0]
|
|
||||||
except ModelNotSupportedError:
|
|
||||||
base_model = model.split(" (Premium)")[0]
|
|
||||||
if base_model in cls.premium_models:
|
|
||||||
return base_model
|
|
||||||
raise
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def fetch_validated(cls, url: str = "https://www.blackbox.ai", force_refresh: bool = False) -> Optional[str]:
|
async def fetch_validated(cls, url: str = "https://www.blackbox.ai", force_refresh: bool = False) -> Optional[str]:
|
||||||
|
|
@ -192,7 +171,21 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
def generate_id(cls, length: int = 7) -> str:
|
def generate_id(cls, length: int = 7) -> str:
|
||||||
chars = string.ascii_letters + string.digits
|
chars = string.ascii_letters + string.digits
|
||||||
return ''.join(random.choice(chars) for _ in range(length))
|
return ''.join(random.choice(chars) for _ in range(length))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def decrypt_data(encrypted_data):
|
||||||
|
try:
|
||||||
|
return json.loads(base64.b64decode(encrypted_data).decode('utf-8'))
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def decrypt_bool(encrypted_data):
|
||||||
|
try:
|
||||||
|
return base64.b64decode(encrypted_data).decode('utf-8').lower() == 'true'
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_async_generator(
|
async def create_async_generator(
|
||||||
cls,
|
cls,
|
||||||
|
|
@ -308,9 +301,9 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
"additionalInfo": "",
|
"additionalInfo": "",
|
||||||
"enableNewChats": False
|
"enableNewChats": False
|
||||||
},
|
},
|
||||||
"session": None,
|
"session": cls.decrypt_data(cls.ENCRYPTED_SESSION),
|
||||||
"isPremium": False,
|
"isPremium": cls.decrypt_bool(cls.ENCRYPTED_IS_PREMIUM),
|
||||||
"subscriptionCache": None,
|
"subscriptionCache": cls.decrypt_data(cls.ENCRYPTED_SUBSCRIPTION_CACHE),
|
||||||
"beastMode": False,
|
"beastMode": False,
|
||||||
"webSearchMode": False
|
"webSearchMode": False
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,18 @@ from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
from aiohttp import ClientSession
|
try:
|
||||||
|
from curl_cffi.requests import Session
|
||||||
|
has_curl_cffi = True
|
||||||
|
except ImportError:
|
||||||
|
has_curl_cffi = False
|
||||||
|
|
||||||
from ..typing import AsyncResult, Messages
|
from ..typing import AsyncResult, Messages
|
||||||
from ..requests.raise_for_status import raise_for_status
|
|
||||||
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
||||||
from .helper import format_prompt
|
from .helper import format_prompt
|
||||||
|
from ..errors import MissingRequirementsError
|
||||||
|
|
||||||
class ChatGptEs(AsyncGeneratorProvider, ProviderModelMixin):
|
class ChatGptEs(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
url = "https://chatgpt.es"
|
url = "https://chatgpt.es"
|
||||||
|
|
@ -23,7 +28,7 @@ class ChatGptEs(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
models = ['gpt-4', default_model, 'gpt-4o-mini']
|
models = ['gpt-4', default_model, 'gpt-4o-mini']
|
||||||
|
|
||||||
SYSTEM_PROMPT = "Your default language is English. Always respond in English unless the user's message is in a different language. If the user's message is not in English, respond in the language of the user's message. Maintain this language behavior throughout the conversation unless explicitly instructed otherwise. User input:"
|
SYSTEM_PROMPT = "Your default language is English. Always respond in English unless the user's message is in a different language. If the user's message is not in English, respond in the language of the user's message. Maintain this language behavior throughout the conversation unless explicitly instructed otherwise. User input:"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_async_generator(
|
async def create_async_generator(
|
||||||
cls,
|
cls,
|
||||||
|
|
@ -32,39 +37,101 @@ class ChatGptEs(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
proxy: str = None,
|
proxy: str = None,
|
||||||
**kwargs
|
**kwargs
|
||||||
) -> AsyncResult:
|
) -> AsyncResult:
|
||||||
|
if not has_curl_cffi:
|
||||||
|
raise MissingRequirementsError('Install or update "curl_cffi" package | pip install -U curl_cffi')
|
||||||
|
|
||||||
model = cls.get_model(model)
|
model = cls.get_model(model)
|
||||||
|
prompt = f"{cls.SYSTEM_PROMPT} {format_prompt(messages)}"
|
||||||
|
|
||||||
headers = {
|
# Use curl_cffi with automatic Cloudflare bypass
|
||||||
"authority": "chatgpt.es",
|
session = Session()
|
||||||
"accept": "application/json",
|
session.headers.update({
|
||||||
|
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
||||||
|
"referer": cls.url,
|
||||||
"origin": cls.url,
|
"origin": cls.url,
|
||||||
"referer": f"{cls.url}/chat",
|
"accept": "*/*",
|
||||||
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
|
"accept-language": "en-US,en;q=0.9",
|
||||||
|
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
|
"x-requested-with": "XMLHttpRequest",
|
||||||
|
})
|
||||||
|
|
||||||
|
if proxy:
|
||||||
|
session.proxies = {"https": proxy, "http": proxy}
|
||||||
|
|
||||||
|
# First request to get nonce and post_id
|
||||||
|
initial_response = session.get(cls.url, impersonate="chrome110")
|
||||||
|
initial_text = initial_response.text
|
||||||
|
|
||||||
|
# More comprehensive nonce extraction
|
||||||
|
nonce_patterns = [
|
||||||
|
r'<input\s+type=[\'"]hidden[\'"]\s+name=[\'"]_wpnonce[\'"]\s+value=[\'"]([^\'"]+)[\'"]',
|
||||||
|
r'"_wpnonce":"([^"]+)"',
|
||||||
|
r'var\s+wpaicg_nonce\s*=\s*[\'"]([^\'"]+)[\'"]',
|
||||||
|
r'wpaicg_nonce\s*:\s*[\'"]([^\'"]+)[\'"]'
|
||||||
|
]
|
||||||
|
|
||||||
|
nonce_ = None
|
||||||
|
for pattern in nonce_patterns:
|
||||||
|
match = re.search(pattern, initial_text)
|
||||||
|
if match:
|
||||||
|
nonce_ = match.group(1)
|
||||||
|
break
|
||||||
|
|
||||||
|
if not nonce_:
|
||||||
|
# Try to find any nonce-like pattern as a last resort
|
||||||
|
general_nonce = re.search(r'nonce[\'"]?\s*[=:]\s*[\'"]([a-zA-Z0-9]+)[\'"]', initial_text)
|
||||||
|
if general_nonce:
|
||||||
|
nonce_ = general_nonce.group(1)
|
||||||
|
else:
|
||||||
|
# Fallback, but this likely won't work
|
||||||
|
nonce_ = "8cf9917be2"
|
||||||
|
|
||||||
|
# Look for post_id in HTML
|
||||||
|
post_id_patterns = [
|
||||||
|
r'<input\s+type=[\'"]hidden[\'"]\s+name=[\'"]post_id[\'"]\s+value=[\'"]([^\'"]+)[\'"]',
|
||||||
|
r'"post_id":"([^"]+)"',
|
||||||
|
r'var\s+post_id\s*=\s*[\'"]?(\d+)[\'"]?'
|
||||||
|
]
|
||||||
|
|
||||||
|
post_id = None
|
||||||
|
for pattern in post_id_patterns:
|
||||||
|
match = re.search(pattern, initial_text)
|
||||||
|
if match:
|
||||||
|
post_id = match.group(1)
|
||||||
|
break
|
||||||
|
|
||||||
|
if not post_id:
|
||||||
|
post_id = "106" # Default from curl example
|
||||||
|
|
||||||
|
client_id = os.urandom(5).hex()
|
||||||
|
|
||||||
|
# Prepare data
|
||||||
|
data = {
|
||||||
|
'_wpnonce': nonce_,
|
||||||
|
'post_id': post_id,
|
||||||
|
'url': cls.url,
|
||||||
|
'action': 'wpaicg_chat_shortcode_message',
|
||||||
|
'message': prompt,
|
||||||
|
'bot_id': '0',
|
||||||
|
'chatbot_identity': 'shortcode',
|
||||||
|
'wpaicg_chat_client_id': client_id,
|
||||||
|
'wpaicg_chat_history': json.dumps([f"Human: {prompt}"])
|
||||||
}
|
}
|
||||||
|
|
||||||
async with ClientSession(headers=headers) as session:
|
# Execute POST request
|
||||||
initial_response = await session.get(cls.url)
|
response = session.post(
|
||||||
nonce_ = re.findall(r'data-nonce="(.+?)"', await initial_response.text())[0]
|
cls.api_endpoint,
|
||||||
post_id = re.findall(r'data-post-id="(.+?)"', await initial_response.text())[0]
|
data=data,
|
||||||
|
impersonate="chrome110"
|
||||||
prompt = f"{cls.SYSTEM_PROMPT} {format_prompt(messages)}"
|
)
|
||||||
|
|
||||||
payload = {
|
if response.status_code != 200:
|
||||||
'check_51710191': '1',
|
raise ValueError(f"Error: {response.status_code} - {response.text}")
|
||||||
'_wpnonce': nonce_,
|
|
||||||
'post_id': post_id,
|
result = response.json()
|
||||||
'url': cls.url,
|
if "data" in result:
|
||||||
'action': 'wpaicg_chat_shortcode_message',
|
if isinstance(result['data'], str) and "Du musst das Kästchen anklicken!" in result['data']:
|
||||||
'message': prompt,
|
raise ValueError(result['data'])
|
||||||
'bot_id': '0',
|
yield result['data']
|
||||||
'chatbot_identity': 'shortcode',
|
else:
|
||||||
'wpaicg_chat_client_id': os.urandom(5).hex(),
|
raise ValueError(f"Unexpected response format: {result}")
|
||||||
'wpaicg_chat_history': None
|
|
||||||
}
|
|
||||||
|
|
||||||
async with session.post(cls.api_endpoint, headers=headers, data=payload) as response:
|
|
||||||
await raise_for_status(response)
|
|
||||||
result = await response.json()
|
|
||||||
if "Du musst das Kästchen anklicken!" in result['data']:
|
|
||||||
raise ValueError(result['data'])
|
|
||||||
yield result['data']
|
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,18 @@ class DeepInfraChat(OpenaiTemplate):
|
||||||
api_base = "https://api.deepinfra.com/v1/openai"
|
api_base = "https://api.deepinfra.com/v1/openai"
|
||||||
working = True
|
working = True
|
||||||
|
|
||||||
default_model = 'meta-llama/Llama-3.3-70B-Instruct-Turbo'
|
default_model = 'deepseek-ai/DeepSeek-V3-Turbo'
|
||||||
default_vision_model = 'meta-llama/Llama-3.2-90B-Vision-Instruct'
|
default_vision_model = 'meta-llama/Llama-3.2-90B-Vision-Instruct'
|
||||||
vision_models = [default_vision_model, 'openbmb/MiniCPM-Llama3-V-2_5']
|
vision_models = [default_vision_model, 'openbmb/MiniCPM-Llama3-V-2_5']
|
||||||
models = [
|
models = [
|
||||||
'meta-llama/Meta-Llama-3.1-8B-Instruct',
|
'meta-llama/Meta-Llama-3.1-8B-Instruct',
|
||||||
default_model,
|
'meta-llama/Llama-3.3-70B-Instruct-Turbo',
|
||||||
'meta-llama/Llama-3.3-70B-Instruct',
|
'meta-llama/Llama-3.3-70B-Instruct',
|
||||||
'deepseek-ai/DeepSeek-V3',
|
'deepseek-ai/DeepSeek-V3',
|
||||||
|
default_model,
|
||||||
'mistralai/Mistral-Small-24B-Instruct-2501',
|
'mistralai/Mistral-Small-24B-Instruct-2501',
|
||||||
'deepseek-ai/DeepSeek-R1',
|
'deepseek-ai/DeepSeek-R1',
|
||||||
|
'deepseek-ai/DeepSeek-R1-Turbo',
|
||||||
'deepseek-ai/DeepSeek-R1-Distill-Llama-70B',
|
'deepseek-ai/DeepSeek-R1-Distill-Llama-70B',
|
||||||
'deepseek-ai/DeepSeek-R1-Distill-Qwen-32B',
|
'deepseek-ai/DeepSeek-R1-Distill-Qwen-32B',
|
||||||
'microsoft/phi-4',
|
'microsoft/phi-4',
|
||||||
|
|
@ -40,7 +42,9 @@ class DeepInfraChat(OpenaiTemplate):
|
||||||
"llama-3.3-70b": "meta-llama/Llama-3.3-70B-Instruct-Turbo",
|
"llama-3.3-70b": "meta-llama/Llama-3.3-70B-Instruct-Turbo",
|
||||||
"llama-3.3-70b": "meta-llama/Llama-3.3-70B-Instruct",
|
"llama-3.3-70b": "meta-llama/Llama-3.3-70B-Instruct",
|
||||||
"deepseek-v3": "deepseek-ai/DeepSeek-V3",
|
"deepseek-v3": "deepseek-ai/DeepSeek-V3",
|
||||||
|
"deepseek-v3": default_model,
|
||||||
"mixtral-small-28b": "mistralai/Mistral-Small-24B-Instruct-2501",
|
"mixtral-small-28b": "mistralai/Mistral-Small-24B-Instruct-2501",
|
||||||
|
"deepseek-r1": "deepseek-ai/DeepSeek-R1-Turbo",
|
||||||
"deepseek-r1": "deepseek-ai/DeepSeek-R1",
|
"deepseek-r1": "deepseek-ai/DeepSeek-R1",
|
||||||
"deepseek-r1-distill-llama": "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
|
"deepseek-r1-distill-llama": "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
|
||||||
"deepseek-r1-distill-qwen": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
|
"deepseek-r1-distill-qwen": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,12 @@ from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
||||||
|
|
||||||
class Free2GPT(AsyncGeneratorProvider, ProviderModelMixin):
|
class Free2GPT(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
url = "https://chat10.free2gpt.xyz"
|
url = "https://chat10.free2gpt.xyz"
|
||||||
|
|
||||||
working = True
|
working = True
|
||||||
supports_message_history = True
|
supports_message_history = True
|
||||||
default_model = 'mistral-7b'
|
|
||||||
models = [default_model]
|
default_model = 'gemini-1.5-pro'
|
||||||
|
models = [default_model, 'gemini-1.5-flash']
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_async_generator(
|
async def create_async_generator(
|
||||||
|
|
@ -36,15 +38,6 @@ class Free2GPT(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
"Content-Type": "text/plain;charset=UTF-8",
|
"Content-Type": "text/plain;charset=UTF-8",
|
||||||
"Referer": f"{cls.url}/",
|
"Referer": f"{cls.url}/",
|
||||||
"Origin": cls.url,
|
"Origin": cls.url,
|
||||||
"Sec-Fetch-Dest": "empty",
|
|
||||||
"Sec-Fetch-Mode": "cors",
|
|
||||||
"Sec-Fetch-Site": "same-origin",
|
|
||||||
"Sec-Ch-Ua": '"Chromium";v="127", "Not)A;Brand";v="99"',
|
|
||||||
"Sec-Ch-Ua-Mobile": "?0",
|
|
||||||
"Sec-Ch-Ua-Platform": '"Linux"',
|
|
||||||
"Cache-Control": "no-cache",
|
|
||||||
"Pragma": "no-cache",
|
|
||||||
"Priority": "u=1, i",
|
|
||||||
}
|
}
|
||||||
async with ClientSession(
|
async with ClientSession(
|
||||||
connector=get_connector(connector, proxy), headers=headers
|
connector=get_connector(connector, proxy), headers=headers
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ class FreeGpt(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
supports_system_message = True
|
supports_system_message = True
|
||||||
|
|
||||||
default_model = 'gemini-1.5-pro'
|
default_model = 'gemini-1.5-pro'
|
||||||
|
models = [default_model, 'gemini-1.5-flash']
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_async_generator(
|
async def create_async_generator(
|
||||||
|
|
|
||||||
|
|
@ -10,29 +10,65 @@ from .helper import get_connector
|
||||||
from ..requests import raise_for_status
|
from ..requests import raise_for_status
|
||||||
|
|
||||||
models = {
|
models = {
|
||||||
"gpt-4o-mini-free": {
|
"claude-3-5-sonnet-20241022": {
|
||||||
"id": "gpt-4o-mini-free",
|
"id": "claude-3-5-sonnet-20241022",
|
||||||
"name": "GPT-4o-Mini-Free",
|
"name": "Claude-3.5-Sonnet-V2",
|
||||||
"model": "ChatGPT",
|
"model": "Claude",
|
||||||
"provider": "OpenAI",
|
"provider": "Anthropic",
|
||||||
"maxLength": 31200,
|
|
||||||
"tokenLimit": 7800,
|
|
||||||
"context": "8K",
|
|
||||||
},
|
|
||||||
"grok-3": {
|
|
||||||
"id": "grok-3",
|
|
||||||
"name": "Grok-3",
|
|
||||||
"model": "Grok",
|
|
||||||
"provider": "x.ai",
|
|
||||||
"maxLength": 800000,
|
"maxLength": 800000,
|
||||||
"tokenLimit": 200000,
|
"tokenLimit": 200000,
|
||||||
"context": "200K",
|
"context": "200K",
|
||||||
},
|
},
|
||||||
"grok-3-r1": {
|
"claude-3-5-sonnet-20241022-t": {
|
||||||
"id": "grok-3-r1",
|
"id": "claude-3-5-sonnet-20241022-t",
|
||||||
"name": "Grok-3-Thinking",
|
"name": "Claude-3.5-Sonnet-V2-T",
|
||||||
"model": "Grok",
|
"model": "Claude",
|
||||||
"provider": "x.ai",
|
"provider": "Anthropic",
|
||||||
|
"maxLength": 800000,
|
||||||
|
"tokenLimit": 200000,
|
||||||
|
"context": "200K",
|
||||||
|
},
|
||||||
|
"claude-3-7-sonnet-20250219": {
|
||||||
|
"id": "claude-3-7-sonnet-20250219",
|
||||||
|
"name": "Claude-3.7-Sonnet",
|
||||||
|
"model": "Claude",
|
||||||
|
"provider": "Anthropic",
|
||||||
|
"maxLength": 800000,
|
||||||
|
"tokenLimit": 200000,
|
||||||
|
"context": "200K",
|
||||||
|
},
|
||||||
|
"claude-3-7-sonnet-20250219-t": {
|
||||||
|
"id": "claude-3-7-sonnet-20250219-t",
|
||||||
|
"name": "Claude-3.7-Sonnet-T",
|
||||||
|
"model": "Claude",
|
||||||
|
"provider": "Anthropic",
|
||||||
|
"maxLength": 800000,
|
||||||
|
"tokenLimit": 200000,
|
||||||
|
"context": "200K",
|
||||||
|
},
|
||||||
|
"claude-3-7-sonnet-20250219-thinking": {
|
||||||
|
"id": "claude-3-7-sonnet-20250219-thinking",
|
||||||
|
"name": "Claude-3.7-Sonnet-Thinking",
|
||||||
|
"model": "Claude",
|
||||||
|
"provider": "Anthropic",
|
||||||
|
"maxLength": 800000,
|
||||||
|
"tokenLimit": 200000,
|
||||||
|
"context": "200K",
|
||||||
|
},
|
||||||
|
"claude-3-opus-20240229": {
|
||||||
|
"id": "claude-3-opus-20240229",
|
||||||
|
"name": "Claude-3-Opus",
|
||||||
|
"model": "Claude",
|
||||||
|
"provider": "Anthropic",
|
||||||
|
"maxLength": 800000,
|
||||||
|
"tokenLimit": 200000,
|
||||||
|
"context": "200K",
|
||||||
|
},
|
||||||
|
"claude-3-sonnet-20240229": {
|
||||||
|
"id": "claude-3-sonnet-20240229",
|
||||||
|
"name": "Claude-3-Sonnet",
|
||||||
|
"model": "Claude",
|
||||||
|
"provider": "Anthropic",
|
||||||
"maxLength": 800000,
|
"maxLength": 800000,
|
||||||
"tokenLimit": 200000,
|
"tokenLimit": 200000,
|
||||||
"context": "200K",
|
"context": "200K",
|
||||||
|
|
@ -64,96 +100,6 @@ models = {
|
||||||
"tokenLimit": 100000,
|
"tokenLimit": 100000,
|
||||||
"context": "128K",
|
"context": "128K",
|
||||||
},
|
},
|
||||||
"gpt-4o-2024-11-20": {
|
|
||||||
"id": "gpt-4o-2024-11-20",
|
|
||||||
"name": "GPT-4o",
|
|
||||||
"model": "ChatGPT",
|
|
||||||
"provider": "OpenAI",
|
|
||||||
"maxLength": 260000,
|
|
||||||
"tokenLimit": 126000,
|
|
||||||
"context": "128K",
|
|
||||||
},
|
|
||||||
"gpt-4o-mini-2024-07-18": {
|
|
||||||
"id": "gpt-4o-mini-2024-07-18",
|
|
||||||
"name": "GPT-4o-Mini",
|
|
||||||
"model": "ChatGPT",
|
|
||||||
"provider": "OpenAI",
|
|
||||||
"maxLength": 260000,
|
|
||||||
"tokenLimit": 126000,
|
|
||||||
"context": "128K",
|
|
||||||
},
|
|
||||||
"o3-mini": {
|
|
||||||
"id": "o3-mini",
|
|
||||||
"name": "o3-mini",
|
|
||||||
"model": "o3",
|
|
||||||
"provider": "OpenAI",
|
|
||||||
"maxLength": 400000,
|
|
||||||
"tokenLimit": 100000,
|
|
||||||
"context": "128K",
|
|
||||||
},
|
|
||||||
"o1-preview-2024-09-12": {
|
|
||||||
"id": "o1-preview-2024-09-12",
|
|
||||||
"name": "o1-preview",
|
|
||||||
"model": "o1",
|
|
||||||
"provider": "OpenAI",
|
|
||||||
"maxLength": 400000,
|
|
||||||
"tokenLimit": 100000,
|
|
||||||
"context": "128K",
|
|
||||||
},
|
|
||||||
"claude-3-opus-20240229": {
|
|
||||||
"id": "claude-3-opus-20240229",
|
|
||||||
"name": "Claude-3-Opus",
|
|
||||||
"model": "Claude",
|
|
||||||
"provider": "Anthropic",
|
|
||||||
"maxLength": 800000,
|
|
||||||
"tokenLimit": 200000,
|
|
||||||
"context": "200K",
|
|
||||||
},
|
|
||||||
"claude-3-5-sonnet-20240620": {
|
|
||||||
"id": "claude-3-5-sonnet-20240620",
|
|
||||||
"name": "Claude-3.5-Sonnet",
|
|
||||||
"model": "Claude",
|
|
||||||
"provider": "Anthropic",
|
|
||||||
"maxLength": 800000,
|
|
||||||
"tokenLimit": 200000,
|
|
||||||
"context": "200K",
|
|
||||||
},
|
|
||||||
"claude-3-5-sonnet-20241022": {
|
|
||||||
"id": "claude-3-5-sonnet-20241022",
|
|
||||||
"name": "Claude-3.5-Sonnet-V2",
|
|
||||||
"model": "Claude",
|
|
||||||
"provider": "Anthropic",
|
|
||||||
"maxLength": 800000,
|
|
||||||
"tokenLimit": 200000,
|
|
||||||
"context": "200K",
|
|
||||||
},
|
|
||||||
"claude-3-sonnet-20240229": {
|
|
||||||
"id": "claude-3-sonnet-20240229",
|
|
||||||
"name": "Claude-3-Sonnet",
|
|
||||||
"model": "Claude",
|
|
||||||
"provider": "Anthropic",
|
|
||||||
"maxLength": 800000,
|
|
||||||
"tokenLimit": 200000,
|
|
||||||
"context": "200K",
|
|
||||||
},
|
|
||||||
"claude-3-opus-20240229-t": {
|
|
||||||
"id": "claude-3-opus-20240229-t",
|
|
||||||
"name": "Claude-3-Opus-T",
|
|
||||||
"model": "Claude",
|
|
||||||
"provider": "Anthropic",
|
|
||||||
"maxLength": 800000,
|
|
||||||
"tokenLimit": 200000,
|
|
||||||
"context": "200K",
|
|
||||||
},
|
|
||||||
"claude-3-5-sonnet-20241022-t": {
|
|
||||||
"id": "claude-3-5-sonnet-20241022-t",
|
|
||||||
"name": "Claude-3.5-Sonnet-V2-T",
|
|
||||||
"model": "Claude",
|
|
||||||
"provider": "Anthropic",
|
|
||||||
"maxLength": 800000,
|
|
||||||
"tokenLimit": 200000,
|
|
||||||
"context": "200K",
|
|
||||||
},
|
|
||||||
"gemini-2.0-flash": {
|
"gemini-2.0-flash": {
|
||||||
"id": "gemini-2.0-flash",
|
"id": "gemini-2.0-flash",
|
||||||
"name": "Gemini-2.0-Flash",
|
"name": "Gemini-2.0-Flash",
|
||||||
|
|
@ -181,34 +127,93 @@ models = {
|
||||||
"tokenLimit": 1000000,
|
"tokenLimit": 1000000,
|
||||||
"context": "1024K",
|
"context": "1024K",
|
||||||
},
|
},
|
||||||
|
"gpt-4o-2024-08-06": {
|
||||||
|
"id": "gpt-4o-2024-08-06",
|
||||||
|
"name": "GPT-4o",
|
||||||
|
"model": "ChatGPT",
|
||||||
|
"provider": "OpenAI",
|
||||||
|
"maxLength": 260000,
|
||||||
|
"tokenLimit": 126000,
|
||||||
|
"context": "128K",
|
||||||
|
},
|
||||||
|
"gpt-4o-mini-2024-07-18": {
|
||||||
|
"id": "gpt-4o-mini-2024-07-18",
|
||||||
|
"name": "GPT-4o-Mini",
|
||||||
|
"model": "ChatGPT",
|
||||||
|
"provider": "OpenAI",
|
||||||
|
"maxLength": 260000,
|
||||||
|
"tokenLimit": 126000,
|
||||||
|
"context": "128K",
|
||||||
|
},
|
||||||
|
"gpt-4o-mini-free": {
|
||||||
|
"id": "gpt-4o-mini-free",
|
||||||
|
"name": "GPT-4o-Mini-Free",
|
||||||
|
"model": "ChatGPT",
|
||||||
|
"provider": "OpenAI",
|
||||||
|
"maxLength": 31200,
|
||||||
|
"tokenLimit": 7800,
|
||||||
|
"context": "8K",
|
||||||
|
},
|
||||||
|
"grok-3": {
|
||||||
|
"id": "grok-3",
|
||||||
|
"name": "Grok-3",
|
||||||
|
"model": "Grok",
|
||||||
|
"provider": "x.ai",
|
||||||
|
"maxLength": 800000,
|
||||||
|
"tokenLimit": 200000,
|
||||||
|
"context": "200K",
|
||||||
|
},
|
||||||
|
"grok-3-r1": {
|
||||||
|
"id": "grok-3-r1",
|
||||||
|
"name": "Grok-3-Thinking",
|
||||||
|
"model": "Grok",
|
||||||
|
"provider": "x.ai",
|
||||||
|
"maxLength": 800000,
|
||||||
|
"tokenLimit": 200000,
|
||||||
|
"context": "200K",
|
||||||
|
},
|
||||||
|
"o3-mini": {
|
||||||
|
"id": "o3-mini",
|
||||||
|
"name": "o3-mini",
|
||||||
|
"model": "o3",
|
||||||
|
"provider": "OpenAI",
|
||||||
|
"maxLength": 400000,
|
||||||
|
"tokenLimit": 100000,
|
||||||
|
"context": "128K",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Liaobots(AsyncGeneratorProvider, ProviderModelMixin):
|
class Liaobots(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
url = "https://liaobots.site"
|
url = "https://liaobots.site"
|
||||||
working = True
|
working = True
|
||||||
supports_message_history = True
|
supports_message_history = True
|
||||||
supports_system_message = True
|
supports_system_message = True
|
||||||
|
|
||||||
default_model = "gpt-4o-2024-11-20"
|
default_model = "gpt-4o-2024-08-06"
|
||||||
models = list(models.keys())
|
models = list(models.keys())
|
||||||
model_aliases = {
|
model_aliases = {
|
||||||
"gpt-4o-mini": "gpt-4o-mini-free",
|
# Anthropic
|
||||||
"gpt-4o": default_model,
|
"claude-3.5-sonnet": "claude-3-5-sonnet-20241022",
|
||||||
"gpt-4o-mini": "gpt-4o-mini-2024-07-18",
|
"claude-3.5-sonnet": "claude-3-5-sonnet-20241022-t",
|
||||||
"gpt-4": default_model,
|
"claude-3.7-sonnet": "claude-3-7-sonnet-20250219",
|
||||||
|
"claude-3.7-sonnet": "claude-3-7-sonnet-20250219-t",
|
||||||
"o1-preview": "o1-preview-2024-09-12",
|
"claude-3.7-sonnet-thinking": "claude-3-7-sonnet-20250219-thinking",
|
||||||
|
"claude-3-opus": "claude-3-opus-20240229",
|
||||||
|
"claude-3-sonnet": "claude-3-sonnet-20240229",
|
||||||
|
|
||||||
|
# DeepSeek
|
||||||
"deepseek-r1": "deepseek-r1-distill-llama-70b",
|
"deepseek-r1": "deepseek-r1-distill-llama-70b",
|
||||||
|
|
||||||
"claude-3-opus": "claude-3-opus-20240229",
|
# Google
|
||||||
"claude-3.5-sonnet": "claude-3-5-sonnet-20240620",
|
|
||||||
"claude-3.5-sonnet": "claude-3-5-sonnet-20241022",
|
|
||||||
"claude-3-sonnet": "claude-3-sonnet-20240229",
|
|
||||||
"claude-3-opus": "claude-3-opus-20240229-t",
|
|
||||||
"claude-3.5-sonnet": "claude-3-5-sonnet-20241022-t",
|
|
||||||
|
|
||||||
"gemini-2.0-flash-thinking": "gemini-2.0-flash-thinking-exp",
|
"gemini-2.0-flash-thinking": "gemini-2.0-flash-thinking-exp",
|
||||||
|
"gemini-2.0-pro": "gemini-2.0-pro-exp",
|
||||||
|
|
||||||
|
# OpenAI
|
||||||
|
"gpt-4": default_model,
|
||||||
|
"gpt-4o": default_model,
|
||||||
|
"gpt-4o-mini": "gpt-4o-mini-2024-07-18",
|
||||||
|
"gpt-4o-mini": "gpt-4o-mini-free",
|
||||||
}
|
}
|
||||||
|
|
||||||
_auth_code = ""
|
_auth_code = ""
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from ..typing import AsyncResult, Messages
|
|
||||||
from .template import OpenaiTemplate
|
|
||||||
|
|
||||||
class Mhystical(OpenaiTemplate):
|
|
||||||
url = "https://mhystical.cc"
|
|
||||||
api_endpoint = "https://api.mhystical.cc/v1/completions"
|
|
||||||
login_url = "https://mhystical.cc/dashboard"
|
|
||||||
api_key = "mhystical"
|
|
||||||
|
|
||||||
working = True
|
|
||||||
supports_stream = False # Set to False, as streaming is not specified in ChatifyAI
|
|
||||||
supports_system_message = False
|
|
||||||
|
|
||||||
default_model = 'gpt-4'
|
|
||||||
models = [default_model]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_model(cls, model: str, **kwargs) -> str:
|
|
||||||
cls.last_model = cls.default_model
|
|
||||||
return cls.default_model
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create_async_generator(
|
|
||||||
cls,
|
|
||||||
model: str,
|
|
||||||
messages: Messages,
|
|
||||||
stream: bool = False,
|
|
||||||
api_key: str = None,
|
|
||||||
**kwargs
|
|
||||||
) -> AsyncResult:
|
|
||||||
headers = {
|
|
||||||
"x-api-key": cls.api_key,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"accept": "*/*",
|
|
||||||
"cache-control": "no-cache",
|
|
||||||
"origin": cls.url,
|
|
||||||
"referer": f"{cls.url}/",
|
|
||||||
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
|
|
||||||
}
|
|
||||||
return super().create_async_generator(
|
|
||||||
model=model,
|
|
||||||
messages=messages,
|
|
||||||
stream=cls.supports_stream,
|
|
||||||
api_endpoint=cls.api_endpoint,
|
|
||||||
headers=headers,
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
|
|
@ -13,7 +13,7 @@ from ..image import to_data_uri
|
||||||
from ..errors import ModelNotFoundError
|
from ..errors import ModelNotFoundError
|
||||||
from ..requests.raise_for_status import raise_for_status
|
from ..requests.raise_for_status import raise_for_status
|
||||||
from ..requests.aiohttp import get_connector
|
from ..requests.aiohttp import get_connector
|
||||||
from ..providers.response import ImageResponse, ImagePreview, FinishReason, Usage, Audio
|
from ..providers.response import ImageResponse, ImagePreview, FinishReason, Usage
|
||||||
from .. import debug
|
from .. import debug
|
||||||
|
|
||||||
DEFAULT_HEADERS = {
|
DEFAULT_HEADERS = {
|
||||||
|
|
@ -32,8 +32,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
supports_message_history = True
|
supports_message_history = True
|
||||||
|
|
||||||
# API endpoints
|
# API endpoints
|
||||||
text_api_endpoint = "https://text.pollinations.ai"
|
text_api_endpoint = "https://text.pollinations.ai/openai"
|
||||||
openai_endpoint = "https://text.pollinations.ai/openai"
|
|
||||||
image_api_endpoint = "https://image.pollinations.ai/"
|
image_api_endpoint = "https://image.pollinations.ai/"
|
||||||
|
|
||||||
# Models configuration
|
# Models configuration
|
||||||
|
|
@ -44,24 +43,21 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
image_models = [default_image_model]
|
image_models = [default_image_model]
|
||||||
extra_image_models = ["flux-pro", "flux-dev", "flux-schnell", "midjourney", "dall-e-3"]
|
extra_image_models = ["flux-pro", "flux-dev", "flux-schnell", "midjourney", "dall-e-3"]
|
||||||
vision_models = [default_vision_model, "gpt-4o-mini", "o1-mini"]
|
vision_models = [default_vision_model, "gpt-4o-mini", "o1-mini"]
|
||||||
extra_text_models = ["claude", "claude-email", "deepseek-reasoner", "deepseek-r1"] + vision_models
|
extra_text_models = vision_models
|
||||||
audio_models = {}
|
|
||||||
_models_loaded = False
|
_models_loaded = False
|
||||||
model_aliases = {
|
model_aliases = {
|
||||||
### Text Models ###
|
### Text Models ###
|
||||||
"gpt-4o-mini": "openai",
|
"gpt-4o-mini": "openai",
|
||||||
"gpt-4": "openai-large",
|
"gpt-4": "openai-large",
|
||||||
"gpt-4o": "openai-large",
|
"gpt-4o": "openai-large",
|
||||||
|
"o1-mini": "openai-reasoning",
|
||||||
"qwen-2.5-coder-32b": "qwen-coder",
|
"qwen-2.5-coder-32b": "qwen-coder",
|
||||||
"llama-3.3-70b": "llama",
|
"llama-3.3-70b": "llama",
|
||||||
"mistral-nemo": "mistral",
|
"mistral-nemo": "mistral",
|
||||||
"gpt-4o": "searchgpt",
|
"gpt-4o-mini": "searchgpt",
|
||||||
"deepseek-chat": "claude-hybridspace",
|
|
||||||
"llama-3.1-8b": "llamalight",
|
"llama-3.1-8b": "llamalight",
|
||||||
"gpt-4o-vision": "gpt-4o",
|
"llama-3.3-70b": "llama-scaleway",
|
||||||
"gpt-4o-mini-vision": "gpt-4o-mini",
|
"phi-4": "phi",
|
||||||
"deepseek-chat": "claude-email",
|
|
||||||
"deepseek-r1": "deepseek-reasoner",
|
|
||||||
"gemini-2.0": "gemini",
|
"gemini-2.0": "gemini",
|
||||||
"gemini-2.0-flash": "gemini",
|
"gemini-2.0-flash": "gemini",
|
||||||
"gemini-2.0-flash-thinking": "gemini-thinking",
|
"gemini-2.0-flash-thinking": "gemini-thinking",
|
||||||
|
|
@ -92,17 +88,10 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
# Update of text models
|
# Update of text models
|
||||||
text_response = requests.get("https://text.pollinations.ai/models")
|
text_response = requests.get("https://text.pollinations.ai/models")
|
||||||
text_response.raise_for_status()
|
text_response.raise_for_status()
|
||||||
models = text_response.json()
|
|
||||||
original_text_models = [
|
original_text_models = [
|
||||||
model.get("name")
|
model.get("name")
|
||||||
for model in models
|
for model in text_response.json()
|
||||||
if model.get("type") == "chat"
|
|
||||||
]
|
]
|
||||||
cls.audio_models = {
|
|
||||||
model.get("name"): model.get("voices")
|
|
||||||
for model in models
|
|
||||||
if model.get("audio")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Combining text models
|
# Combining text models
|
||||||
combined_text = (
|
combined_text = (
|
||||||
|
|
@ -273,18 +262,8 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
"seed": seed,
|
"seed": seed,
|
||||||
"cache": cache
|
"cache": cache
|
||||||
})
|
})
|
||||||
if "gemini" in model:
|
async with session.post(cls.text_api_endpoint, json=data) as response:
|
||||||
data.pop("seed")
|
|
||||||
if model in cls.audio_models:
|
|
||||||
data["voice"] = random.choice(cls.audio_models[model])
|
|
||||||
url = f"{cls.text_api_endpoint}"
|
|
||||||
else:
|
|
||||||
url = cls.openai_endpoint
|
|
||||||
async with session.post(url, json=data) as response:
|
|
||||||
await raise_for_status(response)
|
await raise_for_status(response)
|
||||||
if response.headers["content-type"] == "audio/mpeg":
|
|
||||||
yield Audio(await response.read())
|
|
||||||
return
|
|
||||||
result = await response.json()
|
result = await response.json()
|
||||||
choice = result["choices"][0]
|
choice = result["choices"][0]
|
||||||
message = choice.get("message", {})
|
message = choice.get("message", {})
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ from ..typing import AsyncResult, Messages
|
||||||
from .PollinationsAI import PollinationsAI
|
from .PollinationsAI import PollinationsAI
|
||||||
|
|
||||||
class PollinationsImage(PollinationsAI):
|
class PollinationsImage(PollinationsAI):
|
||||||
|
label = "PollinationsImage"
|
||||||
default_model = "flux"
|
default_model = "flux"
|
||||||
default_vision_model = None
|
default_vision_model = None
|
||||||
default_image_model = default_model
|
default_image_model = default_model
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,11 @@ from .helper import format_prompt
|
||||||
class TeachAnything(AsyncGeneratorProvider, ProviderModelMixin):
|
class TeachAnything(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
url = "https://www.teach-anything.com"
|
url = "https://www.teach-anything.com"
|
||||||
api_endpoint = "/api/generate"
|
api_endpoint = "/api/generate"
|
||||||
|
|
||||||
working = True
|
working = True
|
||||||
default_model = "llama-3.1-70b"
|
|
||||||
models = [default_model]
|
default_model = 'gemini-1.5-pro'
|
||||||
|
models = [default_model, 'gemini-1.5-flash']
|
||||||
@classmethod
|
|
||||||
def get_model(cls, model: str) -> str:
|
|
||||||
if model in cls.models:
|
|
||||||
return model
|
|
||||||
elif model in cls.model_aliases:
|
|
||||||
return cls.model_aliases[model]
|
|
||||||
else:
|
|
||||||
return cls.default_model
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_async_generator(
|
async def create_async_generator(
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,12 @@ from .Glider import Glider
|
||||||
from .ImageLabs import ImageLabs
|
from .ImageLabs import ImageLabs
|
||||||
from .Jmuz import Jmuz
|
from .Jmuz import Jmuz
|
||||||
from .Liaobots import Liaobots
|
from .Liaobots import Liaobots
|
||||||
from .Mhystical import Mhystical
|
|
||||||
from .OIVSCode import OIVSCode
|
from .OIVSCode import OIVSCode
|
||||||
from .PerplexityLabs import PerplexityLabs
|
from .PerplexityLabs import PerplexityLabs
|
||||||
from .Pi import Pi
|
from .Pi import Pi
|
||||||
from .Pizzagpt import Pizzagpt
|
from .Pizzagpt import Pizzagpt
|
||||||
from .PollinationsAI import PollinationsAI
|
from .PollinationsAI import PollinationsAI
|
||||||
from .PollinationsImage import PollinationsImage
|
from .PollinationsImage import PollinationsImage
|
||||||
from .Prodia import Prodia
|
|
||||||
from .TeachAnything import TeachAnything
|
from .TeachAnything import TeachAnything
|
||||||
from .You import You
|
from .You import You
|
||||||
from .Yqcloud import Yqcloud
|
from .Yqcloud import Yqcloud
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,15 @@ from aiohttp import ClientSession
|
||||||
import asyncio
|
import asyncio
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from ..typing import AsyncResult, Messages
|
from ...typing import AsyncResult, Messages
|
||||||
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
||||||
from ..providers.response import ImageResponse
|
from ...providers.response import ImageResponse
|
||||||
|
|
||||||
class Prodia(AsyncGeneratorProvider, ProviderModelMixin):
|
class Prodia(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
url = "https://app.prodia.com"
|
url = "https://app.prodia.com"
|
||||||
api_endpoint = "https://api.prodia.com/generate"
|
api_endpoint = "https://api.prodia.com/generate"
|
||||||
working = True
|
|
||||||
|
working = False
|
||||||
|
|
||||||
default_model = 'absolutereality_v181.safetensors [3d9d4d2b]'
|
default_model = 'absolutereality_v181.safetensors [3d9d4d2b]'
|
||||||
default_image_model = default_model
|
default_image_model = default_model
|
||||||
|
|
@ -19,6 +19,7 @@ from .Koala import Koala
|
||||||
from .MagickPen import MagickPen
|
from .MagickPen import MagickPen
|
||||||
from .MyShell import MyShell
|
from .MyShell import MyShell
|
||||||
from .Poe import Poe
|
from .Poe import Poe
|
||||||
|
from .Prodia import Prodia
|
||||||
from .Raycast import Raycast
|
from .Raycast import Raycast
|
||||||
from .ReplicateHome import ReplicateHome
|
from .ReplicateHome import ReplicateHome
|
||||||
from .RobocodersAPI import RobocodersAPI
|
from .RobocodersAPI import RobocodersAPI
|
||||||
|
|
|
||||||
16
g4f/debug.py
16
g4f/debug.py
|
|
@ -1,17 +1,21 @@
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Callable, List, Optional, Any
|
||||||
|
|
||||||
|
# Warning: name could conflict with Python's built-in logging module
|
||||||
logging: bool = False
|
logging: bool = False
|
||||||
version_check: bool = True
|
version_check: bool = True
|
||||||
version: str = None
|
version: Optional[str] = None
|
||||||
log_handler: callable = print
|
log_handler: Callable = print # More specifically: Callable[[Any, Optional[Any]], None]
|
||||||
logs: list = []
|
logs: List[str] = []
|
||||||
|
|
||||||
def log(text, file = None):
|
def log(text: Any, file: Optional[Any] = None) -> None:
|
||||||
|
"""Log a message if logging is enabled."""
|
||||||
if logging:
|
if logging:
|
||||||
log_handler(text, file=file)
|
log_handler(text, file=file)
|
||||||
|
|
||||||
def error(error, name: str = None):
|
def error(error: Any, name: Optional[str] = None) -> None:
|
||||||
|
"""Log an error message to stderr."""
|
||||||
log(
|
log(
|
||||||
error if isinstance(error, str) else f"{type(error).__name__ if name is None else name}: {error}",
|
error if isinstance(error, str) else f"{type(error).__name__ if name is None else name}: {error}",
|
||||||
file=sys.stderr
|
file=sys.stderr
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from dataclasses import dataclass
|
||||||
|
|
||||||
from .Provider import IterListProvider, ProviderType
|
from .Provider import IterListProvider, ProviderType
|
||||||
from .Provider import (
|
from .Provider import (
|
||||||
### no auth required ###
|
### No Auth Required ###
|
||||||
AllenAI,
|
AllenAI,
|
||||||
Blackbox,
|
Blackbox,
|
||||||
ChatGLM,
|
ChatGLM,
|
||||||
|
|
@ -13,6 +13,8 @@ from .Provider import (
|
||||||
Copilot,
|
Copilot,
|
||||||
DDG,
|
DDG,
|
||||||
DeepInfraChat,
|
DeepInfraChat,
|
||||||
|
Free2GPT,
|
||||||
|
FreeGpt,
|
||||||
HuggingSpace,
|
HuggingSpace,
|
||||||
G4F,
|
G4F,
|
||||||
Janus_Pro_7B,
|
Janus_Pro_7B,
|
||||||
|
|
@ -20,7 +22,6 @@ from .Provider import (
|
||||||
ImageLabs,
|
ImageLabs,
|
||||||
Jmuz,
|
Jmuz,
|
||||||
Liaobots,
|
Liaobots,
|
||||||
Mhystical,
|
|
||||||
OIVSCode,
|
OIVSCode,
|
||||||
PerplexityLabs,
|
PerplexityLabs,
|
||||||
Pi,
|
Pi,
|
||||||
|
|
@ -29,7 +30,7 @@ from .Provider import (
|
||||||
TeachAnything,
|
TeachAnything,
|
||||||
Yqcloud,
|
Yqcloud,
|
||||||
|
|
||||||
### needs auth ###
|
### Needs Auth ###
|
||||||
BingCreateImages,
|
BingCreateImages,
|
||||||
CopilotAccount,
|
CopilotAccount,
|
||||||
Gemini,
|
Gemini,
|
||||||
|
|
@ -80,9 +81,13 @@ default = Model(
|
||||||
Blackbox,
|
Blackbox,
|
||||||
Copilot,
|
Copilot,
|
||||||
DeepInfraChat,
|
DeepInfraChat,
|
||||||
ChatGptEs,
|
AllenAI,
|
||||||
PollinationsAI,
|
PollinationsAI,
|
||||||
OIVSCode,
|
OIVSCode,
|
||||||
|
ChatGptEs,
|
||||||
|
Free2GPT,
|
||||||
|
FreeGpt,
|
||||||
|
Glider,
|
||||||
OpenaiChat,
|
OpenaiChat,
|
||||||
Jmuz,
|
Jmuz,
|
||||||
Cloudflare,
|
Cloudflare,
|
||||||
|
|
@ -115,14 +120,14 @@ default_vision = Model(
|
||||||
gpt_4 = Model(
|
gpt_4 = Model(
|
||||||
name = 'gpt-4',
|
name = 'gpt-4',
|
||||||
base_provider = 'OpenAI',
|
base_provider = 'OpenAI',
|
||||||
best_provider = IterListProvider([DDG, Jmuz, ChatGptEs, PollinationsAI, Yqcloud, Copilot, OpenaiChat, Liaobots, Mhystical])
|
best_provider = IterListProvider([DDG, Jmuz, ChatGptEs, PollinationsAI, Yqcloud, Copilot, OpenaiChat, Liaobots])
|
||||||
)
|
)
|
||||||
|
|
||||||
# gpt-4o
|
# gpt-4o
|
||||||
gpt_4o = VisionModel(
|
gpt_4o = VisionModel(
|
||||||
name = 'gpt-4o',
|
name = 'gpt-4o',
|
||||||
base_provider = 'OpenAI',
|
base_provider = 'OpenAI',
|
||||||
best_provider = IterListProvider([Jmuz, ChatGptEs, PollinationsAI, Copilot, Liaobots, OpenaiChat])
|
best_provider = IterListProvider([Blackbox, Jmuz, ChatGptEs, PollinationsAI, Copilot, Liaobots, OpenaiChat])
|
||||||
)
|
)
|
||||||
|
|
||||||
gpt_4o_mini = Model(
|
gpt_4o_mini = Model(
|
||||||
|
|
@ -135,20 +140,20 @@ gpt_4o_mini = Model(
|
||||||
o1 = Model(
|
o1 = Model(
|
||||||
name = 'o1',
|
name = 'o1',
|
||||||
base_provider = 'OpenAI',
|
base_provider = 'OpenAI',
|
||||||
best_provider = OpenaiAccount
|
best_provider = IterListProvider([Blackbox, OpenaiAccount])
|
||||||
)
|
)
|
||||||
|
|
||||||
o1_preview = Model(
|
o1_mini = Model(
|
||||||
name = 'o1-preview',
|
name = 'o1-mini',
|
||||||
base_provider = 'OpenAI',
|
base_provider = 'OpenAI',
|
||||||
best_provider = Liaobots
|
best_provider = PollinationsAI
|
||||||
)
|
)
|
||||||
|
|
||||||
# o3
|
# o3
|
||||||
o3_mini = Model(
|
o3_mini = Model(
|
||||||
name = 'o3-mini',
|
name = 'o3-mini',
|
||||||
base_provider = 'OpenAI',
|
base_provider = 'OpenAI',
|
||||||
best_provider = IterListProvider([DDG, Liaobots])
|
best_provider = IterListProvider([DDG, Blackbox, Liaobots])
|
||||||
)
|
)
|
||||||
|
|
||||||
### GigaChat ###
|
### GigaChat ###
|
||||||
|
|
@ -194,7 +199,7 @@ llama_3_1_8b = Model(
|
||||||
llama_3_1_70b = Model(
|
llama_3_1_70b = Model(
|
||||||
name = "llama-3.1-70b",
|
name = "llama-3.1-70b",
|
||||||
base_provider = "Meta Llama",
|
base_provider = "Meta Llama",
|
||||||
best_provider = IterListProvider([Blackbox, Glider, Jmuz, TeachAnything])
|
best_provider = IterListProvider([Blackbox, Glider, Jmuz])
|
||||||
)
|
)
|
||||||
|
|
||||||
llama_3_1_405b = Model(
|
llama_3_1_405b = Model(
|
||||||
|
|
@ -289,7 +294,7 @@ phi_3_5_mini = Model(
|
||||||
phi_4 = Model(
|
phi_4 = Model(
|
||||||
name = "phi-4",
|
name = "phi-4",
|
||||||
base_provider = "Microsoft",
|
base_provider = "Microsoft",
|
||||||
best_provider = DeepInfraChat
|
best_provider = IterListProvider([DeepInfraChat, PollinationsAI])
|
||||||
)
|
)
|
||||||
|
|
||||||
# wizardlm
|
# wizardlm
|
||||||
|
|
@ -324,13 +329,13 @@ gemini_exp = Model(
|
||||||
gemini_1_5_flash = Model(
|
gemini_1_5_flash = Model(
|
||||||
name = 'gemini-1.5-flash',
|
name = 'gemini-1.5-flash',
|
||||||
base_provider = 'Google DeepMind',
|
base_provider = 'Google DeepMind',
|
||||||
best_provider = IterListProvider([Blackbox, Jmuz, GeminiPro])
|
best_provider = IterListProvider([Blackbox, Free2GPT, FreeGpt, TeachAnything, Jmuz, GeminiPro])
|
||||||
)
|
)
|
||||||
|
|
||||||
gemini_1_5_pro = Model(
|
gemini_1_5_pro = Model(
|
||||||
name = 'gemini-1.5-pro',
|
name = 'gemini-1.5-pro',
|
||||||
base_provider = 'Google DeepMind',
|
base_provider = 'Google DeepMind',
|
||||||
best_provider = IterListProvider([Jmuz, GeminiPro])
|
best_provider = IterListProvider([Blackbox, Free2GPT, FreeGpt, TeachAnything, Jmuz, GeminiPro])
|
||||||
)
|
)
|
||||||
|
|
||||||
# gemini-2.0
|
# gemini-2.0
|
||||||
|
|
@ -346,6 +351,12 @@ gemini_2_0_flash_thinking = Model(
|
||||||
best_provider = Liaobots
|
best_provider = Liaobots
|
||||||
)
|
)
|
||||||
|
|
||||||
|
gemini_2_0_pro = Model(
|
||||||
|
name = 'gemini-2.0-pro',
|
||||||
|
base_provider = 'Google DeepMind',
|
||||||
|
best_provider = Liaobots
|
||||||
|
)
|
||||||
|
|
||||||
### Anthropic ###
|
### Anthropic ###
|
||||||
# claude 3
|
# claude 3
|
||||||
claude_3_haiku = Model(
|
claude_3_haiku = Model(
|
||||||
|
|
@ -374,6 +385,19 @@ claude_3_5_sonnet = Model(
|
||||||
best_provider = IterListProvider([Jmuz, Liaobots])
|
best_provider = IterListProvider([Jmuz, Liaobots])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# claude 3.7
|
||||||
|
claude_3_7_sonnet = Model(
|
||||||
|
name = 'claude-3.7-sonnet',
|
||||||
|
base_provider = 'Anthropic',
|
||||||
|
best_provider = IterListProvider([Blackbox, Liaobots])
|
||||||
|
)
|
||||||
|
|
||||||
|
claude_3_7_sonnet_thinking = Model(
|
||||||
|
name = 'claude-3.7-sonnet-thinking',
|
||||||
|
base_provider = 'Anthropic',
|
||||||
|
best_provider = Liaobots
|
||||||
|
)
|
||||||
|
|
||||||
### Reka AI ###
|
### Reka AI ###
|
||||||
reka_core = Model(
|
reka_core = Model(
|
||||||
name = 'reka-core',
|
name = 'reka-core',
|
||||||
|
|
@ -468,7 +492,7 @@ pi = Model(
|
||||||
deepseek_chat = Model(
|
deepseek_chat = Model(
|
||||||
name = 'deepseek-chat',
|
name = 'deepseek-chat',
|
||||||
base_provider = 'DeepSeek',
|
base_provider = 'DeepSeek',
|
||||||
best_provider = IterListProvider([Blackbox, Jmuz, PollinationsAI])
|
best_provider = IterListProvider([Blackbox, Jmuz])
|
||||||
)
|
)
|
||||||
|
|
||||||
deepseek_v3 = Model(
|
deepseek_v3 = Model(
|
||||||
|
|
@ -720,7 +744,7 @@ class ModelUtils:
|
||||||
|
|
||||||
# o1
|
# o1
|
||||||
o1.name: o1,
|
o1.name: o1,
|
||||||
o1_preview.name: o1_preview,
|
o1_mini.name: o1_mini,
|
||||||
|
|
||||||
# o3
|
# o3
|
||||||
o3_mini.name: o3_mini,
|
o3_mini.name: o3_mini,
|
||||||
|
|
@ -777,6 +801,7 @@ class ModelUtils:
|
||||||
gemini_1_5_flash.name: gemini_1_5_flash,
|
gemini_1_5_flash.name: gemini_1_5_flash,
|
||||||
gemini_2_0_flash.name: gemini_2_0_flash,
|
gemini_2_0_flash.name: gemini_2_0_flash,
|
||||||
gemini_2_0_flash_thinking.name: gemini_2_0_flash_thinking,
|
gemini_2_0_flash_thinking.name: gemini_2_0_flash_thinking,
|
||||||
|
gemini_2_0_pro.name: gemini_2_0_pro,
|
||||||
|
|
||||||
### Anthropic ###
|
### Anthropic ###
|
||||||
# claude 3
|
# claude 3
|
||||||
|
|
@ -786,6 +811,10 @@ class ModelUtils:
|
||||||
|
|
||||||
# claude 3.5
|
# claude 3.5
|
||||||
claude_3_5_sonnet.name: claude_3_5_sonnet,
|
claude_3_5_sonnet.name: claude_3_5_sonnet,
|
||||||
|
|
||||||
|
# claude 3.7
|
||||||
|
claude_3_7_sonnet.name: claude_3_7_sonnet,
|
||||||
|
claude_3_7_sonnet_thinking.name: claude_3_7_sonnet_thinking,
|
||||||
|
|
||||||
### Reka AI ###
|
### Reka AI ###
|
||||||
reka_core.name: reka_core,
|
reka_core.name: reka_core,
|
||||||
|
|
|
||||||
|
|
@ -1,68 +1,112 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import base64
|
from typing import Union, Dict, List, Optional
|
||||||
from typing import Union
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from urllib.parse import quote_plus, unquote_plus
|
from urllib.parse import quote_plus, unquote_plus
|
||||||
|
|
||||||
def quote_url(url: str) -> str:
|
def quote_url(url: str) -> str:
|
||||||
url = unquote_plus(url)
|
"""
|
||||||
url = url.split("//", maxsplit=1)
|
Quote parts of a URL while preserving the domain structure.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url: The URL to quote
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The properly quoted URL
|
||||||
|
"""
|
||||||
|
# Only unquote if needed to avoid double-unquoting
|
||||||
|
if '%' in url:
|
||||||
|
url = unquote_plus(url)
|
||||||
|
|
||||||
|
url_parts = url.split("//", maxsplit=1)
|
||||||
# If there is no "//" in the URL, then it is a relative URL
|
# If there is no "//" in the URL, then it is a relative URL
|
||||||
if len(url) == 1:
|
if len(url_parts) == 1:
|
||||||
return quote_plus(url[0], '/?&=#')
|
return quote_plus(url_parts[0], '/?&=#')
|
||||||
url[1] = url[1].split("/", maxsplit=1)
|
|
||||||
|
protocol, rest = url_parts
|
||||||
|
domain_parts = rest.split("/", maxsplit=1)
|
||||||
# If there is no "/" after the domain, then it is a domain URL
|
# If there is no "/" after the domain, then it is a domain URL
|
||||||
if len(url[1]) == 1:
|
if len(domain_parts) == 1:
|
||||||
return url[0] + "//" + url[1][0]
|
return f"{protocol}//{domain_parts[0]}"
|
||||||
return url[0] + "//" + url[1][0] + "/" + quote_plus(url[1][1], '/?&=#')
|
|
||||||
|
domain, path = domain_parts
|
||||||
|
return f"{protocol}//{domain}/{quote_plus(path, '/?&=#')}"
|
||||||
|
|
||||||
def quote_title(title: str) -> str:
|
def quote_title(title: str) -> str:
|
||||||
if title:
|
"""
|
||||||
return " ".join(title.split())
|
Normalize whitespace in a title.
|
||||||
return ""
|
|
||||||
|
Args:
|
||||||
|
title: The title to normalize
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The title with normalized whitespace
|
||||||
|
"""
|
||||||
|
return " ".join(title.split()) if title else ""
|
||||||
|
|
||||||
def format_link(url: str, title: str = None) -> str:
|
def format_link(url: str, title: Optional[str] = None) -> str:
|
||||||
|
"""
|
||||||
|
Format a URL and title as a markdown link.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url: The URL to link to
|
||||||
|
title: The title to display. If None, extracts from URL
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted markdown link
|
||||||
|
"""
|
||||||
if title is None:
|
if title is None:
|
||||||
title = unquote_plus(url.split("//", maxsplit=1)[1].split("?")[0].replace("www.", ""))
|
try:
|
||||||
|
title = unquote_plus(url.split("//", maxsplit=1)[1].split("?")[0].replace("www.", ""))
|
||||||
|
except IndexError:
|
||||||
|
title = url
|
||||||
return f"[{quote_title(title)}]({quote_url(url)})"
|
return f"[{quote_title(title)}]({quote_url(url)})"
|
||||||
|
|
||||||
def format_image(image: str, alt: str, preview: str = None) -> str:
|
def format_image(image: str, alt: str, preview: Optional[str] = None) -> str:
|
||||||
"""
|
"""
|
||||||
Formats the given image as a markdown string.
|
Formats the given image as a markdown string.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
image: The image to format.
|
image: The image to format.
|
||||||
alt (str): The alt for the image.
|
alt: The alt text for the image.
|
||||||
preview (str, optional): The preview URL format. Defaults to "{image}?w=200&h=200".
|
preview: The preview URL format. Defaults to the original image.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The formatted markdown string.
|
str: The formatted markdown string.
|
||||||
"""
|
"""
|
||||||
return f"[ if preview else image)})]({quote_url(image)})"
|
preview_url = preview.replace('{image}', image) if preview else image
|
||||||
|
return f"[})]({quote_url(image)})"
|
||||||
|
|
||||||
def format_images_markdown(images: Union[str, list], alt: str, preview: Union[str, list] = None) -> str:
|
def format_images_markdown(images: Union[str, List[str]], alt: str,
|
||||||
|
preview: Union[str, List[str]] = None) -> str:
|
||||||
"""
|
"""
|
||||||
Formats the given images as a markdown string.
|
Formats the given images as a markdown string.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
images: The images to format.
|
images: The image or list of images to format.
|
||||||
alt (str): The alt for the images.
|
alt: The alt text for the images.
|
||||||
preview (str, optional): The preview URL format. Defaults to "{image}?w=200&h=200".
|
preview: The preview URL format or list of preview URLs.
|
||||||
|
If not provided, original images are used.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The formatted markdown string.
|
str: The formatted markdown string.
|
||||||
"""
|
"""
|
||||||
if isinstance(images, list) and len(images) == 1:
|
if isinstance(images, list) and len(images) == 1:
|
||||||
images = images[0]
|
images = images[0]
|
||||||
|
|
||||||
if isinstance(images, str):
|
if isinstance(images, str):
|
||||||
result = format_image(images, alt, preview)
|
result = format_image(images, alt, preview)
|
||||||
else:
|
else:
|
||||||
result = "\n".join(
|
result = "\n".join(
|
||||||
format_image(image, f"#{idx+1} {alt}", preview[idx] if isinstance(preview, list) else preview)
|
format_image(
|
||||||
|
image,
|
||||||
|
f"#{idx+1} {alt}",
|
||||||
|
preview[idx] if isinstance(preview, list) and idx < len(preview) else preview
|
||||||
|
)
|
||||||
for idx, image in enumerate(images)
|
for idx, image in enumerate(images)
|
||||||
)
|
)
|
||||||
|
|
||||||
start_flag = "<!-- generated images start -->\n"
|
start_flag = "<!-- generated images start -->\n"
|
||||||
end_flag = "<!-- generated images end -->\n"
|
end_flag = "<!-- generated images end -->\n"
|
||||||
return f"\n{start_flag}{result}\n{end_flag}\n"
|
return f"\n{start_flag}{result}\n{end_flag}\n"
|
||||||
|
|
@ -70,21 +114,25 @@ def format_images_markdown(images: Union[str, list], alt: str, preview: Union[st
|
||||||
class ResponseType:
|
class ResponseType:
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
"""Convert the response to a string representation."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
class JsonMixin:
|
class JsonMixin:
|
||||||
def __init__(self, **kwargs) -> None:
|
def __init__(self, **kwargs) -> None:
|
||||||
|
"""Initialize with keyword arguments as attributes."""
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
def get_dict(self):
|
def get_dict(self) -> Dict:
|
||||||
|
"""Return a dictionary of non-private attributes."""
|
||||||
return {
|
return {
|
||||||
key: value
|
key: value
|
||||||
for key, value in self.__dict__.items()
|
for key, value in self.__dict__.items()
|
||||||
if not key.startswith("__")
|
if not key.startswith("__")
|
||||||
}
|
}
|
||||||
|
|
||||||
def reset(self):
|
def reset(self) -> None:
|
||||||
|
"""Reset all attributes."""
|
||||||
self.__dict__ = {}
|
self.__dict__ = {}
|
||||||
|
|
||||||
class RawResponse(ResponseType, JsonMixin):
|
class RawResponse(ResponseType, JsonMixin):
|
||||||
|
|
@ -92,17 +140,21 @@ class RawResponse(ResponseType, JsonMixin):
|
||||||
|
|
||||||
class HiddenResponse(ResponseType):
|
class HiddenResponse(ResponseType):
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
"""Hidden responses return an empty string."""
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
class FinishReason(JsonMixin, HiddenResponse):
|
class FinishReason(JsonMixin, HiddenResponse):
|
||||||
def __init__(self, reason: str) -> None:
|
def __init__(self, reason: str) -> None:
|
||||||
|
"""Initialize with a reason."""
|
||||||
self.reason = reason
|
self.reason = reason
|
||||||
|
|
||||||
class ToolCalls(HiddenResponse):
|
class ToolCalls(HiddenResponse):
|
||||||
def __init__(self, list: list):
|
def __init__(self, list: List) -> None:
|
||||||
|
"""Initialize with a list of tool calls."""
|
||||||
self.list = list
|
self.list = list
|
||||||
|
|
||||||
def get_list(self) -> list:
|
def get_list(self) -> List:
|
||||||
|
"""Return the list of tool calls."""
|
||||||
return self.list
|
return self.list
|
||||||
|
|
||||||
class Usage(JsonMixin, HiddenResponse):
|
class Usage(JsonMixin, HiddenResponse):
|
||||||
|
|
@ -113,24 +165,28 @@ class AuthResult(JsonMixin, HiddenResponse):
|
||||||
|
|
||||||
class TitleGeneration(HiddenResponse):
|
class TitleGeneration(HiddenResponse):
|
||||||
def __init__(self, title: str) -> None:
|
def __init__(self, title: str) -> None:
|
||||||
|
"""Initialize with a title."""
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
class DebugResponse(HiddenResponse):
|
class DebugResponse(HiddenResponse):
|
||||||
def __init__(self, log: str) -> None:
|
def __init__(self, log: str) -> None:
|
||||||
|
"""Initialize with a log message."""
|
||||||
self.log = log
|
self.log = log
|
||||||
|
|
||||||
class Reasoning(ResponseType):
|
class Reasoning(ResponseType):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
token: str = None,
|
token: Optional[str] = None,
|
||||||
status: str = None,
|
status: Optional[str] = None,
|
||||||
is_thinking: str = None
|
is_thinking: Optional[str] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""Initialize with token, status, and thinking state."""
|
||||||
self.token = token
|
self.token = token
|
||||||
self.status = status
|
self.status = status
|
||||||
self.is_thinking = is_thinking
|
self.is_thinking = is_thinking
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
"""Return string representation based on available attributes."""
|
||||||
if self.is_thinking is not None:
|
if self.is_thinking is not None:
|
||||||
return self.is_thinking
|
return self.is_thinking
|
||||||
if self.token is not None:
|
if self.token is not None:
|
||||||
|
|
@ -139,20 +195,23 @@ class Reasoning(ResponseType):
|
||||||
return f"{self.status}\n"
|
return f"{self.status}\n"
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def get_dict(self):
|
def get_dict(self) -> Dict:
|
||||||
|
"""Return a dictionary representation of the reasoning."""
|
||||||
if self.is_thinking is None:
|
if self.is_thinking is None:
|
||||||
if self.status is None:
|
if self.status is None:
|
||||||
return {"token": self.token}
|
return {"token": self.token}
|
||||||
{"token": self.token, "status": self.status}
|
return {"token": self.token, "status": self.status}
|
||||||
return {"token": self.token, "status": self.status, "is_thinking": self.is_thinking}
|
return {"token": self.token, "status": self.status, "is_thinking": self.is_thinking}
|
||||||
|
|
||||||
class Sources(ResponseType):
|
class Sources(ResponseType):
|
||||||
def __init__(self, sources: list[dict[str, str]]) -> None:
|
def __init__(self, sources: List[Dict[str, str]]) -> None:
|
||||||
|
"""Initialize with a list of source dictionaries."""
|
||||||
self.list = []
|
self.list = []
|
||||||
for source in sources:
|
for source in sources:
|
||||||
self.add_source(source)
|
self.add_source(source)
|
||||||
|
|
||||||
def add_source(self, source: dict[str, str]):
|
def add_source(self, source: Union[Dict[str, str], str]) -> None:
|
||||||
|
"""Add a source to the list, cleaning the URL if necessary."""
|
||||||
source = source if isinstance(source, dict) else {"url": source}
|
source = source if isinstance(source, dict) else {"url": source}
|
||||||
url = source.get("url", source.get("link", None))
|
url = source.get("url", source.get("link", None))
|
||||||
if url is not None:
|
if url is not None:
|
||||||
|
|
@ -161,86 +220,98 @@ class Sources(ResponseType):
|
||||||
self.list.append(source)
|
self.list.append(source)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
"""Return formatted sources as a string."""
|
||||||
|
if not self.list:
|
||||||
|
return ""
|
||||||
return "\n\n\n\n" + ("\n>\n".join([
|
return "\n\n\n\n" + ("\n>\n".join([
|
||||||
f"> [{idx}] {format_link(link['url'], link.get('title', None))}"
|
f"> [{idx}] {format_link(link['url'], link.get('title', None))}"
|
||||||
for idx, link in enumerate(self.list)
|
for idx, link in enumerate(self.list)
|
||||||
]))
|
]))
|
||||||
|
|
||||||
class YouTube(ResponseType):
|
class YouTube(ResponseType):
|
||||||
def __init__(self, ids: list[str]) -> None:
|
def __init__(self, ids: List[str]) -> None:
|
||||||
|
"""Initialize with a list of YouTube IDs."""
|
||||||
self.ids = ids
|
self.ids = ids
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
"""Return YouTube embeds as a string."""
|
||||||
|
if not self.ids:
|
||||||
|
return ""
|
||||||
return "\n\n" + ("\n".join([
|
return "\n\n" + ("\n".join([
|
||||||
f'<iframe type="text/html" src="https://www.youtube.com/embed/{id}"></iframe>'
|
f'<iframe type="text/html" src="https://www.youtube.com/embed/{id}"></iframe>'
|
||||||
for id in self.ids
|
for id in self.ids
|
||||||
]))
|
]))
|
||||||
|
|
||||||
class Audio(HiddenResponse):
|
|
||||||
def __init__(self, data: bytes) -> None:
|
|
||||||
self.data = data
|
|
||||||
|
|
||||||
def to_string(self) -> str:
|
|
||||||
data_base64 = base64.b64encode(self.data).decode()
|
|
||||||
return f"data:audio/mpeg;base64,{data_base64}"
|
|
||||||
|
|
||||||
class BaseConversation(ResponseType):
|
class BaseConversation(ResponseType):
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
"""Return an empty string by default."""
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
class JsonConversation(BaseConversation, JsonMixin):
|
class JsonConversation(BaseConversation, JsonMixin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class SynthesizeData(HiddenResponse, JsonMixin):
|
class SynthesizeData(HiddenResponse, JsonMixin):
|
||||||
def __init__(self, provider: str, data: dict):
|
def __init__(self, provider: str, data: Dict) -> None:
|
||||||
|
"""Initialize with provider and data."""
|
||||||
self.provider = provider
|
self.provider = provider
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
class RequestLogin(HiddenResponse):
|
class RequestLogin(HiddenResponse):
|
||||||
def __init__(self, label: str, login_url: str) -> None:
|
def __init__(self, label: str, login_url: str) -> None:
|
||||||
|
"""Initialize with label and login URL."""
|
||||||
self.label = label
|
self.label = label
|
||||||
self.login_url = login_url
|
self.login_url = login_url
|
||||||
|
|
||||||
def to_string(self) -> str:
|
def to_string(self) -> str:
|
||||||
|
"""Return formatted login link as a string."""
|
||||||
return format_link(self.login_url, f"[Login to {self.label}]") + "\n\n"
|
return format_link(self.login_url, f"[Login to {self.label}]") + "\n\n"
|
||||||
|
|
||||||
class ImageResponse(ResponseType):
|
class ImageResponse(ResponseType):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
images: Union[str, list],
|
images: Union[str, List[str]],
|
||||||
alt: str,
|
alt: str,
|
||||||
options: dict = {}
|
options: Dict = {}
|
||||||
):
|
) -> None:
|
||||||
|
"""Initialize with images, alt text, and options."""
|
||||||
self.images = images
|
self.images = images
|
||||||
self.alt = alt
|
self.alt = alt
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
"""Return images as markdown."""
|
||||||
return format_images_markdown(self.images, self.alt, self.get("preview"))
|
return format_images_markdown(self.images, self.alt, self.get("preview"))
|
||||||
|
|
||||||
def get(self, key: str):
|
def get(self, key: str) -> any:
|
||||||
|
"""Get an option value by key."""
|
||||||
return self.options.get(key)
|
return self.options.get(key)
|
||||||
|
|
||||||
def get_list(self) -> list[str]:
|
def get_list(self) -> List[str]:
|
||||||
|
"""Return images as a list."""
|
||||||
return [self.images] if isinstance(self.images, str) else self.images
|
return [self.images] if isinstance(self.images, str) else self.images
|
||||||
|
|
||||||
class ImagePreview(ImageResponse):
|
class ImagePreview(ImageResponse):
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
|
"""Return an empty string for preview."""
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self) -> str:
|
||||||
|
"""Return images as markdown."""
|
||||||
return super().__str__()
|
return super().__str__()
|
||||||
|
|
||||||
class PreviewResponse(HiddenResponse):
|
class PreviewResponse(HiddenResponse):
|
||||||
def __init__(self, data: str):
|
def __init__(self, data: str) -> None:
|
||||||
|
"""Initialize with data."""
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self) -> str:
|
||||||
|
"""Return data as a string."""
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
class Parameters(ResponseType, JsonMixin):
|
class Parameters(ResponseType, JsonMixin):
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
|
"""Return an empty string."""
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
class ProviderInfo(JsonMixin, HiddenResponse):
|
class ProviderInfo(JsonMixin, HiddenResponse):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import json
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Callable, AsyncIterator
|
from typing import Optional, Callable, AsyncIterator, Dict, Any, Tuple, List, Union
|
||||||
|
|
||||||
from ..typing import Messages
|
from ..typing import Messages
|
||||||
from ..providers.helper import filter_none
|
from ..providers.helper import filter_none
|
||||||
|
|
@ -17,176 +17,289 @@ from .web_search import do_search, get_search_message
|
||||||
from .files import read_bucket, get_bucket_dir
|
from .files import read_bucket, get_bucket_dir
|
||||||
from .. import debug
|
from .. import debug
|
||||||
|
|
||||||
|
# Constants
|
||||||
BUCKET_INSTRUCTIONS = """
|
BUCKET_INSTRUCTIONS = """
|
||||||
Instruction: Make sure to add the sources of cites using [[domain]](Url) notation after the reference. Example: [[a-z0-9.]](http://example.com)
|
Instruction: Make sure to add the sources of cites using [[domain]](Url) notation after the reference. Example: [[a-z0-9.]](http://example.com)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def validate_arguments(data: dict) -> dict:
|
TOOL_NAMES = {
|
||||||
if "arguments" in data:
|
"SEARCH": "search_tool",
|
||||||
if isinstance(data["arguments"], str):
|
"CONTINUE": "continue_tool",
|
||||||
data["arguments"] = json.loads(data["arguments"])
|
"BUCKET": "bucket_tool"
|
||||||
if not isinstance(data["arguments"], dict):
|
}
|
||||||
raise ValueError("Tool function arguments must be a dictionary or a json string")
|
|
||||||
|
class ToolHandler:
|
||||||
|
"""Handles processing of different tool types"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def validate_arguments(data: dict) -> dict:
|
||||||
|
"""Validate and parse tool arguments"""
|
||||||
|
if "arguments" in data:
|
||||||
|
if isinstance(data["arguments"], str):
|
||||||
|
data["arguments"] = json.loads(data["arguments"])
|
||||||
|
if not isinstance(data["arguments"], dict):
|
||||||
|
raise ValueError("Tool function arguments must be a dictionary or a json string")
|
||||||
|
else:
|
||||||
|
return filter_none(**data["arguments"])
|
||||||
else:
|
else:
|
||||||
return filter_none(**data["arguments"])
|
return {}
|
||||||
else:
|
|
||||||
return {}
|
@staticmethod
|
||||||
|
async def process_search_tool(messages: Messages, tool: dict) -> Messages:
|
||||||
def get_api_key_file(cls) -> Path:
|
"""Process search tool requests"""
|
||||||
return Path(get_cookies_dir()) / f"api_key_{cls.parent if hasattr(cls, 'parent') else cls.__name__}.json"
|
messages = messages.copy()
|
||||||
|
args = ToolHandler.validate_arguments(tool["function"])
|
||||||
async def async_iter_run_tools(provider: ProviderType, model: str, messages, tool_calls: Optional[list] = None, **kwargs):
|
messages[-1]["content"] = await do_search(
|
||||||
# Handle web_search from kwargs
|
messages[-1]["content"],
|
||||||
web_search = kwargs.get('web_search')
|
**args
|
||||||
sources = None
|
)
|
||||||
if web_search:
|
return messages
|
||||||
try:
|
|
||||||
|
@staticmethod
|
||||||
|
def process_continue_tool(messages: Messages, tool: dict, provider: Any) -> Tuple[Messages, Dict[str, Any]]:
|
||||||
|
"""Process continue tool requests"""
|
||||||
|
kwargs = {}
|
||||||
|
if provider not in ("OpenaiAccount", "HuggingFace"):
|
||||||
messages = messages.copy()
|
messages = messages.copy()
|
||||||
web_search = web_search if isinstance(web_search, str) and web_search != "true" else None
|
last_line = messages[-1]["content"].strip().splitlines()[-1]
|
||||||
messages[-1]["content"], sources = await do_search(messages[-1]["content"], web_search)
|
content = f"Carry on from this point:\n{last_line}"
|
||||||
except Exception as e:
|
messages.append({"role": "user", "content": content})
|
||||||
debug.error(f"Couldn't do web search: {e.__class__.__name__}: {e}")
|
else:
|
||||||
# Keep web_search in kwargs for provider native support
|
# Enable provider native continue
|
||||||
pass
|
kwargs["action"] = "continue"
|
||||||
|
return messages, kwargs
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def process_bucket_tool(messages: Messages, tool: dict) -> Messages:
|
||||||
|
"""Process bucket tool requests"""
|
||||||
|
messages = messages.copy()
|
||||||
|
|
||||||
|
def on_bucket(match):
|
||||||
|
return "".join(read_bucket(get_bucket_dir(match.group(1))))
|
||||||
|
|
||||||
|
has_bucket = False
|
||||||
|
for message in messages:
|
||||||
|
if "content" in message and isinstance(message["content"], str):
|
||||||
|
new_message_content = re.sub(r'{"bucket_id":"([^"]*)"}', on_bucket, message["content"])
|
||||||
|
if new_message_content != message["content"]:
|
||||||
|
has_bucket = True
|
||||||
|
message["content"] = new_message_content
|
||||||
|
|
||||||
|
if has_bucket and isinstance(messages[-1]["content"], str):
|
||||||
|
if "\nSource: " in messages[-1]["content"]:
|
||||||
|
if isinstance(messages[-1]["content"], dict):
|
||||||
|
messages[-1]["content"]["content"] += BUCKET_INSTRUCTIONS
|
||||||
|
else:
|
||||||
|
messages[-1]["content"] += BUCKET_INSTRUCTIONS
|
||||||
|
|
||||||
|
return messages
|
||||||
|
|
||||||
# Read api_key from config file
|
@staticmethod
|
||||||
if getattr(provider, "needs_auth", False) and "api_key" not in kwargs:
|
async def process_tools(messages: Messages, tool_calls: List[dict], provider: Any) -> Tuple[Messages, Dict[str, Any]]:
|
||||||
auth_file = get_api_key_file(provider)
|
"""Process all tool calls and return updated messages and kwargs"""
|
||||||
if auth_file.exists():
|
if not tool_calls:
|
||||||
with auth_file.open("r") as f:
|
return messages, {}
|
||||||
auth_result = json.load(f)
|
|
||||||
if "api_key" in auth_result:
|
extra_kwargs = {}
|
||||||
kwargs["api_key"] = auth_result["api_key"]
|
messages = messages.copy()
|
||||||
|
|
||||||
if tool_calls is not None:
|
|
||||||
for tool in tool_calls:
|
for tool in tool_calls:
|
||||||
if tool.get("type") == "function":
|
if tool.get("type") != "function":
|
||||||
if tool.get("function", {}).get("name") == "search_tool":
|
continue
|
||||||
tool["function"]["arguments"] = validate_arguments(tool["function"])
|
|
||||||
messages = messages.copy()
|
function_name = tool.get("function", {}).get("name")
|
||||||
messages[-1]["content"] = await do_search(
|
|
||||||
messages[-1]["content"],
|
if function_name == TOOL_NAMES["SEARCH"]:
|
||||||
**tool["function"]["arguments"]
|
messages = await ToolHandler.process_search_tool(messages, tool)
|
||||||
)
|
|
||||||
elif tool.get("function", {}).get("name") == "continue":
|
elif function_name == TOOL_NAMES["CONTINUE"]:
|
||||||
last_line = messages[-1]["content"].strip().splitlines()[-1]
|
messages, kwargs = ToolHandler.process_continue_tool(messages, tool, provider)
|
||||||
content = f"Carry on from this point:\n{last_line}"
|
extra_kwargs.update(kwargs)
|
||||||
messages.append({"role": "user", "content": content})
|
|
||||||
elif tool.get("function", {}).get("name") == "bucket_tool":
|
elif function_name == TOOL_NAMES["BUCKET"]:
|
||||||
def on_bucket(match):
|
messages = ToolHandler.process_bucket_tool(messages, tool)
|
||||||
return "".join(read_bucket(get_bucket_dir(match.group(1))))
|
|
||||||
has_bucket = False
|
return messages, extra_kwargs
|
||||||
for message in messages:
|
|
||||||
if "content" in message and isinstance(message["content"], str):
|
|
||||||
new_message_content = re.sub(r'{"bucket_id":"([^"]*)"}', on_bucket, message["content"])
|
class AuthManager:
|
||||||
if new_message_content != message["content"]:
|
"""Handles API key management"""
|
||||||
has_bucket = True
|
|
||||||
message["content"] = new_message_content
|
@staticmethod
|
||||||
if has_bucket and isinstance(messages[-1]["content"], str):
|
def get_api_key_file(cls) -> Path:
|
||||||
if "\nSource: " in messages[-1]["content"]:
|
"""Get the path to the API key file for a provider"""
|
||||||
messages[-1]["content"] += BUCKET_INSTRUCTIONS
|
return Path(get_cookies_dir()) / f"api_key_{cls.parent if hasattr(cls, 'parent') else cls.__name__}.json"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load_api_key(provider: Any) -> Optional[str]:
|
||||||
|
"""Load API key from config file if needed"""
|
||||||
|
if not getattr(provider, "needs_auth", False):
|
||||||
|
return None
|
||||||
|
|
||||||
|
auth_file = AuthManager.get_api_key_file(provider)
|
||||||
|
try:
|
||||||
|
if auth_file.exists():
|
||||||
|
with auth_file.open("r") as f:
|
||||||
|
auth_result = json.load(f)
|
||||||
|
return auth_result.get("api_key")
|
||||||
|
except (json.JSONDecodeError, PermissionError, FileNotFoundError) as e:
|
||||||
|
debug.error(f"Failed to load API key: {e.__class__.__name__}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ThinkingProcessor:
|
||||||
|
"""Processes thinking chunks"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def process_thinking_chunk(chunk: str, start_time: float = 0) -> Tuple[float, List[Union[str, Reasoning]]]:
|
||||||
|
"""Process a thinking chunk and return timing and results."""
|
||||||
|
results = []
|
||||||
|
|
||||||
|
# Handle non-thinking chunk
|
||||||
|
if not start_time and "<think>" not in chunk:
|
||||||
|
return 0, [chunk]
|
||||||
|
|
||||||
|
# Handle thinking start
|
||||||
|
if "<think>" in chunk and "`<think>`" not in chunk:
|
||||||
|
before_think, *after = chunk.split("<think>", 1)
|
||||||
|
|
||||||
|
if before_think:
|
||||||
|
results.append(before_think)
|
||||||
|
|
||||||
|
results.append(Reasoning(status="🤔 Is thinking...", is_thinking="<think>"))
|
||||||
|
|
||||||
|
if after and after[0]:
|
||||||
|
results.append(Reasoning(after[0]))
|
||||||
|
|
||||||
|
return time.time(), results
|
||||||
|
|
||||||
|
# Handle thinking end
|
||||||
|
if "</think>" in chunk:
|
||||||
|
before_end, *after = chunk.split("</think>", 1)
|
||||||
|
|
||||||
|
if before_end:
|
||||||
|
results.append(Reasoning(before_end))
|
||||||
|
|
||||||
|
thinking_duration = time.time() - start_time if start_time > 0 else 0
|
||||||
|
|
||||||
|
status = f"Thought for {thinking_duration:.2f}s" if thinking_duration > 1 else "Finished"
|
||||||
|
results.append(Reasoning(status=status, is_thinking="</think>"))
|
||||||
|
|
||||||
|
if after and after[0]:
|
||||||
|
results.append(after[0])
|
||||||
|
|
||||||
|
return 0, results
|
||||||
|
|
||||||
|
# Handle ongoing thinking
|
||||||
|
if start_time:
|
||||||
|
return start_time, [Reasoning(chunk)]
|
||||||
|
|
||||||
|
return start_time, [chunk]
|
||||||
|
|
||||||
|
|
||||||
|
async def perform_web_search(messages: Messages, web_search_param: Any) -> Tuple[Messages, Optional[Sources]]:
|
||||||
|
"""Perform web search and return updated messages and sources"""
|
||||||
|
messages = messages.copy()
|
||||||
|
sources = None
|
||||||
|
|
||||||
|
if not web_search_param:
|
||||||
|
return messages, sources
|
||||||
|
|
||||||
|
try:
|
||||||
|
search_query = web_search_param if isinstance(web_search_param, str) and web_search_param != "true" else None
|
||||||
|
messages[-1]["content"], sources = await do_search(messages[-1]["content"], search_query)
|
||||||
|
except Exception as e:
|
||||||
|
debug.error(f"Couldn't do web search: {e.__class__.__name__}: {e}")
|
||||||
|
|
||||||
|
return messages, sources
|
||||||
|
|
||||||
|
|
||||||
|
async def async_iter_run_tools(
|
||||||
|
provider: ProviderType,
|
||||||
|
model: str,
|
||||||
|
messages: Messages,
|
||||||
|
tool_calls: Optional[List[dict]] = None,
|
||||||
|
**kwargs
|
||||||
|
) -> AsyncIterator:
|
||||||
|
"""Asynchronously run tools and yield results"""
|
||||||
|
# Process web search
|
||||||
|
sources = None
|
||||||
|
web_search = kwargs.get('web_search')
|
||||||
|
if web_search:
|
||||||
|
messages, sources = await perform_web_search(messages, web_search)
|
||||||
|
|
||||||
|
# Get API key if needed
|
||||||
|
api_key = AuthManager.load_api_key(provider)
|
||||||
|
if api_key and "api_key" not in kwargs:
|
||||||
|
kwargs["api_key"] = api_key
|
||||||
|
|
||||||
|
# Process tool calls
|
||||||
|
if tool_calls:
|
||||||
|
messages, extra_kwargs = await ToolHandler.process_tools(messages, tool_calls, provider)
|
||||||
|
kwargs.update(extra_kwargs)
|
||||||
|
|
||||||
|
# Generate response
|
||||||
create_function = provider.get_async_create_function()
|
create_function = provider.get_async_create_function()
|
||||||
response = to_async_iterator(create_function(model=model, messages=messages, **kwargs))
|
response = to_async_iterator(create_function(model=model, messages=messages, **kwargs))
|
||||||
|
|
||||||
async for chunk in response:
|
async for chunk in response:
|
||||||
yield chunk
|
yield chunk
|
||||||
if sources is not None:
|
|
||||||
|
# Yield sources if available
|
||||||
|
if sources:
|
||||||
yield sources
|
yield sources
|
||||||
|
|
||||||
def process_thinking_chunk(chunk: str, start_time: float = 0) -> tuple[float, list]:
|
|
||||||
"""Process a thinking chunk and return timing and results."""
|
|
||||||
results = []
|
|
||||||
|
|
||||||
# Handle non-thinking chunk
|
|
||||||
if not start_time and "<think>" not in chunk:
|
|
||||||
return 0, [chunk]
|
|
||||||
|
|
||||||
# Handle thinking start
|
|
||||||
if "<think>" in chunk and not "`<think>`" in chunk:
|
|
||||||
before_think, *after = chunk.split("<think>", 1)
|
|
||||||
|
|
||||||
if before_think:
|
|
||||||
results.append(before_think)
|
|
||||||
|
|
||||||
results.append(Reasoning(status="🤔 Is thinking...", is_thinking="<think>"))
|
|
||||||
|
|
||||||
if after and after[0]:
|
|
||||||
results.append(Reasoning(after[0]))
|
|
||||||
|
|
||||||
return time.time(), results
|
|
||||||
|
|
||||||
# Handle thinking end
|
|
||||||
if "</think>" in chunk:
|
|
||||||
before_end, *after = chunk.split("</think>", 1)
|
|
||||||
|
|
||||||
if before_end:
|
|
||||||
results.append(Reasoning(before_end))
|
|
||||||
|
|
||||||
thinking_duration = time.time() - start_time if start_time > 0 else 0
|
|
||||||
|
|
||||||
status = f"Thought for {thinking_duration:.2f}s" if thinking_duration > 1 else "Finished"
|
|
||||||
results.append(Reasoning(status=status, is_thinking="</think>"))
|
|
||||||
|
|
||||||
if after and after[0]:
|
|
||||||
results.append(after[0])
|
|
||||||
|
|
||||||
return 0, results
|
|
||||||
|
|
||||||
# Handle ongoing thinking
|
|
||||||
if start_time:
|
|
||||||
return start_time, [Reasoning(chunk)]
|
|
||||||
|
|
||||||
return start_time, [chunk]
|
|
||||||
|
|
||||||
def iter_run_tools(
|
def iter_run_tools(
|
||||||
iter_callback: Callable,
|
iter_callback: Callable,
|
||||||
model: str,
|
model: str,
|
||||||
messages: Messages,
|
messages: Messages,
|
||||||
provider: Optional[str] = None,
|
provider: Optional[str] = None,
|
||||||
tool_calls: Optional[list] = None,
|
tool_calls: Optional[List[dict]] = None,
|
||||||
**kwargs
|
**kwargs
|
||||||
) -> AsyncIterator:
|
) -> AsyncIterator:
|
||||||
# Handle web_search from kwargs
|
"""Run tools synchronously and yield results"""
|
||||||
|
# Process web search
|
||||||
web_search = kwargs.get('web_search')
|
web_search = kwargs.get('web_search')
|
||||||
sources = None
|
sources = None
|
||||||
|
|
||||||
if web_search:
|
if web_search:
|
||||||
try:
|
try:
|
||||||
messages = messages.copy()
|
messages = messages.copy()
|
||||||
web_search = web_search if isinstance(web_search, str) and web_search != "true" else None
|
search_query = web_search if isinstance(web_search, str) and web_search != "true" else None
|
||||||
messages[-1]["content"], sources = asyncio.run(do_search(messages[-1]["content"], web_search))
|
# Note: Using asyncio.run inside sync function is not ideal, but maintaining original pattern
|
||||||
|
messages[-1]["content"], sources = asyncio.run(do_search(messages[-1]["content"], search_query))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
debug.error(f"Couldn't do web search: {e.__class__.__name__}: {e}")
|
debug.error(f"Couldn't do web search: {e.__class__.__name__}: {e}")
|
||||||
# Keep web_search in kwargs for provider native support
|
|
||||||
pass
|
# Get API key if needed
|
||||||
|
if provider is not None and getattr(provider, "needs_auth", False) and "api_key" not in kwargs:
|
||||||
# Read api_key from config file
|
api_key = AuthManager.load_api_key(provider)
|
||||||
if provider is not None and provider.needs_auth and "api_key" not in kwargs:
|
if api_key:
|
||||||
auth_file = get_api_key_file(provider)
|
kwargs["api_key"] = api_key
|
||||||
if auth_file.exists():
|
|
||||||
with auth_file.open("r") as f:
|
# Process tool calls
|
||||||
auth_result = json.load(f)
|
if tool_calls:
|
||||||
if "api_key" in auth_result:
|
|
||||||
kwargs["api_key"] = auth_result["api_key"]
|
|
||||||
|
|
||||||
if tool_calls is not None:
|
|
||||||
for tool in tool_calls:
|
for tool in tool_calls:
|
||||||
if tool.get("type") == "function":
|
if tool.get("type") == "function":
|
||||||
if tool.get("function", {}).get("name") == "search_tool":
|
function_name = tool.get("function", {}).get("name")
|
||||||
tool["function"]["arguments"] = validate_arguments(tool["function"])
|
|
||||||
|
if function_name == TOOL_NAMES["SEARCH"]:
|
||||||
|
tool["function"]["arguments"] = ToolHandler.validate_arguments(tool["function"])
|
||||||
messages[-1]["content"] = get_search_message(
|
messages[-1]["content"] = get_search_message(
|
||||||
messages[-1]["content"],
|
messages[-1]["content"],
|
||||||
raise_search_exceptions=True,
|
raise_search_exceptions=True,
|
||||||
**tool["function"]["arguments"]
|
**tool["function"]["arguments"]
|
||||||
)
|
)
|
||||||
elif tool.get("function", {}).get("name") == "continue_tool":
|
elif function_name == TOOL_NAMES["CONTINUE"]:
|
||||||
if provider not in ("OpenaiAccount", "HuggingFace"):
|
if provider not in ("OpenaiAccount", "HuggingFace"):
|
||||||
last_line = messages[-1]["content"].strip().splitlines()[-1]
|
last_line = messages[-1]["content"].strip().splitlines()[-1]
|
||||||
content = f"Carry on from this point:\n{last_line}"
|
content = f"Carry on from this point:\n{last_line}"
|
||||||
messages.append({"role": "user", "content": content})
|
messages.append({"role": "user", "content": content})
|
||||||
else:
|
else:
|
||||||
# Enable provider native continue
|
# Enable provider native continue
|
||||||
if "action" not in kwargs:
|
kwargs["action"] = "continue"
|
||||||
kwargs["action"] = "continue"
|
elif function_name == TOOL_NAMES["BUCKET"]:
|
||||||
elif tool.get("function", {}).get("name") == "bucket_tool":
|
|
||||||
def on_bucket(match):
|
def on_bucket(match):
|
||||||
return "".join(read_bucket(get_bucket_dir(match.group(1))))
|
return "".join(read_bucket(get_bucket_dir(match.group(1))))
|
||||||
has_bucket = False
|
has_bucket = False
|
||||||
|
|
@ -199,8 +312,11 @@ def iter_run_tools(
|
||||||
if has_bucket and isinstance(messages[-1]["content"], str):
|
if has_bucket and isinstance(messages[-1]["content"], str):
|
||||||
if "\nSource: " in messages[-1]["content"]:
|
if "\nSource: " in messages[-1]["content"]:
|
||||||
messages[-1]["content"] = messages[-1]["content"]["content"] + BUCKET_INSTRUCTIONS
|
messages[-1]["content"] = messages[-1]["content"]["content"] + BUCKET_INSTRUCTIONS
|
||||||
|
|
||||||
|
# Process response chunks
|
||||||
thinking_start_time = 0
|
thinking_start_time = 0
|
||||||
|
processor = ThinkingProcessor()
|
||||||
|
|
||||||
for chunk in iter_callback(model=model, messages=messages, provider=provider, **kwargs):
|
for chunk in iter_callback(model=model, messages=messages, provider=provider, **kwargs):
|
||||||
if isinstance(chunk, FinishReason):
|
if isinstance(chunk, FinishReason):
|
||||||
if sources is not None:
|
if sources is not None:
|
||||||
|
|
@ -214,10 +330,10 @@ def iter_run_tools(
|
||||||
yield chunk
|
yield chunk
|
||||||
continue
|
continue
|
||||||
|
|
||||||
thinking_start_time, results = process_thinking_chunk(chunk, thinking_start_time)
|
thinking_start_time, results = processor.process_thinking_chunk(chunk, thinking_start_time)
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
yield result
|
yield result
|
||||||
|
|
||||||
if sources is not None:
|
if sources is not None:
|
||||||
yield sources
|
yield sources
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue