File size: 4,052 Bytes
40610d7
 
bf7211c
40610d7
bf7211c
40610d7
bf7211c
40610d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bf7211c
 
 
 
 
 
fb31778
bf7211c
 
 
 
 
 
fb31778
bf7211c
 
 
 
 
 
 
 
 
 
 
 
 
40610d7
e196795
bf7211c
 
 
 
 
 
 
 
 
 
e196795
bf7211c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import os
import json
import asyncio
import httpx
import traceback
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse, JSONResponse
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

AIROPS_API_KEY = os.environ.get("AIROPS_API_KEY", "")
AIROPS_APP_ID = os.environ.get("AIROPS_APP_ID", "")
INPUT_VAR = os.environ.get("INPUT_VAR_NAME", "input")

@app.post("/v1/chat/completions")
async def chat_completions(request: Request):
    try:
        try:
            body = await request.json()
        except:
            body = {}
            
        messages = body.get("messages", [])
        
        # 将所有历史消息和设定拼接成一个长剧本
        full_context = ""
        for msg in messages:
            # 强制转换为字符串,防止特殊格式报错
            role = str(msg.get("role", "user")).upper()
            content = str(msg.get("content", ""))
            
            if role == "SYSTEM":
                full_context += f"[系统设定及角色卡]:\n{content}\n\n"
            elif role == "ASSISTANT":
                full_context += f"[角色回复]:\n{content}\n\n"
            else:
                full_context += f"[我的输入]:\n{content}\n\n"
                
        if not full_context.strip():
            full_context = "[我的输入]:\n你好"
        
        headers = {
            "Authorization": f"Bearer {AIROPS_API_KEY}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "inputs": {
                INPUT_VAR: full_context.strip()
            }
        }
        
        async def generate():
            # 同样保持 300 秒超时,给 AI 充分的思考时间
            async with httpx.AsyncClient(timeout=300.0) as client:
                url = f"https://app.airops.com/public_api/airops_apps/{AIROPS_APP_ID}/execute"
                
                try:
                    response = await client.post(url, headers=headers, json=payload)
                    
                    if response.status_code == 200:
                        data = response.json()
                        result_text = data.get("result", "")
                        
                        if isinstance(result_text, (dict, list)):
                            result_text = json.dumps(result_text, ensure_ascii=False)
                        
                        # 模拟 OpenAI 流式打字机效果
                        chunk_size = 3
                        for i in range(0, len(result_text), chunk_size):
                            chunk = result_text[i:i+chunk_size]
                            openai_chunk = {
                                "id": "chatcmpl-airops",
                                "object": "chat.completion.chunk",
                                "choices": [{"delta": {"content": chunk}}]
                            }
                            yield f"data: {json.dumps(openai_chunk)}\n\n"
                            await asyncio.sleep(0.01)
                            
                        yield "data: [DONE]\n\n"
                    else:
                        print(f"AirOps Error: {response.status_code} - {response.text}")
                        err = {"error": f"AirOps 接口报错: {response.status_code}"}
                        yield f"data: {json.dumps(err)}\n\n"
                        yield "data: [DONE]\n\n"
                except Exception as e:
                    traceback.print_exc()
                    err = {"error": f"代理服务器内部错误: {repr(e)}"}
                    yield f"data: {json.dumps(err)}\n\n"
                    yield "data: [DONE]\n\n"

        return StreamingResponse(generate(), media_type="text/event-stream")
        
    except Exception as e:
        traceback.print_exc()
        return JSONResponse(status_code=500, content={"error": f"请求解析错误: {repr(e)}"})