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

XFEstudio/gpt4free

refactor: update model mappings, error handling, and file utils

- Changed `generate_commit_message` return to `.strip("`").strip()` in `commit.py` - Added new model mappings in `PollinationsAI.py`, including `gpt-4.1`, `gpt-4.1-mini`, and `deepseek-r1-distill-*` - Removed `print` debug statement from `PollinationsAI.py` request payload - Replaced temp file handling in `MarkItDown.py` with `get_tempfile` utility - Added `get_tempfile` function to `files.py` for consistent tempfile creation - Added `gpt-4.1` to `text_models` list in `models.py` - Added `ModelNotSupportedError` to exception handling in `OpenaiChat.py` - Updated message content creation to use `to_string()` in `OpenaiChat.py` - Wrapped `get_model()` in try-except to ignore `ModelNotSupportedError` in `OpenaiChat.py` - Adjusted `convert` endpoint in `api/__init__.py` to accept optional `provider` param - Refactored `/api/markitdown` to reuse `convert()` handler in `api/__init__.py

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

代码差异

7 个文件 +46 -33
Modified etc/tool/commit.py +1 -1
@@ -201,7 +201,7 @@ def generate_commit_message(diff_text: str, model: str = DEFAULT_MODEL) -> Optio
201 201 spinner = None
202 202 content.append(chunk.choices[0].delta.content)
203 203 print(chunk.choices[0].delta.content, end="", flush=True)
204 return "".join(content).strip().strip("`")
204 return "".join(content).strip("`").strip()
205 205 except Exception as e:
206 206 # Stop spinner if it's running
207 207 if 'spinner' in locals() and spinner:
Modified g4f/Provider/PollinationsAI.py +8 -2
@@ -59,6 +59,11 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
59 59 "gpt-4o-mini": "openai",
60 60 "gpt-4": "openai-large",
61 61 "gpt-4o": "openai-large",
62 "gpt-4.1": "openai",
63 "gpt-4.1-nano": "openai",
64 "gpt-4.1-mini": "openai-large",
65 "gpt-4.1-xlarge": "openai-xlarge",
66 "o4-mini": "openai-reasoning",
62 67 "qwen-2.5-coder-32b": "qwen-coder",
63 68 "llama-3.3-70b": "llama",
64 69 "llama-4-scout": "llamascout",
@@ -67,10 +72,12 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
67 72 "llama-3.3-70b": "llama-scaleway",
68 73 "phi-4": "phi",
69 74 "deepseek-r1": "deepseek-reasoning-large",
70 "deepseek-r1": "deepseek-reasoning",
75 "deepseek-r1-distill-llama-70b": "deepseek-reasoning-large",
76 "deepseek-r1-distill-qwen-32b": "deepseek-reasoning",
71 77 "deepseek-v3": "deepseek",
72 78 "llama-3.2-11b": "llama-vision",
73 79 "gpt-4o-audio": "openai-audio",
80 "gpt-4o-audio-preview": "openai-audio",
74 81
75 82 ### Image Models ###
76 83 "sdxl-turbo": "turbo",
@@ -331,7 +338,6 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
331 338 "cache": cache,
332 339 **extra_parameters
333 340 })
334 print(f"Requesting {url} with data: {data}")
335 341 async with session.post(url, json=data) as response:
336 342 await raise_for_status(response)
337 343 if response.headers["content-type"].startswith("text/plain"):
Modified g4f/Provider/audio/MarkItDown.py +8 -11
@@ -1,7 +1,5 @@
1 1 from __future__ import annotations
2 2
3 import tempfile
4 import shutil
5 3 import os
6 4
7 5 try:
@@ -11,6 +9,7 @@ except ImportError:
11 9 has_markitdown = False
12 10
13 11 from ...typing import AsyncResult, Messages, MediaListType
12 from ...tools.files import get_tempfile
14 13 from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
15 14
16 15 class MarkItDown(AsyncGeneratorProvider, ProviderModelMixin):
@@ -26,17 +25,15 @@ class MarkItDown(AsyncGeneratorProvider, ProviderModelMixin):
26 25 ) -> AsyncResult:
27 26 md = MaItDo()
28 27 for file, filename in media:
28 text = None
29 29 try:
30 text = md.convert(file, stream_info=StreamInfo(filename=filename)).text_content
30 text = md.convert(file, stream_info=StreamInfo(filename=filename) if filename else None).text_content
31 31 except TypeError:
32 # Copy SpooledTemporaryFile to a NamedTemporaryFile
33 copyfile = tempfile.NamedTemporaryFile(suffix=filename, delete=False)
34 shutil.copyfileobj(file, copyfile)
35 copyfile.close()
36 file.close()
37 # Use the NamedTemporaryFile for conversion
38 text = md.convert(copyfile.name, stream_info=StreamInfo(filename=filename)).text_content
39 os.remove(copyfile.name)
32 copyfile = get_tempfile(file, filename)
33 try:
34 text = md.convert(copyfile).text_content
35 finally:
36 os.remove(copyfile)
40 37 text = text.split("### Audio Transcript:\n")[-1]
41 38 if text:
42 39 yield text
Modified g4f/Provider/needs_auth/OpenaiChat.py +7 -4
@@ -23,11 +23,11 @@ from ...requests.raise_for_status import raise_for_status
23 23 from ...requests import StreamSession
24 24 from ...requests import get_nodriver
25 25 from ...image import ImageRequest, to_image, to_bytes, is_accepted_format
26 from ...errors import MissingAuthError, NoValidHarFileError
26 from ...errors import MissingAuthError, NoValidHarFileError, ModelNotSupportedError
27 27 from ...providers.response import JsonConversation, FinishReason, SynthesizeData, AuthResult, ImageResponse, ImagePreview
28 28 from ...providers.response import Sources, TitleGeneration, RequestLogin, Reasoning
29 29 from ...tools.media import merge_media
30 from ..helper import format_cookies, format_image_prompt
30 from ..helper import format_cookies, format_image_prompt, to_string
31 31 from ..openai.models import default_model, default_image_model, models, image_models, text_models
32 32 from ..openai.har_file import get_request_config
33 33 from ..openai.har_file import RequestConfig, arkReq, arkose_url, start_url, conversation_url, backend_url, backend_anon_url
@@ -221,7 +221,7 @@ class OpenaiChat(AsyncAuthedProvider, ProviderModelMixin):
221 221 messages = [{
222 222 "id": str(uuid.uuid4()),
223 223 "author": {"role": message["role"]},
224 "content": {"content_type": "text", "parts": [message["content"]]},
224 "content": {"content_type": "text", "parts": [to_string(message["content"])]},
225 225 "metadata": {"serialization_metadata": {"custom_symbol_offsets": []}, **({"system_hints": system_hints} if system_hints else {})},
226 226 "create_time": time.time(),
227 227 } for message in messages]
@@ -356,7 +356,10 @@ class OpenaiChat(AsyncAuthedProvider, ProviderModelMixin):
356 356 except Exception as e:
357 357 debug.error("OpenaiChat: Upload image failed")
358 358 debug.error(e)
359 model = cls.get_model(model)
359 try:
360 model = cls.get_model(model)
361 except ModelNotSupportedError:
362 pass
360 363 if conversation is None:
361 364 conversation = Conversation(None, str(uuid.uuid4()), getattr(auth_result, "cookies", {}).get("oai-did"))
362 365 else:
Modified g4f/Provider/openai/models.py +1 -1
@@ -1,6 +1,6 @@
1 1 default_model = "auto"
2 2 default_image_model = "dall-e-3"
3 3 image_models = [default_image_model]
4 text_models = [default_model, "gpt-4", "gpt-4.5", "gpt-4o", "gpt-4o-mini", "o1", "o1-preview", "o1-mini", "o3-mini", "o3-mini-high"]
4 text_models = [default_model, "gpt-4", "gpt-4.1", "gpt-4.5", "gpt-4o", "gpt-4o-mini", "o1", "o1-preview", "o1-mini", "o3-mini", "o3-mini-high"]
5 5 vision_models = text_models
6 6 models = text_models + image_models
Modified g4f/api/__init__.py +11 -13
@@ -494,28 +494,20 @@ class Api:
494 494 }
495 495 @self.app.post("/v1/audio/transcriptions", responses=responses)
496 496 @self.app.post("/api/{path_provider}/audio/transcriptions", responses=responses)
497 @self.app.post("/api/markitdown", responses=responses)
498 497 async def convert(
499 498 file: UploadFile,
500 model: Annotated[Optional[str], Form()] = None,
501 provider: Annotated[Optional[str], Form()] = "MarkItDown",
502 499 path_provider: str = None,
503 prompt: Annotated[Optional[str], Form()] = "Transcribe this audio",
504 api_key: Annotated[Optional[str], Form()] = None,
505 credentials: Annotated[HTTPAuthorizationCredentials, Depends(Api.security)] = None
500 model: Annotated[Optional[str], Form()] = None,
501 provider: Annotated[Optional[str], Form()] = None,
502 prompt: Annotated[Optional[str], Form()] = "Transcribe this audio"
506 503 ):
507 if credentials is not None and credentials.credentials != "secret":
508 api_key = credentials.credentials
509 504 try:
510 505 response = await self.client.chat.completions.create(
511 506 messages=prompt,
512 507 model=model,
508 provider=provider if path_provider is None else path_provider,
513 509 media=[[file.file, file.filename]],
514 modalities=["text"],
515 **filter_none(
516 provider=provider if path_provider is None else path_provider,
517 api_key=api_key
518 )
510 modalities=["text"]
519 511 )
520 512 return {"text": response.choices[0].message.content, "model": response.model, "provider": response.provider}
521 513 except (ModelNotFoundError, ProviderNotFoundError) as e:
@@ -528,6 +520,12 @@ class Api:
528 520 logger.exception(e)
529 521 return ErrorResponse.from_exception(e, None, HTTP_500_INTERNAL_SERVER_ERROR)
530 522
523 @self.app.post("/api/markitdown", responses=responses)
524 async def markitdown(
525 file: UploadFile
526 ):
527 return await convert(file, "MarkItDown")
528
531 529 responses = {
532 530 HTTP_200_OK: {"class": FileResponse},
533 531 HTTP_401_UNAUTHORIZED: {"model": ErrorResponseModel},
Modified g4f/tools/files.py +10 -1
@@ -13,6 +13,8 @@ import zipfile
13 13 import asyncio
14 14 import hashlib
15 15 import base64
16 import tempfile
17 import shutil
16 18
17 19 try:
18 20 import PyPDF2
@@ -578,4 +580,11 @@ async def get_async_streaming(bucket_dir: str, delete_files = False, refine_chun
578 580 except Exception as e:
579 581 if event_stream:
580 582 yield f'data: {json.dumps({"error": {"message": str(e)}})}\n\n'
581 raise e
583 raise e
584
585 def get_tempfile(file, suffix):
586 copyfile = tempfile.NamedTemporaryFile(suffix=suffix, delete=False)
587 shutil.copyfileobj(file, copyfile)
588 copyfile.close()
589 file.close()
590 return copyfile.name