Skip to content

Commit a7ae6cb

Browse files
authored
Merge pull request #246 from lanqian528/dev
Dev to Main
2 parents 54398e2 + 3cc67f0 commit a7ae6cb

File tree

12 files changed

+10603
-7828
lines changed

12 files changed

+10603
-7828
lines changed

chatgpt/ChatService.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ async def get_chat_requirements(self):
183183
url = f'{self.base_url}/sentinel/chat-requirements'
184184
headers = self.base_headers.copy()
185185
try:
186-
config = get_config(self.user_agent)
186+
config = get_config(self.user_agent, self.req_token)
187187
p = get_requirements_token(config)
188188
data = {'p': p}
189189
r = await self.ss.post(url, headers=headers, json=data, timeout=5)
@@ -211,7 +211,7 @@ async def get_chat_requirements(self):
211211
try:
212212
if turnstile_solver_url:
213213
res = await self.s.post(
214-
turnstile_solver_url, json={"url": "https://chatgpt.com", "p": p, "dx": turnstile_dx}
214+
turnstile_solver_url, json={"url": "https://chatgpt.com", "p": p, "dx": turnstile_dx, "ua": self.user_agent}
215215
)
216216
self.turnstile_token = res.json().get("t")
217217
except Exception as e:
@@ -410,6 +410,20 @@ async def get_download_url(self, file_id):
410410
logger.error(f"Failed to get download url: {e}")
411411
return ""
412412

413+
async def get_attachment_url(self, file_id, conversation_id):
414+
url = f"{self.base_url}/conversation/{conversation_id}/attachment/{file_id}/download"
415+
headers = self.base_headers.copy()
416+
try:
417+
r = await self.s.get(url, headers=headers, timeout=10)
418+
if r.status_code == 200:
419+
download_url = r.json().get('download_url')
420+
return download_url
421+
else:
422+
raise HTTPException(status_code=r.status_code, detail=r.text)
423+
except Exception as e:
424+
logger.error(f"Failed to get download url: {e}")
425+
return ""
426+
413427
async def get_download_url_from_upload(self, file_id):
414428
url = f"{self.base_url}/files/{file_id}/uploaded"
415429
headers = self.base_headers.copy()

chatgpt/chatFormat.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ async def stream_response(service, response, model, max_tokens):
137137
last_message_id = None
138138
last_role = None
139139
last_content_type = None
140+
last_status = None
140141
model_slug = None
141142
end = False
142143

@@ -160,6 +161,8 @@ async def stream_response(service, response, model, max_tokens):
160161

161162
async for chunk in response:
162163
chunk = chunk.decode("utf-8")
164+
print(chunk)
165+
print("=====================================")
163166
if end:
164167
logger.info(f"Response Model: {model_slug}")
165168
yield "data: [DONE]\n\n"
@@ -214,6 +217,8 @@ async def stream_response(service, response, model, max_tokens):
214217
if role == 'assistant' and last_role != 'assistant':
215218
if recipient == 'dalle.text2im':
216219
new_text = f"\n```{recipient}\n{part[len_last_content:]}"
220+
elif recipient == 't2uay3k.sj1i4kz':
221+
new_text = f"\n```image_creator\n{part[len_last_content:]}"
217222
elif last_role == None:
218223
new_text = part[len_last_content:]
219224
else:
@@ -225,6 +230,21 @@ async def stream_response(service, response, model, max_tokens):
225230
else:
226231
new_text = part[len_last_content:]
227232
len_last_content = len(part)
233+
elif outer_content_type == "multimodal_text":
234+
parts = content.get("parts", [])
235+
new_text = ""
236+
for part in parts:
237+
file_id = part.get('asset_pointer').replace('sediment://', '')
238+
full_height = part.get("height", 0)
239+
current_height = part.get('metadata', {}).get("generation", {}).get("height", 0)
240+
if full_height > current_height:
241+
completed_rate = current_height / full_height
242+
new_text = f"\n> {completed_rate:.2%}\n"
243+
if last_role != role:
244+
new_text = f"\n```{new_text}"
245+
else:
246+
image_download_url = await service.get_attachment_url(file_id, conversation_id)
247+
new_text = f"\n```\n![image]({image_download_url})\n"
228248
else:
229249
text = content.get("text", "")
230250
if outer_content_type == "code" and last_content_type != "code":
@@ -241,13 +261,16 @@ async def stream_response(service, response, model, max_tokens):
241261
new_text = "\n```\n" + new_text
242262
elif last_content_type == "execution_output" and outer_content_type != "execution_output":
243263
new_text = "\n```\n" + new_text
264+
elif last_content_type == "multimodal_text" and outer_content_type != "multimodal_text":
265+
new_text = "\n```\n" + new_text
244266

245267
delta = {"content": new_text}
246268
last_content_type = outer_content_type
247269
if completion_tokens >= max_tokens:
248270
delta = {}
249271
finish_reason = "length"
250272
end = True
273+
251274
elif status == "finished_successfully":
252275
if content.get("content_type") == "multimodal_text":
253276
parts = content.get("parts", [])
@@ -258,14 +281,19 @@ async def stream_response(service, response, model, max_tokens):
258281
inner_content_type = part.get('content_type')
259282
if inner_content_type == "image_asset_pointer":
260283
last_content_type = "image_asset_pointer"
261-
file_id = part.get('asset_pointer').replace('file-service://', '')
262-
logger.debug(f"file_id: {file_id}")
263-
image_download_url = await service.get_download_url(file_id)
264-
logger.debug(f"image_download_url: {image_download_url}")
265-
if image_download_url:
266-
delta = {"content": f"\n```\n![image]({image_download_url})\n"}
284+
if part.get('asset_pointer').startswith('file-service://'):
285+
file_id = part.get('asset_pointer').replace('file-service://', '')
286+
logger.debug(f"file_id: {file_id}")
287+
image_download_url = await service.get_download_url(file_id)
288+
logger.debug(f"image_download_url: {image_download_url}")
289+
if image_download_url:
290+
delta = {"content": f"\n```\n![image]({image_download_url})\n"}
291+
else:
292+
delta = {"content": f"\n```\nFailed to load the image.\n"}
267293
else:
268-
delta = {"content": f"\n```\nFailed to load the image.\n"}
294+
file_id = part.get('asset_pointer').replace('sediment://', '')
295+
image_download_url = await service.get_attachment_url(file_id, conversation_id)
296+
delta = {"content": f"\n![image]({image_download_url})\n"}
269297
elif message.get("end_turn"):
270298
part = content.get("parts", [])[0]
271299
new_text = part[len_last_content:]
@@ -294,6 +322,7 @@ async def stream_response(service, response, model, max_tokens):
294322
continue
295323
last_message_id = message_id
296324
last_role = role
325+
last_status = status
297326
if not end and not delta.get("content"):
298327
delta = {"role": "assistant", "content": ""}
299328
chunk_new_data["choices"][0]["delta"] = delta

chatgpt/chatFormat_v1.py

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
import asyncio
2+
import json
3+
import random
4+
import re
5+
import string
6+
import time
7+
import uuid
8+
9+
import pybase64
10+
import websockets
11+
from fastapi import HTTPException
12+
13+
from api.files import get_file_content
14+
from api.models import model_system_fingerprint
15+
from api.tokens import split_tokens_from_content, calculate_image_tokens, num_tokens_from_messages
16+
from utils.Logger import logger
17+
18+
moderation_message = "I'm sorry, I cannot provide or engage in any content related to pornography, violence, or any unethical material. If you have any other questions or need assistance, please feel free to let me know. I'll do my best to provide support and assistance."
19+
20+
21+
async def format_not_stream_response(response, prompt_tokens, max_tokens, model):
22+
chat_id = f"chatcmpl-{''.join(random.choice(string.ascii_letters + string.digits) for _ in range(29))}"
23+
system_fingerprint_list = model_system_fingerprint.get(model, None)
24+
system_fingerprint = random.choice(system_fingerprint_list) if system_fingerprint_list else None
25+
created_time = int(time.time())
26+
all_text = ""
27+
async for chunk in response:
28+
try:
29+
if chunk.startswith("data: [DONE]"):
30+
break
31+
elif not chunk.startswith("data: "):
32+
continue
33+
else:
34+
chunk = json.loads(chunk[6:])
35+
if not chunk["choices"][0].get("delta"):
36+
continue
37+
all_text += chunk["choices"][0]["delta"]["content"]
38+
except Exception as e:
39+
logger.error(f"Error: {chunk}, error: {str(e)}")
40+
continue
41+
content, completion_tokens, finish_reason = await split_tokens_from_content(all_text, max_tokens, model)
42+
message = {
43+
"role": "assistant",
44+
"content": content,
45+
}
46+
usage = {
47+
"prompt_tokens": prompt_tokens,
48+
"completion_tokens": completion_tokens,
49+
"total_tokens": prompt_tokens + completion_tokens
50+
}
51+
if not message.get("content"):
52+
raise HTTPException(status_code=403, detail="No content in the message.")
53+
54+
data = {
55+
"id": chat_id,
56+
"object": "chat.completion",
57+
"created": created_time,
58+
"model": model,
59+
"choices": [
60+
{
61+
"index": 0,
62+
"message": message,
63+
"logprobs": None,
64+
"finish_reason": finish_reason
65+
}
66+
],
67+
"usage": usage
68+
}
69+
if system_fingerprint:
70+
data["system_fingerprint"] = system_fingerprint
71+
return data
72+
73+
74+
async def head_process_response(response):
75+
async for chunk in response:
76+
chunk = chunk.decode("utf-8")
77+
if chunk.startswith("data: {"):
78+
chunk_old_data = json.loads(chunk[6:])
79+
message = chunk_old_data.get("message", {})
80+
if not message and "error" in chunk_old_data:
81+
return response, False
82+
role = message.get('author', {}).get('role')
83+
if role == 'user' or role == 'system':
84+
continue
85+
86+
status = message.get("status")
87+
if status == "in_progress":
88+
return response, True
89+
return response, False
90+
91+
92+
async def stream_response(service, response, model, max_tokens):
93+
chat_id = f"chatcmpl-{''.join(random.choice(string.ascii_letters + string.digits) for _ in range(29))}"
94+
created_time = int(time.time())
95+
96+
chunk_new_data = {
97+
"id": chat_id,
98+
"object": "chat.completion.chunk",
99+
"created": created_time,
100+
"model": model,
101+
"choices": [
102+
{
103+
"index": 0,
104+
"delta": {"role": "assistant", "content": ""},
105+
"logprobs": None,
106+
"finish_reason": None
107+
}
108+
]
109+
}
110+
yield f"data: {json.dumps(chunk_new_data)}\n\n"
111+
112+
async for chunk in response:
113+
chunk = chunk.decode("utf-8")
114+
try:
115+
if chunk.startswith("data: {"):
116+
chunk_old_data = json.loads(chunk[6:].strip())
117+
except Exception as e:
118+
logger.error(f"Error: {chunk}, error: {str(e)}")
119+
continue
120+
121+
122+
def get_url_from_content(content):
123+
if isinstance(content, str) and content.startswith('http'):
124+
try:
125+
url = re.match(
126+
r'(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))',
127+
content.split(' ')[0])[0]
128+
content = content.replace(url, '').strip()
129+
return url, content
130+
except Exception:
131+
return None, content
132+
return None, content
133+
134+
135+
def format_messages_with_url(content):
136+
url_list = []
137+
while True:
138+
url, content = get_url_from_content(content)
139+
if url:
140+
url_list.append(url)
141+
logger.info(f"Found a file_url from messages: {url}")
142+
else:
143+
break
144+
if not url_list:
145+
return content
146+
new_content = [
147+
{
148+
"type": "text",
149+
"text": content
150+
}
151+
]
152+
for url in url_list:
153+
new_content.append({
154+
"type": "image_url",
155+
"image_url": {
156+
"url": url
157+
}
158+
})
159+
return new_content
160+
161+
162+
async def api_messages_to_chat(service, api_messages, upload_by_url=False):
163+
file_tokens = 0
164+
chat_messages = []
165+
for api_message in api_messages:
166+
role = api_message.get('role')
167+
content = api_message.get('content')
168+
if upload_by_url:
169+
if isinstance(content, str):
170+
content = format_messages_with_url(content)
171+
if isinstance(content, list):
172+
parts = []
173+
attachments = []
174+
content_type = "multimodal_text"
175+
for i in content:
176+
if i.get("type") == "text":
177+
parts.append(i.get("text"))
178+
elif i.get("type") == "image_url":
179+
image_url = i.get("image_url")
180+
url = image_url.get("url")
181+
detail = image_url.get("detail", "auto")
182+
file_content, mime_type = await get_file_content(url)
183+
file_meta = await service.upload_file(file_content, mime_type)
184+
if file_meta:
185+
file_id = file_meta["file_id"]
186+
file_size = file_meta["size_bytes"]
187+
file_name = file_meta["file_name"]
188+
mime_type = file_meta["mime_type"]
189+
use_case = file_meta["use_case"]
190+
if mime_type.startswith("image/"):
191+
width, height = file_meta["width"], file_meta["height"]
192+
file_tokens += await calculate_image_tokens(width, height, detail)
193+
parts.append({
194+
"content_type": "image_asset_pointer",
195+
"asset_pointer": f"file-service://{file_id}",
196+
"size_bytes": file_size,
197+
"width": width,
198+
"height": height
199+
})
200+
attachments.append({
201+
"id": file_id,
202+
"size": file_size,
203+
"name": file_name,
204+
"mime_type": mime_type,
205+
"width": width,
206+
"height": height
207+
})
208+
else:
209+
if not use_case == "ace_upload":
210+
await service.check_upload(file_id)
211+
file_tokens += file_size // 1000
212+
attachments.append({
213+
"id": file_id,
214+
"size": file_size,
215+
"name": file_name,
216+
"mime_type": mime_type,
217+
})
218+
metadata = {
219+
"attachments": attachments
220+
}
221+
else:
222+
content_type = "text"
223+
parts = [content]
224+
metadata = {}
225+
chat_message = {
226+
"id": f"{uuid.uuid4()}",
227+
"author": {"role": role},
228+
"content": {"content_type": content_type, "parts": parts},
229+
"metadata": metadata
230+
}
231+
chat_messages.append(chat_message)
232+
text_tokens = await num_tokens_from_messages(api_messages, service.resp_model)
233+
prompt_tokens = text_tokens + file_tokens
234+
return chat_messages, prompt_tokens

0 commit comments

Comments
 (0)