更新后台管理消息列表;

This commit is contained in:
karlcarlo
2025-12-15 17:44:35 +08:00
parent 41d2d893d3
commit a7b3454f61
22 changed files with 1620 additions and 356 deletions

View File

@@ -1,3 +1,6 @@
import os
import logging
from contextlib import asynccontextmanager
from pymongo import AsyncMongoClient
@@ -6,10 +9,16 @@ from app.models import models
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
import os
from app.routes import auth_routes, wework_routes, glm_routes, message_routes
# 配置日志
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
@@ -24,27 +33,8 @@ async def lifespan(app: FastAPI):
) # 批量注册模型
print(f"🗄️ 数据库连接成功: {database_name}")
# 初始化GLM服务,确保默认角色存在
try:
from app.services.glm_service import get_glm_service
glm_service = get_glm_service()
await glm_service.ensure_default_role()
print(f"✅ GLM角色配置初始化完成")
except Exception as e:
print(f"⚠️ GLM角色配置初始化失败: {e}")
yield # 应用在此处进入正常运行状态,接收请求
# 关闭GLM服务
try:
from app.services.glm_service import close_glm_service
close_glm_service()
print(f"GLM服务已关闭")
except Exception as e:
print(f"关闭GLM服务时出错: {e}")
# 关闭数据库连接
await client.close()
print(f"数据库连接关闭")
@@ -85,50 +75,4 @@ async def root():
"service": "企业微信认证与会话存档服务",
"version": "1.0.0",
"description": "获取和管理企业微信access_token,会话存档功能,以及DeepSeek AI聊天服务",
"endpoints": {
"docs": "/api/docs",
"redoc": "/api/redoc",
"auth": {"token": "/api/auth/token", "token_info": "/api/auth/token/info"},
"wework": {
"health": "/api/wework/health",
"chat": "/api/wework/chat",
"media": "/api/wework/media",
"decrypt": "/api/wework/decrypt",
"config": "/api/wework/config",
},
"glm": {
"root": "/api/glm/",
"role": "/api/glm/role",
"chat": "/api/glm/chat",
"conversations": "/api/glm/conversations/{conversation_id}",
},
"messages": {
"load": "/api/messages/load",
"list": "/api/messages/",
"stats": "/api/messages/stats",
"detail": "/api/messages/{msgid}",
},
},
}
def main():
"""
主函数,启动FastAPI服务器
"""
# 从环境变量获取主机和端口,使用默认值
host = os.getenv("APP_HOST", "0.0.0.0")
port = int(os.getenv("APP_PORT", "8000"))
print("启动企业微信认证与会话存档服务...")
print(f"API文档地址: http://{host}:{port}/docs")
print(f"API根地址: http://{host}:{port}")
print("企业微信会话存档API: /api/wework/*")
print("DeepSeek AI聊天API: /api/glm/*")
print("消息管理API: /api/messages/*")
uvicorn.run("app.main:app", host=host, port=port, reload=True, log_level="info")
if __name__ == "__main__":
main()

View File

@@ -1,6 +1,6 @@
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel
from typing import List, Optional
from typing import List, Optional, Dict, Any
import httpx
import os
import logging
@@ -23,6 +23,10 @@ class Message(BaseModel):
class ChatRequest(BaseModel):
message: str
conversation_id: Optional[str] = None
enhanced_prompt: Optional[str] = None # 前端生成的完整提示词
customer_tags: Optional[List[Dict[str, Any]]] = None # 客户标签
message_history: Optional[List[Dict[str, Any]]] = None # 企业微信历史消息
workflow_context: Optional[Dict[str, Any]] = None # 工作流上下文
class ChatResponse(BaseModel):
@@ -194,44 +198,233 @@ async def update_role_config(
@router.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest, service: GLMService = Depends(get_glm_service)):
"""处理聊天请求"""
# 创建或获取对话历史
# 步骤1: 记录请求开始
logger.info(
f"收到聊天请求: conversation_id={request.conversation_id or 'None'}, "
f"message_length={len(request.message)}, "
f"message_preview='{request.message[:50]}{'...' if len(request.message) > 50 else ''}'"
)
# 记录增强参数信息
has_enhanced_prompt = request.enhanced_prompt is not None
has_customer_tags = (
request.customer_tags is not None and len(request.customer_tags) > 0
)
has_message_history = (
request.message_history is not None and len(request.message_history) > 0
)
has_workflow_context = request.workflow_context is not None
logger.info(
f"增强参数状态: enhanced_prompt={has_enhanced_prompt}, "
f"customer_tags={has_customer_tags} ({len(request.customer_tags) if has_customer_tags else 0}个标签), "
f"message_history={has_message_history} ({len(request.message_history) if has_message_history else 0}条历史), "
f"workflow_context={has_workflow_context}"
)
# 记录客户标签摘要
if has_customer_tags:
tag_categories = {}
for tag in request.customer_tags:
category = tag.get("TagCategory", "未分类")
name = tag.get("TagName", "未命名")
if category not in tag_categories:
tag_categories[category] = []
tag_categories[category].append(name)
tag_summary = []
for category, names in tag_categories.items():
tag_summary.append(
f"{category}: {', '.join(names[:3])}{'...' if len(names) > 3 else ''}"
)
# 检查是否使用mock数据
is_mock_data = False
for tag in request.customer_tags:
if tag.get("TagName", "").startswith("mock_") or tag.get(
"TagCategory", ""
).startswith("mock_"):
is_mock_data = True
break
mock_note = " [mock数据]" if is_mock_data else ""
logger.info(f"客户标签摘要{mock_note}: {', '.join(tag_summary)}")
# 记录历史消息摘要
if has_message_history:
# 按时间排序,获取最近的消息
sorted_history = sorted(
request.message_history, key=lambda x: x.get("msgtime", ""), reverse=True
)[
:5
] # 只显示最近5条
history_summary = []
for i, msg in enumerate(sorted_history):
from_user = msg.get("from_user", "未知用户")
user_id = (
msg.get("user_id")
or msg.get("userId")
or msg.get("from_user_id")
or "无ID"
)
content = msg.get("text", {}).get("content", "") or msg.get("content", "")
content_preview = content[:30] + ("..." if len(content) > 30 else "")
history_summary.append(f"{from_user}(ID:{user_id}): '{content_preview}'")
# 检查是否使用mock数据
is_mock_data = False
for msg in sorted_history:
if msg.get("from_user", "").startswith("mock_") or msg.get(
"user_id", ""
).startswith("mock_"):
is_mock_data = True
break
mock_note = " [mock数据]" if is_mock_data else ""
logger.info(f"历史消息摘要{mock_note}: {', '.join(history_summary)}")
# 步骤2: 创建或获取对话历史
if request.conversation_id and request.conversation_id in conversations:
conversation_history = conversations[request.conversation_id]
logger.info(
f"使用现有对话: {request.conversation_id}, 历史消息数: {len(conversation_history)}"
)
# 记录历史消息摘要
if conversation_history:
last_messages = conversation_history[-3:] # 显示最近3条消息
history_summary = []
for i, msg in enumerate(last_messages, 1):
role = msg["role"]
content_preview = msg["content"][:30] + (
"..." if len(msg["content"]) > 30 else ""
)
history_summary.append(f"{role}: '{content_preview}'")
logger.debug(f"最近历史消息摘要: {', '.join(history_summary)}")
else:
conversation_history = []
request.conversation_id = f"conv_{len(conversations) + 1}"
conversations[request.conversation_id] = conversation_history
logger.info(f"新建对话: {request.conversation_id}")
# 获取当前角色配置
# 步骤3: 构建系统提示词
try:
role = await service.get_current_role()
system_prompt = build_system_prompt(role.to_role_config_dict())
except Exception as e:
logger.error(f"获取角色配置失败: {e}")
raise HTTPException(status_code=500, detail=f"获取角色配置失败: {str(e)}")
if has_enhanced_prompt:
# 使用前端生成的增强提示词
system_prompt = request.enhanced_prompt
logger.info(f"使用前端增强提示词, 长度: {len(system_prompt)} 字符")
logger.debug(
f"增强提示词预览: '{system_prompt[:200]}{'...' if len(system_prompt) > 200 else ''}'"
)
else:
# 获取当前角色配置并构建系统提示词
role = await service.get_current_role()
role_config = role.to_role_config_dict()
logger.info(
f"获取角色配置: name='{role.name}', "
f"技能数: {len(role_config['skills'].split('\\n')) if role_config['skills'] else 0}, "
f"限制数: {len(role_config['restrictions'].split('\\n')) if role_config['restrictions'] else 0}"
)
# 构建消息列表
system_prompt = build_system_prompt(role_config)
logger.debug(f"系统提示词构建完成, 长度: {len(system_prompt)} 字符")
except Exception as e:
logger.error(
f"构建系统提示词失败: {e}, conversation_id={request.conversation_id}"
)
raise HTTPException(status_code=500, detail=f"构建系统提示词失败: {str(e)}")
# 步骤4: 构建消息列表
messages = [{"role": "system", "content": system_prompt}]
# 添加历史消息
for msg in conversation_history[-10:]: # 保留最近10条历史
# 初始化企业微信历史消息变量
selected_wework_messages = []
# 添加企业微信历史消息(如果提供)
if has_message_history:
logger.info(f"添加企业微信历史消息到上下文: {len(request.message_history)} 条")
# 将企业微信消息转换为大模型消息格式
wework_messages = []
for msg in request.message_history:
from_user = msg.get("from_user", "未知用户")
content = msg.get("text", {}).get("content", "") or msg.get("content", "")
msgtime = msg.get("msgtime", "")
if content:
# 确定角色:如果是客户发送的,则为user;否则为assistant
# 这里需要根据实际业务逻辑判断,暂时假设外部用户是user
role = (
"user"
if "customer" in from_user.lower() or "user" in from_user.lower()
else "assistant"
)
# 格式化消息内容
formatted_content = f"[{msgtime}] {from_user}: {content}"
wework_messages.append({"role": role, "content": formatted_content})
# 添加到消息列表(限制数量,避免过长)
max_wework_messages = 10
selected_wework_messages = wework_messages[
-max_wework_messages:
] # 取最近的消息
messages.extend(selected_wework_messages)
logger.info(
f"已添加 {len(selected_wework_messages)} 条企业微信历史消息到上下文"
)
# 添加与大模型的对话历史
history_messages = conversation_history[-10:] # 保留最近10条历史
for msg in history_messages:
messages.append({"role": msg["role"], "content": msg["content"]})
# 添加当前用户消息
messages.append({"role": "user", "content": request.message})
conversation_history.append({"role": "user", "content": request.message})
# 调用DeepSeek API
logger.info(
f"构建消息列表完成: 系统消息1条, 企业微信历史{len(selected_wework_messages)}条, "
f"对话历史{len(history_messages)}条, 用户消息1条, 总消息数: {len(messages)}"
)
# 记录消息列表摘要
if logger.isEnabledFor(logging.DEBUG):
for i, msg in enumerate(messages):
role = msg["role"]
content_preview = msg["content"][:50] + (
"..." if len(msg["content"]) > 50 else ""
)
logger.debug(f"消息{i+1}: {role} - '{content_preview}'")
# 步骤5: 调用DeepSeek API
try:
logger.info(
f"调用DeepSeek API, conversation_id={request.conversation_id}, 总消息数: {len(messages)}"
)
response_text = await call_deepseek_api(messages)
# 步骤6: 记录API响应
logger.info(
f"DeepSeek API调用成功, conversation_id={request.conversation_id}, "
f"响应长度: {len(response_text)} 字符, "
f"响应预览: '{response_text[:100]}{'...' if len(response_text) > 100 else ''}'"
)
# 添加助手回复到历史
conversation_history.append({"role": "assistant", "content": response_text})
# 步骤7: 返回响应
logger.info(
f"返回聊天响应: conversation_id={request.conversation_id}, 响应长度: {len(response_text)} 字符"
)
return ChatResponse(
response=response_text, conversation_id=request.conversation_id
)
except Exception as e:
logger.error(
f"DeepSeek API调用失败: {e}, conversation_id={request.conversation_id}, message_preview='{request.message[:50]}...'"
)
raise HTTPException(status_code=500, detail=str(e))

View File

@@ -135,6 +135,40 @@ async def get_message_stats(service: MessageService = Depends(get_message_servic
raise HTTPException(status_code=500, detail=f"获取消息统计失败: {str(e)}")
@router.get("/config")
async def get_message_config():
"""
获取消息服务配置信息
返回企业微信SDK配置、文件路径等基本信息
"""
try:
import os
from pathlib import Path
# 从环境变量获取配置
corpid = os.getenv("CORPID", "")
secret = os.getenv("WEWORK_SECRET", "")
# 构建文件路径
backend_dir = Path(__file__).parent.parent.parent
lib_path = backend_dir / "lib" / "sdk" / "libWeWorkFinanceSdk_C.so"
data_dir = backend_dir / "data"
config = {
"corpid": corpid,
# "secret": secret[:10] + "..." if secret else "", # 只显示前10个字符
"libPath": str(lib_path),
"dataDir": str(data_dir),
}
return {"success": True, "message": "配置获取成功", "data": config}
except Exception as e:
logger.error(f"获取配置信息失败: {e}")
raise HTTPException(status_code=500, detail=f"获取配置信息失败: {str(e)}")
@router.get("/{msgid}")
async def get_message_by_id(
msgid: str, service: MessageService = Depends(get_message_service)
@@ -150,13 +184,3 @@ async def get_message_by_id(
except Exception as e:
logger.error(f"查询消息详情失败 (msgid: {msgid}): {e}")
raise HTTPException(status_code=500, detail=f"查询消息详情失败: {str(e)}")
# 应用关闭时的清理
@router.on_event("shutdown")
async def shutdown_event():
"""应用关闭时清理资源"""
from app.services.message_service import close_message_service
close_message_service()
logger.info("消息服务已关闭")

View File

@@ -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服务已关闭")

View File

@@ -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,
},