File size: 4,559 Bytes
ec41d51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
731d915
 
ec41d51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"""
账号数据模型定义 - 支持 Web Session Token (OAuth) 方式
"""
from pydantic import BaseModel, Field
from typing import Optional, Literal, Dict, Any
from datetime import datetime
import uuid


class OAuthToken(BaseModel):
    """OAuth Token 信息"""
    access_token: str
    refresh_token: str
    expires_in: int = 3600
    expiry_timestamp: int = 0  # Unix 时间戳
    project_id: Optional[str] = None
    session_id: str = Field(default_factory=lambda: str(uuid.uuid4()))


class Account(BaseModel):
    """API 账号模型 - Web Session Token 方式"""
    id: str = Field(default_factory=lambda: str(uuid.uuid4())[:8])
    email: str
    token: OAuthToken
    enabled: bool = True
    created_at: datetime = Field(default_factory=datetime.now)
    
    # 统计信息
    total_requests: int = 0
    successful_requests: int = 0
    failed_requests: int = 0
    last_used: Optional[datetime] = None
    last_error: Optional[str] = None
    
    # 冷却状态
    cooldown_until: Optional[datetime] = None
    
    def is_available(self) -> bool:
        """检查账号是否可用"""
        if not self.enabled:
            return False
        if self.cooldown_until and datetime.now() < self.cooldown_until:
            return False
        return True
    
    def is_token_expired(self) -> bool:
        """检查 token 是否过期(提前5分钟刷新)"""
        now = int(datetime.now().timestamp())
        return now >= self.token.expiry_timestamp - 300
    
    def display_name(self) -> str:
        """显示名称"""
        return self.email


class AccountStats(BaseModel):
    """账号统计汇总"""
    total_accounts: int = 0
    available_accounts: int = 0
    total_requests: int = 0
    success_rate: float = 0.0


class ServiceConfig(BaseModel):
    """服务配置"""
    api_key: str = "sk-antigravity"
    admin_username: str = "admin"
    admin_password: str = "antigravity"
    port: int = 7860
    enable_cors: bool = True
    max_retries: int = 3
    retry_delay: float = 1.0
    cooldown_duration: int = 60  # 秒


# ============ OpenAI 兼容格式 ============

class OpenAIMessage(BaseModel):
    """OpenAI 消息格式"""
    role: Literal["system", "user", "assistant"]
    content: str


class OpenAIChatRequest(BaseModel):
    """OpenAI Chat Completion 请求"""
    model: str
    messages: list[OpenAIMessage]
    temperature: Optional[float] = 1.0
    top_p: Optional[float] = 0.95
    max_tokens: Optional[int] = 8192
    stream: bool = False


class OpenAIChatChoice(BaseModel):
    """OpenAI 响应选项"""
    index: int = 0
    message: Optional[Dict[str, Any]] = None
    delta: Optional[Dict[str, Any]] = None
    finish_reason: Optional[str] = None


class OpenAIChatResponse(BaseModel):
    """OpenAI Chat Completion 响应"""
    id: str = Field(default_factory=lambda: f"chatcmpl-{uuid.uuid4().hex[:8]}")
    object: str = "chat.completion"
    created: int = Field(default_factory=lambda: int(datetime.now().timestamp()))
    model: str
    choices: list[OpenAIChatChoice]
    usage: Optional[Dict[str, int]] = None


# ============ 模型映射 ============

MODEL_MAPPING: Dict[str, str] = {
    # Claude 到 Gemini 映射
    "claude-sonnet-4-5-thinking": "gemini-2.5-pro-preview",
    "claude-sonnet-4-5": "gemini-2.5-flash-preview", 
    "claude-opus-4-5": "gemini-2.5-pro-preview",
    "claude-3-5-sonnet": "gemini-2.5-flash-preview",
    "claude-3-5-haiku": "gemini-2.5-flash-lite-preview",
    
    # Gemini 模型直通
    "gemini-3-flash": "gemini-3-flash-preview",
    "gemini-3-pro": "gemini-3-pro-preview",
    "gemini-3-pro-high": "gemini-3-pro-preview",
    "gemini-2.5-pro": "gemini-2.5-pro-preview",
    "gemini-2.5-flash": "gemini-2.5-flash-preview",
    "gemini-2.5-flash-lite": "gemini-2.5-flash-lite-preview",
}

SUPPORTED_MODELS = [
    # Gemini 3 系列
    {"id": "gemini-3-flash", "name": "Gemini 3 Flash (极速预览)"},
    {"id": "gemini-3-pro", "name": "Gemini 3 Pro (经典版)"},
    {"id": "gemini-3-pro-high", "name": "Gemini 3 Pro (最强推理)"},
    
    # Gemini 2.5 系列
    {"id": "gemini-2.5-pro", "name": "Gemini 2.5 Pro (极致推理)"},
    {"id": "gemini-2.5-flash", "name": "Gemini 2.5 Flash (极速响应)"},
    {"id": "gemini-2.5-flash-lite", "name": "Gemini 2.5 Flash Lite (轻量极速)"},
    
    # Claude 映射
    {"id": "claude-sonnet-4-5-thinking", "name": "Claude Sonnet 4.5 - 思维链"},
    {"id": "claude-sonnet-4-5", "name": "Claude Sonnet 4.5"},
    {"id": "claude-opus-4-5", "name": "Claude Opus 4.5"},
]