diff --git a/docs/providers-and-models.md b/docs/providers-and-models.md index 31744eb0..6b608c1c 100644 --- a/docs/providers-and-models.md +++ b/docs/providers-and-models.md @@ -26,6 +26,7 @@ This document provides an overview of various AI providers and models, including - **Optional API key** - Works without authentication, but you can provide an API key for better rate limits or additional features. The service is usable without an API key. - **API key / Cookies** - Supports both authentication methods. You can use either an API key or browser cookies for authentication. - **No auth required** - No authentication needed. The service is publicly available without any credentials. +- **No auth / HAR file** - Supports both authentication methods. The service works without authentication, but you can also use HAR file authentication for potentially enhanced features or capabilities. **Symbols:** - ✔ - Feature is supported @@ -34,108 +35,110 @@ This document provides an overview of various AI providers and models, including --- ### Providers No auth required -| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Vision (Image Upload) | 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`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[ai-arta.com](https://ai-arta.com)|No auth required|`g4f.Provider.ARTA`|❌|✔ _**(17+)**_|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[blackbox.ai](https://www.blackbox.ai)|No auth required|`g4f.Provider.Blackbox`|`blackboxai, blackboxai-pro, gpt-4o-mini, deepseek-chat, deepseek-v3, deepseek-r1, gpt-4o, o1, o3-mini, claude-3.7-sonnet` _**(40+)**_|`flux`|❌|`blackboxai, gpt-4o, o1, o3-mini, deepseek-v3` _**(7+)**_|![](https://img.shields.io/badge/Active-brightgreen)| -|[chatglm.cn](https://chatglm.cn)|No auth required|`g4f.Provider.ChatGLM`|`glm-4`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[chatgpt.com](https://chatgpt.com)|No auth required|`g4f.Provider.ChatGpt`|✔ _**(7+)**_|❌|❌|❌|![Error](https://img.shields.io/badge/HTTPError-f48d37)| -|[chatgpt.es](https://chatgpt.es)|No auth required|`g4f.Provider.ChatGptEs`|`gpt-4, gpt-4o, gpt-4o-mini`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[playground.ai.cloudflare.com](https://playground.ai.cloudflare.com)|[Automatic cookies](https://playground.ai.cloudflare.com)|`g4f.Provider.Cloudflare`|`llama-2-7b, llama-3-8b, llama-3.1-8b, llama-3.2-1b, qwen-1.5-7b`|❌|❌|❌|![Error](https://img.shields.io/badge/Active-brightgreen)| -|[copilot.microsoft.com](https://copilot.microsoft.com)|Optional API key|`g4f.Provider.Copilot`|`gpt-4, o1`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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-24b, 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`|![](https://img.shields.io/badge/Active-brightgreen)| -|[dynaspark.onrender.com](https://dynaspark.onrender.com)|No auth required|`g4f.Provider.Dynaspark`|`gemini-1.5-flash, gemini-2.0-flash`|❌|❌|`gemini-1.5-flash, gemini-2.0-flash`|![](https://img.shields.io/badge/Active-brightgreen)| -|[chat10.free2gpt.xyz](https://chat10.free2gpt.xyz)|No auth required|`g4f.Provider.Free2GPT`|`gemini-1.5-pro, gemini-1.5-flash`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[freegptsnav.aifree.site](https://freegptsnav.aifree.site)|No auth required|`g4f.Provider.FreeGpt`|`gemini-1.5-pro, gemini-1.5-flash`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[app.giz.ai/assistant](https://app.giz.ai/assistant)|No auth required|`g4f.Provider.GizAI`|`gemini-1.5-flash`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[goabror.uz](https://goabror.uz)|No auth required|`g4f.Provider.Goabror`|`gpt-4`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[hailuo.ai](https://www.hailuo.ai)|No auth required|`g4f.Provider.HailuoAI`|`MiniMax` _**(1+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[editor.imagelabs.net](editor.imagelabs.net)|No auth required|`g4f.Provider.ImageLabs`|❌|`sdxl-turbo`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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, command-a`|`flux-dev, flux-schnell, sd-3.5`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[jmuz.me](https://jmuz.me)|Optional API key|`g4f.Provider.Jmuz`|`claude-3-haiku, claude-3-opus, 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`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[lambda.chat](https://lambda.chat)|No auth required|`g4f.Provider.LambdaChat`|`deepseek-v3, deepseek-r1, hermes-3, nemotron-70b, llama-3.3-70b`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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`|![](https://img.shields.io/badge/Active-brightgreen)| -|[labs.perplexity.ai](https://labs.perplexity.ai)|No auth required|`g4f.Provider.PerplexityLabs`|`sonar, sonar-pro, sonar-reasoning, sonar-reasoning-pro`|❌|❌|❌|![Error](https://img.shields.io/badge/Active-brightgreen)| -|[pi.ai/talk](https://pi.ai/talk)|[Manual cookies](https://pi.ai/talk)|`g4f.Provider.Pi`|`pi`|❌|❌|❌|![Error](https://img.shields.io/badge/Active-brightgreen)| -|[pizzagpt.it](https://www.pizzagpt.it)|No auth required|`g4f.Provider.Pizzagpt`|`gpt-4o-mini`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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` _**(9+)**_|`flux, flux-pro, flux-dev, flux-schnell, dall-e-3, sdxl-turbo`|`gpt-4o-audio`|`gpt-4o, gpt-4o-mini, o1-mini, o3-mini`|![](https://img.shields.io/badge/Active-brightgreen)| -|[pollinations.ai](https://pollinations.ai)|No auth required|`g4f.Provider.PollinationsImage`|❌|`flux, flux-pro, flux-dev, flux-schnell, dall-e-3, sdxl-turbo`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[teach-anything.com](https://www.teach-anything.com)|No auth required|`g4f.Provider.TeachAnything`|`gemini-1.5-pro, gemini-1.5-flash`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[chat.typegpt.net](https://chat.typegpt.net)|No auth required|`g4f.Provider.TypeGPT`|`gpt-3.5-turbo, o3-mini, deepseek-r1, deepseek-v3, evil, o1`|❌|❌|`gpt-3.5-turbo, o3-mini`|![](https://img.shields.io/badge/Active-brightgreen)| -|[you.com](https://you.com)|[Manual cookies](https://you.com)|`g4f.Provider.You`|✔|✔|❌|✔|![](https://img.shields.io/badge/Active-brightgreen)| -|[websim.ai](https://websim.ai)|No auth required|`g4f.Provider.Websim`|`gemini-1.5-pro, gemini-1.5-flash`|`flux`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[chat9.yqcloud.top](https://chat9.yqcloud.top)|No auth required|`g4f.Provider.Yqcloud`|`gpt-4`|✔|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Video generation | Vision (Image Upload) | 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, olmo-2-32b`|❌|❌|❌|`olmo-4-synthetic`|![](https://img.shields.io/badge/Active-brightgreen)| +|[ai-arta.com](https://ai-arta.com)|No auth required|`g4f.Provider.ARTA`|❌|`flux` _**(16+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[blackbox.ai](https://www.blackbox.ai)|No auth / HAR file|`g4f.Provider.Blackbox`|`blackboxai, blackboxai-pro, gpt-4o-mini, deepseek-chat, deepseek-v3, deepseek-r1, gpt-4o, o1, o3-mini, claude-3.7-sonnet, llama-3.3-70b, mixtral-small-24b, qwq-32b` _**(40+)**_|`flux`|❌|❌|`blackboxai, gpt-4o, o1, o3-mini, deepseek-v3` _**(7+)**_|![](https://img.shields.io/badge/Active-brightgreen)| +|[chatglm.cn](https://chatglm.cn)|No auth required|`g4f.Provider.ChatGLM`|`glm-4`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[chatgpt.com](https://chatgpt.com)|No auth required|`g4f.Provider.ChatGpt`|✔ _**(7+)**_|❌|❌|❌|❌|![Error](https://img.shields.io/badge/HTTPError-f48d37)| +|[chatgpt.es](https://chatgpt.es)|No auth required|`g4f.Provider.ChatGptEs`|`gpt-4, gpt-4o, gpt-4o-mini`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[playground.ai.cloudflare.com](https://playground.ai.cloudflare.com)|[Automatic cookies](https://playground.ai.cloudflare.com)|`g4f.Provider.Cloudflare`|`llama-2-7b, llama-3-8b, llama-3.1-8b, llama-3.2-1b, qwen-1.5-7b`|❌|❌|❌|❌|![Error](https://img.shields.io/badge/Active-brightgreen)| +|[copilot.microsoft.com](https://copilot.microsoft.com)|Optional API key|`g4f.Provider.Copilot`|`gpt-4, o1`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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-24b, 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`|![](https://img.shields.io/badge/Active-brightgreen)| +|[dynaspark.onrender.com](https://dynaspark.onrender.com)|No auth required|`g4f.Provider.Dynaspark`|`gemini-1.5-flash, gemini-2.0-flash`|❌|❌|❌|`gemini-1.5-flash, gemini-2.0-flash`|![](https://img.shields.io/badge/Active-brightgreen)| +|[chat10.free2gpt.xyz](https://chat10.free2gpt.xyz)|No auth required|`g4f.Provider.Free2GPT`|`gemini-1.5-pro, gemini-1.5-flash`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[freegptsnav.aifree.site](https://freegptsnav.aifree.site)|No auth required|`g4f.Provider.FreeGpt`|`gemini-1.5-pro, gemini-1.5-flash`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[app.giz.ai/assistant](https://app.giz.ai/assistant)|No auth required|`g4f.Provider.GizAI`|`gemini-1.5-flash`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[goabror.uz](https://goabror.uz)|No auth required|`g4f.Provider.Goabror`|`gpt-4`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[hailuo.ai](https://www.hailuo.ai)|No auth required|`g4f.Provider.HailuoAI`|`MiniMax` _**(1+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[editor.imagelabs.net](editor.imagelabs.net)|No auth required|`g4f.Provider.ImageLabs`|❌|`sdxl-turbo`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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, command-a`|`flux-dev, flux-schnell, sd-3.5`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[jmuz.me](https://jmuz.me)|Optional API key|`g4f.Provider.Jmuz`|`claude-3-haiku, claude-3-opus, 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`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[lambda.chat](https://lambda.chat)|No auth required|`g4f.Provider.LambdaChat`|`deepseek-v3, deepseek-r1, hermes-3, nemotron-70b, llama-3.3-70b`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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`|![](https://img.shields.io/badge/Active-brightgreen)| +|[labs.perplexity.ai](https://labs.perplexity.ai)|No auth required|`g4f.Provider.PerplexityLabs`|`sonar, sonar-pro, sonar-reasoning, sonar-reasoning-pro`|❌|❌|❌|❌|![Error](https://img.shields.io/badge/Active-brightgreen)| +|[pi.ai/talk](https://pi.ai/talk)|[Manual cookies](https://pi.ai/talk)|`g4f.Provider.Pi`|`pi`|❌|❌|❌|❌|![Error](https://img.shields.io/badge/Active-brightgreen)| +|[pizzagpt.it](https://www.pizzagpt.it)|No auth required|`g4f.Provider.Pizzagpt`|`gpt-4o-mini`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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. qwq-32b, deepseek-v3, llama-3.2-11b` _**(9+)**_|`flux, flux-pro, flux-dev, flux-schnell, dall-e-3, sdxl-turbo`|`gpt-4o-audio` _**(3+)**_|❌|`gpt-4o, gpt-4o-mini, o1-mini, o3-mini`|![](https://img.shields.io/badge/Active-brightgreen)| +|[pollinations.ai](https://pollinations.ai)|No auth required|`g4f.Provider.PollinationsImage`|❌|`flux, flux-pro, flux-dev, flux-schnell, dall-e-3, sdxl-turbo`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[teach-anything.com](https://www.teach-anything.com)|No auth required|`g4f.Provider.TeachAnything`|`gemini-1.5-pro, gemini-1.5-flash`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[chat.typegpt.net](https://chat.typegpt.net)|No auth required|`g4f.Provider.TypeGPT`|`gpt-3.5-turbo, o3-mini, deepseek-r1, deepseek-v3, evil, o1`|❌|❌|❌|`gpt-3.5-turbo, o3-mini`|![](https://img.shields.io/badge/Active-brightgreen)| +|[you.com](https://you.com)|[Manual cookies](https://you.com)|`g4f.Provider.You`|✔|✔|❌|❌|✔|![](https://img.shields.io/badge/Active-brightgreen)| +|[websim.ai](https://websim.ai)|No auth required|`g4f.Provider.Websim`|`gemini-1.5-pro, gemini-1.5-flash`|`flux`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[chat9.yqcloud.top](https://chat9.yqcloud.top)|No auth required|`g4f.Provider.Yqcloud`|`gpt-4`|✔|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| --- ### Providers HuggingFace -| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Vision (Image Upload) | 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`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[huggingface.co/chat](https://huggingface.co/chat)|[API key / Cookies](https://huggingface.co/settings/tokens)|`g4f.Provider.HuggingFace`|✔ _**(47+)**_|✔ _**(9+)**_|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[api-inference.huggingface.co](https://api-inference.huggingface.co)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.HuggingFaceAPI`|✔ _**(9+)**_|✔ _**(2+)**_|❌|✔ _**(1+)**_|![](https://img.shields.io/badge/Active-brightgreen)| +| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Video generation | Vision (Image Upload) | 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`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[huggingface.co/chat](https://huggingface.co/chat)|[API key / Cookies](https://huggingface.co/settings/tokens)|`g4f.Provider.HuggingFace`|✔ _**(47+)**_|✔ _**(9+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[api-inference.huggingface.co](https://api-inference.huggingface.co)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.HuggingFaceAPI`|✔ _**(9+)**_|✔ _**(2+)**_|❌|❌|✔ _**(1+)**_|![](https://img.shields.io/badge/Active-brightgreen)| --- ### Providers HuggingSpace -| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Vision (Image Upload) | Status | -|----------|-------------|--------------|---------------|--------|--------|------|------| -|[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.BlackForestLabs_Flux1Dev`|❌|`flux, flux-dev`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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.BlackForestLabs_Flux1Schnell`|❌|`flux, flux-schnell`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[cohereforai-c4ai-command.hf.space](https://cohereforai-c4ai-command.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.CohereForAI_C4AI_Command`|`command-r, command-r-plus, command-r7b`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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.DeepseekAI_Janus_Pro_7b`|✔|✔|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[roxky-flux-1-dev.hf.space](https://roxky-flux-1-dev.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.G4F`|✔ _**(1+)**_|✔ _**(4+)**_|❌|✔ _**(1+)**_|![](https://img.shields.io/badge/Active-brightgreen)| -|[microsoft-phi-4-multimodal.hf.space](https://microsoft-phi-4-multimodal.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Microsoft_Phi_4`|`phi-4`|❌|❌|`phi-4`|![](https://img.shields.io/badge/Active-brightgreen)| -|[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`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[qwen-qwen2-5.hf.space](https://qwen-qwen2-5.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_Qwen_2_5`|`qwen-2.5`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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`|`qwen-2.5-1m`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[qwen-qwen2-5-max-demo.hf.space](https://qwen-qwen2-5-max-demo.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_Qwen_2_5_Max`|`qwen-2-5-max`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[qwen-qwen2-72b-instruct.hf.space](https://qwen-qwen2-72b-instruct.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_Qwen_2_72B`|`qwen-2-72b`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[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.StabilityAI_SD35Large`|❌|`sd-3.5`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[voodoohop-flux-1-schnell.hf.space](https://voodoohop-flux-1-schnell.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Voodoohop_Flux1Schnell`|❌|`flux, flux-schnell`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Video generation | Vision (Image Upload) | Status | +|----------|-------------|--------------|---------------|--------|--------|------|------|------| +|[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.BlackForestLabs_Flux1Dev`|❌|`flux, flux-dev`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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.BlackForestLabs_Flux1Schnell`|❌|`flux, flux-schnell`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[cohereforai-c4ai-command.hf.space](https://cohereforai-c4ai-command.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.CohereForAI_C4AI_Command`|`command-r, command-r-plus, command-r7b`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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.DeepseekAI_Janus_Pro_7b`|✔|✔|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[roxky-flux-1-dev.hf.space](https://roxky-flux-1-dev.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.G4F`|✔ _**(1+)**_|✔ _**(4+)**_|❌|❌|✔ _**(1+)**_|![](https://img.shields.io/badge/Active-brightgreen)| +|[microsoft-phi-4-multimodal.hf.space](https://microsoft-phi-4-multimodal.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Microsoft_Phi_4`|`phi-4`|❌|❌|❌|`phi-4`|![](https://img.shields.io/badge/Active-brightgreen)| +|[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`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[qwen-qwen2-5.hf.space](https://qwen-qwen2-5.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_Qwen_2_5`|`qwen-2.5`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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`|`qwen-2.5-1m`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[qwen-qwen2-5-max-demo.hf.space](https://qwen-qwen2-5-max-demo.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_Qwen_2_5_Max`|`qwen-2-5-max`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[qwen-qwen2-72b-instruct.hf.space](https://qwen-qwen2-72b-instruct.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Qwen_Qwen_2_72B`|`qwen-2-72b`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[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.StabilityAI_SD35Large`|❌|`sd-3.5`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[voodoohop-flux-1-schnell.hf.space](https://voodoohop-flux-1-schnell.hf.space)|[Get API key](https://huggingface.co/settings/tokens)|`g4f.Provider.Voodoohop_Flux1Schnell`|❌|`flux, flux-schnell`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| ### Providers Local -| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Vision (Image Upload) | Status | -|----------|-------------|--------------|---------------|--------|--------|------|------| -|[]( )|No auth required|`g4f.Provider.Local`|✔|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[ollama.com](https://ollama.com)|No auth required|`g4f.Provider.Ollama`|✔|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Video generation | Vision (Image Upload) | Status | +|----------|-------------|--------------|---------------|--------|--------|------|------|------| +|[]( )|No auth required|`g4f.Provider.Local`|✔|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[ollama.com](https://ollama.com)|No auth required|`g4f.Provider.Ollama`|✔|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| --- ### Providers MiniMax -| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Vision (Image Upload) | 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+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Video generation | Vision (Image Upload) | 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+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| --- ### Providers Needs Auth -| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Vision (Image Upload) | Status | -|----------|-------------|--------------|---------------|--------|--------|------|------| -|[console.anthropic.com](https://console.anthropic.com)|[Get API key](https://console.anthropic.com/settings/keys)|`g4f.Provider.Anthropic`|✔ _**(8+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[bing.com/images/create](https://www.bing.com/images/create)|[Manual cookies](https://www.bing.com)|`g4f.Provider.BingCreateImages`|❌|`dall-e-3`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[cablyai.com/chat](https://cablyai.com/chat)|[Get API key](https://cablyai.com)|`g4f.Provider.CablyAI`|✔|✔|❌|✔|![](https://img.shields.io/badge/Active-brightgreen)| -|[inference.cerebras.ai](https://inference.cerebras.ai/)|[Get API key](https://cloud.cerebras.ai)|`g4f.Provider.Cerebras`|✔ _**(3+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[copilot.microsoft.com](https://copilot.microsoft.com)|[Manual cookies](https://copilot.microsoft.com)|`g4f.Provider.CopilotAccount`|✔ _**(1+)**_|✔ _**(1+)**_|❌|✔ _**(1+)**_|![](https://img.shields.io/badge/Active-brightgreen)| -|[deepinfra.com](https://deepinfra.com)|[Get API key](https://deepinfra.com/dash/api_keys)|`g4f.Provider.DeepInfra`|✔ _**(17+)**_|✔ _**(6+)**_|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[platform.deepseek.com](https://platform.deepseek.com)|[Get API key](https://platform.deepseek.com/api_keys)|`g4f.Provider.DeepSeek`|✔ _**(1+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[gemini.google.com](https://gemini.google.com)|[Manual cookies](https://gemini.google.com)|`g4f.Provider.Gemini`|`gemini-2.0`|`gemini-2.0`|❌|`gemini-2.0`|![](https://img.shields.io/badge/Active-brightgreen)| -|[ai.google.dev](https://ai.google.dev)|[Get API key](https://aistudio.google.com/u/0/apikey)|`g4f.Provider.GeminiPro`|`gemini-1.5-flash, gemini-1.5-pro, gemini-2.0-flash`|❌|❌|`gemini-1.5-pro`|![](https://img.shields.io/badge/Active-brightgreen)| -|[developers.sber.ru/gigachat](https://developers.sber.ru/gigachat)|[Manual cookies](https://developers.sber.ru/gigachat)|`g4f.Provider.GigaChat`|✔ _**(3+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[github.com/copilot](https://github.com/copilot)|[Manual cookies](https://github.com/copilot)|`g4f.Provider.GithubCopilot`|✔ _**(4+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[glhf.chat](https://glhf.chat)|[Get API key](https://glhf.chat/user-settings/api)|`g4f.Provider.GlhfChat`|✔ _**(22+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[console.groq.com/playground](https://console.groq.com/playground)|[Get API key](https://console.groq.com/keys)|`g4f.Provider.Groq`|✔ _**(18+)**_|❌|❌|✔|![](https://img.shields.io/badge/Active-brightgreen)| -|[meta.ai](https://www.meta.ai)|[Manual cookies](https://www.meta.ai)|`g4f.Provider.MetaAI`|`meta-ai`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[meta.ai](https://www.meta.ai)|[Manual cookies](https://www.meta.ai)|`g4f.Provider.MetaAIAccount`|❌|`meta-ai`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[designer.microsoft.com](https://designer.microsoft.com)|[Manual cookies](https://designer.microsoft.com)|`g4f.Provider.MicrosoftDesigner`|❌|`dall-e-3`|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[platform.openai.com](https://platform.openai.com)|[Get API key](https://platform.openai.com/settings/organization/api-keys)|`g4f.Provider.OpenaiAPI`|✔|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[chatgpt.com](https://chatgpt.com)|[Manual cookies](https://chatgpt.com)|`g4f.Provider.OpenaiChat`|`gpt-4o, gpt-4o-mini, gpt-4` _**(8+)**_|✔ _**(1)**_|❌|✔ _**(8+)**_|![](https://img.shields.io/badge/Active-brightgreen)| -|[perplexity.ai](https://www.perplexity.ai)|[Get API key](https://www.perplexity.ai/settings/api)|`g4f.Provider.PerplexityApi`|✔ _**(6+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[chat.reka.ai](https://chat.reka.ai)|[Manual cookies](https://chat.reka.ai)|`g4f.Provider.Reka`|`reka-core`|✔|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[replicate.com](https://replicate.com)|[Get API key](https://replicate.com/account/api-tokens)|`g4f.Provider.Replicate`|✔ _**(1+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[beta.theb.ai](https://beta.theb.ai)|[Get API key](https://beta.theb.ai)|`g4f.Provider.ThebApi`|✔ _**(21+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[whiterabbitneo.com](https://www.whiterabbitneo.com)|[Manual cookies](https://www.whiterabbitneo.com)|`g4f.Provider.WhiteRabbitNeo`|✔|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| -|[console.x.ai](https://console.x.ai)|[Get API key](https://console.x.ai)|`g4f.Provider.xAI`|✔|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +| Website | API Credentials | Provider | Text generation | Image generation | Audio generation | Video generation | Vision (Image Upload) | Status | +|----------|-------------|--------------|---------------|--------|--------|------|------|------| +|[console.anthropic.com](https://console.anthropic.com)|[Get API key](https://console.anthropic.com/settings/keys)|`g4f.Provider.Anthropic`|✔ _**(8+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[bing.com/images/create](https://www.bing.com/images/create)|[Manual cookies](https://www.bing.com)|`g4f.Provider.BingCreateImages`|❌|`dall-e-3`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[cablyai.com/chat](https://cablyai.com/chat)|[Get API key](https://cablyai.com)|`g4f.Provider.CablyAI`|✔|✔|❌|❌|✔|![](https://img.shields.io/badge/Active-brightgreen)| +|[inference.cerebras.ai](https://inference.cerebras.ai/)|[Get API key](https://cloud.cerebras.ai)|`g4f.Provider.Cerebras`|✔ _**(3+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[copilot.microsoft.com](https://copilot.microsoft.com)|[Manual cookies](https://copilot.microsoft.com)|`g4f.Provider.CopilotAccount`|✔ _**(1+)**_|✔ _**(1+)**_|❌|❌|✔ _**(1+)**_|![](https://img.shields.io/badge/Active-brightgreen)| +|[deepinfra.com](https://deepinfra.com)|[Get API key](https://deepinfra.com/dash/api_keys)|`g4f.Provider.DeepInfra`|✔ _**(17+)**_|✔ _**(6+)**_|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[platform.deepseek.com](https://platform.deepseek.com)|[Get API key](https://platform.deepseek.com/api_keys)|`g4f.Provider.DeepSeek`|✔ _**(1+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[gemini.google.com](https://gemini.google.com)|[Manual cookies](https://gemini.google.com)|`g4f.Provider.Gemini`|`gemini-2.0`|`gemini-2.0`|❌|❌|`gemini-2.0`|![](https://img.shields.io/badge/Active-brightgreen)| +|[ai.google.dev](https://ai.google.dev)|[Get API key](https://aistudio.google.com/u/0/apikey)|`g4f.Provider.GeminiPro`|`gemini-1.5-flash, gemini-1.5-pro, gemini-2.0-flash`|❌|❌|❌|`gemini-1.5-pro`|![](https://img.shields.io/badge/Active-brightgreen)| +|[developers.sber.ru/gigachat](https://developers.sber.ru/gigachat)|[Manual cookies](https://developers.sber.ru/gigachat)|`g4f.Provider.GigaChat`|✔ _**(3+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[github.com/copilot](https://github.com/copilot)|[Manual cookies](https://github.com/copilot)|`g4f.Provider.GithubCopilot`|✔ _**(4+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[glhf.chat](https://glhf.chat)|[Get API key](https://glhf.chat/user-settings/api)|`g4f.Provider.GlhfChat`|✔ _**(22+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[console.groq.com/playground](https://console.groq.com/playground)|[Get API key](https://console.groq.com/keys)|`g4f.Provider.Groq`|✔ _**(18+)**_|❌|❌|❌|✔|![](https://img.shields.io/badge/Active-brightgreen)| +|[meta.ai](https://www.meta.ai)|[Manual cookies](https://www.meta.ai)|`g4f.Provider.MetaAI`|`meta-ai`|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[meta.ai](https://www.meta.ai)|[Manual cookies](https://www.meta.ai)|`g4f.Provider.MetaAIAccount`|❌|`meta-ai`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[designer.microsoft.com](https://designer.microsoft.com)|[Manual cookies](https://designer.microsoft.com)|`g4f.Provider.MicrosoftDesigner`|❌|`dall-e-3`|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[platform.openai.com](https://platform.openai.com)|[Get API key](https://platform.openai.com/settings/organization/api-keys)|`g4f.Provider.OpenaiAPI`|✔|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[chatgpt.com](https://chatgpt.com)|[Manual cookies](https://chatgpt.com)|`g4f.Provider.OpenaiChat`|`gpt-4o, gpt-4o-mini, gpt-4` _**(8+)**_|✔ _**(1)**_|❌|❌|✔ _**(8+)**_|![](https://img.shields.io/badge/Active-brightgreen)| +|[perplexity.ai](https://www.perplexity.ai)|[Get API key](https://www.perplexity.ai/settings/api)|`g4f.Provider.PerplexityApi`|✔ _**(6+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[chatgpt.com](https://chatgpt.com)|[Manual cookies](https://chatgpt.com)|`g4f.Provider.OpenaiChat`|`gpt-4o, gpt-4o-mini, gpt-4` _**(8+)**_|✔ _**(1)**_|❌|❌|✔ _**(8+)**_|![](https://img.shields.io/badge/Active-brightgreen)| +|[perplexity.ai](https://www.perplexity.ai)|[Get API key](https://www.perplexity.ai/settings/api)|`g4f.Provider.PerplexityApi`|✔ _**(6+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[chat.reka.ai](https://chat.reka.ai)|[Manual cookies](https://chat.reka.ai)|`g4f.Provider.Reka`|`reka-core`|✔|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[replicate.com](https://replicate.com)|[Get API key](https://replicate.com/account/api-tokens)|`g4f.Provider.Replicate`|✔ _**(1+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[beta.theb.ai](https://beta.theb.ai)|[Get API key](https://beta.theb.ai)|`g4f.Provider.ThebApi`|✔ _**(21+)**_|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[whiterabbitneo.com](https://www.whiterabbitneo.com)|[Manual cookies](https://www.whiterabbitneo.com)|`g4f.Provider.WhiteRabbitNeo`|✔|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| +|[console.x.ai](https://console.x.ai)|[Get API key](https://console.x.ai)|`g4f.Provider.xAI`|✔|❌|❌|❌|❌|![](https://img.shields.io/badge/Active-brightgreen)| --- ## Models @@ -160,13 +163,13 @@ This document provides an overview of various AI providers and models, including |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-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|4+ Providers|[ai.meta.com](https://ai.meta.com/blog/llama-3-2-connect-2024-vision-edge-mobile-devices/)| |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|7+ Providers|[ai.meta.com](https://ai.meta.com/blog/llama-3-3/)| +|llama-3.3-70b|Meta Llama|8+ 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-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)| -|mixtral-small-24b|Mistral|2+ Providers|[huggingface.co](https://huggingface.co/mistralai/Mistral-Small-24B-Instruct-2501)| +|mixtral-small-24b|Mistral|3+ Providers|[huggingface.co](https://huggingface.co/mistralai/Mistral-Small-24B-Instruct-2501)| |hermes-3|NousResearch|1+ Providers|[huggingface.co](https://huggingface.co/NousResearch/Hermes-3-Llama-3.1-405B-FP8)| |phi-3.5-mini|Microsoft|1+ Providers|[huggingface.co](https://huggingface.co/microsoft/Phi-3.5-mini-instruct)| |phi-4|Microsoft|3+ 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)| @@ -199,11 +202,11 @@ This document provides an overview of various AI providers and models, including |qwen-2.5-coder-32b|Qwen|3+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2.5-Coder-32B)| |qwen-2.5-1m|Qwen|1+ Providers|[huggingface.co](https://huggingface.co/Qwen/Qwen2.5-1M-Demo)| |qwen-2-5-max|Qwen|1+ Providers|[qwen-ai.com](https://www.qwen-ai.com/2-5-max/)| -|qwq-32b|Qwen|2+ Providers|[huggingface.co](https://huggingface.co/Qwen/QwQ-32B-Preview)| +|qwq-32b|Qwen|4+ Providers|[huggingface.co](https://huggingface.co/Qwen/QwQ-32B-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)| |deepseek-chat|DeepSeek|2+ Providers|[huggingface.co](https://huggingface.co/deepseek-ai/deepseek-llm-67b-chat)| -|deepseek-v3|DeepSeek|5+ Providers|[api-docs.deepseek.com](https://api-docs.deepseek.com/news/news250120)| +|deepseek-v3|DeepSeek|6+ Providers|[api-docs.deepseek.com](https://api-docs.deepseek.com/news/news250120)| |deepseek-r1|DeepSeek|10+ Providers|[api-docs.deepseek.com](https://api-docs.deepseek.com/news/news250120)| |janus-pro-7b|DeepSeek|2+ Providers|[api-docs.deepseek.com](https://api-docs.deepseek.com/docs/janus-pro-7b)| |grok-3|x.ai|1+ Providers|[x.ai](https://x.ai/blog/grok-3)| @@ -223,11 +226,13 @@ This document provides an overview of various AI providers and models, including |airoboros-70b|DeepInfra|1+ Providers|[huggingface.co](https://huggingface.co/cognitivecomputations/dolphin-2.9.1-llama-3-70b)| |lzlv-70b|Lizpreciatior|1+ Providers|[huggingface.co](https://huggingface.co/cognitivecomputations/dolphin-2.9.1-llama-3-70b)| |minicpm-2.5|OpenBMB|1+ Providers|[huggingface.co](https://huggingface.co/openbmb/MiniCPM-Llama3-V-2_5)| -|tulu-3-405b|Ai2|1+ Providers|[allenai.org](https://allenai.org/documentation)| -|olmo-2-13b|Ai2|1+ Providers|[allenai.org](https://allenai.org/documentation)| |tulu-3-1-8b|Ai2|1+ Providers|[allenai.org](https://allenai.org/documentation)| |tulu-3-70b|Ai2|1+ Providers|[allenai.org](https://allenai.org/documentation)| -|olmoe-0125|Ai2|1+ Providers|[allenai.org](https://allenai.org/documentation)| +|tulu-3-405b|Ai2|1+ Providers|[allenai.org](https://allenai.org/documentation)| +|olmo-1-7b|Ai2|1+ Providers|[allenai.org](https://allenai.org/olmo)| +|olmo-2-13b|Ai2|1+ Providers|[allenai.org](https://allenai.org/olmo)| +|olmo-2-32b|Ai2|1+ Providers|[allenai.org](https://allenai.org/olmo)| +|olmo-4-synthetic|Ai2|1+ Providers|[allenai.org](https://allenai.org/olmo)| |lfm-40b|Liquid AI|1+ Providers|[liquid.ai](https://www.liquid.ai/liquid-foundation-models)| |evil|Evil Mode - Experimental|2+ Providers|[]( )| @@ -237,7 +242,7 @@ This document provides an overview of various AI providers and models, including |-------|---------------|-----------|---------| |sdxl-turbo|Stability AI|2+ Providers|[huggingface.co](https://huggingface.co/stabilityai/sdxl-turbo)| |sd-3.5|Stability AI|1+ Providers|[huggingface.co](https://huggingface.co/stabilityai/stable-diffusion-3.5-large)| -|flux|Black Forest Labs|4+ Providers|[github.com/black-forest-labs/flux](https://github.com/black-forest-labs/flux)| +|flux|Black Forest Labs|5+ Providers|[github.com/black-forest-labs/flux](https://github.com/black-forest-labs/flux)| |flux-pro|Black Forest Labs|1+ Providers|[huggingface.co](https://huggingface.co/enhanceaiteam/FLUX.1-Pro)| |flux-dev|Black Forest Labs|4+ Providers|[huggingface.co](https://huggingface.co/black-forest-labs/FLUX.1-dev)| |flux-schnell|Black Forest Labs|4+ Providers|[huggingface.co](https://huggingface.co/black-forest-labs/FLUX.1-schnell)| diff --git a/etc/tool/commit.py b/etc/tool/commit.py new file mode 100755 index 00000000..568a3ef8 --- /dev/null +++ b/etc/tool/commit.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +""" +AI Commit Message Generator using gpt4free (g4f) + +This tool uses AI to generate meaningful git commit messages based on +staged changes. It analyzes the git diff and suggests appropriate commit +messages following conventional commit format. + +Usage: + python -m etc.tool.commit +""" +import subprocess +import sys +from g4f.client import Client + +def get_git_diff(): + """Get the current git diff for staged changes""" + try: + diff_process = subprocess.run( + ["git", "diff", "--staged"], + capture_output=True, + text=True + ) + return diff_process.stdout + except Exception as e: + print(f"Error running git diff: {e}") + return None + +def generate_commit_message(diff_text): + """Generate a commit message based on the git diff""" + if not diff_text or diff_text.strip() == "": + return "No changes staged for commit" + + client = Client() + + prompt = f""" + {diff_text} + ``` + + Analyze ONLY the exact changes in this git diff and create a precise commit message. + + FORMAT: + 1. First line: ": " (max 70 chars) + - Type: feat, fix, docs, refactor, test, etc. + - Summary must describe ONLY actual changes shown in the diff + + 2. Leave one blank line + + 3. Add sufficient bullet points to: + - Describe ALL specific changes seen in the diff + - Reference exact functions/files/components that were modified + - Do NOT mention anything not explicitly shown in the code changes + - Avoid general statements or assumptions not directly visible in diff + - Include enough points to cover all significant changes (don't limit to a specific number) + + IMPORTANT: Be 100% factual. Only mention code that was actually changed. Never invent or assume changes not shown in the diff. If unsure about a change's purpose, describe what changed rather than why. Output nothing except for the commit message, and don't surround it in quotes. + """ + + try: + response = client.chat.completions.create( + model="claude-3.7-sonnet", + messages=[{"role": "user", "content": prompt}] + ) + + return response.choices[0].message.content.strip() + except Exception as e: + print(f"Error generating commit message: {e}") + return None + +def main(): + print("Fetching git diff...") + diff = get_git_diff() + + if diff is None: + print("Failed to get git diff. Are you in a git repository?") + sys.exit(1) + + if diff.strip() == "": + print("No changes staged for commit. Stage changes with 'git add' first.") + sys.exit(0) + + print("Generating commit message...") + commit_message = generate_commit_message(diff) + + if commit_message: + print("\nGenerated commit message:") + print("-" * 50) + print(commit_message) + print("-" * 50) + + user_input = input("\nDo you want to use this commit message? (y/n): ") + if user_input.lower() == 'y': + try: + subprocess.run( + ["git", "commit", "-m", commit_message], + check=True + ) + print("Commit successful!") + except subprocess.CalledProcessError as e: + print(f"Error making commit: {e}") + else: + print("Failed to generate commit message.") + +if __name__ == "__main__": + main() diff --git a/g4f/Provider/ARTA.py b/g4f/Provider/ARTA.py index 9aeda361..008ce38c 100644 --- a/g4f/Provider/ARTA.py +++ b/g4f/Provider/ARTA.py @@ -27,7 +27,8 @@ class ARTA(AsyncGeneratorProvider, ProviderModelMixin): default_model = "Flux" default_image_model = default_model model_aliases = { - "flux": "Flux", + default_image_model: default_image_model, + "flux": default_image_model, "medieval": "Medieval", "vincent_van_gogh": "Vincent Van Gogh", "f_dev": "F Dev", @@ -91,7 +92,17 @@ class ARTA(AsyncGeneratorProvider, ProviderModelMixin): # Step 1: Generate Authentication Token auth_payload = {"clientType": "CLIENT_TYPE_ANDROID"} async with session.post(cls.auth_url, json=auth_payload, proxy=proxy) as auth_response: - auth_data = await auth_response.json() + if auth_response.status >= 400: + error_text = await auth_response.text() + raise ResponseError(f"Failed to obtain authentication token. Status: {auth_response.status}, Response: {error_text}") + + try: + auth_data = await auth_response.json() + except Exception as e: + error_text = await auth_response.text() + content_type = auth_response.headers.get('Content-Type', 'unknown') + raise ResponseError(f"Failed to parse auth response as JSON. Content-Type: {content_type}, Error: {str(e)}, Response: {error_text}") + auth_token = auth_data.get("idToken") #refresh_token = auth_data.get("refreshToken") if not auth_token: @@ -107,7 +118,17 @@ class ARTA(AsyncGeneratorProvider, ProviderModelMixin): "refresh_token": refresh_token, } async with session.post(cls.token_refresh_url, data=payload, proxy=proxy) as response: - response_data = await response.json() + if response.status >= 400: + error_text = await response.text() + raise ResponseError(f"Failed to refresh token. Status: {response.status}, Response: {error_text}") + + try: + response_data = await response.json() + except Exception as e: + error_text = await response.text() + content_type = response.headers.get('Content-Type', 'unknown') + raise ResponseError(f"Failed to parse token refresh response as JSON. Content-Type: {content_type}, Error: {str(e)}, Response: {error_text}") + return response_data.get("id_token"), response_data.get("refresh_token") @classmethod @@ -167,9 +188,18 @@ class ARTA(AsyncGeneratorProvider, ProviderModelMixin): } async with session.post(cls.image_generation_url, data=image_payload, headers=headers, proxy=proxy) as image_response: - image_data = await image_response.json() + if image_response.status >= 400: + error_text = await image_response.text() + raise ResponseError(f"Failed to initiate image generation. Status: {image_response.status}, Response: {error_text}") + + try: + image_data = await image_response.json() + except Exception as e: + error_text = await image_response.text() + content_type = image_response.headers.get('Content-Type', 'unknown') + raise ResponseError(f"Failed to parse response as JSON. Content-Type: {content_type}, Error: {str(e)}, Response: {error_text}") + record_id = image_data.get("record_id") - if not record_id: raise ResponseError(f"Failed to initiate image generation: {image_data}") @@ -180,7 +210,17 @@ class ARTA(AsyncGeneratorProvider, ProviderModelMixin): last_status = None while True: async with session.get(status_url, headers=headers, proxy=proxy) as status_response: - status_data = await status_response.json() + if status_response.status >= 400: + error_text = await status_response.text() + raise ResponseError(f"Failed to check image generation status. Status: {status_response.status}, Response: {error_text}") + + try: + status_data = await status_response.json() + except Exception as e: + error_text = await status_response.text() + content_type = status_response.headers.get('Content-Type', 'unknown') + raise ResponseError(f"Failed to parse status response as JSON. Content-Type: {content_type}, Error: {str(e)}, Response: {error_text}") + status = status_data.get("status") if status == "DONE": diff --git a/g4f/Provider/AllenAI.py b/g4f/Provider/AllenAI.py index bac03e6b..1e8298a8 100644 --- a/g4f/Provider/AllenAI.py +++ b/g4f/Provider/AllenAI.py @@ -2,21 +2,23 @@ from __future__ import annotations import json from uuid import uuid4 from aiohttp import ClientSession -from ..typing import AsyncResult, Messages +from ..typing import AsyncResult, Messages, MediaListType +from ..image import to_bytes, is_accepted_format, to_data_uri from .base_provider import AsyncGeneratorProvider, ProviderModelMixin from ..requests.raise_for_status import raise_for_status from ..providers.response import FinishReason, JsonConversation -from .helper import format_prompt, get_last_user_message +from .helper import format_prompt, get_last_user_message, format_image_prompt +from ..tools.media import merge_media class Conversation(JsonConversation): - parent: str = None x_anonymous_user_id: str = None def __init__(self, model: str): super().__init__() # Ensure parent class is initialized self.model = model self.messages = [] # Instance-specific list + self.parent = None # Initialize parent as instance attribute if not self.x_anonymous_user_id: self.x_anonymous_user_id = str(uuid4()) @@ -35,42 +37,73 @@ class AllenAI(AsyncGeneratorProvider, ProviderModelMixin): supports_message_history = True default_model = 'tulu3-405b' - models = [ - default_model, - 'OLMo-2-1124-13B-Instruct', - 'tulu-3-1-8b', - 'Llama-3-1-Tulu-3-70B', - 'olmoe-0125' - ] + default_vision_model = 'mm-olmo-uber-model-v4-synthetic' + vision_models = [default_vision_model] + # Map models to their required hosts + model_hosts = { + default_model: "inferd", + "OLMo-2-1124-13B-Instruct": "modal", + "tulu-3-1-8b": "modal", + "Llama-3-1-Tulu-3-70B": "modal", + "olmoe-0125": "modal", + "olmo-2-0325-32b-instruct": "modal", + "mm-olmo-uber-model-v4-synthetic": "modal", + } + + models = list(model_hosts.keys()) model_aliases = { "tulu-3-405b": default_model, + "olmo-1-7b": "olmoe-0125", "olmo-2-13b": "OLMo-2-1124-13B-Instruct", + "olmo-2-32b": "olmo-2-0325-32b-instruct", "tulu-3-1-8b": "tulu-3-1-8b", "tulu-3-70b": "Llama-3-1-Tulu-3-70B", "llama-3.1-405b": "tulu3-405b", "llama-3.1-8b": "tulu-3-1-8b", "llama-3.1-70b": "Llama-3-1-Tulu-3-70B", + "olmo-4-synthetic": "mm-olmo-uber-model-v4-synthetic", } + @classmethod async def create_async_generator( cls, model: str, messages: Messages, proxy: str = None, - host: str = "inferd", + host: str = None, private: bool = True, top_p: float = None, temperature: float = None, conversation: Conversation = None, return_conversation: bool = False, + media: MediaListType = None, **kwargs ) -> AsyncResult: - prompt = format_prompt(messages) if conversation is None else get_last_user_message(messages) + actual_model = cls.get_model(model) + + # Use format_image_prompt for vision models when media is provided + if media is not None and len(media) > 0: + # For vision models, use format_image_prompt + if actual_model in cls.vision_models: + prompt = format_image_prompt(messages) + else: + # For non-vision models with images, still use the last user message + prompt = get_last_user_message(messages) + else: + # For text-only messages, use the standard format + prompt = format_prompt(messages) if conversation is None else get_last_user_message(messages) + + # Determine the correct host for the model + if host is None: + # Use model-specific host from model_hosts dictionary + host = cls.model_hosts[actual_model] + # Initialize or update conversation - if conversation is None: - conversation = Conversation(model) + # For mm-olmo-uber-model-v4-synthetic, always create a new conversation + if conversation is None or actual_model == 'mm-olmo-uber-model-v4-synthetic': + conversation = Conversation(actual_model) # Generate new boundary for each request boundary = f"----WebKitFormBoundary{uuid4().hex}" @@ -101,7 +134,7 @@ class AllenAI(AsyncGeneratorProvider, ProviderModelMixin): ] # Add parent if exists in conversation - if conversation.parent: + if hasattr(conversation, 'parent') and conversation.parent: form_data.append( f'--{boundary}\r\n' f'Content-Disposition: form-data; name="parent"\r\n\r\n{conversation.parent}\r\n' @@ -120,8 +153,25 @@ class AllenAI(AsyncGeneratorProvider, ProviderModelMixin): f'Content-Disposition: form-data; name="top_p"\r\n\r\n{top_p}\r\n' ) + # Always create a new conversation when an image is attached to avoid 403 errors + if media is not None and len(media) > 0: + conversation = Conversation(actual_model) + + # Add image if provided + if media is not None and len(media) > 0: + # For each image in the media list (using merge_media to handle different formats) + for image, image_name in merge_media(media, messages): + image_bytes = to_bytes(image) + form_data.extend([ + f'--{boundary}\r\n' + f'Content-Disposition: form-data; name="files"; filename="{image_name}"\r\n' + f'Content-Type: {is_accepted_format(image_bytes)}\r\n\r\n' + ]) + form_data.append(image_bytes.decode('latin1')) + form_data.append('\r\n') + form_data.append(f'--{boundary}--\r\n') - data = "".join(form_data).encode() + data = "".join(form_data).encode('latin1') async with ClientSession(headers=headers) as session: async with session.post( @@ -164,6 +214,9 @@ class AllenAI(AsyncGeneratorProvider, ProviderModelMixin): # Processing the final response if data.get("final") or data.get("finish_reason") == "stop": if current_parent: + # Ensure the parent attribute exists before setting it + if not hasattr(conversation, 'parent'): + setattr(conversation, 'parent', None) conversation.parent = current_parent # Add a message to the story diff --git a/g4f/Provider/Blackbox.py b/g4f/Provider/Blackbox.py index 6ece1bc0..44d8248c 100644 --- a/g4f/Provider/Blackbox.py +++ b/g4f/Provider/Blackbox.py @@ -43,18 +43,79 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin): default_vision_model = default_model default_image_model = 'flux' - # Completely free models + # Free models (available without subscription) fallback_models = [ - "blackboxai", + default_model, + "gpt-4o-mini", + "DeepSeek-V3", + "DeepSeek-R1", + "Meta-Llama-3.3-70B-Instruct-Turbo", + "Mistral-Small-24B-Instruct-2501", + "DeepSeek-LLM-Chat-(67B)", + "Qwen-QwQ-32B-Preview", + # Image models + "flux", + # Trending agent modes + 'Python Agent', + 'HTML Agent', + 'Builder Agent', + 'Java Agent', + 'JavaScript Agent', + 'React Agent', + 'Android Agent', + 'Flutter Agent', + 'Next.js Agent', + 'AngularJS Agent', + 'Swift Agent', + 'MongoDB Agent', + 'PyTorch Agent', + 'Xcode Agent', + 'Azure Agent', + 'Bitbucket Agent', + 'DigitalOcean Agent', + 'Docker Agent', + 'Electron Agent', + 'Erlang Agent', + 'FastAPI Agent', + 'Firebase Agent', + 'Flask Agent', + 'Git Agent', + 'Gitlab Agent', + 'Go Agent', + 'Godot Agent', + 'Google Cloud Agent', + 'Heroku Agent' + ] + + # Premium models (require subscription) + premium_models = [ + "GPT-4o", + "o1", + "o3-mini", + "Claude-sonnet-3.7", + "Claude-sonnet-3.5", + "Gemini-Flash-2.0", + "DBRX-Instruct", + "blackboxai-pro", + "Gemini-PRO" + ] + + # Models available in the demo account + demo_models = [ + default_model, "blackboxai-pro", "gpt-4o-mini", "GPT-4o", "o1", "o3-mini", "Claude-sonnet-3.7", + "Claude-sonnet-3.5", "DeepSeek-V3", "DeepSeek-R1", "DeepSeek-LLM-Chat-(67B)", + "Meta-Llama-3.3-70B-Instruct-Turbo", + "Mistral-Small-24B-Instruct-2501", + "Qwen-QwQ-32B-Preview", # Image models "flux", # Trending agent modes @@ -92,13 +153,14 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin): image_models = [default_image_model] vision_models = [default_vision_model, 'GPT-4o', 'o1', 'o3-mini', 'Gemini-PRO', 'Gemini Agent', 'llama-3.1-8b Agent', 'llama-3.1-70b Agent', 'llama-3.1-405 Agent', 'Gemini-Flash-2.0', 'DeepSeek-V3'] - userSelectedModel = ['GPT-4o', 'o1', 'o3-mini', 'Gemini-PRO', 'Claude-sonnet-3.7', 'DeepSeek-V3', 'DeepSeek-R1', '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'] + userSelectedModel = ['GPT-4o', 'o1', 'o3-mini', 'Gemini-PRO', 'Claude-sonnet-3.7', 'Claude-sonnet-3.5', 'DeepSeek-V3', 'DeepSeek-R1', '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'] # Agent mode configurations agentMode = { 'GPT-4o': {'mode': True, 'id': "GPT-4o", 'name': "GPT-4o"}, 'Gemini-PRO': {'mode': True, 'id': "Gemini-PRO", 'name': "Gemini-PRO"}, 'Claude-sonnet-3.7': {'mode': True, 'id': "Claude-sonnet-3.7", 'name': "Claude-sonnet-3.7"}, + 'Claude-sonnet-3.5': {'mode': True, 'id': "Claude-sonnet-3.5", 'name': "Claude-sonnet-3.5"}, 'DeepSeek-V3': {'mode': True, 'id': "deepseek-chat", 'name': "DeepSeek-V3"}, '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"}, @@ -150,13 +212,174 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin): # Complete list of all models (for authorized users) _all_models = list(dict.fromkeys([ - default_model, - *userSelectedModel, + *fallback_models, # Include all free models + *premium_models, # Include all premium models *image_models, *list(agentMode.keys()), *list(trendingAgentMode.keys()) ])) + + # Initialize models with fallback_models + models = fallback_models + model_aliases = { + "gpt-4o": "GPT-4o", + "claude-3.7-sonnet": "Claude-sonnet-3.7", + "claude-3.5-sonnet": "Claude-sonnet-3.5", + "deepseek-v3": "DeepSeek-V3", + "deepseek-r1": "DeepSeek-R1", + "deepseek-chat": "DeepSeek-LLM-Chat-(67B)", + "llama-3.3-70b": "Meta-Llama-3.3-70B-Instruct-Turbo", + "mixtral-small-24b": "Mistral-Small-24B-Instruct-2501", + "qwq-32b": "Qwen-QwQ-32B-Preview", + } + + @classmethod + async def get_models_async(cls) -> list: + """ + Asynchronous version of get_models that checks subscription status. + Returns a list of available models based on subscription status. + Premium users get the full list of models. + Free users get fallback_models. + Demo accounts get demo_models. + """ + # Check if there are valid session data in HAR files + session_data = cls._find_session_in_har_files() + + if not session_data: + # For demo accounts - return demo models + debug.log(f"Blackbox: Returning demo model list with {len(cls.demo_models)} models") + return cls.demo_models + + # Check if this is a demo session + demo_session = cls.generate_session() + is_demo = (session_data['user'].get('email') == demo_session['user'].get('email')) + + if is_demo: + # For demo accounts - return demo models + debug.log(f"Blackbox: Returning demo model list with {len(cls.demo_models)} models") + return cls.demo_models + + # For non-demo accounts, check subscription status + if 'user' in session_data and 'email' in session_data['user']: + subscription = await cls.check_subscription(session_data['user']['email']) + if subscription['status'] == "PREMIUM": + debug.log(f"Blackbox: Returning premium model list with {len(cls._all_models)} models") + return cls._all_models + + # For free accounts - return free models + debug.log(f"Blackbox: Returning free model list with {len(cls.fallback_models)} models") + return cls.fallback_models + + @classmethod + def get_models(cls) -> list: + """ + Returns a list of available models based on authorization status. + Authorized users get the full list of models. + Free users get fallback_models. + Demo accounts get demo_models. + + Note: This is a synchronous method that can't check subscription status, + so it falls back to the basic premium access check. + For more accurate results, use get_models_async when possible. + """ + # Check if there are valid session data in HAR files + session_data = cls._find_session_in_har_files() + + if not session_data: + # For demo accounts - return demo models + debug.log(f"Blackbox: Returning demo model list with {len(cls.demo_models)} models") + return cls.demo_models + + # Check if this is a demo session + demo_session = cls.generate_session() + is_demo = (session_data['user'].get('email') == demo_session['user'].get('email')) + + if is_demo: + # For demo accounts - return demo models + debug.log(f"Blackbox: Returning demo model list with {len(cls.demo_models)} models") + return cls.demo_models + + # For non-demo accounts, check premium access + has_premium_access = cls._check_premium_access() + + if has_premium_access: + # For premium users - all models + debug.log(f"Blackbox: Returning premium model list with {len(cls._all_models)} models") + return cls._all_models + + # For free accounts - return free models + debug.log(f"Blackbox: Returning free model list with {len(cls.fallback_models)} models") + return cls.fallback_models + + @classmethod + async def check_subscription(cls, email: str) -> dict: + """ + Check subscription status for a given email using the Blackbox API. + + Args: + email: The email to check subscription for + + Returns: + dict: Subscription status information with keys: + - status: "PREMIUM" or "FREE" + - customerId: Customer ID if available + - isTrialSubscription: Whether this is a trial subscription + """ + if not email: + return {"status": "FREE", "customerId": None, "isTrialSubscription": False} + + headers = { + 'accept': '*/*', + 'accept-language': 'en', + 'content-type': 'application/json', + 'origin': 'https://www.blackbox.ai', + 'referer': 'https://www.blackbox.ai/?ref=login-success', + 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36' + } + + try: + async with ClientSession(headers=headers) as session: + async with session.post( + 'https://www.blackbox.ai/api/check-subscription', + json={"email": email} + ) as response: + if response.status != 200: + debug.log(f"Blackbox: Subscription check failed with status {response.status}") + return {"status": "FREE", "customerId": None, "isTrialSubscription": False} + + result = await response.json() + status = "PREMIUM" if result.get("hasActiveSubscription", False) else "FREE" + + return { + "status": status, + "customerId": result.get("customerId"), + "isTrialSubscription": result.get("isTrialSubscription", False) + } + except Exception as e: + debug.log(f"Blackbox: Error checking subscription: {e}") + return {"status": "FREE", "customerId": None, "isTrialSubscription": False} + + @classmethod + def _check_premium_access(cls) -> bool: + """ + Checks for an authorized session in HAR files. + Returns True if a valid session is found that differs from the demo. + """ + try: + session_data = cls._find_session_in_har_files() + if not session_data: + return False + + # Check if this is not a demo session + demo_session = cls.generate_session() + if (session_data['user'].get('email') != demo_session['user'].get('email')): + return True + return False + except Exception as e: + debug.log(f"Blackbox: Error checking premium access: {e}") + return False + @classmethod def generate_session(cls, id_length: int = 21, days_ahead: int = 365) -> dict: """ @@ -196,94 +419,17 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin): } @classmethod - async def fetch_validated(cls, url: str = "https://www.blackbox.ai", force_refresh: bool = False) -> Optional[str]: - cache_file = Path(get_cookies_dir()) / 'blackbox.json' - - if not force_refresh and cache_file.exists(): - try: - with open(cache_file, 'r') as f: - data = json.load(f) - if data.get('validated_value'): - return data['validated_value'] - except Exception as e: - debug.log(f"Blackbox: Error reading cache: {e}") - - js_file_pattern = r'static/chunks/\d{4}-[a-fA-F0-9]+\.js' - uuid_pattern = r'["\']([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})["\']' - - def is_valid_context(text: str) -> bool: - return any(char + '=' in text for char in 'abcdefghijklmnopqrstuvwxyz') - - async with ClientSession() as session: - try: - async with session.get(url) as response: - if response.status != 200: - return None - - page_content = await response.text() - js_files = re.findall(js_file_pattern, page_content) - - for js_file in js_files: - js_url = f"{url}/_next/{js_file}" - async with session.get(js_url) as js_response: - if js_response.status == 200: - js_content = await js_response.text() - for match in re.finditer(uuid_pattern, js_content): - start = max(0, match.start() - 10) - end = min(len(js_content), match.end() + 10) - context = js_content[start:end] - - if is_valid_context(context): - validated_value = match.group(1) - - cache_file.parent.mkdir(exist_ok=True) - try: - with open(cache_file, 'w') as f: - json.dump({'validated_value': validated_value}, f) - except Exception as e: - debug.log(f"Blackbox: Error writing cache: {e}") - - return validated_value - - except Exception as e: - debug.log(f"Blackbox: Error retrieving validated_value: {e}") - - return None - - @classmethod - def generate_id(cls, length: int = 7) -> str: - chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for _ in range(length)) - - @classmethod - def get_models(cls) -> list: + def _find_session_in_har_files(cls) -> Optional[dict]: """ - Returns a list of available models based on authorization status. - Authorized users get the full list of models. - Unauthorized users only get fallback_models. - """ - # Check if there are valid session data in HAR files - has_premium_access = cls._check_premium_access() + Search for valid session data in HAR files. - if has_premium_access: - # For authorized users - all models - debug.log(f"Blackbox: Returning full model list with {len(cls._all_models)} models") - return cls._all_models - else: - # For demo accounts - only free models - debug.log(f"Blackbox: Returning free model list with {len(cls.fallback_models)} models") - return cls.fallback_models - - @classmethod - def _check_premium_access(cls) -> bool: - """ - Checks for an authorized session in HAR files. - Returns True if a valid session is found that differs from the demo. + Returns: + Optional[dict]: Session data if found, None otherwise """ try: har_dir = get_cookies_dir() if not os.access(har_dir, os.R_OK): - return False + return None for root, _, files in os.walk(har_dir): for file in files: @@ -293,91 +439,45 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin): har_data = json.load(f) for entry in har_data['log']['entries']: - # Only check requests to blackbox API + # Only look at blackbox API responses if 'blackbox.ai/api' in entry['request']['url']: + # Look for a response that has the right structure if 'response' in entry and 'content' in entry['response']: content = entry['response']['content'] + # Look for both regular and Google auth session formats if ('text' in content and isinstance(content['text'], str) and '"user"' in content['text'] and - '"email"' in content['text']): + '"email"' in content['text'] and + '"expires"' in content['text']): try: - # Process request text + # Remove any HTML or other non-JSON content text = content['text'].strip() if text.startswith('{') and text.endswith('}'): + # Replace escaped quotes text = text.replace('\\"', '"') - session_data = json.loads(text) + har_session = json.loads(text) - # Check if this is a valid session - if (isinstance(session_data, dict) and - 'user' in session_data and - 'email' in session_data['user']): + # Check if this is a valid session object + if (isinstance(har_session, dict) and + 'user' in har_session and + 'email' in har_session['user'] and + 'expires' in har_session): - # Check if this is not a demo session - demo_session = cls.generate_session() - if (session_data['user'].get('email') != - demo_session['user'].get('email')): - # This is not a demo session, so user has premium access - return True - except: - pass - except: - pass - return False + debug.log(f"Blackbox: Found session in HAR file: {file}") + return har_session + except json.JSONDecodeError as e: + # Only print error for entries that truly look like session data + if ('"user"' in content['text'] and + '"email"' in content['text']): + debug.log(f"Blackbox: Error parsing likely session data: {e}") + except Exception as e: + debug.log(f"Blackbox: Error reading HAR file {file}: {e}") + return None except Exception as e: - debug.log(f"Blackbox: Error checking premium access: {e}") - return False - - # Initialize models with fallback_models - models = fallback_models - - model_aliases = { - "gpt-4o": "GPT-4o", - "claude-3.7-sonnet": "Claude-sonnet-3.7", - "deepseek-v3": "DeepSeek-V3", - "deepseek-r1": "DeepSeek-R1", - "deepseek-chat": "DeepSeek-LLM-Chat-(67B)", - } - - @classmethod - def generate_session(cls, id_length: int = 21, days_ahead: int = 365) -> dict: - """ - Generate a dynamic session with proper ID and expiry format. - - Args: - id_length: Length of the numeric ID (default: 21) - days_ahead: Number of days ahead for expiry (default: 365) - - Returns: - dict: A session dictionary with user information and expiry - """ - # Generate numeric ID - numeric_id = ''.join(random.choice('0123456789') for _ in range(id_length)) - - # Generate future expiry date - future_date = datetime.now() + timedelta(days=days_ahead) - expiry = future_date.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z' - - # Decode the encoded email - encoded_email = "Z2lzZWxlQGJsYWNrYm94LmFp" # Base64 encoded email - email = base64.b64decode(encoded_email).decode('utf-8') - - # Generate random image ID for the new URL format - chars = string.ascii_letters + string.digits + "-" - random_img_id = ''.join(random.choice(chars) for _ in range(48)) - image_url = f"https://lh3.googleusercontent.com/a/ACg8oc{random_img_id}=s96-c" - - return { - "user": { - "name": "BLACKBOX AI", - "email": email, - "image": image_url, - "id": numeric_id - }, - "expires": expiry - } - + debug.log(f"Blackbox: Error searching HAR files: {e}") + return None @classmethod async def fetch_validated(cls, url: str = "https://www.blackbox.ai", force_refresh: bool = False) -> Optional[str]: @@ -494,71 +594,42 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin): "title": "" } - # Try to get session data from HAR files - session_data = cls.generate_session() # Default fallback - session_found = False - - # Look for HAR session data - har_dir = get_cookies_dir() - if os.access(har_dir, os.R_OK): - for root, _, files in os.walk(har_dir): - for file in files: - if file.endswith(".har"): - try: - with open(os.path.join(root, file), 'rb') as f: - har_data = json.load(f) - - for entry in har_data['log']['entries']: - # Only look at blackbox API responses - if 'blackbox.ai/api' in entry['request']['url']: - # Look for a response that has the right structure - if 'response' in entry and 'content' in entry['response']: - content = entry['response']['content'] - # Look for both regular and Google auth session formats - if ('text' in content and - isinstance(content['text'], str) and - '"user"' in content['text'] and - '"email"' in content['text'] and - '"expires"' in content['text']): - - try: - # Remove any HTML or other non-JSON content - text = content['text'].strip() - if text.startswith('{') and text.endswith('}'): - # Replace escaped quotes - text = text.replace('\\"', '"') - har_session = json.loads(text) - - # Check if this is a valid session object (supports both regular and Google auth) - if (isinstance(har_session, dict) and - 'user' in har_session and - 'email' in har_session['user'] and - 'expires' in har_session): - - file_path = os.path.join(root, file) - debug.log(f"Blackbox: Found session in HAR file") - - session_data = har_session - session_found = True - break - except json.JSONDecodeError as e: - # Only print error for entries that truly look like session data - if ('"user"' in content['text'] and - '"email"' in content['text']): - debug.log(f"Blackbox: Error parsing likely session data: {e}") - - if session_found: - break - - except Exception as e: - debug.log(f"Blackbox: Error reading HAR file: {e}") - - if session_found: - break - - if session_found: - break - + # Get session data - try HAR files first, fall back to generated session + session_data = cls._find_session_in_har_files() or cls.generate_session() + + # Log which session type is being used + demo_session = cls.generate_session() + is_demo = (session_data['user'].get('email') == demo_session['user'].get('email')) + + if is_demo: + debug.log("Blackbox: Using generated demo session") + # For demo account, set default values without checking subscription + subscription_status = {"status": "FREE", "customerId": None, "isTrialSubscription": False} + # Check if the requested model is in demo_models + is_premium = model in cls.demo_models + if not is_premium: + debug.log(f"Blackbox: Model {model} not available in demo account, falling back to default model") + model = cls.default_model + is_premium = True + else: + debug.log(f"Blackbox: Using session from HAR file (email: {session_data['user'].get('email', 'unknown')})") + # Only check subscription for non-demo accounts + subscription_status = {"status": "FREE", "customerId": None, "isTrialSubscription": False} + if session_data.get('user', {}).get('email'): + subscription_status = await cls.check_subscription(session_data['user']['email']) + debug.log(f"Blackbox: Subscription status for {session_data['user']['email']}: {subscription_status['status']}") + + # Determine if user has premium access based on subscription status + if subscription_status['status'] == "PREMIUM": + is_premium = True + else: + # For free accounts, check if the requested model is in fallback_models + is_premium = model in cls.fallback_models + if not is_premium: + debug.log(f"Blackbox: Model {model} not available in free account, falling back to default model") + model = cls.default_model + is_premium = True + data = { "messages": current_messages, "agentMode": cls.agentMode.get(model, {}) if model in cls.agentMode else {}, @@ -595,29 +666,19 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin): "additionalInfo": "", "enableNewChats": False }, - "session": session_data if session_data else cls.generate_session(), - "isPremium": True, - "subscriptionCache": None, + "session": session_data, + "isPremium": is_premium, + "subscriptionCache": { + "status": subscription_status['status'], + "customerId": subscription_status['customerId'], + "isTrialSubscription": subscription_status['isTrialSubscription'], + "lastChecked": int(datetime.now().timestamp() * 1000) + }, "beastMode": False, + "reasoningMode": False, "webSearchMode": False } - # Add debugging before making the API call - if isinstance(session_data, dict) and 'user' in session_data: - # Генеруємо демо-сесію для порівняння - demo_session = cls.generate_session() - is_demo = False - - if demo_session and isinstance(demo_session, dict) and 'user' in demo_session: - if session_data['user'].get('email') == demo_session['user'].get('email'): - is_demo = True - - if is_demo: - debug.log(f"Blackbox: Making API request with built-in Developer Premium Account") - else: - user_email = session_data['user'].get('email', 'unknown') - debug.log(f"Blackbox: Making API request with HAR session email: {user_email}") - # Continue with the API request and async generator behavior async with session.post(cls.api_endpoint, json=data, proxy=proxy) as response: await raise_for_status(response) diff --git a/g4f/Provider/DDG.py b/g4f/Provider/DDG.py index 3b79a294..f389733b 100644 --- a/g4f/Provider/DDG.py +++ b/g4f/Provider/DDG.py @@ -26,6 +26,9 @@ except ImportError: class DuckDuckGoSearchException(Exception): """Base exception class for duckduckgo_search.""" +class DuckDuckGoChallengeError(ResponseStatusError): + """Raised when DuckDuckGo presents a challenge that needs to be solved.""" + class Conversation(JsonConversation): vqd: str = None vqd_hash_1: str = None @@ -48,14 +51,19 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): supports_message_history = True default_model = "gpt-4o-mini" - models = [default_model, "meta-llama/Llama-3.3-70B-Instruct-Turbo", "claude-3-haiku-20240307", "o3-mini", "mistralai/Mistral-Small-24B-Instruct-2501"] - - model_aliases = { - "gpt-4": "gpt-4o-mini", + + # Model mapping from user-friendly names to API model names + _chat_models = { + "gpt-4": default_model, + "gpt-4o-mini": default_model, "llama-3.3-70b": "meta-llama/Llama-3.3-70B-Instruct-Turbo", "claude-3-haiku": "claude-3-haiku-20240307", + "o3-mini": "o3-mini", "mixtral-small-24b": "mistralai/Mistral-Small-24B-Instruct-2501", } + + # Available models (user-friendly names) + models = list(_chat_models.keys()) last_request_time = 0 max_retries = 3 @@ -100,19 +108,52 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): def build_x_vqd_hash_1(cls, vqd_hash_1: str, headers: dict) -> str: """Build the x-vqd-hash-1 header value.""" try: - decoded = base64.b64decode(vqd_hash_1).decode() - server_hashes = cls.parse_server_hashes(decoded) - dom_fingerprint = cls.parse_dom_fingerprint(decoded) - + # If we received a valid base64 string, try to decode it + if vqd_hash_1 and len(vqd_hash_1) > 20: + try: + # Try to decode and parse as JSON first + decoded_json = json.loads(base64.b64decode(vqd_hash_1).decode()) + # If it's already a complete structure with meta, return it as is + if isinstance(decoded_json, dict) and "meta" in decoded_json: + return vqd_hash_1 + + # Otherwise, extract what we can from it + if isinstance(decoded_json, dict) and "server_hashes" in decoded_json: + server_hashes = decoded_json.get("server_hashes", ["1", "2"]) + else: + # Fall back to parsing from string + decoded = base64.b64decode(vqd_hash_1).decode() + server_hashes = cls.parse_server_hashes(decoded) + except (json.JSONDecodeError, UnicodeDecodeError): + # If it's not valid JSON, try to parse it as a string + decoded = base64.b64decode(vqd_hash_1).decode() + server_hashes = cls.parse_server_hashes(decoded) + else: + # Default server hashes if we can't extract them + server_hashes = ["1", "2"] + + # Generate fingerprints + dom_fingerprint = "1000" # Default value ua_fingerprint = headers.get("User-Agent", "") + headers.get("sec-ch-ua", "") ua_hash = cls.sha256_base64(ua_fingerprint) dom_hash = cls.sha256_base64(dom_fingerprint) - + + # Create a challenge ID (random hex string) + challenge_id = ''.join(random.choice('0123456789abcdef') for _ in range(40)) + 'h8jbt' + + # Build the complete structure including meta final_result = { "server_hashes": server_hashes, "client_hashes": [ua_hash, dom_hash], "signals": {}, + "meta": { + "v": "1", + "challenge_id": challenge_id, + "origin": "https://duckduckgo.com", + "stack": "Error\nat ke (https://duckduckgo.com/dist/wpm.chat.js:1:29526)\nat async dispatchServiceInitialVQD (https://duckduckgo.com/dist/wpm.chat.js:1:45076)" + } } + base64_final_result = base64.b64encode(json.dumps(final_result).encode()).decode() return base64_final_result except Exception as e: @@ -121,13 +162,18 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): @classmethod def validate_model(cls, model: str) -> str: - """Validates and returns the correct model name""" + """Validates and returns the correct model name for the API""" if not model: return cls.default_model + + # Check aliases first if model in cls.model_aliases: model = cls.model_aliases[model] + + # Check if it's a valid model name if model not in cls.models: raise ModelNotSupportedError(f"Model {model} not supported. Available models: {cls.models}") + return model @classmethod @@ -147,18 +193,45 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): await cls.sleep() # Make initial request to get cookies async with session.get(cls.url) as response: - # We also manually set required cookies + # Set the required cookies cookies = {} cookies_dict = {'dcs': '1', 'dcm': '3'} + # Add any cookies from the response + for cookie in response.cookies.values(): + cookies[cookie.key] = cookie.value + + # Ensure our required cookies are set for name, value in cookies_dict.items(): cookies[name] = value url_obj = URL(cls.url) session.cookie_jar.update_cookies({name: value}, url_obj) + # Make a second request to the status endpoint to get any additional cookies + headers = { + "accept": "text/event-stream", + "accept-language": "en", + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "origin": "https://duckduckgo.com", + "referer": "https://duckduckgo.com/", + } + + await cls.sleep() + async with session.get(cls.status_url, headers=headers) as status_response: + # Add any cookies from the status response + for cookie in status_response.cookies.values(): + cookies[cookie.key] = cookie.value + url_obj = URL(cls.url) + session.cookie_jar.update_cookies({cookie.key: cookie.value}, url_obj) + return cookies except Exception as e: - return {} + # Return at least the required cookies on error + cookies = {'dcs': '1', 'dcm': '3'} + url_obj = URL(cls.url) + for name, value in cookies.items(): + session.cookie_jar.update_cookies({name: value}, url_obj) + return cookies @classmethod async def fetch_fe_version(cls, session: ClientSession) -> str: @@ -175,26 +248,38 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): # Extract x-fe-version components try: + # Try to extract the version components xfe1 = content.split('__DDG_BE_VERSION__="', 1)[1].split('"', 1)[0] xfe2 = content.split('__DDG_FE_CHAT_HASH__="', 1)[1].split('"', 1)[0] - cls._chat_xfe = f"{xfe1}-{xfe2}" + + # Format it like "serp_YYYYMMDD_HHMMSS_ET-hash" + from datetime import datetime + current_date = datetime.now().strftime("%Y%m%d_%H%M%S") + cls._chat_xfe = f"serp_{current_date}_ET-{xfe2}" + return cls._chat_xfe except Exception: - # If extraction fails, return an empty string - return "" + # Fallback to a default format if extraction fails + from datetime import datetime + current_date = datetime.now().strftime("%Y%m%d_%H%M%S") + cls._chat_xfe = f"serp_{current_date}_ET-78c2e87e3d286691cc21" + return cls._chat_xfe except Exception: - return "" + # Fallback to a default format if request fails + from datetime import datetime + current_date = datetime.now().strftime("%Y%m%d_%H%M%S") + cls._chat_xfe = f"serp_{current_date}_ET-78c2e87e3d286691cc21" + return cls._chat_xfe @classmethod async def fetch_vqd_and_hash(cls, session: ClientSession, retry_count: int = 0) -> tuple[str, str]: """Fetches the required VQD token and hash for the chat session with retries.""" headers = { "accept": "text/event-stream", - "accept-language": "en-US,en;q=0.9", + "accept-language": "en", "cache-control": "no-cache", - "content-type": "application/json", "pragma": "no-cache", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", "origin": "https://duckduckgo.com", "referer": "https://duckduckgo.com/", "x-vqd-accept": "1", @@ -270,30 +355,44 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): last_message = get_last_user_message(messages.copy()) conversation.message_history.append({"role": "user", "content": last_message}) - # Step 4: Prepare headers - IMPORTANT: send empty x-vqd-hash-1 for the first request + # Step 4: Prepare headers with proper x-vqd-hash-1 headers = { "accept": "text/event-stream", - "accept-language": "en-US,en;q=0.9", + "accept-language": "en", + "cache-control": "no-cache", "content-type": "application/json", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", "origin": "https://duckduckgo.com", "referer": "https://duckduckgo.com/", - "sec-ch-ua": '"Chromium";v="133", "Not_A Brand";v="8"', + "pragma": "no-cache", + "priority": "u=1, i", + "sec-ch-ua": '"Not:A-Brand";v="24", "Chromium";v="134"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Linux"', + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", "x-fe-version": conversation.fe_version or cls._chat_xfe, "x-vqd-4": conversation.vqd, - "x-vqd-hash-1": "", # Send empty string initially } + + # For the first request, send an empty x-vqd-hash-1 header + # This matches the behavior in the duckduckgo_search module + headers["x-vqd-hash-1"] = "" # Step 5: Prepare the request data + # Convert the user-friendly model name to the API model name + api_model = cls._chat_models.get(model, model) + data = { - "model": model, + "model": api_model, "messages": conversation.message_history, } # Step 6: Send the request await cls.sleep(multiplier=1.0 + retry_count * 0.5) async with session.post(cls.api_endpoint, json=data, headers=headers, proxy=proxy) as response: - # Handle 429 errors specifically + # Handle 429 and 418 errors specifically if response.status == 429: response_text = await response.text() @@ -307,7 +406,69 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): continue else: raise RateLimitError(f"Rate limited after {cls.max_retries} retries") + elif response.status == 418: + # Check if it's a challenge error + try: + response_text = await response.text() + try: + response_json = json.loads(response_text) + + # Extract challenge data if available + challenge_data = None + if response_json.get("type") == "ERR_CHALLENGE" and "cd" in response_json: + challenge_data = response_json["cd"] + + if retry_count < cls.max_retries: + retry_count += 1 + wait_time = cls.base_delay * (2 ** retry_count) * (1 + random.random()) + await asyncio.sleep(wait_time) + + # Reset tokens and try again with fresh session + conversation = None + cls._chat_xfe = "" + + # Get fresh cookies + cookies = await cls.get_default_cookies(session) + + # If we have challenge data, try to use it + if challenge_data and isinstance(challenge_data, dict): + # Extract any useful information from challenge data + # This could be used to build a better response in the future + pass + + continue + else: + raise DuckDuckGoChallengeError(f"Challenge error after {cls.max_retries} retries") + except json.JSONDecodeError: + # If we can't parse the JSON, assume it's a challenge error anyway + if retry_count < cls.max_retries: + retry_count += 1 + wait_time = cls.base_delay * (2 ** retry_count) * (1 + random.random()) + await asyncio.sleep(wait_time) + + # Reset tokens and try again with fresh session + conversation = None + cls._chat_xfe = "" + cookies = await cls.get_default_cookies(session) + continue + else: + raise DuckDuckGoChallengeError(f"Challenge error after {cls.max_retries} retries") + except Exception as e: + # If any other error occurs during handling, still try to recover + if retry_count < cls.max_retries: + retry_count += 1 + wait_time = cls.base_delay * (2 ** retry_count) * (1 + random.random()) + await asyncio.sleep(wait_time) + + # Reset tokens and try again with fresh session + conversation = None + cls._chat_xfe = "" + cookies = await cls.get_default_cookies(session) + continue + else: + raise DuckDuckGoChallengeError(f"Challenge error after {cls.max_retries} retries: {str(e)}") + # For other status codes, use the standard error handler await raise_for_status(response) reason = None full_message = "" @@ -328,6 +489,11 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): if error_type == "ERR_CONVERSATION_LIMIT": raise ConversationLimitError(error_type) raise RateLimitError(error_type) + elif message.get("status") == 418 and error_type == "ERR_CHALLENGE": + # Handle challenge error by refreshing tokens and retrying + if retry_count < cls.max_retries: + # Don't raise here, let the outer exception handler retry + raise DuckDuckGoChallengeError(f"Challenge detected: {error_type}") raise DuckDuckGoSearchException(error_type) if "message" in message: @@ -339,15 +505,19 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): reason = "stop" # Step 8: Update conversation with response information + # Always update the VQD tokens from the response headers + conversation.vqd = response.headers.get("x-vqd-4", conversation.vqd) + conversation.vqd_hash_1 = response.headers.get("x-vqd-hash-1", conversation.vqd_hash_1) + + # Update cookies + conversation.cookies = { + n: c.value + for n, c in session.cookie_jar.filter_cookies(URL(cls.url)).items() + } + + # If requested, return the updated conversation if return_conversation: conversation.message_history.append({"role": "assistant", "content": full_message}) - # Update tokens from response headers - conversation.vqd = response.headers.get("x-vqd-4", conversation.vqd) - conversation.vqd_hash_1 = response.headers.get("x-vqd-hash-1", conversation.vqd_hash_1) - conversation.cookies = { - n: c.value - for n, c in session.cookie_jar.filter_cookies(URL(cls.url)).items() - } yield conversation if reason is not None: @@ -356,11 +526,18 @@ class DDG(AsyncGeneratorProvider, ProviderModelMixin): # If we got here, the request was successful break - except (RateLimitError, ResponseStatusError) as e: - if "429" in str(e) and retry_count < cls.max_retries: + except (RateLimitError, ResponseStatusError, DuckDuckGoChallengeError) as e: + if ("429" in str(e) or isinstance(e, DuckDuckGoChallengeError)) and retry_count < cls.max_retries: retry_count += 1 wait_time = cls.base_delay * (2 ** retry_count) * (1 + random.random()) await asyncio.sleep(wait_time) + + # For challenge errors, refresh tokens and cookies + if isinstance(e, DuckDuckGoChallengeError): + # Reset conversation to force new token acquisition + conversation = None + # Clear class cache to force refresh + cls._chat_xfe = "" else: raise except asyncio.TimeoutError as e: diff --git a/g4f/Provider/PollinationsAI.py b/g4f/Provider/PollinationsAI.py index d33d8929..5b5f2599 100644 --- a/g4f/Provider/PollinationsAI.py +++ b/g4f/Provider/PollinationsAI.py @@ -46,11 +46,13 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin): default_model = "openai" default_image_model = "flux" default_vision_model = default_model + default_audio_model = "openai-audio" text_models = [default_model] image_models = [default_image_model] + audio_models = [default_audio_model] extra_image_models = ["flux-pro", "flux-dev", "flux-schnell", "midjourney", "dall-e-3", "turbo"] - vision_models = [default_vision_model, "gpt-4o-mini", "o3-mini", "openai", "openai-large"] - extra_text_models = vision_models + vision_models = ["gpt-4o-mini", "o3-mini", "openai-large"] # Removed duplicates with default_model + extra_text_models = [] # Will be populated with unique vision models _models_loaded = False model_aliases = { ### Text Models ### @@ -68,7 +70,12 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin): "gemini-2.0": "gemini", "gemini-2.0-flash": "gemini", "gemini-2.0-flash-thinking": "gemini-thinking", - "deepseek-r1": "deepseek-r1-llama", + "gemini-2.0-flash-thinking": "gemini-reasoning", + "deepseek-r1": "deepseek-reasoning-large", + "deepseek-r1": "deepseek-reasoning", + "deepseek-v3": "deepseek", + "qwq-32b": "qwen-reasoning", + "llama-3.2-11b": "llama-vision", "gpt-4o-audio": "openai-audio", ### Image Models ### @@ -86,37 +93,52 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin): else: new_image_models = [] - # Combine models without duplicates - all_image_models = ( - cls.image_models + # Already contains the default - cls.extra_image_models + - new_image_models - ) - cls.image_models = list(dict.fromkeys(all_image_models)) + # Combine image models without duplicates + all_image_models = [cls.default_image_model] # Start with default model + + # Add extra image models if not already in the list + for model in cls.extra_image_models + new_image_models: + if model not in all_image_models: + all_image_models.append(model) + + cls.image_models = all_image_models # Update of text models text_response = requests.get("https://text.pollinations.ai/models") text_response.raise_for_status() models = text_response.json() - original_text_models = [ + + # Purpose of text models + cls.text_models = [ model.get("name") for model in models - if model.get("type") == "chat" + if "input_modalities" in model and "text" in model["input_modalities"] ] + + # Purpose of audio models cls.audio_models = { model.get("name"): model.get("voices") for model in models if model.get("audio") } + + # Create a set of unique text models starting with default model + unique_text_models = {cls.default_model} - # Combining text models - combined_text = ( - cls.text_models + # Already contains the default - cls.extra_text_models + - original_text_models + - cls.vision_models - ) - cls.text_models = list(dict.fromkeys(combined_text)) + # Add models from vision_models + unique_text_models.update(cls.vision_models) + + # Add models from the API response + for model in models: + model_name = model.get("name") + if model_name and "input_modalities" in model and "text" in model["input_modalities"]: + unique_text_models.add(model_name) + + # Convert to list and update text_models + cls.text_models = list(unique_text_models) + + # Update extra_text_models with unique vision models + cls.extra_text_models = [model for model in cls.vision_models if model != cls.default_model] cls._models_loaded = True @@ -128,7 +150,13 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin): cls.image_models = [cls.default_image_model] debug.error(f"Failed to fetch models: {e}") - return cls.text_models + cls.image_models + # Return unique models across all categories + all_models = set(cls.text_models) + all_models.update(cls.image_models) + all_models.update(cls.audio_models.keys()) + result = list(all_models) + return result + @classmethod async def create_async_generator( diff --git a/g4f/Provider/PollinationsImage.py b/g4f/Provider/PollinationsImage.py index f0955a11..2d1d1b0c 100644 --- a/g4f/Provider/PollinationsImage.py +++ b/g4f/Provider/PollinationsImage.py @@ -11,6 +11,7 @@ class PollinationsImage(PollinationsAI): default_model = "flux" default_vision_model = None default_image_model = default_model + audio_models = None image_models = [default_image_model] # Default models _models_loaded = False # Add a checkbox for synchronization diff --git a/g4f/gui/client/static/js/chat.v1.js b/g4f/gui/client/static/js/chat.v1.js index 3a7eecef..74ab2c05 100644 --- a/g4f/gui/client/static/js/chat.v1.js +++ b/g4f/gui/client/static/js/chat.v1.js @@ -2306,7 +2306,7 @@ async function on_api() { models.forEach((model) => { let option = document.createElement("option"); option.value = model.name; - option.text = model.name + (model.image ? " (Image Generation)" : "") + (model.vision ? " (Image Upload)" : ""); + option.text = model.name + (model.image ? " (Image Generation)" : "") + (model.vision ? " (Image Upload)" : "") + (model.audio ? " (Audio Generation)" : "") + (model.video ? " (Video Generation)" : ""); option.dataset.providers = model.providers.join(" "); modelSelect.appendChild(option); is_demo = model.demo; @@ -2355,6 +2355,8 @@ async function on_api() { option.text = provider.label + (provider.vision ? " (Image Upload)" : "") + (provider.image ? " (Image Generation)" : "") + + (provider.audio ? " (Audio Generation)" : "") + + (provider.video ? " (Video Generation)" : "") + (provider.nodriver ? " (Browser)" : "") + (provider.hf_space ? " (HuggingSpace)" : "") + (!provider.nodriver && provider.auth ? " (Auth)" : ""); @@ -2942,7 +2944,7 @@ async function load_provider_models(provider=null) { let option = document.createElement('option'); option.value = model.model; option.dataset.label = model.model; - option.text = `${model.model}${model.image ? " (Image Generation)" : ""}${model.vision ? " (Image Upload)" : ""}`; + option.text = `${model.model}${model.image ? " (Image Generation)" : ""}${model.audio ? " (Audio Generation)" : ""}${model.video ? " (Video Generation)" : ""}${model.vision ? " (Image Upload)" : ""}`; if (model.task) { option.text += ` (${model.task})`; } diff --git a/g4f/gui/server/api.py b/g4f/gui/server/api.py index a554e4a2..28d19344 100644 --- a/g4f/gui/server/api.py +++ b/g4f/gui/server/api.py @@ -30,6 +30,8 @@ class Api: "name": model.name, "image": isinstance(model, models.ImageModel), "vision": isinstance(model, models.VisionModel), + "audio": isinstance(model, models.AudioModel), + "video": isinstance(model, models.VideoModel), "providers": [ getattr(provider, "parent", provider.__name__) for provider in providers @@ -52,6 +54,8 @@ class Api: "model": model, "default": model == provider.default_model, "vision": getattr(provider, "default_vision_model", None) == model or model in getattr(provider, "vision_models", []), + "audio": getattr(provider, "default_audio_model", None) == model or model in getattr(provider, "audio_models", []), + "video": getattr(provider, "default_video_model", None) == model or model in getattr(provider, "video_models", []), "image": False if provider.image_models is None else model in provider.image_models, "task": None if not hasattr(provider, "task_mapping") else provider.task_mapping[model] if model in provider.task_mapping else None } @@ -66,6 +70,8 @@ class Api: "label": provider.label if hasattr(provider, "label") else provider.__name__, "parent": getattr(provider, "parent", None), "image": bool(getattr(provider, "image_models", False)), + "audio": getattr(provider, "audio_models", None) is not None, + "video": getattr(provider, "video_models", None) is not None, "vision": getattr(provider, "default_vision_model", None) is not None, "nodriver": getattr(provider, "use_nodriver", False), "hf_space": getattr(provider, "hf_space", False), diff --git a/g4f/gui/server/backend_api.py b/g4f/gui/server/backend_api.py index a5dda0fa..b0b7ee76 100644 --- a/g4f/gui/server/backend_api.py +++ b/g4f/gui/server/backend_api.py @@ -99,6 +99,8 @@ class Backend_Api(Api): "name": model.name, "image": isinstance(model, models.ImageModel), "vision": isinstance(model, models.VisionModel), + "audio": isinstance(model, models.AudioModel), + "video": isinstance(model, models.VideoModel), "providers": [ getattr(provider, "parent", provider.__name__) for provider in providers diff --git a/g4f/models.py b/g4f/models.py index 8a1e4d5d..7ce8be1b 100644 --- a/g4f/models.py +++ b/g4f/models.py @@ -6,6 +6,7 @@ from .Provider import IterListProvider, ProviderType from .Provider import ( ### No Auth Required ### AllenAI, + ARTA, Blackbox, ChatGLM, ChatGptEs, @@ -77,7 +78,10 @@ class ImageModel(Model): class AudioModel(Model): pass - + +class VideoModel(Model): + pass + class VisionModel(Model): pass @@ -105,7 +109,7 @@ default = Model( ]) ) -default_vision = Model( +default_vision = VisionModel( name = "", base_provider = "", best_provider = IterListProvider([ @@ -115,6 +119,7 @@ default_vision = Model( DeepInfraChat, PollinationsAI, Dynaspark, + AllenAI, HuggingSpace, GeminiPro, HuggingFaceAPI, @@ -263,7 +268,7 @@ llama_3_2_90b = Model( llama_3_3_70b = Model( name = "llama-3.3-70b", base_provider = "Meta Llama", - best_provider = IterListProvider([DDG, DeepInfraChat, LambdaChat, PollinationsAI, Jmuz, HuggingChat, HuggingFace]) + best_provider = IterListProvider([Blackbox, DDG, DeepInfraChat, LambdaChat, PollinationsAI, Jmuz, HuggingChat, HuggingFace]) ) ### Mistral ### @@ -287,7 +292,7 @@ mistral_nemo = Model( mixtral_small_24b = Model( name = "mixtral-small-24b", base_provider = "Mistral", - best_provider = IterListProvider([DDG, DeepInfraChat]) + best_provider = IterListProvider([Blackbox, DDG, DeepInfraChat]) ) ### NousResearch ### @@ -383,7 +388,7 @@ claude_3_haiku = Model( claude_3_5_sonnet = Model( name = 'claude-3.5-sonnet', base_provider = 'Anthropic', - best_provider = IterListProvider([Jmuz, Liaobots]) + best_provider = IterListProvider([Blackbox, Jmuz, Liaobots]) ) # claude 3.7 @@ -491,7 +496,7 @@ qwen_2_5_max = Model( qwq_32b = Model( name = 'qwq-32b', base_provider = 'Qwen', - best_provider = IterListProvider([Jmuz, HuggingChat]) + best_provider = IterListProvider([Blackbox, PollinationsAI, Jmuz, HuggingChat]) ) qvq_72b = VisionModel( name = 'qvq-72b', @@ -516,7 +521,7 @@ deepseek_chat = Model( deepseek_v3 = Model( name = 'deepseek-v3', base_provider = 'DeepSeek', - best_provider = IterListProvider([Blackbox, DeepInfraChat, LambdaChat, OIVSCode, TypeGPT, Liaobots]) + best_provider = IterListProvider([Blackbox, DeepInfraChat, LambdaChat, PollinationsAI, OIVSCode, TypeGPT, Liaobots]) ) deepseek_r1 = Model( @@ -645,8 +650,8 @@ minicpm_2_5 = Model( ) ### Ai2 ### -tulu_3_405b = Model( - name = "tulu-3-405b", +olmo_1_7b = Model( + name = "olmo-1-7b", base_provider = "Ai2", best_provider = AllenAI ) @@ -657,6 +662,18 @@ olmo_2_13b = Model( best_provider = AllenAI ) +olmo_2_32b = Model( + name = "olmo-2-32b", + base_provider = "Ai2", + best_provider = AllenAI +) + +olmo_4_synthetic = VisionModel( + name = "olmo-4-synthetic", + base_provider = "Ai2", + best_provider = AllenAI +) + tulu_3_1_8b = Model( name = "tulu-3-1-8b", base_provider = "Ai2", @@ -669,12 +686,13 @@ tulu_3_70b = Model( best_provider = AllenAI ) -olmoe_0125 = Model( - name = "olmoe-0125", +tulu_3_405b = Model( + name = "tulu-3-405b", base_provider = "Ai2", best_provider = AllenAI ) +### Liquid AI ### lfm_40b = Model( name = "lfm-40b", base_provider = "Liquid AI", @@ -710,7 +728,7 @@ sd_3_5 = ImageModel( flux = ImageModel( name = 'flux', base_provider = 'Black Forest Labs', - best_provider = IterListProvider([Blackbox, PollinationsImage, Websim, HuggingSpace]) + best_provider = IterListProvider([Blackbox, PollinationsImage, Websim, HuggingSpace, ARTA]) ) flux_pro = ImageModel( @@ -922,11 +940,13 @@ class ModelUtils: minicpm_2_5.name: minicpm_2_5, ### Ai2 ### - tulu_3_405b.name: tulu_3_405b, + olmo_1_7b.name: olmo_1_7b, olmo_2_13b.name: olmo_2_13b, + olmo_2_32b.name: olmo_2_32b, + olmo_4_synthetic.name: olmo_4_synthetic, tulu_3_1_8b.name: tulu_3_1_8b, tulu_3_70b.name: tulu_3_70b, - olmoe_0125.name: olmoe_0125, + tulu_3_405b.name: tulu_3_405b, ### Liquid AI ### lfm_40b.name: lfm_40b,