File size: 5,535 Bytes
b50b5a5
 
 
9432aa8
 
b9ab4c6
 
 
 
bdc2de3
 
 
 
 
 
 
 
 
 
b9ab4c6
 
 
9432aa8
e9670f4
bdc2de3
 
 
 
 
 
 
 
b50b5a5
9432aa8
b50b5a5
de54e43
 
b50b5a5
bdc2de3
b2591f0
 
faaab61
b2591f0
 
 
 
 
 
 
 
 
faaab61
b2591f0
bdc2de3
 
 
133532e
 
bdc2de3
 
 
 
8e183da
9432aa8
8e183da
b50b5a5
 
 
 
 
 
 
 
 
bdc2de3
 
9432aa8
b50b5a5
b9ab4c6
 
 
bdc2de3
b9ab4c6
46b5c24
9432aa8
d7b2837
9432aa8
bdc2de3
 
 
b9ab4c6
9432aa8
bdc2de3
b50b5a5
 
bdc2de3
b50b5a5
 
 
 
 
 
 
9432aa8
bdc2de3
b50b5a5
bdc2de3
 
 
 
de54e43
faaab61
9432aa8
bdc2de3
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
105
106
107
108
109
110
111
112
113
114
115
import httpx
import asyncio
from starlette.responses import Response
from api_key_sb import get_api_key_info, update_api_key_ran_at, supabase as sb_client # 移除 get_supabase_client
# from supabase import Client
from dotenv import load_dotenv
import os
from datetime import timezone, timedelta, datetime
from fastapi import FastAPI, Request, HTTPException, Depends, status
import httpx
import asyncio
from starlette.responses import Response
from api_key_sb import get_api_key_info, update_api_key_ran_at, supabase as sb_client
from dotenv import load_dotenv
import os
from datetime import timezone, timedelta, datetime
from fastapi import FastAPI, Request, HTTPException, status
import logging
import json

load_dotenv()

logger = logging.getLogger(__name__)

def _create_error_response(status_code: int, detail: str, error_type: str = "ProxyError"):
    """Creates a standardized error response."""
    return Response(
        content=json.dumps({"detail": detail, "error_type": error_type}),
        status_code=status_code,
        media_type="application/json"
    )

async def do_proxy(url: str, method: str, headers: dict, content: str, max_retries: int = 3):
    logger.info(f"Proxy service started for URL: {url}")
    client = None
    try:
        async with httpx.AsyncClient() as client:
            for attempt in range(max_retries):
                model_name = None
                try:
                    content_json = json.loads(content)
                    
                    model_name = content_json.get('model')
                    if model_name:
                        logger.info(f"从内容中提取的模型名称: {model_name}")
                    else:
                        logger.warning("内容中未找到 'model' 键。")
                except json.JSONDecodeError:
                    logger.warning("内容不是有效的 JSON 格式,无法提取 'model' 键。")
                except Exception as e:
                    logger.error(f"提取模型名称时发生错误: {str(e)}")
                # api_key_info = await get_api_key_info('chat', model_name)
                api_key_info = await get_api_key_info(model_name)
                if not api_key_info:
                    return _create_error_response(status.HTTP_500_INTERNAL_SERVER_ERROR, "无法获取API密钥信息", "APIKeyError")
                
                api_key = api_key_info.get('api_key')
                api_key_id = api_key_info.get('api_key_id')
                
                if not api_key:
                    return _create_error_response(status.HTTP_500_INTERNAL_SERVER_ERROR, "API密钥为空", "APIKeyError")

                api_key_show = api_key[:5]+'*****'+api_key[-5:]
                logger.info(f"使用API密钥:{api_key_show}")
                headers["Authorization"] = f"Bearer {api_key}"
                response = await client.request(
                    method=method,
                    url=url,
                    headers=headers,
                    content=content,
                    timeout=30
                )
                
                if response.status_code == 429:
                    retry_after = response.headers.get("Retry-After", "5")
                    wait_time = int(retry_after) + attempt * 2
                    logger.warning(f"⚠️ 429错误!{wait_time}秒后重试 (尝试:{attempt+1})")
                    await asyncio.sleep(wait_time)

                    try:
                        beijing_tz = timezone(timedelta(hours=8))
                        now_beijing = datetime.now(beijing_tz)
                        future_time = now_beijing + timedelta(days=1)
                        future_timestamp = future_time.isoformat()
                        logger.info(f'future_timestamp: {future_timestamp}')
                        await update_api_key_ran_at(api_key_id, future_time)
                        logger.info('API密钥运行时间更新成功')
                    except HTTPException as e:
                        logger.error(f"更新API密钥运行时间失败!错误信息:{e.detail}")
                        return _create_error_response(e.status_code, e.detail, "APIKeyUpdateError")
                    except Exception as e:
                        logger.error(f"更新API密钥运行时间失败!错误信息:{str(e)}")
                        return _create_error_response(status.HTTP_500_INTERNAL_SERVER_ERROR, f"更新API密钥运行时间失败!错误信息:{str(e)}", "APIKeyUpdateError")
                    continue
                    
                response.raise_for_status()
                return Response(
                    content=response.content,
                    status_code=response.status_code,
                    headers=dict(response.headers)
                )
                
    except httpx.HTTPStatusError as e:
        logger.error(f"🚨 服务器错误 {e.response.status_code}: {e.request.url}")
        return _create_error_response(e.response.status_code, str(e), "HTTPStatusError")
        
    except HTTPException as e:
        logger.error(f"🔥 HTTPException: {e.detail}")
        return _create_error_response(e.status_code, e.detail, "HTTPException")

    except Exception as e:
        print('请检查当前是否运行在本机开发环境')
        logger.error(f"🔥 致命错误: {type(e).__name__}: {str(e)}")
        return _create_error_response(status.HTTP_500_INTERNAL_SERVER_ERROR, f"内部服务器错误: {str(e)}", "InternalServerError")