from datetime import datetime from typing import Optional from sqlmodel import SQLModel, Field, Column, select from pydantic import BaseModel from enum import Enum from app.model.abstract.model import AbstractModel, DefaultTimes class UserStatActionEnum(str, Enum): download_count = "download_count" register_count = "register_count" task_complete_count = "task_complete_count" task_failed_count = "task_failed_count" file_download_count = "file_download_count" file_generate_count = "file_generate_count" paid_amount_on_avg_task = "paid_amount_on_avg_task" class UserStatActionIn(BaseModel): user_id: int | None = None action: UserStatActionEnum value: int = 1 model_type: str | None = None class UserStat(AbstractModel, DefaultTimes, table=True): id: int = Field(default=None, primary_key=True) user_id: int = Field(foreign_key="user.id", index=True, description="User ID") # Model usage type: 'cloud' or 'local' model_type: str = Field(default="unused", description="Model usage type: 'cloud' or 'local'") # Product page statistics download_count: int = Field(default=0, description="Number of downloads by the user") register_count: int = Field(default=0, description="Number of registrations (for product page)") task_complete_count: int = Field(default=0, description="Number of tasks completed by the user") task_failed_count: int = Field(default=0, description="Number of tasks failed by the user") file_download_count: int = Field(default=0, description="Number of files downloaded by the user") file_generate_count: int = Field(default=0, description="Number of files generated by the user") # Payment statistics paid_amount_on_avg_task: int = Field(default=0, description="Total paid amount on average task completion") @classmethod def record_action(cls, session, action_in: UserStatActionIn): """ Record or update user operation statistics using a Pydantic model. If no record exists for the user, create one. Otherwise, update the corresponding field. Supported actions: download_count, register_count, task_complete_count, task_failed_count, file_download_count, file_generate_count, paid_amount_on_avg_task. If model_type is provided, update it as well. """ stat = session.exec(select(cls).where(cls.user_id == action_in.user_id)).first() if not stat: stat = cls(user_id=action_in.user_id) session.add(stat) if action_in.action in [ UserStatActionEnum.download_count, UserStatActionEnum.register_count, UserStatActionEnum.task_complete_count, UserStatActionEnum.task_failed_count, UserStatActionEnum.file_download_count, UserStatActionEnum.file_generate_count, ]: setattr(stat, action_in.action.value, getattr(stat, action_in.action.value, 0) + action_in.value) elif action_in.action == UserStatActionEnum.paid_amount_on_avg_task: stat.paid_amount_on_avg_task += action_in.value else: raise ValueError(f"Unsupported action: {action_in.action}") if action_in.model_type is not None: stat.model_type = action_in.model_type session.add(stat) session.commit() session.refresh(stat) return stat class UserStatOut(BaseModel): model_type: str | None = None download_count: int = 0 register_count: int = 0 task_complete_count: int = 0 task_failed_count: int = 0 file_download_count: int = 0 file_generate_count: int = 0 paid_amount_on_avg_task: int = 0 # cusotmer task_queries: int = 0 mcp_install_count: int = 0 storage_used: float = 0