103 lines
4.1 KiB
Python
103 lines
4.1 KiB
Python
"""OpenAI 请求-响应模型定义"""
|
|
|
|
from fastapi import HTTPException
|
|
from typing import Optional, List, Union, Dict, Any
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
from app.models.grok_models import Models
|
|
|
|
|
|
class OpenAIChatRequest(BaseModel):
|
|
"""OpenAI聊天请求"""
|
|
|
|
model: str = Field(..., description="模型名称", min_length=1)
|
|
messages: List[Dict[str, Any]] = Field(..., description="消息列表", min_length=1)
|
|
stream: bool = Field(False, description="流式响应")
|
|
temperature: Optional[float] = Field(0.7, ge=0, le=2, description="采样温度")
|
|
max_tokens: Optional[int] = Field(None, ge=1, le=100000, description="最大Token数")
|
|
top_p: Optional[float] = Field(1.0, ge=0, le=1, description="采样参数")
|
|
|
|
@classmethod
|
|
@field_validator('messages')
|
|
def validate_messages(cls, v):
|
|
"""验证消息格式"""
|
|
if not v:
|
|
raise HTTPException(status_code=400, detail="消息列表不能为空")
|
|
|
|
for msg in v:
|
|
if not isinstance(msg, dict):
|
|
raise HTTPException(status_code=400, detail="每个消息必须是字典")
|
|
if 'role' not in msg:
|
|
raise HTTPException(status_code=400, detail="消息缺少 'role' 字段")
|
|
if 'content' not in msg:
|
|
raise HTTPException(status_code=400, detail="消息缺少 'content' 字段")
|
|
if msg['role'] not in ['system', 'user', 'assistant']:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"无效角色 '{msg['role']}', 必须是 system/user/assistant"
|
|
)
|
|
|
|
return v
|
|
|
|
@classmethod
|
|
@field_validator('model')
|
|
def validate_model(cls, v):
|
|
"""验证模型名称"""
|
|
if not Models.is_valid_model(v):
|
|
supported = Models.get_all_model_names()
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"不支持的模型 '{v}', 支持: {', '.join(supported)}"
|
|
)
|
|
return v
|
|
|
|
|
|
class OpenAIChatCompletionMessage(BaseModel):
|
|
"""聊天完成消息"""
|
|
role: str = Field(..., description="角色")
|
|
content: str = Field(..., description="内容")
|
|
reference_id: Optional[str] = Field(default=None, description="参考ID")
|
|
annotations: Optional[List[str]] = Field(default=None, description="注释")
|
|
|
|
|
|
class OpenAIChatCompletionChoice(BaseModel):
|
|
"""聊天完成选项"""
|
|
index: int = Field(..., description="索引")
|
|
message: OpenAIChatCompletionMessage = Field(..., description="消息")
|
|
logprobs: Optional[float] = Field(default=None, description="对数概率")
|
|
finish_reason: str = Field(default="stop", description="完成原因")
|
|
|
|
|
|
class OpenAIChatCompletionResponse(BaseModel):
|
|
"""聊天完成响应"""
|
|
id: str = Field(..., description="响应ID")
|
|
object: str = Field("chat.completion", description="对象类型")
|
|
created: int = Field(..., description="创建时间戳")
|
|
model: str = Field(..., description="模型")
|
|
choices: List[OpenAIChatCompletionChoice] = Field(..., description="选项")
|
|
usage: Optional[Dict[str, Any]] = Field(None, description="令牌使用")
|
|
|
|
|
|
class OpenAIChatCompletionChunkMessage(BaseModel):
|
|
"""流式消息片段"""
|
|
role: str = Field(..., description="角色")
|
|
content: str = Field(..., description="内容")
|
|
|
|
|
|
class OpenAIChatCompletionChunkChoice(BaseModel):
|
|
"""流式选项"""
|
|
index: int = Field(..., description="索引")
|
|
delta: Optional[Union[Dict[str, Any], OpenAIChatCompletionChunkMessage]] = Field(
|
|
None, description="Delta数据"
|
|
)
|
|
finish_reason: Optional[str] = Field(None, description="完成原因")
|
|
|
|
|
|
class OpenAIChatCompletionChunkResponse(BaseModel):
|
|
"""流式聊天响应"""
|
|
id: str = Field(..., description="响应ID")
|
|
object: str = Field(default="chat.completion.chunk", description="对象类型")
|
|
created: int = Field(..., description="创建时间戳")
|
|
model: str = Field(..., description="模型")
|
|
system_fingerprint: Optional[str] = Field(default=None, description="系统指纹")
|
|
choices: List[OpenAIChatCompletionChunkChoice] = Field(..., description="选项") |