This commit is contained in:
Windpicker-owo
2025-12-08 17:19:33 +08:00
136 changed files with 2188 additions and 2230 deletions

View File

@@ -12,9 +12,7 @@ from functools import lru_cache
from typing import Any, Generic, TypeVar
from sqlalchemy import delete, func, select, update
from sqlalchemy.engine import CursorResult, Result
from src.common.database.core.models import Base
from src.common.database.core.session import get_db_session
from src.common.database.optimization import (
BatchOperation,

View File

@@ -15,7 +15,6 @@ from sqlalchemy import and_, asc, desc, func, or_, select
# 导入 CRUD 辅助函数以避免重复定义
from src.common.database.api.crud import _dict_to_model, _model_to_dict
from src.common.database.core.models import Base
from src.common.database.core.session import get_db_session
from src.common.database.optimization import get_cache, record_preload_access
from src.common.logger import get_logger

View File

@@ -91,7 +91,7 @@ async def store_action_info(
)
# 使用get_or_create保存记录
saved_record, created = await _action_records_crud.get_or_create(
saved_record, _created = await _action_records_crud.get_or_create(
defaults=record_data,
action_id=action_id,
)
@@ -438,7 +438,7 @@ async def update_relationship_affinity(
"""
try:
# 获取或创建关系
relationship, created = await _user_relationships_crud.get_or_create(
relationship, _created = await _user_relationships_crud.get_or_create(
defaults={"affinity": 0.0, "interaction_count": 0},
platform=platform,
user_id=user_id,

View File

@@ -300,7 +300,7 @@ async def db_save(
crud = CRUDBase(model_class)
# 使用get_or_create (返回tuple[T, bool])
instance, created = await crud.get_or_create(
instance, _created = await crud.get_or_create(
defaults=data,
**{key_field: key_value},
)

View File

@@ -100,14 +100,14 @@ async def check_and_migrate_database(existing_engine=None):
def add_columns_sync(conn):
dialect = conn.dialect
for column_name in missing_columns:
column = table.c[column_name]
# 获取列类型的 SQL 表示
# 直接使用 compile 方法,它会自动选择正确的方言
column_type_sql = column.type.compile(dialect=dialect)
# 构建 ALTER TABLE 语句
sql = f"ALTER TABLE {table.name} ADD COLUMN {column.name} {column_type_sql}"
@@ -285,7 +285,7 @@ def _normalize_pg_type(type_name: str) -> str:
async def _check_and_fix_column_types(connection, inspector, table_name, table, db_columns_info):
"""检查并修复列类型不匹配的问题(仅 PostgreSQL
Args:
connection: 数据库连接
inspector: SQLAlchemy inspector
@@ -296,41 +296,41 @@ async def _check_and_fix_column_types(connection, inspector, table_name, table,
# 获取数据库方言
def get_dialect_name(conn):
return conn.dialect.name
dialect_name = await connection.run_sync(get_dialect_name)
# 目前只处理 PostgreSQL
if dialect_name != "postgresql":
return
for (fix_table, fix_column), (expected_type_category, using_clause) in _COLUMN_TYPE_FIXES.items():
if fix_table != table_name:
continue
if fix_column not in db_columns_info:
continue
col_info = db_columns_info[fix_column]
current_type = _normalize_pg_type(str(col_info.get("type", "")))
expected_type = _get_expected_pg_type(expected_type_category)
# 如果类型已经正确,跳过
if current_type == expected_type:
continue
# 检查是否需要修复:如果当前是 numeric 但期望是 boolean
if current_type == "numeric" and expected_type == "boolean":
logger.warning(
f"发现列类型不匹配: {table_name}.{fix_column} "
f"(当前: {current_type}, 期望: {expected_type})"
)
# PostgreSQL 需要先删除默认值,再修改类型,最后重新设置默认值
using_sql = using_clause.format(column=fix_column)
drop_default_sql = f"ALTER TABLE {table_name} ALTER COLUMN {fix_column} DROP DEFAULT"
alter_type_sql = f"ALTER TABLE {table_name} ALTER COLUMN {fix_column} TYPE BOOLEAN {using_sql}"
set_default_sql = f"ALTER TABLE {table_name} ALTER COLUMN {fix_column} SET DEFAULT FALSE"
try:
def execute_alter(conn):
# 步骤 1: 删除默认值
@@ -342,7 +342,7 @@ async def _check_and_fix_column_types(connection, inspector, table_name, table,
conn.execute(text(alter_type_sql))
# 步骤 3: 重新设置默认值
conn.execute(text(set_default_sql))
await connection.run_sync(execute_alter)
await connection.commit()
logger.info(f"成功修复列类型: {table_name}.{fix_column} -> BOOLEAN")

View File

@@ -651,7 +651,7 @@ class UserPermissions(Base):
class UserRelationships(Base):
"""用户关系模型 - 存储用户与bot的关系数据
核心字段:
- relationship_text: 当前印象描述(用于兼容旧系统,逐步迁移到 impression_text
- impression_text: 长期印象(新字段,自然叙事风格)
@@ -667,19 +667,19 @@ class UserRelationships(Base):
user_id: Mapped[str] = mapped_column(get_string_field(100), nullable=False, unique=True, index=True)
user_name: Mapped[str | None] = mapped_column(get_string_field(100), nullable=True)
user_aliases: Mapped[str | None] = mapped_column(Text, nullable=True) # 用户别名,逗号分隔
# 印象相关(新旧兼容)
relationship_text: Mapped[str | None] = mapped_column(Text, nullable=True) # 旧字段,保持兼容
impression_text: Mapped[str | None] = mapped_column(Text, nullable=True) # 新字段:长期印象(自然叙事)
# 用户信息
preference_keywords: Mapped[str | None] = mapped_column(Text, nullable=True) # 用户偏好关键词,逗号分隔
key_facts: Mapped[str | None] = mapped_column(Text, nullable=True) # 关键信息JSON生日、职业等
# 关系状态
relationship_score: Mapped[float] = mapped_column(Float, nullable=False, default=0.3) # 好感度(0-1)
relationship_stage: Mapped[str | None] = mapped_column(get_string_field(50), nullable=True, default="stranger") # 关系阶段
# 时间记录
first_met_time: Mapped[float | None] = mapped_column(Float, nullable=True) # 首次认识时间戳
last_impression_update: Mapped[float | None] = mapped_column(Float, nullable=True) # 上次更新印象时间

View File

@@ -378,7 +378,7 @@ class AdaptiveBatchScheduler:
# 过滤掉 id 为 None 的键,让数据库自动生成主键
filtered_data = {k: v for k, v in op.data.items() if not (k == "id" and v is None)}
all_data.append(filtered_data)
if not all_data:
return

View File

@@ -440,8 +440,8 @@ class MultiLevelCache:
# 计算共享键和独占键
shared_keys = l1_keys & l2_keys
l1_only_keys = l1_keys - l2_keys
l2_only_keys = l2_keys - l1_keys
l1_keys - l2_keys
l2_keys - l1_keys
# 🔧 修复:并行计算内存使用,避免锁嵌套
l1_size_task = asyncio.create_task(self._calculate_memory_usage_safe(self.l1_cache, l1_keys))

View File

@@ -10,7 +10,7 @@ import asyncio
import functools
import hashlib
import time
from collections.abc import Awaitable, Callable, Coroutine
from collections.abc import Callable, Coroutine
from typing import Any, ParamSpec, TypeVar
from sqlalchemy.exc import DBAPIError, OperationalError