|
|
from dataclasses import dataclass
|
|
|
from typing import Any
|
|
|
|
|
|
from fastapi import Query
|
|
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
|
|
|
|
from app.core.base_params import BaseQueryParam, TenantByQueryParam, UserByQueryParam
|
|
|
|
|
|
|
|
|
class ChatQuerySchema(BaseModel):
|
|
|
"""WebSocket聊天查询模型"""
|
|
|
|
|
|
message: str | None = Field("", description="消息内容(停止时可为空)")
|
|
|
session_id: str | None = Field(None, description="会话ID")
|
|
|
files: list[dict[str, Any]] | None = Field(None, description="文件信息")
|
|
|
action: str | None = Field(None, description="动作类型:stop=停止生成 | None=对话")
|
|
|
|
|
|
|
|
|
class ChatSessionCreateSchema(BaseModel):
|
|
|
"""创建会话模型"""
|
|
|
|
|
|
title: str = Field(..., min_length=1, max_length=200, description="会话标题")
|
|
|
|
|
|
@field_validator("title")
|
|
|
@classmethod
|
|
|
def validate_title(cls, v: str) -> str:
|
|
|
v = v.strip()
|
|
|
if len(v) < 1 or len(v) > 200:
|
|
|
raise ValueError("会话标题长度必须在1-200个字符之间")
|
|
|
return v
|
|
|
|
|
|
|
|
|
class ChatSessionUpdateSchema(BaseModel):
|
|
|
"""更新会话模型"""
|
|
|
|
|
|
title: str = Field(..., min_length=1, max_length=200, description="会话标题")
|
|
|
|
|
|
@field_validator("title")
|
|
|
@classmethod
|
|
|
def validate_title(cls, v: str) -> str:
|
|
|
v = v.strip()
|
|
|
if len(v) < 1 or len(v) > 200:
|
|
|
raise ValueError("会话标题长度必须在1-200个字符之间")
|
|
|
return v
|
|
|
|
|
|
|
|
|
class ChatSessionMessageSchema(BaseModel):
|
|
|
"""会话消息模型"""
|
|
|
|
|
|
id: str = Field(..., description="消息ID")
|
|
|
role: str = Field(..., description="消息角色")
|
|
|
content: str = Field(..., description="消息内容")
|
|
|
created_at: int | None = Field(None, description="创建时间(Unix时间戳)")
|
|
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
class ChatSessionQueryParam(BaseQueryParam, UserByQueryParam, TenantByQueryParam):
|
|
|
"""会话查询参数"""
|
|
|
|
|
|
title: str | None = Query(None, description="会话标题")
|
|
|
|
|
|
|
|
|
class AiChatRequestSchema(BaseModel):
|
|
|
"""AI 对话请求模型(非流式)"""
|
|
|
|
|
|
message: str = Field(..., min_length=1, description="用户消息内容")
|
|
|
session_id: str | None = Field(None, description="会话ID,不传则创建新会话")
|
|
|
|
|
|
@field_validator("message")
|
|
|
@classmethod
|
|
|
def validate_message(cls, v: str) -> str:
|
|
|
v = v.strip()
|
|
|
if len(v) < 1:
|
|
|
raise ValueError("用户消息内容不能为空")
|
|
|
return v
|
|
|
|
|
|
|
|
|
class AiChatResponseSchema(BaseModel):
|
|
|
"""AI 对话响应模型(非流式)"""
|
|
|
|
|
|
response: str = Field(..., description="AI 回复内容")
|
|
|
session_id: str = Field(..., description="会话ID")
|
|
|
function_calls: list[dict[str, Any]] | None = Field(None, description="函数调用信息")
|
|
|
action: dict[str, Any] | None = Field(None, description="建议执行的操作")
|
|
|
|
|
|
|
|
|
class AiModelConfigSchema(BaseModel):
|
|
|
"""AI 模型配置项"""
|
|
|
|
|
|
name: str = Field(..., min_length=1, max_length=50, description="配置名称(用户可读)")
|
|
|
base_url: str = Field(..., min_length=1, max_length=500, description="API Base URL,如 https://api.openai.com/v1")
|
|
|
api_key: str = Field(..., min_length=1, max_length=500, description="API 密钥")
|
|
|
model_id: str = Field(..., min_length=1, max_length=100, description="模型 ID")
|
|
|
temperature: float = Field(0.7, ge=0.0, le=2.0, description="温度参数")
|
|
|
|
|
|
@field_validator("base_url")
|
|
|
@classmethod
|
|
|
def validate_base_url(cls, v: str) -> str:
|
|
|
v = v.strip().rstrip("/")
|
|
|
if not v.startswith(("http://", "https://")):
|
|
|
raise ValueError("Base URL 必须以 http:// 或 https:// 开头")
|
|
|
return v
|
|
|
|
|
|
@field_validator("model_id")
|
|
|
@classmethod
|
|
|
def validate_model_id(cls, v: str) -> str:
|
|
|
v = v.strip()
|
|
|
if not v:
|
|
|
raise ValueError("模型 ID 不能为空")
|
|
|
return v
|
|
|
|
|
|
|
|
|
class AiModelConfigItemSchema(AiModelConfigSchema):
|
|
|
"""带 ID 的模型配置项(存储与返回)"""
|
|
|
|
|
|
id: str = Field(..., min_length=1, max_length=64, description="配置项唯一 ID")
|
|
|
created_time: str | None = Field(None, description="创建时间(ISO 字符串)")
|
|
|
|
|
|
|
|
|
class AiModelConfigUpdateSchema(AiModelConfigSchema):
|
|
|
"""更新 AI 模型配置(与创建结构相同,不含 id)"""
|
|
|
|
|
|
|
|
|
class AiModelConfigListResponse(BaseModel):
|
|
|
"""模型配置列表响应"""
|
|
|
|
|
|
items: list[AiModelConfigItemSchema] = Field(default_factory=list, description="配置项列表")
|
|
|
active_id: str | None = Field(None, description="当前激活的配置项 ID;为空表示使用系统默认")
|