Files
huihuiSquare/backend/app/schemas/__init__.py
stefanfeng 958eaeda8a fix: 多项修复
- main.py: 加 _CNJSONResponse 修复 datetime 序列化时区(+00:00→+08:00)
- schemas/__init__.py: 加 _fmt_dt 函数和 sync_to_platform 字段
- ai_service.py: 评论 max_tokens 从 300 提升到 500 避免截断
- scheduler.py: datetime.utcnow() 全部改为 datetime.now()(北京时间)
- docker-compose.yml: MySQL 容器加 TZ=Asia/Shanghai
- Interactions.vue: 文章标题链接从系统配置读取域名,格式为 {域名}/huihui-h5/#/news/share?id={id}&login=no
2026-04-01 18:07:42 +08:00

230 lines
6.5 KiB
Python
Executable File

"""Pydantic数据模型 - 请求/响应模式"""
from datetime import datetime
from typing import Optional, List, Any
from pydantic import BaseModel, Field
from datetime import timezone, timedelta
_CST = timedelta(hours=8)
def _fmt_dt(dt):
if dt is None: return None
if hasattr(dt, "strftime"): return dt.strftime("%Y-%m-%dT%H:%M:%S+08:00")
return dt
# ===== 通用响应 =====
class ApiResponse(BaseModel):
code: int = 200
message: str = "success"
data: Any = None
class PageResult(BaseModel):
total: int
page: int
page_size: int
items: List[Any]
# ===== 虚拟用户 =====
class UserCreateRequest(BaseModel):
# 必填
account: str = Field(..., min_length=1, max_length=128, description="新闻平台账号(必填)")
password: str = Field(..., min_length=6, max_length=64, description="登录密码(必填)")
# 选填
nickname: Optional[str] = Field(None, max_length=64, description="昵称(选填,为空自动生成)")
avatar_url: Optional[str] = None
activity_level: int = Field(default=1, ge=0, le=2)
daily_comment_limit: int = Field(default=10, ge=1, le=100)
daily_like_limit: int = Field(default=30, ge=1, le=200)
remark: Optional[str] = None
class UserUpdateRequest(BaseModel):
nickname: Optional[str] = Field(None, min_length=1, max_length=64)
password: Optional[str] = Field(None, min_length=6, max_length=64)
avatar_url: Optional[str] = None
real_name: Optional[str] = None
sex: Optional[int] = None
description: Optional[str] = None
email: Optional[str] = None
activity_level: Optional[int] = Field(None, ge=0, le=2)
daily_comment_limit: Optional[int] = Field(None, ge=1, le=100)
daily_like_limit: Optional[int] = Field(None, ge=1, le=200)
remark: Optional[str] = None
is_enabled: Optional[int] = None
sync_to_platform: bool = False
class UserResponse(BaseModel):
id: int
nickname: str
account: str
avatar_url: Optional[str]
real_name: Optional[str] = None
sex: int = 0
platform_uid: Optional[str] = None
status: int
status_label: str
activity_level: int
activity_label: str
daily_comment_limit: int
daily_like_limit: int
today_comment_count: int
today_like_count: int
total_interactions: int
last_login_at: Optional[datetime]
last_interact_at: Optional[datetime]
remark: Optional[str]
is_enabled: int
created_at: datetime
personality: Optional[dict] = None
class Config:
from_attributes = True
class UserBatchRequest(BaseModel):
user_ids: List[int]
action: str # enable/disable/logout/delete
# ===== 人格 =====
class PersonalityUpdateRequest(BaseModel):
character_type: Optional[str] = None
language_style: Optional[str] = None
interest_tags: Optional[List[str]] = None
interact_tendency: Optional[str] = None
word_count_min: Optional[int] = Field(None, ge=10, le=500)
word_count_max: Optional[int] = Field(None, ge=10, le=1000)
personality_desc: Optional[str] = None
class PersonalityResponse(BaseModel):
id: int
user_id: int
character_type: Optional[str]
language_style: Optional[str]
interest_tags: Optional[List[str]]
interact_tendency: Optional[str]
word_count_min: int
word_count_max: int
personality_desc: Optional[str]
updated_at: datetime
class Config:
from_attributes = True
# ===== 互动记录 =====
class InteractionQueryParams(BaseModel):
page: int = Field(default=1, ge=1)
page_size: int = Field(default=20, ge=1, le=100)
user_id: Optional[int] = None
interact_type: Optional[str] = None
status: Optional[int] = None
start_date: Optional[str] = None
end_date: Optional[str] = None
keyword: Optional[str] = None
class InteractionResponse(BaseModel):
id: int
user_id: int
user_nickname: Optional[str]
user_account: Optional[str]
article_id: Optional[str]
article_title: Optional[str]
interact_type: str
interact_type_label: str
content: Optional[str]
token_consumed: int
status: int
status_label: str
error_msg: Optional[str]
retry_count: int
executed_at: datetime
class Config:
from_attributes = True
# ===== AI模型配置 =====
class AIModelCreateRequest(BaseModel):
model_name: str = Field(..., min_length=1, max_length=64)
provider: str = Field(..., pattern="^(openai|zhipu|wenxin|qianwen|local)$")
api_base_url: Optional[str] = None
api_key: Optional[str] = None
model_version: Optional[str] = None
temperature: float = Field(default=0.7, ge=0.0, le=2.0)
max_tokens: int = Field(default=1000, ge=1, le=32000)
timeout_seconds: int = Field(default=30, ge=5, le=300)
is_default: int = Field(default=0, ge=0, le=1)
class AIModelUpdateRequest(BaseModel):
model_name: Optional[str] = None
api_base_url: Optional[str] = None
api_key: Optional[str] = None
model_version: Optional[str] = None
temperature: Optional[float] = Field(None, ge=0.0, le=2.0)
max_tokens: Optional[int] = Field(None, ge=1, le=32000)
timeout_seconds: Optional[int] = Field(None, ge=5, le=300)
is_default: Optional[int] = None
is_enabled: Optional[int] = None
class AIModelResponse(BaseModel):
id: int
model_name: str
provider: str
api_base_url: Optional[str]
has_api_key: bool
model_version: Optional[str]
temperature: float
max_tokens: int
timeout_seconds: int
is_default: int
is_enabled: int
created_at: datetime
class Config:
from_attributes = True
class AIModelTestRequest(BaseModel):
model_id: int
test_prompt: str = "你好,请简单介绍一下自己。"
# ===== 系统配置 =====
class SystemConfigUpdateRequest(BaseModel):
configs: dict
# ===== 数据统计 =====
class DashboardResponse(BaseModel):
user_stats: dict
today_interactions: dict
monthly_stats: dict
token_stats: dict
system_status: dict
online_users: int
# ===== 调度配置 =====
class SchedulerConfigRequest(BaseModel):
interact_time_start: Optional[str] = None
interact_time_end: Optional[str] = None
interact_interval_min: Optional[int] = None
interact_interval_max: Optional[int] = None
max_concurrent_users: Optional[int] = None
daily_token_limit: Optional[int] = None
comment_probability: Optional[float] = None
reply_probability: Optional[float] = None
like_probability: Optional[float] = None
collect_probability: Optional[float] = None
forward_probability: Optional[float] = None
scheduler_enabled: Optional[bool] = None