hzruo commited on
Commit
de43fe0
·
verified ·
1 Parent(s): ecd020f

Delete main.py

Browse files
Files changed (1) hide show
  1. main.py +0 -832
main.py DELETED
@@ -1,832 +0,0 @@
1
- from fastapi import FastAPI, Request, Depends, HTTPException
2
- from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
3
- from fastapi.responses import StreamingResponse, HTMLResponse
4
- from fastapi.background import BackgroundTasks
5
- from contextlib import asynccontextmanager
6
- import requests
7
- from curl_cffi import requests as cffi_requests
8
- import uuid
9
- import json
10
- import time
11
- from typing import Optional
12
- import asyncio
13
- import base64
14
- import tempfile
15
- import os
16
- import re
17
- import threading
18
- import logging
19
- from dotenv import load_dotenv
20
- from playwright.sync_api import sync_playwright
21
-
22
- # 加载环境变量
23
- load_dotenv(override=True)
24
-
25
- # 配置日志
26
- logging.basicConfig(
27
- level=logging.INFO, # 改为 INFO 级别
28
- format='%(asctime)s - %(levelname)s - %(message)s'
29
- )
30
- logger = logging.getLogger(__name__)
31
-
32
- # 修改全局数据存储
33
- global_data = {
34
- "cookie": None,
35
- "cookies": None,
36
- "last_update": 0,
37
- "cookie_expires": 0 # 添加 cookie 过期时间
38
- }
39
-
40
- @asynccontextmanager
41
- async def lifespan(app: FastAPI):
42
- # 启动时获取 cookie
43
- logger.info("Starting FastAPI application, initializing cookie fetcher...")
44
-
45
- # 创建并启动线程
46
- cookie_thread = threading.Thread(target=get_cookie_with_retry)
47
- cookie_thread.daemon = True # 设置为守护线程
48
- cookie_thread.start()
49
-
50
- logger.info("Cookie fetcher thread started")
51
- yield
52
-
53
- # 关闭时清理资源
54
- logger.info("Shutting down FastAPI application")
55
- global_data["cookie"] = None
56
- global_data["cookies"] = None
57
- global_data["last_update"] = 0
58
-
59
- def get_cookie_with_retry(max_retries=3, retry_delay=5):
60
- """带重试机制的获取 cookie 函数"""
61
- retries = 0
62
- while retries < max_retries:
63
- logger.info(f"Cookie fetching attempt {retries + 1}/{max_retries}")
64
- cookie = get_cookie()
65
- if cookie:
66
- logger.info("Successfully retrieved cookie")
67
- return cookie
68
-
69
- retries += 1
70
- if retries < max_retries:
71
- logger.info(f"Retrying cookie fetch in {retry_delay} seconds...")
72
- time.sleep(retry_delay)
73
-
74
- logger.error(f"Failed to fetch cookie after {max_retries} attempts")
75
- return None
76
-
77
- app = FastAPI(lifespan=lifespan)
78
- security = HTTPBearer()
79
-
80
- # OpenAI API Key 配置,可以通过环境变量覆盖
81
- OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", None)
82
- logger.info(f"OPENAI_API_KEY is set: {OPENAI_API_KEY is not None}")
83
- logger.info(f"OPENAI_API_KEY value: {OPENAI_API_KEY}")
84
-
85
- def get_cookie():
86
- try:
87
- logger.info("Starting cookie retrieval process...")
88
-
89
- with sync_playwright() as p:
90
- try:
91
- # 启动浏览器
92
- logger.info("Launching browser...")
93
- browser = p.chromium.launch(
94
- headless=True,
95
- args=[
96
- '--no-sandbox',
97
- '--disable-dev-shm-usage',
98
- '--disable-gpu',
99
- '--disable-software-rasterizer',
100
- '--disable-extensions',
101
- '--disable-setuid-sandbox',
102
- '--no-first-run',
103
- '--no-zygote',
104
- '--single-process',
105
- '--window-size=1920,1080',
106
- '--disable-blink-features=AutomationControlled' # 禁用自动化控制检测
107
- ]
108
- )
109
-
110
- logger.info("Browser launched successfully")
111
-
112
- # 创建上下文,添加更多浏览器特征
113
- logger.info("Creating browser context...")
114
- context = browser.new_context(
115
- viewport={'width': 1920, 'height': 1080},
116
- user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
117
- locale='en-US',
118
- timezone_id='America/New_York',
119
- permissions=['geolocation'],
120
- extra_http_headers={
121
- 'Accept-Language': 'en-US,en;q=0.9',
122
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
123
- 'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
124
- 'Sec-Ch-Ua-Mobile': '?0',
125
- 'Sec-Ch-Ua-Platform': '"macOS"',
126
- 'Sec-Fetch-Dest': 'document',
127
- 'Sec-Fetch-Mode': 'navigate',
128
- 'Sec-Fetch-Site': 'none',
129
- 'Sec-Fetch-User': '?1',
130
- 'Upgrade-Insecure-Requests': '1'
131
- }
132
- )
133
-
134
- logger.info("Browser context created successfully")
135
-
136
- # 创建页面
137
- logger.info("Creating new page...")
138
- page = context.new_page()
139
- logger.info("Page created successfully")
140
-
141
- # 设置页面超时
142
- page.set_default_timeout(60000)
143
-
144
- # 访问目标网站
145
- logger.info("Navigating to target website...")
146
- page.goto("https://chat.akash.network/", timeout=50000)
147
-
148
- # 等待页面加载
149
- logger.info("Waiting for page load...")
150
- try:
151
- # 首先等待 DOM 加载完成
152
- page.wait_for_load_state("domcontentloaded", timeout=30000)
153
- logger.info("DOM content loaded")
154
-
155
- # 等待一段时间,让 Cloudflare 检查完成
156
- logger.info("Waiting for Cloudflare check...")
157
- time.sleep(5)
158
-
159
- # 尝试点击页面,模拟用户行为
160
- try:
161
- page.mouse.move(100, 100)
162
- page.mouse.click(100, 100)
163
- logger.info("Simulated user interaction")
164
- except Exception as e:
165
- logger.warning(f"Failed to simulate user interaction: {e}")
166
-
167
- # 再次等待一段时间
168
- time.sleep(5)
169
-
170
- except Exception as e:
171
- logger.warning(f"Timeout waiting for load state: {e}")
172
-
173
- # 获取 cookies
174
- logger.info("Getting cookies...")
175
- cookies = context.cookies()
176
-
177
- if not cookies:
178
- logger.error("No cookies found")
179
- browser.close()
180
- return None
181
-
182
- # 检查是否有 cf_clearance cookie
183
- cf_cookie = next((cookie for cookie in cookies if cookie['name'] == 'cf_clearance'), None)
184
- if not cf_cookie:
185
- logger.error("cf_clearance cookie not found")
186
- browser.close()
187
- return None
188
-
189
- # 构建 cookie 字符串
190
- cookie_str = '; '.join([f"{cookie['name']}={cookie['value']}" for cookie in cookies])
191
- global_data["cookie"] = cookie_str
192
- global_data["cookies"] = cookies # 保存完整的 cookies 列表
193
- global_data["last_update"] = time.time()
194
-
195
- # 查找 session_token cookie 的过期时间
196
- session_cookie = next((cookie for cookie in cookies if cookie['name'] == 'session_token'), None)
197
- if session_cookie and 'expires' in session_cookie and session_cookie['expires'] > 0:
198
- global_data["cookie_expires"] = session_cookie['expires']
199
- logger.info(f"Session token expires at: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(session_cookie['expires']))}")
200
- else:
201
- # 如果没有明确的过期时间,默认设置为1小时后过期
202
- global_data["cookie_expires"] = time.time() + 3600
203
- logger.info("No explicit expiration in session_token cookie, setting default 1 hour expiration")
204
-
205
- logger.info("Successfully retrieved cookies")
206
- browser.close()
207
- return cookie_str
208
-
209
- except Exception as e:
210
- logger.error(f"Error in browser operations: {e}")
211
- logger.error(f"Error type: {type(e)}")
212
- import traceback
213
- logger.error(f"Traceback: {traceback.format_exc()}")
214
- return None
215
-
216
- except Exception as e:
217
- logger.error(f"Error fetching cookie: {str(e)}")
218
- logger.error(f"Error type: {type(e)}")
219
- import traceback
220
- logger.error(f"Traceback: {traceback.format_exc()}")
221
- return None
222
-
223
- # 添加刷新 cookie 的函数
224
- async def refresh_cookie():
225
- logger.info("Refreshing cookie due to 401 error")
226
- # 标记 cookie 为过期
227
- global_data["cookie_expires"] = 0
228
- # 获取新的 cookie
229
- return get_cookie()
230
-
231
- async def check_and_update_cookie(background_tasks: BackgroundTasks):
232
- # 如果 cookie 不存在或已过期,则更新
233
- current_time = time.time()
234
- if not global_data["cookie"] or current_time >= global_data["cookie_expires"]:
235
- logger.info("Cookie expired or not available, refreshing...")
236
- background_tasks.add_task(get_cookie)
237
- else:
238
- logger.info("Using existing cookie")
239
-
240
- async def get_api_key(credentials: HTTPAuthorizationCredentials = Depends(security)):
241
- token = credentials.credentials
242
- logger.info(f"Received token: {token}")
243
-
244
- # 如果设置了 OPENAI_API_KEY,则��要验证
245
- if OPENAI_API_KEY is not None:
246
- # 去掉 Bearer 前缀后再比较
247
- clean_token = token.replace("Bearer ", "") if token.startswith("Bearer ") else token
248
- logger.info(f"Clean token: {clean_token}")
249
- if clean_token != OPENAI_API_KEY:
250
- logger.error(f"Token mismatch. Expected: {OPENAI_API_KEY}, Got: {clean_token}")
251
- raise HTTPException(
252
- status_code=401,
253
- detail="Invalid API key"
254
- )
255
- logger.info("API key validation passed")
256
-
257
- return True
258
-
259
- async def validate_cookie(background_tasks: BackgroundTasks):
260
- # 检查并更新 cookie(如果需要)
261
- await check_and_update_cookie(background_tasks)
262
-
263
- # 等待 cookie 初始化完成
264
- max_wait = 30 # 最大等待时间(秒)
265
- start_time = time.time()
266
- while not global_data["cookie"] and time.time() - start_time < max_wait:
267
- await asyncio.sleep(1)
268
- logger.info("Waiting for cookie initialization...")
269
-
270
- # 检查是否有有效的 cookie
271
- if not global_data["cookie"]:
272
- logger.error("Cookie not available after waiting")
273
- raise HTTPException(
274
- status_code=503,
275
- detail="Service temporarily unavailable - Cookie not available"
276
- )
277
-
278
- logger.info("Cookie validation passed")
279
- return global_data["cookie"]
280
-
281
- async def check_image_status(session: requests.Session, job_id: str, headers: dict) -> Optional[str]:
282
- """检查图片生成状态并获取生成的图片"""
283
- max_retries = 30
284
- for attempt in range(max_retries):
285
- try:
286
- print(f"\nAttempt {attempt + 1}/{max_retries} for job {job_id}")
287
- response = session.get(
288
- f'https://chat.akash.network/api/image-status?ids={job_id}',
289
- headers=headers
290
- )
291
- print(f"Status response code: {response.status_code}")
292
- status_data = response.json()
293
-
294
- if status_data and isinstance(status_data, list) and len(status_data) > 0:
295
- job_info = status_data[0]
296
- status = job_info.get('status')
297
- print(f"Job status: {status}")
298
-
299
- # 只有当状态为 completed 时才处理结果
300
- if status == "completed":
301
- result = job_info.get("result")
302
- if result and not result.startswith("Failed"):
303
- print("Got valid result, attempting upload...")
304
- image_url = await upload_to_xinyew(result, job_id)
305
- if image_url:
306
- print(f"Successfully uploaded image: {image_url}")
307
- return image_url
308
- print("Image upload failed")
309
- return None
310
- print("Invalid result received")
311
- return None
312
- elif status == "failed":
313
- print(f"Job {job_id} failed")
314
- return None
315
-
316
- # 如果状态是其他(如 pending),继续等待
317
- await asyncio.sleep(1)
318
- continue
319
-
320
- except Exception as e:
321
- print(f"Error checking status: {e}")
322
- return None
323
-
324
- print(f"Timeout waiting for job {job_id}")
325
- return None
326
-
327
- @app.get("/", response_class=HTMLResponse)
328
- async def health_check():
329
- """Health check endpoint"""
330
- # 检查 cookie 状态
331
- cookie_status = "ok" if global_data["cookie"] is not None else "error"
332
- cookie_status_color = "#4CAF50" if cookie_status == "ok" else "#f44336"
333
-
334
- status = {
335
- "status": cookie_status,
336
- "version": "1.0.0",
337
- "cookie_status": {
338
- "available": global_data["cookie"] is not None,
339
- "last_update": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(global_data["last_update"])) if global_data["last_update"] > 0 else None,
340
- "expires": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(global_data["cookie_expires"])) if global_data["cookie_expires"] > 0 else None
341
- }
342
- }
343
-
344
- html = f"""
345
- <!DOCTYPE html>
346
- <html>
347
- <head>
348
- <title>Akash API Status</title>
349
- <style>
350
- body {{
351
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
352
- line-height: 1.6;
353
- margin: 0;
354
- padding: 20px;
355
- background-color: #f5f5f5;
356
- }}
357
- .container {{
358
- max-width: 800px;
359
- margin: 0 auto;
360
- background-color: white;
361
- padding: 20px;
362
- border-radius: 8px;
363
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
364
- }}
365
- h1 {{
366
- color: #333;
367
- margin-top: 0;
368
- }}
369
- .status {{
370
- display: inline-block;
371
- padding: 4px 8px;
372
- border-radius: 4px;
373
- font-weight: bold;
374
- background-color: {cookie_status_color};
375
- color: white;
376
- }}
377
- .info {{
378
- margin-top: 20px;
379
- }}
380
- .info-item {{
381
- margin-bottom: 10px;
382
- }}
383
- .label {{
384
- font-weight: bold;
385
- color: #666;
386
- }}
387
- .value {{
388
- color: #333;
389
- }}
390
- .cookie-status {{
391
- margin-top: 20px;
392
- padding: 15px;
393
- background-color: #f8f9fa;
394
- border-radius: 4px;
395
- }}
396
- .cookie-status .available {{
397
- color: {cookie_status_color};
398
- }}
399
- .error-message {{
400
- color: #f44336;
401
- margin-top: 10px;
402
- padding: 10px;
403
- background-color: #ffebee;
404
- border-radius: 4px;
405
- display: {"block" if cookie_status == "error" else "none"};
406
- }}
407
- </style>
408
- </head>
409
- <body>
410
- <div class="container">
411
- <h1>Akash API Status <span class="status">{status["status"]}</span></h1>
412
-
413
- <div class="info">
414
- <div class="info-item">
415
- <span class="label">Version:</span>
416
- <span class="value">{status["version"]}</span>
417
- </div>
418
- </div>
419
-
420
- <div class="cookie-status">
421
- <h2>Cookie Status</h2>
422
- <div class="info-item">
423
- <span class="label">Available:</span>
424
- <span class="value available">{str(status["cookie_status"]["available"])}</span>
425
- </div>
426
- <div class="info-item">
427
- <span class="label">Last Update:</span>
428
- <span class="value">{status["cookie_status"]["last_update"] or "Never"}</span>
429
- </div>
430
- <div class="info-item">
431
- <span class="label">Expires:</span>
432
- <span class="value">{status["cookie_status"]["expires"] or "Unknown"}</span>
433
- </div>
434
-
435
- <div class="error-message">
436
- Cookie retrieval failed. The service may not be fully functional.
437
- </div>
438
- </div>
439
- </div>
440
- </body>
441
- </html>
442
- """
443
-
444
- return html
445
-
446
- @app.post("/v1/chat/completions")
447
- async def chat_completions(
448
- request: Request,
449
- background_tasks: BackgroundTasks,
450
- api_key: bool = Depends(get_api_key),
451
- cookie: str = Depends(validate_cookie)
452
- ):
453
- try:
454
- data = await request.json()
455
-
456
- chat_id = str(uuid.uuid4()).replace('-', '')[:16]
457
-
458
- akash_data = {
459
- "id": chat_id,
460
- "messages": data.get('messages', []),
461
- "model": data.get('model', "DeepSeek-R1"),
462
- "system": data.get('system_message', "You are a helpful assistant."),
463
- "temperature": data.get('temperature', 0.6),
464
- "topP": data.get('top_p', 0.95)
465
- }
466
-
467
- # 构建请求头
468
- headers = {
469
- "Content-Type": "application/json",
470
- "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
471
- "Accept": "*/*",
472
- "Accept-Language": "en-US,en;q=0.9",
473
- "Accept-Encoding": "gzip, deflate, br",
474
- "Origin": "https://chat.akash.network",
475
- "Referer": "https://chat.akash.network/",
476
- "Sec-Fetch-Dest": "empty",
477
- "Sec-Fetch-Mode": "cors",
478
- "Sec-Fetch-Site": "same-origin",
479
- "Connection": "keep-alive"
480
- }
481
-
482
- # 设置 Cookie
483
- headers["Cookie"] = cookie
484
-
485
- with requests.Session() as session:
486
- response = session.post(
487
- 'https://chat.akash.network/api/chat',
488
- json=akash_data,
489
- headers=headers,
490
- stream=True
491
- )
492
-
493
- # 检查响应状态码,如果是 401,尝试刷新 cookie 并重试
494
- if response.status_code == 401:
495
- logger.info("Cookie expired, refreshing...")
496
- new_cookie = await refresh_cookie()
497
- if new_cookie:
498
- headers["Cookie"] = new_cookie
499
- response = session.post(
500
- 'https://chat.akash.network/api/chat',
501
- json=akash_data,
502
- headers=headers,
503
- stream=True
504
- )
505
-
506
- if response.status_code != 200:
507
- logger.error(f"Akash API error: {response.text}")
508
- raise HTTPException(
509
- status_code=response.status_code,
510
- detail=f"Akash API error: {response.text}"
511
- )
512
-
513
- def generate():
514
- content_buffer = ""
515
- for line in response.iter_lines():
516
- if not line:
517
- continue
518
-
519
- try:
520
- line_str = line.decode('utf-8')
521
- msg_type, msg_data = line_str.split(':', 1)
522
-
523
- if msg_type == '0':
524
- if msg_data.startswith('"') and msg_data.endswith('"'):
525
- msg_data = msg_data.replace('\\"', '"')
526
- msg_data = msg_data[1:-1]
527
- msg_data = msg_data.replace("\\n", "\n")
528
-
529
- # 在处理消息时先判断模型类型
530
- if data.get('model') == 'AkashGen' and "<image_generation>" in msg_data:
531
- # 图片生成模型的特殊处理
532
- async def process_and_send():
533
- messages = await process_image_generation(msg_data, session, headers, chat_id)
534
- if messages:
535
- return messages
536
- return None
537
-
538
- # 创建新的事件循环
539
- loop = asyncio.new_event_loop()
540
- asyncio.set_event_loop(loop)
541
- try:
542
- result_messages = loop.run_until_complete(process_and_send())
543
- finally:
544
- loop.close()
545
-
546
- if result_messages:
547
- for message in result_messages:
548
- yield f"data: {json.dumps(message)}\n\n"
549
- continue
550
-
551
- content_buffer += msg_data
552
-
553
- chunk = {
554
- "id": f"chatcmpl-{chat_id}",
555
- "object": "chat.completion.chunk",
556
- "created": int(time.time()),
557
- "model": data.get('model'),
558
- "choices": [{
559
- "delta": {"content": msg_data},
560
- "index": 0,
561
- "finish_reason": None
562
- }]
563
- }
564
- yield f"data: {json.dumps(chunk)}\n\n"
565
-
566
- elif msg_type in ['e', 'd']:
567
- chunk = {
568
- "id": f"chatcmpl-{chat_id}",
569
- "object": "chat.completion.chunk",
570
- "created": int(time.time()),
571
- "model": data.get('model'),
572
- "choices": [{
573
- "delta": {},
574
- "index": 0,
575
- "finish_reason": "stop"
576
- }]
577
- }
578
- yield f"data: {json.dumps(chunk)}\n\n"
579
- yield "data: [DONE]\n\n"
580
- break
581
-
582
- except Exception as e:
583
- print(f"Error processing line: {e}")
584
- continue
585
-
586
- return StreamingResponse(
587
- generate(),
588
- media_type='text/event-stream',
589
- headers={
590
- 'Cache-Control': 'no-cache',
591
- 'Connection': 'keep-alive',
592
- 'Content-Type': 'text/event-stream'
593
- }
594
- )
595
-
596
- except Exception as e:
597
- print(f"Error in chat_completions: {e}")
598
- import traceback
599
- print(traceback.format_exc())
600
- return {"error": str(e)}
601
-
602
- @app.get("/v1/models")
603
- async def list_models(
604
- background_tasks: BackgroundTasks,
605
- cookie: str = Depends(validate_cookie)
606
- ):
607
- try:
608
- headers = {
609
- "accept": "application/json",
610
- "accept-language": "en-US,en;q=0.9",
611
- "sec-ch-ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
612
- "sec-ch-ua-mobile": "?0",
613
- "sec-ch-ua-platform": '"macOS"',
614
- "sec-fetch-dest": "document",
615
- "sec-fetch-mode": "cors",
616
- "sec-fetch-site": "same-origin",
617
- "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
618
- "referer": "https://chat.akash.network/"
619
- }
620
-
621
- # 设置 Cookie
622
- headers["Cookie"] = cookie
623
-
624
- print(f"Using cookie: {headers.get('Cookie', 'None')}")
625
- print("Sending request to get models...")
626
-
627
- response = requests.get(
628
- 'https://chat.akash.network/api/models',
629
- headers=headers
630
- )
631
-
632
- print(f"Models response status: {response.status_code}")
633
- print(f"Models response headers: {response.headers}")
634
-
635
- if response.status_code == 401:
636
- print("Authentication failed. Please check your API key.")
637
- return {"error": "Authentication failed. Please check your API key."}
638
-
639
- akash_response = response.json()
640
-
641
- # 添加错误处理和调试信息
642
- print(f"Akash API response: {akash_response}")
643
-
644
- # 检查响应格式并适配
645
- models_list = []
646
- if isinstance(akash_response, list):
647
- # 如果直接是列表
648
- models_list = akash_response
649
- elif isinstance(akash_response, dict):
650
- # 如果是字典格式
651
- models_list = akash_response.get("models", [])
652
- else:
653
- print(f"Unexpected response format: {type(akash_response)}")
654
- models_list = []
655
-
656
- # 转换为标准 OpenAI 格式
657
- openai_models = {
658
- "object": "list",
659
- "data": [
660
- {
661
- "id": model["id"] if isinstance(model, dict) else model,
662
- "object": "model",
663
- "created": int(time.time()),
664
- "owned_by": "akash",
665
- "permission": [{
666
- "id": f"modelperm-{model['id'] if isinstance(model, dict) else model}",
667
- "object": "model_permission",
668
- "created": int(time.time()),
669
- "allow_create_engine": False,
670
- "allow_sampling": True,
671
- "allow_logprobs": True,
672
- "allow_search_indices": False,
673
- "allow_view": True,
674
- "allow_fine_tuning": False,
675
- "organization": "*",
676
- "group": None,
677
- "is_blocking": False
678
- }]
679
- } for model in models_list
680
- ]
681
- }
682
-
683
- return openai_models
684
-
685
- except Exception as e:
686
- print(f"Error in list_models: {e}")
687
- import traceback
688
- print(traceback.format_exc())
689
- return {"error": str(e)}
690
-
691
- async def process_image_generation(msg_data: str, session: requests.Session, headers: dict, chat_id: str) -> Optional[list]:
692
- """处理图片生成的逻辑,返回多个消息块"""
693
- match = re.search(r"jobId='([^']+)' prompt='([^']+)' negative='([^']*)'", msg_data)
694
- if match:
695
- job_id, prompt, negative = match.groups()
696
- print(f"Starting image generation process for job_id: {job_id}")
697
-
698
- # 记录开始时间
699
- start_time = time.time()
700
-
701
- # 发送思考开始的消息
702
- think_msg = "<think>\n"
703
- think_msg += "🎨 Generating image...\n\n"
704
- think_msg += f"Prompt: {prompt}\n"
705
-
706
- # 检查图片状态和上传
707
- result = await check_image_status(session, job_id, headers)
708
-
709
- # 计算实际花费的时间
710
- elapsed_time = time.time() - start_time
711
-
712
- # 完成思考部分
713
- think_msg += f"\n🤔 Thinking for {elapsed_time:.1f}s...\n"
714
- think_msg += "</think>"
715
-
716
- # 返回两个独立的消息块
717
- messages = []
718
-
719
- # 第一个消息块:思考过程
720
- messages.append({
721
- "id": f"chatcmpl-{chat_id}-think",
722
- "object": "chat.completion.chunk",
723
- "created": int(time.time()),
724
- "model": "AkashGen",
725
- "choices": [{
726
- "delta": {"content": think_msg},
727
- "index": 0,
728
- "finish_reason": None
729
- }]
730
- })
731
-
732
- # 第二个消息块:图片结果
733
- if result:
734
- image_msg = f"\n\n![Generated Image]({result})"
735
- messages.append({
736
- "id": f"chatcmpl-{chat_id}-image",
737
- "object": "chat.completion.chunk",
738
- "created": int(time.time()),
739
- "model": "AkashGen",
740
- "choices": [{
741
- "delta": {"content": image_msg},
742
- "index": 0,
743
- "finish_reason": None
744
- }]
745
- })
746
- else:
747
- fail_msg = "\n\n*Image generation or upload failed.*"
748
- messages.append({
749
- "id": f"chatcmpl-{chat_id}-fail",
750
- "object": "chat.completion.chunk",
751
- "created": int(time.time()),
752
- "model": "AkashGen",
753
- "choices": [{
754
- "delta": {"content": fail_msg},
755
- "index": 0,
756
- "finish_reason": None
757
- }]
758
- })
759
-
760
- return messages
761
- return None
762
-
763
- async def upload_to_xinyew(image_base64: str, job_id: str) -> Optional[str]:
764
- """上传图片到新野图床并返回URL"""
765
- try:
766
- print(f"\n=== Starting image upload for job {job_id} ===")
767
- print(f"Base64 data length: {len(image_base64)}")
768
-
769
- # 解码base64图片数据
770
- try:
771
- image_data = base64.b64decode(image_base64.split(',')[1] if ',' in image_base64 else image_base64)
772
- print(f"Decoded image data length: {len(image_data)} bytes")
773
- except Exception as e:
774
- print(f"Error decoding base64: {e}")
775
- print(f"First 100 chars of base64: {image_base64[:100]}...")
776
- return None
777
-
778
- # 创建临时文件
779
- with tempfile.NamedTemporaryFile(suffix='.jpeg', delete=False) as temp_file:
780
- temp_file.write(image_data)
781
- temp_file_path = temp_file.name
782
-
783
- try:
784
- filename = f"{job_id}.jpeg"
785
- print(f"Using filename: {filename}")
786
-
787
- # 准备文件上传
788
- files = {
789
- 'file': (filename, open(temp_file_path, 'rb'), 'image/jpeg')
790
- }
791
-
792
- print("Sending request to xinyew.cn...")
793
- response = requests.post(
794
- 'https://api.xinyew.cn/api/jdtc',
795
- files=files,
796
- timeout=30
797
- )
798
-
799
- print(f"Upload response status: {response.status_code}")
800
- if response.status_code == 200:
801
- result = response.json()
802
- print(f"Upload response: {result}")
803
-
804
- if result.get('errno') == 0:
805
- url = result.get('data', {}).get('url')
806
- if url:
807
- print(f"Successfully got image URL: {url}")
808
- return url
809
- print("No URL in response data")
810
- else:
811
- print(f"Upload failed: {result.get('message')}")
812
- else:
813
- print(f"Upload failed with status {response.status_code}")
814
- print(f"Response content: {response.text}")
815
- return None
816
-
817
- finally:
818
- # 清理临时文件
819
- try:
820
- os.unlink(temp_file_path)
821
- except Exception as e:
822
- print(f"Error removing temp file: {e}")
823
-
824
- except Exception as e:
825
- print(f"Error in upload_to_xinyew: {e}")
826
- import traceback
827
- print(traceback.format_exc())
828
- return None
829
-
830
- if __name__ == '__main__':
831
- import uvicorn
832
- uvicorn.run(app, host='0.0.0.0', port=9000)