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

XFEstudio/gpt4free

Refactor Copilot provider to improve authentication handling and streamline media uploads; add error handling for user retrieval. Enhance QwenCode provider to manage token validation and refresh logic. Update backend API to include new error handling for model and provider not found scenarios. Add start-browser script for automated Chrome launch.

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

代码差异

5 个文件 +79 -64
Modified g4f/Provider/Copilot.py +55 -55
@@ -119,7 +119,7 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
119 119 model = cls.get_model(model)
120 120 websocket_url = cls.websocket_url
121 121 headers = None
122 if cls._access_token:
122 if cls._access_token or cls.needs_auth:
123 123 if api_key is not None:
124 124 cls._access_token = api_key
125 125 if cls._access_token is None:
@@ -144,17 +144,17 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
144 144 ) as session:
145 145 if cls._access_token is not None:
146 146 cls._cookies = session.cookies.jar if hasattr(session.cookies, "jar") else session.cookies
147 response = await session.get("https://copilot.microsoft.com/c/api/user?api-version=2", headers={"x-useridentitytype": useridentitytype})
148 if response.status_code == 401:
149 raise MissingAuthError("Status 401: Invalid access token")
150 response.raise_for_status()
151 user = response.json().get('firstName')
152 if user is None:
153 if cls.needs_auth:
154 raise MissingAuthError("No user found, please login first")
155 cls._access_token = None
156 else:
157 debug.log(f"Copilot: User: {user}")
147 response = await session.get("https://copilot.microsoft.com/c/api/user?api-version=2", headers={"x-useridentitytype": useridentitytype})
148 if response.status_code == 401:
149 raise MissingAuthError("Status 401: Invalid access token")
150 response.raise_for_status()
151 user = response.json().get('firstName')
152 if user is None:
153 if cls.needs_auth:
154 raise MissingAuthError("No user found, please login first")
155 cls._access_token = None
156 else:
157 debug.log(f"Copilot: User: {user}")
158 158 if conversation is None:
159 159 response = await session.post(cls.conversation_url, headers={"x-useridentitytype": useridentitytype})
160 160 response.raise_for_status()
@@ -168,50 +168,50 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
168 168 yield conversation
169 169
170 170 uploaded_attachments = []
171
172 # Upload regular media (images)
173 for media, _ in merge_media(media, messages):
174 if not isinstance(media, str):
175 data = to_bytes(media)
176 response = await session.post(
177 "https://copilot.microsoft.com/c/api/attachments",
178 headers={
179 "content-type": is_accepted_format(data),
180 "content-length": str(len(data)),
181 "x-useridentitytype": useridentitytype
182 },
183 data=data
184 )
185 response.raise_for_status()
186 media = response.json().get("url")
187 uploaded_attachments.append({"type":"image", "url": media})
171 if cls._access_token is not None:
172 # Upload regular media (images)
173 for media, _ in merge_media(media, messages):
174 if not isinstance(media, str):
175 data = to_bytes(media)
176 response = await session.post(
177 "https://copilot.microsoft.com/c/api/attachments",
178 headers={
179 "content-type": is_accepted_format(data),
180 "content-length": str(len(data)),
181 "x-useridentitytype": useridentitytype
182 },
183 data=data
184 )
185 response.raise_for_status()
186 media = response.json().get("url")
187 uploaded_attachments.append({"type":"image", "url": media})
188 188
189 # Upload bucket files
190 bucket_items = extract_bucket_items(messages)
191 for item in bucket_items:
192 try:
193 # Handle plain text content from bucket
194 bucket_path = Path(get_bucket_dir(item["bucket_id"]))
195 for text_chunk in read_bucket(bucket_path):
196 if text_chunk.strip():
197 # Upload plain text as a text file
198 text_data = text_chunk.encode('utf-8')
199 data = CurlMime()
200 data.addpart("file", filename=f"bucket_{item['bucket_id']}.txt", content_type="text/plain", data=text_data)
201 response = await session.post(
202 "https://copilot.microsoft.com/c/api/attachments",
203 multipart=data,
204 headers={"x-useridentitytype": useridentitytype}
205 )
206 response.raise_for_status()
207 data = response.json()
208 uploaded_attachments.append({"type": "document", "attachmentId": data.get("id")})
209 debug.log(f"Copilot: Uploaded bucket text content: {item['bucket_id']}")
210 else:
211 debug.log(f"Copilot: No text content found in bucket: {item['bucket_id']}")
212 except Exception as e:
213 debug.log(f"Copilot: Failed to upload bucket item: {item}")
214 debug.error(e)
189 # Upload bucket files
190 bucket_items = extract_bucket_items(messages)
191 for item in bucket_items:
192 try:
193 # Handle plain text content from bucket
194 bucket_path = Path(get_bucket_dir(item["bucket_id"]))
195 for text_chunk in read_bucket(bucket_path):
196 if text_chunk.strip():
197 # Upload plain text as a text file
198 text_data = text_chunk.encode('utf-8')
199 data = CurlMime()
200 data.addpart("file", filename=f"bucket_{item['bucket_id']}.txt", content_type="text/plain", data=text_data)
201 response = await session.post(
202 "https://copilot.microsoft.com/c/api/attachments",
203 multipart=data,
204 headers={"x-useridentitytype": useridentitytype}
205 )
206 response.raise_for_status()
207 data = response.json()
208 uploaded_attachments.append({"type": "document", "attachmentId": data.get("id")})
209 debug.log(f"Copilot: Uploaded bucket text content: {item['bucket_id']}")
210 else:
211 debug.log(f"Copilot: No text content found in bucket: {item['bucket_id']}")
212 except Exception as e:
213 debug.log(f"Copilot: Failed to upload bucket item: {item}")
214 debug.error(e)
215 215
216 216 if prompt is None:
217 217 prompt = get_last_user_message(messages, False)
Modified g4f/Provider/qwen/QwenCode.py +6 -4
@@ -20,7 +20,11 @@ class QwenCode(OpenaiTemplate):
20 20
21 21 @classmethod
22 22 def get_models(cls, **kwargs):
23 if cls.live == 0 and cls.client.shared_manager.isTokenValid(cls.client.shared_manager.getCurrentCredentials()):
23 if cls.live == 0:
24 cls.client.shared_manager.checkAndReloadIfNeeded()
25 creds = cls.client.shared_manager.getCurrentCredentials()
26 if creds:
27 cls.client.shared_manager.isTokenValid(creds)
24 28 cls.live += 1
25 29 return cls.models
26 30
@@ -46,9 +50,7 @@ class QwenCode(OpenaiTemplate):
46 50 if chunk != last_chunk:
47 51 yield chunk
48 52 last_chunk = chunk
49 except TokenManagerError as e:
50 raise MissingAuthError(f"QwenCode: No valid authentication available: {e}")
51 except MissingAuthError:
53 except TokenManagerError:
52 54 await cls.client.shared_manager.getValidCredentials(cls.client.qwen_client, True)
53 55 creds = await cls.client.get_valid_token()
54 56 last_chunk = None
Modified g4f/Provider/qwen/sharedTokenManager.py +4 -3
@@ -86,7 +86,7 @@ class SharedTokenManager(AuthFileMixin):
86 86
87 87 async def getValidCredentials(self, qwen_client: IQwenOAuth2Client, force_refresh: bool = False):
88 88 try:
89 await self.checkAndReloadIfNeeded()
89 self.checkAndReloadIfNeeded()
90 90
91 91 if (
92 92 self.memory_cache["credentials"]
@@ -107,7 +107,7 @@ class SharedTokenManager(AuthFileMixin):
107 107 raise
108 108 raise TokenManagerError(TokenError.REFRESH_FAILED, str(e), e)
109 109
110 async def checkAndReloadIfNeeded(self):
110 def checkAndReloadIfNeeded(self):
111 111 now = int(time.time() * 1000)
112 112 if now - self.memory_cache["last_check"] < CACHE_CHECK_INTERVAL_MS:
113 113 return
@@ -149,12 +149,13 @@ class SharedTokenManager(AuthFileMixin):
149 149 async def performTokenRefresh(self, qwen_client: IQwenOAuth2Client, force_refresh: bool):
150 150 lock_path = self.getLockFilePath()
151 151 try:
152 qwen_client.setCredentials(self.memory_cache["credentials"])
152 153 current_credentials = qwen_client.getCredentials()
153 154 if not current_credentials.get("refresh_token"):
154 155 raise TokenManagerError(TokenError.NO_REFRESH_TOKEN, "No refresh token")
155 156 await self.acquireLock(lock_path)
156 157
157 await self.checkAndReloadIfNeeded()
158 self.checkAndReloadIfNeeded()
158 159
159 160 if (
160 161 not force_refresh
Modified g4f/gui/server/backend_api.py +8 -2
@@ -31,7 +31,7 @@ try:
31 31 except ImportError as e:
32 32 has_markitdown = False
33 33 try:
34 from .crypto import rsa, serialization, create_or_read_keys, decrypt_data, encrypt_data, get_session_key
34 from .crypto import serialization, create_or_read_keys, decrypt_data, encrypt_data, get_session_key
35 35 has_crypto = True
36 36 except ImportError:
37 37 has_crypto = False
@@ -42,7 +42,7 @@ from ...providers.response import FinishReason, AudioResponse, MediaResponse, Re
42 42 from ...client.helper import filter_markdown
43 43 from ...tools.files import supports_filename, get_streaming, get_bucket_dir, get_tempfile
44 44 from ...tools.run_tools import iter_run_tools
45 from ...errors import ProviderNotFoundError, MissingAuthError
45 from ...errors import ModelNotFoundError, ProviderNotFoundError, MissingAuthError, RateLimitError
46 46 from ...image import is_allowed_extension, process_image, MEDIA_TYPE_MAP
47 47 from ...cookies import get_cookies_dir
48 48 from ...image.copy_images import secure_filename, get_source_url, get_media_dir, copy_media
@@ -368,6 +368,12 @@ class Backend_Api(Api):
368 368 response = response if isinstance(response, str) else "".join(response)
369 369 return Response(filter_markdown(response, None if is_true_filter else do_filter, response if is_true_filter else ""), mimetype='text/plain')
370 370 return Response(response, mimetype='text/plain')
371 except (ModelNotFoundError, ProviderNotFoundError) as e:
372 return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 404
373 except MissingAuthError as e:
374 return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 401
375 except RateLimitError as e:
376 return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 429
371 377 except Exception as e:
372 378 logger.exception(e)
373 379 return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 500
Added scripts/start-browser.sh +6 -0
@@ -0,0 +1,6 @@
1 #!/bin/bash
2 while true; do
3 sleep 5
4 rm ~/.config/g4f/cookies/.nodriver_is_open
5 google-chrome --remote-allow-origins=* --no-first-run --no-service-autorun --no-default-browser-check --homepage=about:blank --no-pings --password-store=basic --disable-infobars --disable-breakpad --disable-dev-shm-usage --disable-session-crashed-bubble --disable-search-engine-choice-screen --user-data-dir="~/.config/g4f-nodriver" --disable-session-crashed-bubble --disable-features=IsolateOrigins,site-per-process --no-sandbox --remote-debugging-host=127.0.0.1 --remote-debugging-port=57011
6 done