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

XFEstudio/gpt4free

feat(Blackbox): add image generation support and enhance response handling

f2f04a00
kqlio67 <kqlio67@users.noreply.github.com>
提交于

代码差异

1 个文件 +62 -15
Modified g4f/Provider/Blackbox.py +62 -15
@@ -3,11 +3,12 @@ from __future__ import annotations
3 3 import uuid
4 4 import secrets
5 5 import re
6 from aiohttp import ClientSession, ClientResponse
6 import base64
7 from aiohttp import ClientSession
7 8 from typing import AsyncGenerator, Optional
8 9
9 10 from ..typing import AsyncResult, Messages, ImageType
10 from ..image import to_data_uri
11 from ..image import to_data_uri, ImageResponse
11 12 from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
12 13
13 14 class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
@@ -20,12 +21,25 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
20 21 "llama-3.1-8b",
21 22 'llama-3.1-70b',
22 23 'llama-3.1-405b',
24 'ImageGeneration',
23 25 ]
24 26
25 27 model_aliases = {
26 28 "gemini-flash": "gemini-1.5-flash",
27 29 }
28 30
31 agent_mode_map = {
32 'ImageGeneration': {"mode": True, "id": "ImageGenerationLV45LJp", "name": "Image Generation"},
33 }
34
35 model_id_map = {
36 "blackbox": {},
37 "gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
38 "llama-3.1-8b": {'mode': True, 'id': "llama-3.1-8b"},
39 'llama-3.1-70b': {'mode': True, 'id': "llama-3.1-70b"},
40 'llama-3.1-405b': {'mode': True, 'id': "llama-3.1-405b"}
41 }
42
29 43 @classmethod
30 44 def get_model(cls, model: str) -> str:
31 45 if model in cls.models:
@@ -35,6 +49,15 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
35 49 else:
36 50 return cls.default_model
37 51
52 @classmethod
53 async def download_image_to_base64_url(cls, url: str) -> str:
54 async with ClientSession() as session:
55 async with session.get(url) as response:
56 image_data = await response.read()
57 base64_data = base64.b64encode(image_data).decode('utf-8')
58 mime_type = response.headers.get('Content-Type', 'image/jpeg')
59 return f"data:{mime_type};base64,{base64_data}"
60
38 61 @classmethod
39 62 async def create_async_generator(
40 63 cls,
@@ -44,7 +67,7 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
44 67 image: Optional[ImageType] = None,
45 68 image_name: Optional[str] = None,
46 69 **kwargs
47 ) -> AsyncGenerator[str, None]:
70 ) -> AsyncGenerator[AsyncResult, None]:
48 71 if image is not None:
49 72 messages[-1]["data"] = {
50 73 "fileText": image_name,
@@ -72,20 +95,12 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
72 95
73 96 model = cls.get_model(model) # Resolve the model alias
74 97
75 model_id_map = {
76 "blackbox": {},
77 "gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
78 "llama-3.1-8b": {'mode': True, 'id': "llama-3.1-8b"},
79 'llama-3.1-70b': {'mode': True, 'id': "llama-3.1-70b"},
80 'llama-3.1-405b': {'mode': True, 'id': "llama-3.1-405b"}
81 }
82
83 98 data = {
84 99 "messages": messages,
85 100 "id": random_id,
86 101 "userId": random_user_id,
87 102 "codeModelMode": True,
88 "agentMode": {},
103 "agentMode": cls.agent_mode_map.get(model, {}),
89 104 "trendingAgentMode": {},
90 105 "isMicMode": False,
91 106 "isChromeExt": False,
@@ -93,7 +108,7 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
93 108 "webSearchMode": False,
94 109 "userSystemPrompt": "",
95 110 "githubToken": None,
96 "trendingAgentModel": model_id_map.get(model, {}), # Default to empty dict if model not found
111 "trendingAgentModel": cls.model_id_map.get(model, {}),
97 112 "maxTokens": None
98 113 }
99 114
@@ -101,9 +116,41 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
101 116 f"{cls.url}/api/chat", json=data, proxy=proxy
102 117 ) as response:
103 118 response.raise_for_status()
119 full_response = ""
120 buffer = ""
121 image_base64_url = None
104 122 async for chunk in response.content.iter_any():
105 123 if chunk:
106 # Decode the chunk and clean up unwanted prefixes using a regex
107 124 decoded_chunk = chunk.decode()
108 125 cleaned_chunk = re.sub(r'\$@\$.+?\$@\$|\$@\$', '', decoded_chunk)
109 yield cleaned_chunk
126
127 buffer += cleaned_chunk
128
129 # Check if there's a complete image line in the buffer
130 image_match = re.search(r'!\[Generated Image\]\((https?://[^\s\)]+)\)', buffer)
131 if image_match:
132 image_url = image_match.group(1)
133 # Download the image and convert to base64 URL
134 image_base64_url = await cls.download_image_to_base64_url(image_url)
135
136 # Remove the image line from the buffer
137 buffer = re.sub(r'!\[Generated Image\]\(https?://[^\s\)]+\)', '', buffer)
138
139 # Send text line by line
140 lines = buffer.split('\n')
141 for line in lines[:-1]:
142 if line.strip():
143 full_response += line + '\n'
144 yield line + '\n'
145 buffer = lines[-1] # Keep the last incomplete line in the buffer
146
147 # Send the remaining buffer if it's not empty
148 if buffer.strip():
149 full_response += buffer
150 yield buffer
151
152 # If an image was found, send it as ImageResponse
153 if image_base64_url:
154 alt_text = "Generated Image"
155 image_response = ImageResponse(image_base64_url, alt=alt_text)
156 yield image_response