airops-api-proxy / main.py
wanazesi's picture
Update main.py
bf7211c verified
Raw
History Blame Contribute Delete
4.05 kB
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)}"})