更新后台管理消息列表;
This commit is contained in:
@@ -3,8 +3,13 @@ GLM聊天服务,包含角色配置管理
|
||||
"""
|
||||
|
||||
import logging
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Optional
|
||||
from pymongo import AsyncMongoClient
|
||||
from beanie import init_beanie
|
||||
from app.models.glm_role import GLMRole
|
||||
from app.models import models
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -14,11 +19,19 @@ class GLMService:
|
||||
|
||||
def __init__(self):
|
||||
self._current_role: Optional[GLMRole] = None
|
||||
self._max_retries = 3
|
||||
self._retry_delay = 1 # 秒
|
||||
self._db_client: Optional[AsyncMongoClient] = None
|
||||
self._db_initialized = False
|
||||
|
||||
async def get_current_role(self) -> GLMRole:
|
||||
"""获取当前激活的角色配置"""
|
||||
if self._current_role is None:
|
||||
self._current_role = await self._load_or_create_role()
|
||||
logger.info("当前无缓存角色,开始加载角色配置")
|
||||
self._current_role = await self._load_or_create_role_with_retry()
|
||||
logger.info(f"角色加载完成: name='{self._current_role.name}'")
|
||||
else:
|
||||
logger.debug(f"使用缓存角色: name='{self._current_role.name}'")
|
||||
return self._current_role
|
||||
|
||||
async def update_role(self, role_data: dict) -> GLMRole:
|
||||
@@ -30,33 +43,153 @@ class GLMService:
|
||||
Returns:
|
||||
更新后的GLMRole实例
|
||||
"""
|
||||
logger.info(f"开始更新角色配置,更新字段: {list(role_data.keys())}")
|
||||
role = await self.get_current_role()
|
||||
|
||||
# 更新字段
|
||||
if "name" in role_data:
|
||||
# 记录更新前的值
|
||||
changes = []
|
||||
if "name" in role_data and role_data["name"] != role.name:
|
||||
changes.append(f"name: '{role.name}' -> '{role_data['name']}'")
|
||||
role.name = role_data["name"]
|
||||
if "description" in role_data:
|
||||
|
||||
if "description" in role_data and role_data["description"] != role.description:
|
||||
changes.append(
|
||||
f"description: {len(role.description)}字符 -> {len(role_data['description'])}字符"
|
||||
)
|
||||
role.description = role_data["description"]
|
||||
if "skills" in role_data:
|
||||
|
||||
if "skills" in role_data and role_data["skills"] != role.skills:
|
||||
old_skills_count = len(role.skills.split("\n")) if role.skills else 0
|
||||
new_skills_count = (
|
||||
len(role_data["skills"].split("\n")) if role_data["skills"] else 0
|
||||
)
|
||||
changes.append(f"skills: {old_skills_count}条 -> {new_skills_count}条")
|
||||
role.skills = role_data["skills"]
|
||||
if "restrictions" in role_data:
|
||||
|
||||
if (
|
||||
"restrictions" in role_data
|
||||
and role_data["restrictions"] != role.restrictions
|
||||
):
|
||||
old_restrictions_count = (
|
||||
len(role.restrictions.split("\n")) if role.restrictions else 0
|
||||
)
|
||||
new_restrictions_count = (
|
||||
len(role_data["restrictions"].split("\n"))
|
||||
if role_data["restrictions"]
|
||||
else 0
|
||||
)
|
||||
changes.append(
|
||||
f"restrictions: {old_restrictions_count}条 -> {new_restrictions_count}条"
|
||||
)
|
||||
role.restrictions = role_data["restrictions"]
|
||||
|
||||
role.update_timestamp()
|
||||
await role.save()
|
||||
|
||||
if changes:
|
||||
logger.info(f"角色配置变更: {', '.join(changes)}")
|
||||
else:
|
||||
logger.info("角色配置无实际变更")
|
||||
|
||||
# 使用重试机制保存
|
||||
await self._save_with_retry(role)
|
||||
|
||||
# 更新缓存
|
||||
self._current_role = role
|
||||
|
||||
logger.info(f"角色配置已更新: {role.name}")
|
||||
logger.info(f"角色配置更新完成: name='{role.name}'")
|
||||
return role
|
||||
|
||||
async def _load_or_create_role_with_retry(self) -> GLMRole:
|
||||
"""使用重试机制加载或创建默认角色"""
|
||||
for attempt in range(self._max_retries):
|
||||
try:
|
||||
return await self._load_or_create_role()
|
||||
except Exception as e:
|
||||
if attempt < self._max_retries - 1:
|
||||
logger.warning(f"加载角色配置失败,第{attempt + 1}次重试: {e}")
|
||||
await asyncio.sleep(self._retry_delay * (attempt + 1))
|
||||
else:
|
||||
logger.error(f"加载角色配置失败,已达到最大重试次数: {e}")
|
||||
raise
|
||||
|
||||
async def _ensure_db_connection(self) -> None:
|
||||
"""确保数据库连接正常,如果连接已关闭则重新连接"""
|
||||
if not self._db_initialized:
|
||||
await self._init_db_connection()
|
||||
|
||||
async def _init_db_connection(self) -> None:
|
||||
"""初始化数据库连接"""
|
||||
try:
|
||||
# 从环境变量获取数据库配置
|
||||
mongodb_url = os.getenv("MONGODB_URL", "mongodb://localhost:27017")
|
||||
database_name = os.getenv("DATABASE_NAME", "douba_chat_dev")
|
||||
|
||||
# 创建新的数据库连接
|
||||
if self._db_client:
|
||||
try:
|
||||
await self._db_client.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
self._db_client = AsyncMongoClient(mongodb_url)
|
||||
await init_beanie(
|
||||
database=self._db_client[database_name], document_models=models
|
||||
)
|
||||
self._db_initialized = True
|
||||
logger.info(f"数据库连接初始化成功: {database_name}")
|
||||
except Exception as e:
|
||||
logger.error(f"数据库连接初始化失败: {e}")
|
||||
self._db_initialized = False
|
||||
raise
|
||||
|
||||
async def _load_or_create_role(self) -> GLMRole:
|
||||
"""加载或创建默认角色"""
|
||||
try:
|
||||
# 确保数据库连接正常
|
||||
await self._ensure_db_connection()
|
||||
|
||||
# 1. 尝试获取激活的角色
|
||||
active_role = await GLMRole.find_one(GLMRole.is_active == True)
|
||||
if active_role:
|
||||
logger.info(f"加载激活角色: {active_role.name}")
|
||||
return active_role
|
||||
|
||||
# 2. 尝试获取默认角色
|
||||
default_role = await GLMRole.find_one(GLMRole.is_default == True)
|
||||
if default_role:
|
||||
default_role.is_active = True
|
||||
await default_role.save()
|
||||
logger.info(f"加载默认角色并激活: {default_role.name}")
|
||||
return default_role
|
||||
|
||||
# 3. 创建默认角色
|
||||
logger.info("创建默认角色配置")
|
||||
return await self._create_default_role()
|
||||
except Exception as e:
|
||||
logger.error(f"加载或创建角色失败: {e}")
|
||||
# 检查是否是数据库连接错误
|
||||
if (
|
||||
"Cannot use AsyncMongoClient after close" in str(e)
|
||||
or "not connected" in str(e).lower()
|
||||
):
|
||||
logger.error("数据库连接已关闭,尝试重新连接...")
|
||||
self._db_initialized = False
|
||||
# 尝试重新连接
|
||||
try:
|
||||
await self._init_db_connection()
|
||||
logger.info("数据库重新连接成功,重试操作...")
|
||||
# 重试操作
|
||||
return await self._retry_after_reconnect()
|
||||
except Exception as reconnect_error:
|
||||
logger.error(f"数据库重新连接失败: {reconnect_error}")
|
||||
raise
|
||||
|
||||
async def _retry_after_reconnect(self) -> GLMRole:
|
||||
"""重新连接后重试操作"""
|
||||
# 1. 尝试获取激活的角色
|
||||
active_role = await GLMRole.find_one(GLMRole.is_active == True)
|
||||
if active_role:
|
||||
logger.info(f"加载激活角色: {active_role.name}")
|
||||
logger.info(f"重新连接后加载激活角色: {active_role.name}")
|
||||
return active_role
|
||||
|
||||
# 2. 尝试获取默认角色
|
||||
@@ -64,11 +197,11 @@ class GLMService:
|
||||
if default_role:
|
||||
default_role.is_active = True
|
||||
await default_role.save()
|
||||
logger.info(f"加载默认角色并激活: {default_role.name}")
|
||||
logger.info(f"重新连接后加载默认角色并激活: {default_role.name}")
|
||||
return default_role
|
||||
|
||||
# 3. 创建默认角色
|
||||
logger.info("创建默认角色配置")
|
||||
logger.info("重新连接后创建默认角色配置")
|
||||
return await self._create_default_role()
|
||||
|
||||
async def _create_default_role(self) -> GLMRole:
|
||||
@@ -89,10 +222,40 @@ class GLMService:
|
||||
logger.info(f"默认角色创建成功: {role.name}")
|
||||
return role
|
||||
|
||||
async def _save_with_retry(self, role: GLMRole) -> None:
|
||||
"""使用重试机制保存角色"""
|
||||
for attempt in range(self._max_retries):
|
||||
try:
|
||||
# 确保数据库连接正常
|
||||
await self._ensure_db_connection()
|
||||
await role.save()
|
||||
return
|
||||
except Exception as e:
|
||||
if attempt < self._max_retries - 1:
|
||||
logger.warning(f"保存角色配置失败,第{attempt + 1}次重试: {e}")
|
||||
# 检查是否是数据库连接错误
|
||||
if (
|
||||
"Cannot use AsyncMongoClient after close" in str(e)
|
||||
or "not connected" in str(e).lower()
|
||||
):
|
||||
logger.warning("检测到数据库连接问题,尝试重新连接...")
|
||||
self._db_initialized = False
|
||||
try:
|
||||
await self._init_db_connection()
|
||||
logger.info("数据库重新连接成功,继续重试...")
|
||||
except Exception as reconnect_error:
|
||||
logger.error(f"数据库重新连接失败: {reconnect_error}")
|
||||
await asyncio.sleep(self._retry_delay * (attempt + 1))
|
||||
else:
|
||||
logger.error(f"保存角色配置失败,已达到最大重试次数: {e}")
|
||||
raise
|
||||
|
||||
async def ensure_default_role(self):
|
||||
"""确保存在默认角色配置(应用启动时调用)"""
|
||||
try:
|
||||
role = await self._load_or_create_role()
|
||||
# 确保数据库连接正常
|
||||
await self._ensure_db_connection()
|
||||
role = await self._load_or_create_role_with_retry()
|
||||
logger.info(f"默认角色已确保存在: {role.name}")
|
||||
return role
|
||||
except Exception as e:
|
||||
@@ -102,6 +265,13 @@ class GLMService:
|
||||
async def close(self):
|
||||
"""关闭服务,清理资源"""
|
||||
self._current_role = None
|
||||
if self._db_client:
|
||||
try:
|
||||
await self._db_client.close()
|
||||
logger.info("数据库连接已关闭")
|
||||
except Exception as e:
|
||||
logger.error(f"关闭数据库连接时出错: {e}")
|
||||
self._db_initialized = False
|
||||
logger.info("GLM服务已关闭")
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
消息服务
|
||||
提供加载会话存档、解密、保存到数据库的整合功能
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import base64
|
||||
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import List, Dict, Any, Optional
|
||||
import sys
|
||||
|
||||
|
||||
# 添加scripts目录到路径
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "scripts"))
|
||||
@@ -22,6 +22,9 @@ from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
|
||||
from app.models.message import Message
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -36,10 +39,8 @@ class MessageService:
|
||||
corpid: 企业ID,如果为None则从环境变量CORPID读取
|
||||
secret: 聊天内容存档的Secret,如果为None则从环境变量WEWORK_SECRET读取
|
||||
"""
|
||||
self.corpid = corpid or os.getenv("CORPID", "wwdf65802ca25ec195")
|
||||
self.secret = secret or os.getenv(
|
||||
"WEWORK_SECRET", "-Ta6WMWxBhfGolWnnlO15nQckj3DRKAowUOdX2fwvzE"
|
||||
)
|
||||
self.corpid = corpid or os.getenv("CORPID", "")
|
||||
self.secret = secret or os.getenv("WEWORK_SECRET", "")
|
||||
|
||||
# SDK实例(延迟初始化)
|
||||
self._sdk: Optional[WeWorkFinanceSDK] = None
|
||||
@@ -266,25 +267,6 @@ class MessageService:
|
||||
logger.info(f"开始将 {len(messages)} 条消息存储到数据库...")
|
||||
|
||||
try:
|
||||
# 导入数据库相关模块
|
||||
from pymongo import AsyncMongoClient
|
||||
from beanie import init_beanie
|
||||
from app.models import models
|
||||
from app.models.message import Message
|
||||
|
||||
# 从环境变量获取数据库配置
|
||||
mongodb_url = os.getenv(
|
||||
"MONGODB_URL",
|
||||
"mongodb://dblink:mgdb4link@localhost:27017/?authSource=admin",
|
||||
)
|
||||
database_name = os.getenv("DATABASE_NAME", "douba_chat_dev")
|
||||
|
||||
# 初始化数据库连接
|
||||
client = AsyncMongoClient(mongodb_url)
|
||||
await init_beanie(database=client[database_name], document_models=models)
|
||||
|
||||
logger.info(f"数据库连接成功: {database_name}")
|
||||
|
||||
# 批量处理消息
|
||||
batch_size = 100
|
||||
for i in range(0, len(messages), batch_size):
|
||||
@@ -352,9 +334,6 @@ class MessageService:
|
||||
logger.error(f"批量插入失败: {e}")
|
||||
stats["failed"] += len(new_messages)
|
||||
|
||||
# 关闭数据库连接
|
||||
await client.close()
|
||||
|
||||
logger.info(f"数据库存储完成:")
|
||||
logger.info(f" 总计消息: {stats['total_messages']}")
|
||||
logger.info(f" 成功存储: {stats['saved']}")
|
||||
@@ -392,23 +371,6 @@ class MessageService:
|
||||
分页查询结果
|
||||
"""
|
||||
try:
|
||||
# 导入数据库相关模块
|
||||
from pymongo import AsyncMongoClient
|
||||
from beanie import init_beanie
|
||||
from app.models import models
|
||||
from app.models.message import Message
|
||||
|
||||
# 从环境变量获取数据库配置
|
||||
mongodb_url = os.getenv(
|
||||
"MONGODB_URL",
|
||||
"mongodb://dblink:mgdb4link@localhost:27017/?authSource=admin",
|
||||
)
|
||||
database_name = os.getenv("DATABASE_NAME", "douba_chat_dev")
|
||||
|
||||
# 初始化数据库连接
|
||||
client = AsyncMongoClient(mongodb_url)
|
||||
await init_beanie(database=client[database_name], document_models=models)
|
||||
|
||||
# 构建查询条件
|
||||
query = {}
|
||||
if msgtype:
|
||||
@@ -432,8 +394,12 @@ class MessageService:
|
||||
# 获取总记录数
|
||||
total_count = await Message.find(query).count()
|
||||
|
||||
# 关闭数据库连接
|
||||
await client.close()
|
||||
# 记录成功日志
|
||||
logger.info(
|
||||
f"成功查询消息列表: 查询条件={query}, "
|
||||
f"页码={page}, 每页数量={page_size}, "
|
||||
f"总记录数={total_count}, 返回记录数={len(messages)}"
|
||||
)
|
||||
|
||||
# 准备响应数据
|
||||
return {
|
||||
@@ -519,6 +485,7 @@ class MessageService:
|
||||
"decrypted_failed": 0,
|
||||
"saved_count": 0,
|
||||
"duplicates_skipped": 0,
|
||||
"seq": seq,
|
||||
"max_seq": seq,
|
||||
"next_seq": seq,
|
||||
},
|
||||
@@ -552,6 +519,7 @@ class MessageService:
|
||||
"saved_count": db_stats["saved"],
|
||||
"duplicates_skipped": db_stats["skipped_duplicates"],
|
||||
"failed_to_save": db_stats["failed"],
|
||||
"seq": seq,
|
||||
"max_seq": max_seq,
|
||||
"next_seq": max_seq + 1 if total_fetched > 0 else seq,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user