XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/gpt4free

refactor: simplify model alias management and update providers

- Removed specific model aliases for various models (e.g., "gpt-4.1-mini", "phi-4", "grok-3-mini"). - Replaced the `get_model` method with a simplified approach using `get_alias` for alias resolution. - Updated model alias management in `PollinationsAI` to handle model aliases in `get_models` method. - Refined the logic for adding models to `text_models` and `vision_models` in `PollinationsAI`. - Replaced `deepseek-v3` and other model aliases with direct models in `PollinationsAI`. - Modified `Ollama` class to handle local models and improve model fetching with API key. - Changed the `create_async_generator` in `Ollama` to support local model handling and proxy use. - Updated `Azure` class to remove unused `extra_body` argument and streamline stream handling. - Updated model providers in `g4f/models.py` to remove certain providers (e.g., `PollinationsAI`) from `best_provider` lists for some models.

28c4c61f
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

5 个文件 +87 -86
Modified g4f/Provider/PollinationsAI.py +15 -50
@@ -88,21 +88,8 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
88 88 vision_models = [default_vision_model]
89 89 _models_loaded = False
90 90 model_aliases = {
91 "gpt-4.1-mini": "openai",
92 "gpt-4.1-nano": "openai-fast",
93 "gpt-4.1": "openai-large",
94 "o4-mini": "openai-reasoning",
95 "qwen-2.5-coder-32b": "qwen-coder",
96 "llama-3.3-70b": "llama",
97 91 "llama-4-scout": "llamascout",
98 "mistral-small-3.1-24b": "mistral",
99 "phi-4": "phi",
100 92 "deepseek-r1": "deepseek-reasoning",
101 "deepseek-v3-0324": "deepseek",
102 "deepseek-v3": "deepseek",
103 "grok-3-mini": "grok",
104 "grok-3-mini-high": "grok",
105 "gpt-4o-mini-audio": "openai-audio",
106 93 "sdxl-turbo": "turbo",
107 94 "gpt-image": "gptimage",
108 95 "flux-dev": "flux",
@@ -111,27 +98,11 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
111 98 "flux": "flux",
112 99 "flux-kontext": "kontext",
113 100 }
114 swap_models = {value: key for key, value in model_aliases.items()}
115
116 @classmethod
117 def get_model(cls, model: str) -> str:
118 """Get the internal model name from the user-provided model name."""
119 if not model:
120 return cls.default_model
121
122 # Check if there's an alias for this model
123 if model in cls.model_aliases:
124 return cls.model_aliases[model]
125
126 # Check if the model exists directly in our model lists
127 if model in cls.text_models or model in cls.image_models or model in cls.audio_models:
128 return model
129
130 # If no match is found, raise an error
131 raise ModelNotFoundError(f"PollinationsAI: Model {model} not found")
132 101
133 102 @classmethod
134 103 def get_models(cls, **kwargs):
104 def get_alias(model: dict) -> str:
105 return model.get("aliases", model.get("name")).replace("-instruct", "").replace("qwen-", "qwen").replace("qwen", "qwen-")
135 106 if not cls._models_loaded:
136 107 try:
137 108 # Update of image models
@@ -166,25 +137,19 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
166 137 cls.audio_models.update({alias: {}})
167 138
168 139 cls.vision_models.extend([
169 cls.swap_models.get(model.get("name"), model.get("name"))
140 get_alias(model)
170 141 for model in models
171 if model.get("vision") and model not in cls.vision_models
142 if model.get("vision") and get_alias(model) not in cls.vision_models
172 143 ])
173 for alias, model in cls.model_aliases.items():
174 if model in cls.vision_models and alias not in cls.vision_models:
175 cls.vision_models.append(alias)
176 144
177 # Create a set of unique text models starting with default model
178 text_models = cls.text_models.copy()
179
180 # Add models from the API response
181 145 for model in models:
182 model_name = model.get("name")
183 if model_name and "input_modalities" in model and "text" in model["input_modalities"]:
184 text_models.append(cls.swap_models.get(model_name, model_name))
185
186 # Convert to list and update text_models
187 cls.text_models = list(dict.fromkeys(text_models))
146 alias = get_alias(model)
147 if alias not in cls.text_models:
148 cls.text_models.append(alias)
149 if alias != model.get("name"):
150 cls.model_aliases[alias] = model.get("name")
151 elif model.get("name") not in cls.text_models:
152 cls.text_models.append(model.get("name"))
188 153
189 154 cls._models_loaded = True
190 155
@@ -259,10 +224,10 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
259 224 has_audio = True
260 225 break
261 226 model = cls.default_audio_model if has_audio else model
262 try:
263 model = cls.get_model(model) if model else None
264 except ModelNotFoundError:
265 pass
227 elif cls._models_loaded or cls.get_models():
228 if model in cls.model_aliases:
229 model = cls.model_aliases[model]
230 debug.log(f"Using model: {model}")
266 231 if model in cls.image_models:
267 232 async for chunk in cls._generate_image(
268 233 model="gptimage" if model == "transparent" else model,
Modified g4f/Provider/local/Ollama.py +49 -9
@@ -1,22 +1,35 @@
1 1 from __future__ import annotations
2 2
3 import json
3 4 import requests
4 5 import os
5 6
6 7 from ..needs_auth.OpenaiAPI import OpenaiAPI
8 from ...requests import StreamSession, raise_for_status
9 from ...providers.response import Usage, Reasoning
7 10 from ...typing import AsyncResult, Messages
8 11
9 12 class Ollama(OpenaiAPI):
10 13 label = "Ollama"
11 14 url = "https://ollama.com"
12 login_url = None
15 login_url = "https://ollama.com/settings/keys"
16 api_endpoint = "https://ollama.com/api/chat"
13 17 needs_auth = False
14 18 working = True
15 active_by_default = False
19 active_by_default = True
20 local_models: list[str] = []
21 model_aliases = {
22 "gpt-oss-120b": "gpt-oss:120b",
23 "gpt-oss-20b": "gpt-oss:20b"
24 }
16 25
17 26 @classmethod
18 def get_models(cls, api_base: str = None, **kwargs):
27 def get_models(cls, api_key: str = None, api_base: str = None, **kwargs):
19 28 if not cls.models:
29 cls.models = []
30 if api_key:
31 models = requests.get("https://ollama.com/api/tags", {"headers": {"Authorization": f"Bearer {api_key}"}}).json()["models"]
32 cls.models = [model["name"] for model in models]
20 33 if api_base is None:
21 34 host = os.getenv("OLLAMA_HOST", "127.0.0.1")
22 35 port = os.getenv("OLLAMA_PORT", "11434")
@@ -26,23 +39,50 @@ class Ollama(OpenaiAPI):
26 39 try:
27 40 models = requests.get(url).json()["models"]
28 41 except requests.exceptions.RequestException as e:
29 return cls.fallback_models
30 cls.models = [model["name"] for model in models]
42 return cls.models
43 cls.local_models = [model["name"] for model in models]
44 cls.models = cls.models + cls.local_models
31 45 cls.default_model = next(iter(cls.models), None)
32 46 return cls.models
33 47
34 48 @classmethod
35 def create_async_generator(
49 async def create_async_generator(
36 50 cls,
37 51 model: str,
38 52 messages: Messages,
53 api_key: str = None,
39 54 api_base: str = None,
55 proxy: str = None,
40 56 **kwargs
41 57 ) -> AsyncResult:
42 58 if api_base is None:
43 59 host = os.getenv("OLLAMA_HOST", "localhost")
44 60 port = os.getenv("OLLAMA_PORT", "11434")
45 61 api_base: str = f"http://{host}:{port}/v1"
46 return super().create_async_generator(
47 model, messages, api_base=api_base, **kwargs
48 )
62 if model in cls.local_models or not api_key:
63 for chunk in super().create_async_generator(
64 model, messages, api_base=api_base, proxy=proxy, **kwargs
65 ):
66 yield chunk
67 else:
68 async with StreamSession(headers={"Authorization": f"Bearer {api_key}"}, proxy=proxy) as session:
69 async with session.post(cls.api_endpoint, json={
70 "model": model,
71 "messages": messages,
72 }) as response:
73 await raise_for_status(response)
74 last_data = {}
75 async for chunk in response.iter_lines():
76 data = json.loads(chunk)
77 last_data = data
78 thinking = data.get("message", {}).get("thinking", "")
79 if thinking:
80 yield Reasoning(thinking)
81 content = data.get("message", {}).get("content", "")
82 if content:
83 yield content
84 yield Usage(
85 prompt_tokens=last_data.get("prompt_eval_count", 0),
86 completion_tokens=last_data.get("eval_count", 0),
87 total_tokens=last_data.get("prompt_eval_count", 0) + last_data.get("eval_count", 0),
88 )
Modified g4f/Provider/needs_auth/Azure.py +10 -10
@@ -63,7 +63,6 @@ class Azure(OpenaiTemplate):
63 63 messages: Messages,
64 64 stream: bool = True,
65 65 media: MediaListType = None,
66 extra_body: dict = None,
67 66 api_key: str = None,
68 67 api_endpoint: str = None,
69 68 **kwargs
@@ -118,17 +117,19 @@ class Azure(OpenaiTemplate):
118 117 async with session.post(api_endpoint, data=form, json=data) as response:
119 118 data = await response.json()
120 119 await raise_for_status(response, data)
121 async for chunk in save_response_media(data["data"][0]["b64_json"], prompt, content_type=f"image/{output_format}"):
120 async for chunk in save_response_media(
121 data["data"][0]["b64_json"],
122 prompt,
123 content_type=f"image/{output_format.replace('jpg', 'jpeg')}"
124 ):
122 125 yield chunk
123 126 return
124 if extra_body is None:
125 if model in cls.model_extra_body:
126 extra_body = cls.model_extra_body[model]
127 stream = False
128 else:
129 extra_body = {}
127 if model in cls.model_extra_body:
128 for key, value in cls.model_extra_body[model].items():
129 kwargs.setdefault(key, value)
130 stream = False
130 131 if stream:
131 extra_body.setdefault("stream_options", {"include_usage": True})
132 kwargs.setdefault("stream_options", {"include_usage": True})
132 133 try:
133 134 async for chunk in super().create_async_generator(
134 135 model=model,
@@ -137,7 +138,6 @@ class Azure(OpenaiTemplate):
137 138 media=media,
138 139 api_key=api_key,
139 140 api_endpoint=api_endpoint,
140 extra_body=extra_body,
141 141 **kwargs
142 142 ):
143 143 yield chunk
Modified g4f/Provider/template/OpenaiTemplate.py +5 -3
@@ -80,7 +80,7 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
80 80 headers: dict = None,
81 81 impersonate: str = None,
82 82 download_media: bool = True,
83 extra_parameters: list[str] = ["tools", "parallel_tool_calls", "tool_choice", "reasoning_effort", "logit_bias", "modalities", "audio"],
83 extra_parameters: list[str] = ["tools", "parallel_tool_calls", "tool_choice", "reasoning_effort", "logit_bias", "modalities", "audio", "stream_options"],
84 84 extra_body: dict = None,
85 85 **kwargs
86 86 ) -> AsyncResult:
@@ -88,6 +88,7 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
88 88 api_key = cls.api_key
89 89 if cls.needs_auth and api_key is None:
90 90 raise MissingAuthError('Add a "api_key"')
91 print(cls.get_headers(stream, api_key, headers))
91 92 async with StreamSession(
92 93 proxy=proxy,
93 94 headers=cls.get_headers(stream, api_key, headers),
@@ -135,9 +136,10 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
135 136 **extra_body
136 137 )
137 138 if api_endpoint is None:
138 api_endpoint = cls.api_endpoint
139 if api_endpoint is None:
139 if api_base:
140 140 api_endpoint = f"{api_base.rstrip('/')}/chat/completions"
141 if api_endpoint is None:
142 api_endpoint = cls.api_endpoint
141 143 async with session.post(api_endpoint, json=data, ssl=cls.ssl) as response:
142 144 async for chunk in read_response(response, stream, prompt, cls.get_dict(), download_media):
143 145 yield chunk
Modified g4f/models.py +8 -14
@@ -214,7 +214,7 @@ gpt_4o_mini = Model(
214 214 )
215 215
216 216 gpt_4o_mini_audio = AudioModel(
217 name = 'gpt-4o-mini-audio',
217 name = 'gpt-4o-mini-audio-preview',
218 218 base_provider = 'OpenAI',
219 219 best_provider = PollinationsAI
220 220 )
@@ -255,7 +255,7 @@ o3_mini_high = Model(
255 255 o4_mini = Model(
256 256 name = 'o4-mini',
257 257 base_provider = 'OpenAI',
258 best_provider = IterListProvider([PollinationsAI, OpenaiChat])
258 best_provider = OpenaiChat
259 259 )
260 260
261 261 o4_mini_high = Model(
@@ -274,7 +274,7 @@ gpt_4_1 = Model(
274 274 gpt_4_1_mini = Model(
275 275 name = 'gpt-4.1-mini',
276 276 base_provider = 'OpenAI',
277 best_provider = IterListProvider([Blackbox, OIVSCodeSer0501, PollinationsAI])
277 best_provider = IterListProvider([Blackbox, OIVSCodeSer0501])
278 278 )
279 279
280 280 gpt_4_1_nano = Model(
@@ -390,7 +390,7 @@ llama_3_2_90b = Model(
390 390 llama_3_3_70b = Model(
391 391 name = "llama-3.3-70b",
392 392 base_provider = "Meta Llama",
393 best_provider = IterListProvider([DeepInfraChat, LambdaChat, PollinationsAI, Together, HuggingChat, HuggingFace])
393 best_provider = IterListProvider([DeepInfraChat, LambdaChat, Together, HuggingChat, HuggingFace])
394 394 )
395 395
396 396 # llama-4
@@ -456,7 +456,7 @@ phi_3_5_mini = Model(
456 456 phi_4 = Model(
457 457 name = "phi-4",
458 458 base_provider = "Microsoft",
459 best_provider = IterListProvider([DeepInfraChat, PollinationsAI, HuggingSpace])
459 best_provider = IterListProvider([DeepInfraChat, HuggingSpace])
460 460 )
461 461
462 462 phi_4_multimodal = VisionModel(
@@ -753,7 +753,7 @@ qwq_32b = Model(
753 753 deepseek_v3 = Model(
754 754 name = 'deepseek-v3',
755 755 base_provider = 'DeepSeek',
756 best_provider = IterListProvider([DeepInfraChat, PollinationsAI, Together])
756 best_provider = IterListProvider([DeepInfraChat, Together])
757 757 )
758 758
759 759 # deepseek-r1
@@ -810,7 +810,7 @@ deepseek_prover_v2_671b = Model(
810 810 deepseek_v3_0324 = Model(
811 811 name = 'deepseek-v3-0324',
812 812 base_provider = 'DeepSeek',
813 best_provider = IterListProvider([DeepInfraChat, LambdaChat, PollinationsAI])
813 best_provider = IterListProvider([DeepInfraChat, LambdaChat])
814 814 )
815 815
816 816 deepseek_v3_0324_turbo = Model(
@@ -823,7 +823,7 @@ deepseek_v3_0324_turbo = Model(
823 823 deepseek_r1_0528 = Model(
824 824 name = 'deepseek-r1-0528',
825 825 base_provider = 'DeepSeek',
826 best_provider = IterListProvider([DeepInfraChat, LambdaChat])
826 best_provider = IterListProvider([DeepInfraChat, LambdaChat, PollinationsAI])
827 827 )
828 828
829 829 deepseek_r1_0528_turbo = Model(
@@ -852,12 +852,6 @@ grok_3 = Model(
852 852 best_provider = Grok
853 853 )
854 854
855 grok_3_mini = Model(
856 name = 'grok-3-mini',
857 base_provider = 'x.ai',
858 best_provider = PollinationsAI
859 )
860
861 855 grok_3_r1 = Model(
862 856 name = 'grok-3-r1',
863 857 base_provider = 'x.ai',