sanbo commited on
Commit
31b509b
·
1 Parent(s): 98b8872

update sth. at 2025-01-11 21:14:37

Browse files
Files changed (4) hide show
  1. Dockerfile +11 -58
  2. degpt.py +173 -133
  3. more_core.py +30 -19
  4. requirements.txt +3 -10
Dockerfile CHANGED
@@ -4,45 +4,19 @@ FROM python:3.11-slim-bullseye AS builder
4
  ENV PYTHONDONTWRITEBYTECODE=1 \
5
  PYTHONUNBUFFERED=1 \
6
  PIP_NO_CACHE_DIR=1 \
7
- DEBIAN_FRONTEND=noninteractive \
8
- PLAYWRIGHT_BROWSERS_PATH=/root/.cache/ms-playwright
9
 
10
  WORKDIR /build
11
 
12
- # 安装最小化系统依赖
13
  RUN apt-get update && apt-get install -y --no-install-recommends \
14
- build-essential \
15
  curl \
16
  ca-certificates \
17
- wget \
18
- gnupg \
19
- libnss3 \
20
- libnspr4 \
21
- libcups2 \
22
- libglib2.0-0 \
23
- libc6 \
24
- libatk1.0-0 \
25
- libatk-bridge2.0-0 \
26
- libdrm2 \
27
- libxkbcommon0 \
28
- libxcomposite1 \
29
- libxdamage1 \
30
- libxfixes3 \
31
- libxrandr2 \
32
- libgbm1 \
33
- libasound2 \
34
- libpango-1.0-0 \
35
- libpangocairo-1.0-0 \
36
- libx11-6 \
37
- libxcb1 \
38
- && rm -rf /var/lib/apt/lists/*
39
 
40
- # 安装Python包和Playwright
41
  COPY requirements.txt .
42
- RUN pip install --upgrade pip && \
43
- pip install --no-cache-dir -r requirements.txt && \
44
- playwright install chromium --with-deps && \
45
- ls -la /root/.cache/ms-playwright
46
 
47
  # Runtime stage
48
  FROM python:3.11-slim-bullseye
@@ -50,41 +24,20 @@ FROM python:3.11-slim-bullseye
50
  ENV PYTHONDONTWRITEBYTECODE=1 \
51
  PYTHONUNBUFFERED=1 \
52
  PORT=7860 \
53
- DEBUG=false \
54
- PLAYWRIGHT_BROWSERS_PATH=/root/.cache/ms-playwright
55
 
56
  WORKDIR /app
57
 
58
- # 安装运行时依赖
 
 
 
 
59
  RUN apt-get update && apt-get install -y --no-install-recommends \
60
- libnss3 \
61
- libnspr4 \
62
- libcups2 \
63
- libglib2.0-0 \
64
- libc6 \
65
- libatk1.0-0 \
66
- libatk-bridge2.0-0 \
67
- libdrm2 \
68
- libxkbcommon0 \
69
- libxcomposite1 \
70
- libxdamage1 \
71
- libxfixes3 \
72
- libxrandr2 \
73
- libgbm1 \
74
- libasound2 \
75
- libpango-1.0-0 \
76
- libpangocairo-1.0-0 \
77
- libx11-6 \
78
- libxcb1 \
79
  curl \
80
  ca-certificates \
81
  && rm -rf /var/lib/apt/lists/*
82
 
83
- # 复制必要文件
84
- COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
85
- COPY --from=builder /root/.cache/ms-playwright /root/.cache/ms-playwright
86
- COPY more_core.py degpt.py ./
87
-
88
  HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
89
  CMD curl -f http://localhost:${PORT}/health || exit 1
90
 
 
4
  ENV PYTHONDONTWRITEBYTECODE=1 \
5
  PYTHONUNBUFFERED=1 \
6
  PIP_NO_CACHE_DIR=1 \
7
+ DEBIAN_FRONTEND=noninteractive
 
8
 
9
  WORKDIR /build
10
 
11
+ # Install minimal dependencies and Python packages
12
  RUN apt-get update && apt-get install -y --no-install-recommends \
 
13
  curl \
14
  ca-certificates \
15
+ && rm -rf /var/lib/apt/lists/* \
16
+ && pip install --upgrade pip
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
 
18
  COPY requirements.txt .
19
+ RUN pip install --no-cache-dir -r requirements.txt
 
 
 
20
 
21
  # Runtime stage
22
  FROM python:3.11-slim-bullseye
 
24
  ENV PYTHONDONTWRITEBYTECODE=1 \
25
  PYTHONUNBUFFERED=1 \
26
  PORT=7860 \
27
+ DEBUG=false
 
28
 
29
  WORKDIR /app
30
 
31
+ # Copy Python packages and application files
32
+ COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
33
+ COPY more_core.py degpt.py ./
34
+
35
+ # Install runtime dependencies
36
  RUN apt-get update && apt-get install -y --no-install-recommends \
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  curl \
38
  ca-certificates \
39
  && rm -rf /var/lib/apt/lists/*
40
 
 
 
 
 
 
41
  HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
42
  CMD curl -f http://localhost:${PORT}/health || exit 1
43
 
degpt.py CHANGED
@@ -2,19 +2,17 @@
2
  update time: 2025.01.09
3
  verson: 0.1.125
4
  """
5
- import aiohttp
6
- import time
7
- import requests
8
- import asyncio
9
-
10
- from playwright.async_api import async_playwright
11
  import json
12
- import logging
13
  import re
14
- from typing import List, Dict, Optional
15
  from datetime import datetime, timedelta
 
 
 
 
16
 
17
- debug = False
 
18
  # 全局变量
19
  last_request_time = 0 # 上次请求的时间戳
20
  cache_duration = 14400 # 缓存有效期,单位:秒 (4小时)
@@ -42,7 +40,8 @@ base_addrs = [
42
  '''基础域名'''
43
  base_url = 'https://singapore-chat.degpt.ai/api'
44
 
45
-
 
46
  # 全局变量:存储所有模型的统计信息
47
  # 格式:{model_name: {"calls": 调用次数, "fails": 失败次数, "last_fail": 最后失败时间}}
48
  MODEL_STATS: Dict[str, Dict] = {}
@@ -65,11 +64,11 @@ def record_call(model_name: str, success: bool = True) -> None:
65
  stats["last_fail"] = datetime.now()
66
 
67
 
68
- async def get_auto_model(cooldown_seconds: int = 300) -> str:
69
  """异步获取最优模型"""
70
  try:
71
  if not MODEL_STATS:
72
- await get_models()
73
 
74
  best_model = None
75
  best_rate = -1.0
@@ -86,17 +85,17 @@ async def get_auto_model(cooldown_seconds: int = 300) -> str:
86
  best_rate = success_rate
87
  best_model = name
88
 
89
- default_model = best_model or "Pixtral-124B"
90
  if debug:
91
  print(f"选择模型: {default_model}")
92
  return default_model
93
  except Exception as e:
94
  if debug:
95
  print(f"模型选择错误: {e}")
96
- return "Pixtral-124B"
97
 
98
 
99
- async def reload_check():
100
  """检查并更新系统状态
101
  1. 如果模型数据为空,更新模型数据
102
  2. 测试当前base_url是否可用,不可用则切换
@@ -108,11 +107,11 @@ async def reload_check():
108
  if not cached_models["data"]:
109
  if debug:
110
  print("模型数据为空,开始更新...")
111
- await get_models()
112
 
113
  # 测试用例 - 平衡效率和功能验证
114
  test_payload = {
115
- "model": "Pixtral-124B",
116
  "messages": [{
117
  "role": "user",
118
  "content": [{"type": "text", "text": "test"}]
@@ -130,10 +129,10 @@ async def reload_check():
130
  'Content-Type': 'application/json'
131
  }
132
 
133
- async with aiohttp.ClientSession() as session:
134
  # 测试当前URL
135
  try:
136
- async with session.post(
137
  f"{base_url}/v0/chat/completion/proxy",
138
  headers=headers,
139
  json=test_payload,
@@ -141,7 +140,7 @@ async def reload_check():
141
  ) as response:
142
  if response.status == 200:
143
  # 验证响应格式
144
- if await response.read():
145
  if debug:
146
  print(f"当前URL可用: {base_url}")
147
  return
@@ -154,13 +153,13 @@ async def reload_check():
154
  if url == base_url:
155
  continue
156
  try:
157
- async with session.post(
158
  f"{url}/v0/chat/completion/proxy",
159
  headers=headers,
160
  json=test_payload,
161
  timeout=5
162
  ) as response:
163
- if response.status == 200 and await response.read():
164
  base_url = url
165
  if debug:
166
  print(f"切换到新URL: {base_url}")
@@ -177,11 +176,12 @@ async def reload_check():
177
  if debug:
178
  print(f"系统检查失败: {e}")
179
 
180
- async def _fetch_and_update_models():
 
181
  """Thread-safe model fetching and cache updating"""
182
  global cached_models
183
  try:
184
- await get_model_names_from_js()
185
  except Exception as e:
186
  print(f"{e}")
187
  try:
@@ -189,17 +189,18 @@ async def _fetch_and_update_models():
189
  except Exception as e:
190
  print(f"{e}")
191
 
192
- async def get_models():
193
- """Async model data retrieval with thread safety"""
 
194
  global cached_models, last_request_time
195
  current_time = time.time()
196
  if (current_time - last_request_time) > cache_duration:
197
  try:
198
  # Update timestamp before awaiting to prevent concurrent updates
199
  last_request_time = current_time
200
- await _fetch_and_update_models()
201
  except Exception as e:
202
- print(e)
203
 
204
  return json.dumps(cached_models)
205
 
@@ -259,11 +260,12 @@ def get_alive_models():
259
  print(f"请求失败,状态码: {response.status_code}")
260
 
261
 
262
- async def parse_models_from_js(js_content: str) -> List[Dict]:
263
  """解析JS内容中的模型信息"""
264
  try:
265
  pattern = r'models\s*:\s*\[([^\]]+)\]'
266
  match = re.search(pattern, js_content)
 
267
  if match:
268
  models_data = match.group(1)
269
  models_data = re.sub(r'(\w+):', r'"\1":', models_data)
@@ -272,103 +274,138 @@ async def parse_models_from_js(js_content: str) -> List[Dict]:
272
 
273
  try:
274
  models = json.loads(models_data)
275
- # print(f"成功解析到 {len(models)} 个模型信息")
276
  return models
277
  except json.JSONDecodeError as e:
278
- print(f"JSON解析错误: {str(e)}")
279
  return []
 
280
  return []
 
281
  except Exception as e:
282
- print(f"解析模型信息时发生错误: {str(e)}")
283
  return []
284
 
285
 
286
- async def get_model_names_from_js(url="https://www.degpt.ai/", timeout: int = 60):
287
- global cached_models
288
- try:
289
- async with async_playwright() as p:
290
- browser = await p.chromium.launch(
291
- headless=True,
292
- args=['--no-sandbox']
293
- )
294
- context = await browser.new_context(
295
- viewport={'width': 1920, 'height': 1080},
296
- user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/119.0.0.0 Safari/537.36'
297
- )
298
- page = await context.new_page()
299
-
300
- async def handle_response(response):
301
- try:
302
- if response.request.resource_type == "script":
303
- content_type = response.headers.get('content-type', '').lower()
304
- if 'javascript' in content_type:
305
- js_content = await response.text()
306
- if 'models' in js_content:
307
- # print(f"找到包含模型信息的JS文件: {response.url}")
308
- models = await parse_models_from_js(js_content)
309
- if models:
310
- # print("\n提取的模型列表:")
311
- existing_ids = {m.get('id') for m in cached_models["data"]}
312
- for model in models:
313
- model_id = model.get('model', '').strip()
314
- # print(f"- 名称: {model.get('name', '')}")
315
- # print(f" 模型: {model.get('model', '')}")
316
- # print(f" 描述: {model.get('desc', '')}")
317
- record_call(model_id)
318
- if model_id and model_id not in existing_ids:
319
- model_data = {
320
- "id": model_id,
321
- "object": "model",
322
- "model": model_id,
323
- "created": int(time.time()),
324
- "owned_by": model_id.split("-")[0] if "-" in model_id else "unknown",
325
- "name": model.get('name', ''),
326
- "description": model.get('desc', ''),
327
- "support": model.get('support', 'text'),
328
- "tip": model.get('tip', '')
329
- }
330
- cached_models["data"].append(model_data)
331
- # print(f"添加新模型: {model_id}")
332
- except Exception as e:
333
- print(f"处理响应时发生错误: {str(e)}")
334
- logging.error(f"Response处理异常: {e}", exc_info=True)
335
-
336
- page.on("response", handle_response)
337
-
338
- try:
339
- await page.goto(url, timeout=timeout * 1000, wait_until='networkidle')
340
- await page.wait_for_timeout(5000)
341
- except Exception as e:
342
- print(f"页面加载错误: {str(e)}")
343
- logging.error(f"页面加载异常: {e}", exc_info=True)
344
- finally:
345
- await browser.close()
346
- except Exception as e:
347
- print(f"提取过程发生错误: {str(e)}")
348
- await get_from_js()
349
- raise
350
-
351
- async def get_from_js():
352
- import requests
353
- import re
354
- import json
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
  global cached_models
356
  # 获取 JavaScript 文件内容
357
  # url = "https://www.degpt.ai/_app/immutable/chunks/index.83d92b06.js"
358
- url = "https://www.degpt.ai/_app/immutable/chunks/index.4aecf75a.js"
 
359
  response = requests.get(url)
360
 
361
  if response.status_code == 200:
362
  js_content = response.text
363
- models = await parse_models_from_js(js_content)
 
364
  if models:
365
- # print("\n提取的模型列表:")
 
366
  existing_ids = {m.get('id') for m in cached_models["data"]}
367
  for model in models:
368
  model_id = model.get('model', '').strip()
369
- # print(f"- 名称: {model.get('name', '')}")
370
- # print(f" 模型: {model.get('model', '')}")
371
- # print(f" 描述: {model.get('desc', '')}")
 
372
  record_call(model_id)
373
  if model_id and model_id not in existing_ids:
374
  model_data = {
@@ -383,10 +420,11 @@ async def get_from_js():
383
  "tip": model.get('tip', '')
384
  }
385
  cached_models["data"].append(model_data)
386
- # print(f"添加新模型: {model_id}")
 
387
 
388
 
389
- async def is_model_available(model_id: str, cooldown_seconds: int = 300) -> bool:
390
  """
391
  判断模型是否在模型列表中且非最近失败的模型
392
 
@@ -405,7 +443,7 @@ async def is_model_available(model_id: str, cooldown_seconds: int = 300) -> bool
405
 
406
  # 如果MODEL_STATS为空,加载模型数据
407
  if not MODEL_STATS:
408
- await get_models()
409
 
410
  # 检查模型是否在统计信息中
411
  if model_id not in MODEL_STATS:
@@ -421,7 +459,7 @@ async def is_model_available(model_id: str, cooldown_seconds: int = 300) -> bool
421
  return True
422
 
423
 
424
- async def get_model_by_autoupdate(model_id: Optional[str] = None, cooldown_seconds: int = 300) -> Optional[str]:
425
  """
426
  检查提供的model_id是否可用,如果不可用则返回成功率最高的模型
427
 
@@ -441,17 +479,17 @@ async def get_model_by_autoupdate(model_id: Optional[str] = None, cooldown_secon
441
 
442
  # 如果MODEL_STATS为空,加载模型数据
443
  if not MODEL_STATS:
444
- await get_models()
445
 
446
  # 如果提供了model_id且可用,直接返回
447
- if model_id and await is_model_available(model_id, cooldown_seconds):
448
  return model_id
449
 
450
  # 否则返回成功率最高的可用模型
451
- return await get_auto_model(cooldown_seconds=cooldown_seconds)
452
 
453
 
454
- async def is_chatgpt_format(data):
455
  """Check if the data is in the expected ChatGPT format"""
456
  try:
457
  # If the data is a string, try to parse it as JSON
@@ -473,12 +511,12 @@ async def is_chatgpt_format(data):
473
  return False
474
 
475
 
476
- async def chat_completion_message(
477
  user_prompt,
478
  user_id: str = None,
479
  session_id: str = None,
480
  system_prompt="You are a helpful assistant.",
481
- model="Pixtral-124B",
482
  project="DecentralGPT", stream=False,
483
  temperature=0.3, max_tokens=1024, top_p=0.5,
484
  frequency_penalty=0, presence_penalty=0):
@@ -487,20 +525,25 @@ async def chat_completion_message(
487
  {"role": "system", "content": system_prompt},
488
  {"role": "user", "content": user_prompt}
489
  ]
490
- return await chat_completion_messages(messages, user_id, session_id, model, project, stream, temperature, max_tokens,
491
  top_p, frequency_penalty,
492
  presence_penalty)
493
 
494
 
495
- async def chat_completion_messages(
496
  messages,
497
- model="Pixtral-124B",
498
  user_id: str = None,
499
  session_id: str = None,
500
  project="DecentralGPT", stream=False, temperature=0.3, max_tokens=1024, top_p=0.5,
501
  frequency_penalty=0, presence_penalty=0):
502
- # url = 'https://usa-chat.degpt.ai/api/v0/chat/completion/proxy'
503
- url = 'https://singapore-chat.degpt.ai/api/v0/chat/completion/proxy'
 
 
 
 
 
504
  headers = {
505
  'sec-ch-ua-platform': '"macOS"',
506
  'Referer': 'https://www.degpt.ai/',
@@ -510,13 +553,6 @@ async def chat_completion_messages(
510
  'Content-Type': 'application/json',
511
  'sec-ch-ua-mobile': '?0'
512
  }
513
- # 确保model有效
514
- if not model or model == "auto":
515
- model = await get_auto_model()
516
- else:
517
- model = await get_model_by_autoupdate(model)
518
- if debug:
519
- print(f"校准后的model: {model}")
520
  payload = {
521
  # make sure ok
522
  "model": model,
@@ -532,23 +568,27 @@ async def chat_completion_messages(
532
  }
533
  # print(json.dumps(headers, indent=4))
534
  # print(json.dumps(payload, indent=4))
535
- return await chat_completion(url,model, headers, payload)
536
 
537
 
538
- async def chat_completion(url,model, headers, payload):
539
  """处理用户请求并保留上下文"""
540
  try:
 
541
  response = requests.post(url, headers=headers, json=payload)
542
  response.encoding = 'utf-8'
543
  response.raise_for_status()
544
  return response.json()
545
  except requests.exceptions.RequestException as e:
546
  print(f"请求失败: {e}")
547
- await record_call(model, False)
548
  return "请求失败,请检查网络或参数配置。"
549
  except (KeyError, IndexError) as e:
550
  print(f"解析响应时出错: {e}")
551
- await record_call(model, False)
552
  return "解析响应内容失败。"
553
  return {}
554
 
 
 
 
 
 
 
2
  update time: 2025.01.09
3
  verson: 0.1.125
4
  """
 
 
 
 
 
 
5
  import json
 
6
  import re
7
+ import time
8
  from datetime import datetime, timedelta
9
+ from typing import List, Dict, Optional
10
+
11
+ import aiohttp
12
+ import requests
13
 
14
+
15
+ debug = True
16
  # 全局变量
17
  last_request_time = 0 # 上次请求的时间戳
18
  cache_duration = 14400 # 缓存有效期,单位:秒 (4小时)
 
40
  '''基础域名'''
41
  base_url = 'https://singapore-chat.degpt.ai/api'
42
 
43
+ '''基础模型'''
44
+ base_model = "Pixtral-124B"
45
  # 全局变量:存储所有模型的统计信息
46
  # 格式:{model_name: {"calls": 调用次数, "fails": 失败次数, "last_fail": 最后失败时间}}
47
  MODEL_STATS: Dict[str, Dict] = {}
 
64
  stats["last_fail"] = datetime.now()
65
 
66
 
67
+ def get_auto_model(cooldown_seconds: int = 300) -> str:
68
  """异步获取最优模型"""
69
  try:
70
  if not MODEL_STATS:
71
+ get_models()
72
 
73
  best_model = None
74
  best_rate = -1.0
 
85
  best_rate = success_rate
86
  best_model = name
87
 
88
+ default_model = best_model or base_model
89
  if debug:
90
  print(f"选择模型: {default_model}")
91
  return default_model
92
  except Exception as e:
93
  if debug:
94
  print(f"模型选择错误: {e}")
95
+ return base_model
96
 
97
 
98
+ def reload_check():
99
  """检查并更新系统状态
100
  1. 如果模型数据为空,更新模型数据
101
  2. 测试当前base_url是否可用,不可用则切换
 
107
  if not cached_models["data"]:
108
  if debug:
109
  print("模型数据为空,开始更新...")
110
+ get_models()
111
 
112
  # 测试用例 - 平衡效率和功能验证
113
  test_payload = {
114
+ "model": base_model,
115
  "messages": [{
116
  "role": "user",
117
  "content": [{"type": "text", "text": "test"}]
 
129
  'Content-Type': 'application/json'
130
  }
131
 
132
+ with aiohttp.ClientSession() as session:
133
  # 测试当前URL
134
  try:
135
+ with session.post(
136
  f"{base_url}/v0/chat/completion/proxy",
137
  headers=headers,
138
  json=test_payload,
 
140
  ) as response:
141
  if response.status == 200:
142
  # 验证响应格式
143
+ if response.read():
144
  if debug:
145
  print(f"当前URL可用: {base_url}")
146
  return
 
153
  if url == base_url:
154
  continue
155
  try:
156
+ with session.post(
157
  f"{url}/v0/chat/completion/proxy",
158
  headers=headers,
159
  json=test_payload,
160
  timeout=5
161
  ) as response:
162
+ if response.status == 200 and response.read():
163
  base_url = url
164
  if debug:
165
  print(f"切换到新URL: {base_url}")
 
176
  if debug:
177
  print(f"系统检查失败: {e}")
178
 
179
+
180
+ def _fetch_and_update_models():
181
  """Thread-safe model fetching and cache updating"""
182
  global cached_models
183
  try:
184
+ get_from_js()
185
  except Exception as e:
186
  print(f"{e}")
187
  try:
 
189
  except Exception as e:
190
  print(f"{e}")
191
 
192
+
193
+ def get_models():
194
+ """model data retrieval with thread safety"""
195
  global cached_models, last_request_time
196
  current_time = time.time()
197
  if (current_time - last_request_time) > cache_duration:
198
  try:
199
  # Update timestamp before awaiting to prevent concurrent updates
200
  last_request_time = current_time
201
+ _fetch_and_update_models()
202
  except Exception as e:
203
+ print(f"{e}")
204
 
205
  return json.dumps(cached_models)
206
 
 
260
  print(f"请求失败,状态码: {response.status_code}")
261
 
262
 
263
+ def parse_models_from_js(js_content: str) -> List[Dict]:
264
  """解析JS内容中的模型信息"""
265
  try:
266
  pattern = r'models\s*:\s*\[([^\]]+)\]'
267
  match = re.search(pattern, js_content)
268
+
269
  if match:
270
  models_data = match.group(1)
271
  models_data = re.sub(r'(\w+):', r'"\1":', models_data)
 
274
 
275
  try:
276
  models = json.loads(models_data)
 
277
  return models
278
  except json.JSONDecodeError as e:
 
279
  return []
280
+
281
  return []
282
+
283
  except Exception as e:
 
284
  return []
285
 
286
 
287
+ # def get_model_names_from_js(url="https://www.degpt.ai/", timeout: int = 60):
288
+ # global cached_models
289
+ # try:
290
+ # with async_playwright() as p:
291
+ # browser = p.chromium.launch(
292
+ # headless=True,
293
+ # args=['--no-sandbox']
294
+ # )
295
+ # context = browser.new_context(
296
+ # viewport={'width': 1920, 'height': 1080},
297
+ # user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/119.0.0.0 Safari/537.36'
298
+ # )
299
+ # page = context.new_page()
300
+ #
301
+ # def handle_response(response):
302
+ # try:
303
+ # if response.request.resource_type == "script":
304
+ # content_type = response.headers.get('content-type', '').lower()
305
+ # if 'javascript' in content_type:
306
+ # js_content = response.text()
307
+ # if 'models' in js_content:
308
+ # # print(f"找到包含模型信息的JS文件: {response.url}")
309
+ # models = parse_models_from_js(js_content)
310
+ # if models:
311
+ # # print("\n提取的模型列表:")
312
+ # existing_ids = {m.get('id') for m in cached_models["data"]}
313
+ # for model in models:
314
+ # model_id = model.get('model', '').strip()
315
+ # # print(f"- 名称: {model.get('name', '')}")
316
+ # # print(f" 模型: {model.get('model', '')}")
317
+ # # print(f" 描述: {model.get('desc', '')}")
318
+ # record_call(model_id)
319
+ # if model_id and model_id not in existing_ids:
320
+ # model_data = {
321
+ # "id": model_id,
322
+ # "object": "model",
323
+ # "model": model_id,
324
+ # "created": int(time.time()),
325
+ # "owned_by": model_id.split("-")[0] if "-" in model_id else "unknown",
326
+ # "name": model.get('name', ''),
327
+ # "description": model.get('desc', ''),
328
+ # "support": model.get('support', 'text'),
329
+ # "tip": model.get('tip', '')
330
+ # }
331
+ # cached_models["data"].append(model_data)
332
+ # # print(f"添加新模型: {model_id}")
333
+ # except Exception as e:
334
+ # print(f"处理响应时发生错误: {str(e)}")
335
+ # logging.error(f"Response处理异常: {e}", exc_info=True)
336
+ #
337
+ # page.on("response", handle_response)
338
+ #
339
+ # try:
340
+ # page.goto(url, timeout=timeout * 1000, wait_until='networkidle')
341
+ # page.wait_for_timeout(5000)
342
+ # except Exception as e:
343
+ # print(f"页面加载错误: {str(e)}")
344
+ # logging.error(f"页面加载异常: {e}", exc_info=True)
345
+ # finally:
346
+ # browser.close()
347
+ # except Exception as e:
348
+ # print(f"提取过程发生错误: {str(e)}")
349
+ # get_from_js()
350
+ # raise
351
+
352
+
353
+ # def parse_models_and_urls_from_js(js_content: str) -> Dict:
354
+ # """从JS内容中解析模型和URL信息"""
355
+ # result = {"models": [], "urls": []}
356
+ #
357
+ # try:
358
+ # # 提取模型信息
359
+ # model_pattern = r'models\s*:\s*\[([^\]]+)\]'
360
+ # model_match = re.search(model_pattern, js_content)
361
+ #
362
+ # if model_match:
363
+ # models_data = model_match.group(1)
364
+ # models_data = re.sub(r'(\w+):', r'"\1":', models_data)
365
+ # models_data = models_data.replace("'", '"')
366
+ # models_data = f"[{models_data}]"
367
+ #
368
+ # try:
369
+ # models = json.loads(models_data)
370
+ # result["models"] = models
371
+ # except json.JSONDecodeError as e:
372
+ # print(f"Error decoding models JSON: {e}")
373
+ #
374
+ # # 提取URL信息
375
+ # url_pattern = r'\{name\s*:\s*"([^"]+)"\s*,\s*url\s*:\s*"([^"]+)"'
376
+ # url_matches = re.findall(url_pattern, js_content)
377
+ #
378
+ # if url_matches:
379
+ # urls = [{"name": name, "url": url} for name, url in url_matches]
380
+ # result["urls"] = urls
381
+ #
382
+ # return result
383
+ #
384
+ # except Exception as e:
385
+ # print(f"Error parsing JS content: {e}")
386
+ # return result
387
+ def get_from_js():
388
  global cached_models
389
  # 获取 JavaScript 文件内容
390
  # url = "https://www.degpt.ai/_app/immutable/chunks/index.83d92b06.js"
391
+ # url = "https://www.degpt.ai/_app/immutable/chunks/index.4aecf75a.js"
392
+ url = "https://www.degpt.ai/_app/immutable/chunks/index.e0d19999.js"
393
  response = requests.get(url)
394
 
395
  if response.status_code == 200:
396
  js_content = response.text
397
+ models = parse_models_from_js(js_content)
398
+ # xx = parse_models_and_urls_from_js(js_content)
399
  if models:
400
+ if debug:
401
+ print("get_from_js提取的模型列表:")
402
  existing_ids = {m.get('id') for m in cached_models["data"]}
403
  for model in models:
404
  model_id = model.get('model', '').strip()
405
+ if debug:
406
+ print(f"get_from_js 名称: {model.get('name', '')}")
407
+ print(f"get_from_js 模型: {model.get('model', '')}")
408
+ print(f"get_from_js 描述: {model.get('desc', '')}")
409
  record_call(model_id)
410
  if model_id and model_id not in existing_ids:
411
  model_data = {
 
420
  "tip": model.get('tip', '')
421
  }
422
  cached_models["data"].append(model_data)
423
+ if debug:
424
+ print(f"get_from_js添加新模型: {model_id}")
425
 
426
 
427
+ def is_model_available(model_id: str, cooldown_seconds: int = 300) -> bool:
428
  """
429
  判断模型是否在模型列表中且非最近失败的模型
430
 
 
443
 
444
  # 如果MODEL_STATS为空,加载模型数据
445
  if not MODEL_STATS:
446
+ get_models()
447
 
448
  # 检查模型是否在统计信息中
449
  if model_id not in MODEL_STATS:
 
459
  return True
460
 
461
 
462
+ def get_model_by_autoupdate(model_id: Optional[str] = None, cooldown_seconds: int = 300) -> Optional[str]:
463
  """
464
  检查提供的model_id是否可用,如果不可用则返回成功率最高的模型
465
 
 
479
 
480
  # 如果MODEL_STATS为空,加载模型数据
481
  if not MODEL_STATS:
482
+ get_models()
483
 
484
  # 如果提供了model_id且可用,直接返回
485
+ if model_id and is_model_available(model_id, cooldown_seconds):
486
  return model_id
487
 
488
  # 否则返回成功率最高的可用模型
489
+ return get_auto_model(cooldown_seconds=cooldown_seconds)
490
 
491
 
492
+ def is_chatgpt_format(data):
493
  """Check if the data is in the expected ChatGPT format"""
494
  try:
495
  # If the data is a string, try to parse it as JSON
 
511
  return False
512
 
513
 
514
+ def chat_completion_message(
515
  user_prompt,
516
  user_id: str = None,
517
  session_id: str = None,
518
  system_prompt="You are a helpful assistant.",
519
+ model=base_model,
520
  project="DecentralGPT", stream=False,
521
  temperature=0.3, max_tokens=1024, top_p=0.5,
522
  frequency_penalty=0, presence_penalty=0):
 
525
  {"role": "system", "content": system_prompt},
526
  {"role": "user", "content": user_prompt}
527
  ]
528
+ return chat_completion_messages(messages, user_id, session_id, model, project, stream, temperature, max_tokens,
529
  top_p, frequency_penalty,
530
  presence_penalty)
531
 
532
 
533
+ def chat_completion_messages(
534
  messages,
535
+ model=base_model,
536
  user_id: str = None,
537
  session_id: str = None,
538
  project="DecentralGPT", stream=False, temperature=0.3, max_tokens=1024, top_p=0.5,
539
  frequency_penalty=0, presence_penalty=0):
540
+ # 确保model有效
541
+ if not model or model == "auto":
542
+ model = get_auto_model()
543
+ else:
544
+ model = get_model_by_autoupdate(model)
545
+ if debug:
546
+ print(f"校准后的model: {model}")
547
  headers = {
548
  'sec-ch-ua-platform': '"macOS"',
549
  'Referer': 'https://www.degpt.ai/',
 
553
  'Content-Type': 'application/json',
554
  'sec-ch-ua-mobile': '?0'
555
  }
 
 
 
 
 
 
 
556
  payload = {
557
  # make sure ok
558
  "model": model,
 
568
  }
569
  # print(json.dumps(headers, indent=4))
570
  # print(json.dumps(payload, indent=4))
571
+ return chat_completion(headers, payload)
572
 
573
 
574
+ def chat_completion(headers, payload):
575
  """处理用户请求并保留上下文"""
576
  try:
577
+ url = f'{base_url}/v0/chat/completion/proxy'
578
  response = requests.post(url, headers=headers, json=payload)
579
  response.encoding = 'utf-8'
580
  response.raise_for_status()
581
  return response.json()
582
  except requests.exceptions.RequestException as e:
583
  print(f"请求失败: {e}")
 
584
  return "请求失败,请检查网络或参数配置。"
585
  except (KeyError, IndexError) as e:
586
  print(f"解析响应时出错: {e}")
 
587
  return "解析响应内容失败。"
588
  return {}
589
 
590
+ # if __name__ == '__main__':
591
+ # print("get_models: ",get_models())
592
+ # print("cached_models:",cached_models)
593
+ # print("base_url: ",base_url)
594
+ # print("MODEL_STATS:",MODEL_STATS)
more_core.py CHANGED
@@ -1,5 +1,4 @@
1
  import json
2
- import json
3
  import multiprocessing
4
  import os
5
  import random
@@ -17,7 +16,7 @@ from starlette.responses import HTMLResponse
17
  import degpt as dg
18
 
19
  # debug for Log
20
- debug = False
21
 
22
  app = FastAPI(
23
  title="ones",
@@ -38,27 +37,27 @@ class APIServer:
38
  self.scheduler.start()
39
 
40
  def _setup_routes(self) -> None:
41
- """Initialize API routes"""
42
 
43
  # Static routes with names for filtering
44
  @self.app.get("/", name="root", include_in_schema=False)
45
- async def root():
46
  return HTMLResponse(content="<h1>hello. It's home page.</h1>")
47
 
48
  @self.app.get("/web", name="web")
49
- async def web():
50
  return HTMLResponse(content="<h1>hello. It's web page.</h1>")
51
 
52
  @self.app.get("/health", name="health")
53
- async def health():
54
  return JSONResponse(content={"status": "working"})
55
 
56
 
57
  @self.app.get("/v1/models", name="models")
58
- async def models():
59
  if debug:
60
  print("Fetching models...")
61
- models_str = await dg.get_models()
62
  try:
63
  models_json = json.loads(models_str)
64
  return JSONResponse(content=models_json)
@@ -105,11 +104,13 @@ class APIServer:
105
 
106
  async def chat_endpoint(request: Request) -> Dict[str, Any]:
107
  try:
 
 
108
  headers = dict(request.headers)
109
  data = await request.json()
110
  if debug:
111
  print(f"Request received...\r\n\tHeaders: {headers},\r\n\tData: {data}")
112
- return await self._generate_response(headers, data)
113
  except Exception as e:
114
  if debug:
115
  print(f"Request processing error: {e}")
@@ -165,7 +166,7 @@ class APIServer:
165
  result['model'] = model # 根据需要设置model值
166
  return result
167
 
168
- async def _generate_response(self, headers: Dict[str, str], data: Dict[str, Any]) -> Dict[str, Any]:
169
  """Generate API response"""
170
  global debug
171
  if debug:
@@ -176,7 +177,7 @@ class APIServer:
176
  # print(f"model: {model}")
177
  # just auto will check
178
  if "auto" == model:
179
- model = await dg.get_auto_model()
180
  # else:
181
  # if not dg.is_model_available(model):
182
  # raise HTTPException(status_code=400, detail="Invalid Model")
@@ -195,19 +196,17 @@ class APIServer:
195
 
196
  if debug:
197
  print(f"request model: {model}")
198
- print(f"request token: {token}")
 
199
  print(f"request messages: {msgs}")
200
 
201
- result = await dg.chat_completion_messages(
202
  messages=msgs,
203
  model=model
204
  )
205
  if debug:
206
  print(f"result: {result}---- {self.is_chatgpt_format(result)}")
207
 
208
- # # Assuming this 'result' comes from your model or some other logic
209
- # result = "This is a test result."
210
-
211
  # If the request body data already matches ChatGPT format, return it directly
212
  if self.is_chatgpt_format(result):
213
  # If data already follows ChatGPT format, use it directly
@@ -246,7 +245,7 @@ class APIServer:
246
 
247
  return response_data
248
  except Exception as e:
249
- await dg.record_call(model,False)
250
  if debug:
251
  print(f"Response generation error: {e}")
252
  raise HTTPException(status_code=500, detail=str(e)) from e
@@ -287,8 +286,20 @@ class APIServer:
287
  server = uvicorn.Server(config)
288
  server.run()
289
 
290
- async def _reload_check(self) -> None:
291
- await dg.reload_check()
 
 
 
 
 
 
 
 
 
 
 
 
292
 
293
  def _schedule_route_check(self) -> None:
294
  """
 
1
  import json
 
2
  import multiprocessing
3
  import os
4
  import random
 
16
  import degpt as dg
17
 
18
  # debug for Log
19
+ debug = True
20
 
21
  app = FastAPI(
22
  title="ones",
 
37
  self.scheduler.start()
38
 
39
  def _setup_routes(self) -> None:
40
+ self.routes = """Initialize API routes"""
41
 
42
  # Static routes with names for filtering
43
  @self.app.get("/", name="root", include_in_schema=False)
44
+ def root():
45
  return HTMLResponse(content="<h1>hello. It's home page.</h1>")
46
 
47
  @self.app.get("/web", name="web")
48
+ def web():
49
  return HTMLResponse(content="<h1>hello. It's web page.</h1>")
50
 
51
  @self.app.get("/health", name="health")
52
+ def health():
53
  return JSONResponse(content={"status": "working"})
54
 
55
 
56
  @self.app.get("/v1/models", name="models")
57
+ def models():
58
  if debug:
59
  print("Fetching models...")
60
+ models_str = dg.get_models()
61
  try:
62
  models_json = json.loads(models_str)
63
  return JSONResponse(content=models_json)
 
104
 
105
  async def chat_endpoint(request: Request) -> Dict[str, Any]:
106
  try:
107
+ if debug:
108
+ print(f"Request chat_endpoint...")
109
  headers = dict(request.headers)
110
  data = await request.json()
111
  if debug:
112
  print(f"Request received...\r\n\tHeaders: {headers},\r\n\tData: {data}")
113
+ return self._generate_response(headers, data)
114
  except Exception as e:
115
  if debug:
116
  print(f"Request processing error: {e}")
 
166
  result['model'] = model # 根据需要设置model值
167
  return result
168
 
169
+ def _generate_response(self, headers: Dict[str, str], data: Dict[str, Any]) -> Dict[str, Any]:
170
  """Generate API response"""
171
  global debug
172
  if debug:
 
177
  # print(f"model: {model}")
178
  # just auto will check
179
  if "auto" == model:
180
+ model = dg.get_auto_model()
181
  # else:
182
  # if not dg.is_model_available(model):
183
  # raise HTTPException(status_code=400, detail="Invalid Model")
 
196
 
197
  if debug:
198
  print(f"request model: {model}")
199
+ if token:
200
+ print(f"request token: {token}")
201
  print(f"request messages: {msgs}")
202
 
203
+ result = dg.chat_completion_messages(
204
  messages=msgs,
205
  model=model
206
  )
207
  if debug:
208
  print(f"result: {result}---- {self.is_chatgpt_format(result)}")
209
 
 
 
 
210
  # If the request body data already matches ChatGPT format, return it directly
211
  if self.is_chatgpt_format(result):
212
  # If data already follows ChatGPT format, use it directly
 
245
 
246
  return response_data
247
  except Exception as e:
248
+ dg.record_call(model,False)
249
  if debug:
250
  print(f"Response generation error: {e}")
251
  raise HTTPException(status_code=500, detail=str(e)) from e
 
286
  server = uvicorn.Server(config)
287
  server.run()
288
 
289
+ """
290
+ 异步方法 `_reload_check` 用于执行模块的热重载检查。
291
+
292
+ 此方法调用 `dg.reload_check()` 来检测是否有代码更新,并在必要时重新加载模块。
293
+ 这是一个内部实现细节,通常不需要外部调用。
294
+
295
+ 参数:
296
+
297
+
298
+ 返回:
299
+ None
300
+ """
301
+ def _reload_check(self) -> None:
302
+ dg.reload_check()
303
 
304
  def _schedule_route_check(self) -> None:
305
  """
requirements.txt CHANGED
@@ -2,22 +2,15 @@
2
  fastapi
3
  uvicorn[standard]
4
  tiktoken
5
- playwright
6
  requests
7
  starlette
8
  pydantic
9
 
10
- # Async support
11
  uvloop
12
  httptools
13
  aiohttp
14
- asyncio
15
 
16
- # Utils
17
  apscheduler
18
- python-json-logger
19
- typing-extensions
20
- python-dotenv
21
-
22
- # Optional performance optimization
23
- ujson
 
2
  fastapi
3
  uvicorn[standard]
4
  tiktoken
 
5
  requests
6
  starlette
7
  pydantic
8
 
9
+ # Performance optimization
10
  uvloop
11
  httptools
12
  aiohttp
 
13
 
14
+ # Scheduling & Utils
15
  apscheduler
16
+ python-dotenv