File size: 5,345 Bytes
6dfddfb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
数据库模型模块
"""
import datetime
from sqlalchemy import Column, Integer, String, Text, DateTime, JSON, Boolean, BigInteger, Enum
import enum

from app.database.connection import Base


class Settings(Base):
    """
    设置表,对应.env中的配置项
    """
    __tablename__ = "t_settings"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    key = Column(String(100), nullable=False, unique=True, comment="配置项键名")
    value = Column(Text, nullable=True, comment="配置项值")
    description = Column(String(255), nullable=True, comment="配置项描述")
    created_at = Column(DateTime, default=datetime.datetime.now, comment="创建时间")
    updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment="更新时间")
    
    def __repr__(self):
        return f"<Settings(key='{self.key}', value='{self.value}')>"


class ErrorLog(Base):
    """
    错误日志表
    """
    __tablename__ = "t_error_logs"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    gemini_key = Column(String(100), nullable=True, comment="Gemini API密钥")
    model_name = Column(String(100), nullable=True, comment="模型名称")
    error_type = Column(String(50), nullable=True, comment="错误类型")
    error_log = Column(Text, nullable=True, comment="错误日志")
    error_code = Column(Integer, nullable=True, comment="错误代码")
    request_msg = Column(JSON, nullable=True, comment="请求消息")
    request_time = Column(DateTime, default=datetime.datetime.now, comment="请求时间")
    
    def __repr__(self):
        return f"<ErrorLog(id='{self.id}', gemini_key='{self.gemini_key}')>"


class RequestLog(Base):
    """
    API 请求日志表
    """

    __tablename__ = "t_request_log"

    id = Column(Integer, primary_key=True, autoincrement=True)
    request_time = Column(DateTime, default=datetime.datetime.now, comment="请求时间")
    model_name = Column(String(100), nullable=True, comment="模型名称")
    api_key = Column(String(100), nullable=True, comment="使用的API密钥")
    is_success = Column(Boolean, nullable=False, comment="请求是否成功")
    status_code = Column(Integer, nullable=True, comment="API响应状态码")
    latency_ms = Column(Integer, nullable=True, comment="请求耗时(毫秒)")

    def __repr__(self):
        return f"<RequestLog(id='{self.id}', key='{self.api_key[:4]}...', success='{self.is_success}')>"


class FileState(enum.Enum):
    """文件状态枚举"""
    PROCESSING = "PROCESSING"
    ACTIVE = "ACTIVE"
    FAILED = "FAILED"


class FileRecord(Base):
    """
    文件记录表,用于存储上传到 Gemini 的文件信息
    """
    __tablename__ = "t_file_records"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    
    # 文件基本信息
    name = Column(String(255), unique=True, nullable=False, comment="文件名称,格式: files/{file_id}")
    display_name = Column(String(255), nullable=True, comment="用户上传时的原始文件名")
    mime_type = Column(String(100), nullable=False, comment="MIME 类型")
    size_bytes = Column(BigInteger, nullable=False, comment="文件大小(字节)")
    sha256_hash = Column(String(255), nullable=True, comment="文件的 SHA256 哈希值")
    
    # 状态信息
    state = Column(Enum(FileState), nullable=False, default=FileState.PROCESSING, comment="文件状态")
    
    # 时间戳
    create_time = Column(DateTime, nullable=False, comment="创建时间")
    update_time = Column(DateTime, nullable=False, comment="更新时间")
    expiration_time = Column(DateTime, nullable=False, comment="过期时间")
    
    # API 相关
    uri = Column(String(500), nullable=False, comment="文件访问 URI")
    api_key = Column(String(100), nullable=False, comment="上传时使用的 API Key")
    upload_url = Column(Text, nullable=True, comment="临时上传 URL(用于分块上传)")
    
    # 额外信息
    user_token = Column(String(100), nullable=True, comment="上传用户的 token")
    upload_completed = Column(DateTime, nullable=True, comment="上传完成时间")
    
    def __repr__(self):
        return f"<FileRecord(name='{self.name}', state='{self.state.value if self.state else 'None'}', api_key='{self.api_key[:8]}...')>"
    
    def to_dict(self):
        """转换为字典格式,用于 API 响应"""
        return {
            "name": self.name,
            "displayName": self.display_name,
            "mimeType": self.mime_type,
            "sizeBytes": str(self.size_bytes),
            "createTime": self.create_time.isoformat() + "Z",
            "updateTime": self.update_time.isoformat() + "Z",
            "expirationTime": self.expiration_time.isoformat() + "Z",
            "sha256Hash": self.sha256_hash,
            "uri": self.uri,
            "state": self.state.value if self.state else "PROCESSING"
        }
    
    def is_expired(self):
        """检查文件是否已过期"""
        # 确保比较时都是 timezone-aware
        expiration_time = self.expiration_time
        if expiration_time.tzinfo is None:
            expiration_time = expiration_time.replace(tzinfo=datetime.timezone.utc)
        return datetime.datetime.now(datetime.timezone.utc) > expiration_time