返回提交历史
Modified
g4f/Provider/Copilot.py
+63
-11
XFEstudio/gpt4free
Upload bucket files as attachments instead of using render_messages
Co-authored-by: hlohaus <983577+hlohaus@users.noreply.github.com>
9c6d2a93
代码差异
1 个文件
+63
-11
@@ -20,7 +20,7 @@ except ImportError:
20
20
has_nodriver = False
21
21
22
22
from .base_provider import AsyncAuthedProvider, ProviderModelMixin
23
from .helper import format_prompt_max_length, render_messages
23
from .helper import format_prompt_max_length
24
24
from .openai.har_file import get_headers, get_har_files
25
25
from ..typing import AsyncResult, Messages, MediaListType
26
26
from ..errors import MissingRequirementsError, NoValidHarFileError, MissingAuthError
@@ -29,6 +29,9 @@ from ..tools.media import merge_media
29
29
from ..requests import get_nodriver
30
30
from ..image import to_bytes, is_accepted_format
31
31
from .helper import get_last_user_message
32
from ..files import get_bucket_dir
33
from ..tools.files import get_filenames
34
from pathlib import Path
32
35
from .. import debug
33
36
34
37
class Conversation(JsonConversation):
@@ -37,6 +40,16 @@ class Conversation(JsonConversation):
37
40
def __init__(self, conversation_id: str):
38
41
self.conversation_id = conversation_id
39
42
43
def extract_bucket_ids(messages: Messages) -> list[str]:
44
"""Extract bucket_ids from messages content."""
45
bucket_ids = []
46
for message in messages:
47
if isinstance(message, dict) and isinstance(message.get("content"), list):
48
for content_item in message["content"]:
49
if isinstance(content_item, dict) and "bucket_id" in content_item:
50
bucket_ids.append(content_item["bucket_id"])
51
return bucket_ids
52
40
53
class Copilot(AsyncAuthedProvider, ProviderModelMixin):
41
54
label = "Microsoft Copilot"
42
55
url = "https://copilot.microsoft.com"
@@ -140,28 +153,26 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
140
153
cls._access_token = None
141
154
else:
142
155
debug.log(f"Copilot: User: {user}")
143
# Process messages to include bucket content once
144
rendered_messages = list(render_messages(messages))
145
146
156
if conversation is None:
147
157
response = await session.post(cls.conversation_url)
148
158
response.raise_for_status()
149
159
conversation_id = response.json().get("id")
150
160
conversation = Conversation(conversation_id)
151
161
if prompt is None:
152
prompt = format_prompt_max_length(rendered_messages, 10000)
162
prompt = format_prompt_max_length(messages, 10000)
153
163
debug.log(f"Copilot: Created conversation: {conversation_id}")
154
164
else:
155
165
conversation_id = conversation.conversation_id
156
166
if prompt is None:
157
prompt = get_last_user_message(rendered_messages)
167
prompt = get_last_user_message(messages)
158
168
debug.log(f"Copilot: Use conversation: {conversation_id}")
159
169
if return_conversation:
160
170
yield conversation
161
171
162
uploaded_images = []
163
# Use rendered messages for media processing to ensure consistency
164
for media, _ in merge_media(media, rendered_messages):
172
uploaded_attachments = []
173
174
# Upload regular media (images)
175
for media, _ in merge_media(media, messages):
165
176
if not isinstance(media, str):
166
177
data = to_bytes(media)
167
178
response = await session.post(
@@ -174,7 +185,48 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
174
185
)
175
186
response.raise_for_status()
176
187
media = response.json().get("url")
177
uploaded_images.append({"type":"image", "url": media})
188
uploaded_attachments.append({"type":"image", "url": media})
189
190
# Upload bucket files
191
bucket_ids = extract_bucket_ids(messages)
192
for bucket_id in bucket_ids:
193
bucket_dir = Path(get_bucket_dir(bucket_id))
194
if bucket_dir.exists():
195
filenames = get_filenames(bucket_dir)
196
for filename in filenames:
197
file_path = bucket_dir / filename
198
if file_path.exists() and file_path.is_file():
199
try:
200
with open(file_path, "rb") as f:
201
file_data = f.read()
202
203
# Determine content type based on file extension
204
content_type = "application/octet-stream"
205
if filename.endswith(".pdf"):
206
content_type = "application/pdf"
207
elif filename.endswith(".docx"):
208
content_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
209
elif filename.endswith(".txt"):
210
content_type = "text/plain"
211
elif filename.endswith(".md"):
212
content_type = "text/markdown"
213
214
response = await session.post(
215
"https://copilot.microsoft.com/c/api/attachments",
216
headers={
217
"content-type": content_type,
218
"content-length": str(len(file_data)),
219
},
220
data=file_data
221
)
222
response.raise_for_status()
223
file_url = response.json().get("url")
224
uploaded_attachments.append({"type": "file", "url": file_url, "name": filename})
225
debug.log(f"Copilot: Uploaded bucket file: {filename}")
226
except Exception as e:
227
debug.log(f"Copilot: Failed to upload bucket file {filename}: {e}")
228
else:
229
debug.log(f"Copilot: Bucket directory not found: {bucket_id}")
178
230
179
231
wss = await session.ws_connect(cls.websocket_url, timeout=3)
180
232
if "Think" in model:
@@ -186,7 +238,7 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
186
238
await wss.send(json.dumps({
187
239
"event": "send",
188
240
"conversationId": conversation_id,
189
"content": [*uploaded_images, {
241
"content": [*uploaded_attachments, {
190
242
"type": "text",
191
243
"text": prompt,
192
244
}],