添加用户消息记录接口;
This commit is contained in:
114
backend/app/routes/auth_routes.py
Normal file
114
backend/app/routes/auth_routes.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from typing import Dict
|
||||
from app.deps.auth_deps import get_valid_token, get_token_information, get_valid_ticket, get_ticket_information
|
||||
from app.services.auth_service import generate_signature
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["认证"])
|
||||
|
||||
|
||||
@router.get("/token")
|
||||
async def get_token(
|
||||
token: str = Depends(get_valid_token)
|
||||
) -> Dict:
|
||||
"""
|
||||
获取access_token
|
||||
"""
|
||||
return {
|
||||
"success": True,
|
||||
"access_token": token,
|
||||
"message": "获取token成功"
|
||||
}
|
||||
|
||||
|
||||
@router.get("/token/info")
|
||||
async def get_token_info(
|
||||
token_info: Dict = Depends(get_token_information)
|
||||
) -> Dict:
|
||||
"""
|
||||
获取token的详细信息
|
||||
包括获取时间、过期时间、剩余时间等
|
||||
"""
|
||||
return {
|
||||
"success": True,
|
||||
"data": token_info,
|
||||
"message": "获取token信息成功"
|
||||
}
|
||||
|
||||
|
||||
@router.get("/ticket")
|
||||
async def get_ticket(
|
||||
ticket: str = Depends(get_valid_ticket)
|
||||
) -> Dict:
|
||||
"""
|
||||
获取jsapi_ticket
|
||||
"""
|
||||
return {
|
||||
"success": True,
|
||||
"ticket": ticket,
|
||||
"message": "获取ticket成功"
|
||||
}
|
||||
|
||||
|
||||
@router.get("/ticket/info")
|
||||
async def get_ticket_info(
|
||||
ticket_info: Dict = Depends(get_ticket_information)
|
||||
) -> Dict:
|
||||
"""
|
||||
获取ticket的详细信息
|
||||
包括获取时间、过期时间、剩余时间等
|
||||
"""
|
||||
return {
|
||||
"success": True,
|
||||
"data": ticket_info,
|
||||
"message": "获取ticket信息成功"
|
||||
}
|
||||
|
||||
|
||||
@router.post("/signature")
|
||||
async def get_signature(request: Request) -> Dict:
|
||||
"""
|
||||
生成应用签名
|
||||
|
||||
请求参数:
|
||||
{
|
||||
"url": "当前页面完整URL",
|
||||
"timestamp": 时间戳(可选,秒),
|
||||
"nonceStr": "随机字符串(可选)"
|
||||
}
|
||||
"""
|
||||
try:
|
||||
# 解析请求体
|
||||
body = await request.json()
|
||||
url = body.get("url")
|
||||
|
||||
if not url:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "缺少必要参数:url"
|
||||
}
|
||||
|
||||
timestamp = body.get("timestamp")
|
||||
nonce_str = body.get("nonceStr")
|
||||
|
||||
# 生成签名
|
||||
signature_data = generate_signature(
|
||||
url=url,
|
||||
timestamp=timestamp,
|
||||
nonce_str=nonce_str
|
||||
)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"signature": signature_data["signature"],
|
||||
"timestamp": signature_data["timestamp"],
|
||||
"nonceStr": signature_data["nonceStr"]
|
||||
},
|
||||
"message": "签名生成成功"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"生成签名失败: {str(e)}"
|
||||
}
|
||||
206
backend/app/routes/glm_routes.py
Normal file
206
backend/app/routes/glm_routes.py
Normal file
@@ -0,0 +1,206 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Optional
|
||||
import httpx
|
||||
import os
|
||||
|
||||
# 创建API路由,使用/glm前缀
|
||||
router = APIRouter(prefix="/glm", tags=["GLM聊天"])
|
||||
|
||||
|
||||
# 数据模型
|
||||
class Message(BaseModel):
|
||||
role: str
|
||||
content: str
|
||||
|
||||
|
||||
class ChatRequest(BaseModel):
|
||||
message: str
|
||||
conversation_id: Optional[str] = None
|
||||
|
||||
|
||||
class ChatResponse(BaseModel):
|
||||
response: str
|
||||
conversation_id: str
|
||||
|
||||
|
||||
class RoleConfig(BaseModel):
|
||||
name: str
|
||||
description: str
|
||||
skills: List[str]
|
||||
restrictions: List[str]
|
||||
|
||||
|
||||
# 默认角色配置
|
||||
DEFAULT_ROLE_CONFIG = RoleConfig(
|
||||
name="兜兜",
|
||||
description="你是兜兜,1989年出生,有一个5岁的女儿(2018年出生)。你是一位对用户负责、选品严格的宝妈客服。当用户给你发来疑问时,你总能第一时间回复,并以亲切温暖的风格与用户交流。",
|
||||
skills=[
|
||||
"亲切温暖的沟通",
|
||||
"轻松友好的语气",
|
||||
"简洁明了的描述",
|
||||
"亲昵且口语化的用词",
|
||||
"乱码话术重复问询",
|
||||
],
|
||||
restrictions=[
|
||||
"回复必须基于提供的知识库中的内容",
|
||||
"每条回复应保持在80字以内,使用口语化语言",
|
||||
"回复中可以适当加入表情符号,但不要过度使用",
|
||||
"只讨论与宝妈相关的主题,如育儿、选品、团购等",
|
||||
"始终以用户的需求和满意度为优先",
|
||||
],
|
||||
)
|
||||
|
||||
# 全局变量存储角色配置和对话历史
|
||||
current_role_config = DEFAULT_ROLE_CONFIG
|
||||
conversations = {}
|
||||
|
||||
|
||||
def build_system_prompt(role_config: RoleConfig) -> str:
|
||||
"""构建系统提示词"""
|
||||
prompt = f"""# 角色
|
||||
{role_config.description}
|
||||
|
||||
## 技能
|
||||
|
||||
### 技能 1: 亲切温暖的沟通
|
||||
- **风格**:你的风格非常亲切,像是一个知心朋友在和大家聊天,给人一种温暖的感觉。你经常使用"宝"、"美妈"等亲昵的称呼,拉近了与用户的距离。
|
||||
- **耐心细致**:你总是耐心解答用户的问题,尤其是对于新用户或不熟悉流程的用户,你会反复提醒他们查看群公告,保持安静等待开团。
|
||||
- **负责靠谱**:你给人一种非常靠谱的感觉,尤其是在售后问题上,你会主动承担责任,承诺包处理满意,给用户很强的信任感。
|
||||
|
||||
### 技能 2: 轻松友好的语气
|
||||
- **轻松友好**:你的语气非常轻松,像是在和朋友聊天,不会给人压力。比如"不着急哦"、"爱你!"等表达方式,让人感到轻松愉快。
|
||||
- **安抚性**:当用户有疑问或遇到问题时,你的语气总是充满安抚性,比如"美妈不用担心"、"兜兜来处理哈",给人一种安心感。
|
||||
- **鼓励性**:你经常用"不着急"、"等开团的时候会有统一说明"等话语,鼓励用户耐心等待,保持积极的心态。
|
||||
|
||||
### 技能 3: 简洁明了的描述
|
||||
- **简洁明了**:你的描述非常简洁,直接回答用户的问题,不会绕弯子。比如"贝亲是咱们深度合作品牌,经常上团的",直接给出了明确的答案。
|
||||
- **细节丰富**:在回答问题时,你会提供一些细节信息,比如"一般2天左右就会来"、"奶粉类的,贝亲,世喜,赫根,等常见品牌都有",让用户对情况有更清晰的了解。
|
||||
- **引导性**:你经常引导用户查看群公告,保持安静等待开团,比如"不熟悉的可以看一下群公告哦"、"现在安静的等开团就行啦",帮助用户更好地参与活动。
|
||||
|
||||
### 技能 4: 亲昵且口语化的用词
|
||||
- **亲昵称呼**:你经常使用"宝"、"美妈"、"大家"等亲昵的称呼,拉近与用户的距离,给人一种亲切感。
|
||||
- **口语化**:你的用词非常口语化,像是日常聊天,比如"不着急哦"、"爱你!"、"兜兜来处理哈",给人一种轻松自然的感觉,称呼自己为"兜兜"或者"我"。
|
||||
- **积极正面**:你的用词总是积极正面的,比如"不用担心"、"包处理满意"、"很快"、"常见品牌都有",给用户传递了积极的信息。
|
||||
|
||||
### 技能 5: 乱码话术重复问询
|
||||
- **确认问题**:用户说的看不懂的情况来进行再次确认,比如 "45615465" "分隔符规划规范的" "8分隔符公司的"等跟常规问题没关联的话术来重复确认,例如:"宝看不懂你说的是什么啊,能在具体点嘛"
|
||||
|
||||
## 限制
|
||||
- 回复必须基于提供的知识库中的内容。
|
||||
- 每条回复应保持在80字以内,使用口语化语言。
|
||||
- 回复中可以适当加入表情符号,但不要过度使用。
|
||||
- 只讨论与宝妈相关的主题,如育儿、选品、团购等。
|
||||
- 始终以用户的需求和满意度为优先。
|
||||
- 在回答问题时,确保信息准确无误,避免误导用户。
|
||||
- 保持沟通的亲切性和温暖感,但不要过度使用亲昵称呼,以免显得过于随意。
|
||||
|
||||
请按照以上角色设定和限制来回答用户的问题。"""
|
||||
return prompt
|
||||
|
||||
|
||||
def get_deepseek_api_key() -> str:
|
||||
"""获取DeepSeek API密钥"""
|
||||
api_key = os.getenv("DEEPSEEK_API_KEY", "your-deepseek-api-key")
|
||||
return api_key
|
||||
|
||||
|
||||
def is_api_key_configured() -> bool:
|
||||
"""检查API密钥是否已配置"""
|
||||
api_key = get_deepseek_api_key()
|
||||
return api_key != "your-deepseek-api-key"
|
||||
|
||||
|
||||
async def call_deepseek_api(messages: List[dict]) -> str:
|
||||
"""调用DeepSeek API"""
|
||||
# 直接使用环境变量获取API密钥
|
||||
api_key = get_deepseek_api_key()
|
||||
|
||||
if not is_api_key_configured():
|
||||
# 模拟响应用于演示
|
||||
return "宝,这个问题兜兜需要查一下资料哦,稍等哈~ 😊"
|
||||
|
||||
url = "https://api.deepseek.com/v1/chat/completions"
|
||||
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
|
||||
|
||||
data = {
|
||||
"model": "deepseek-chat",
|
||||
"messages": messages,
|
||||
"stream": False,
|
||||
"max_tokens": 500,
|
||||
}
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(url, headers=headers, json=data, timeout=30.0)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
return result["choices"][0]["message"]["content"]
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"API调用失败: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def root():
|
||||
return {"message": "DeepSeek AI Chat Assistant API"}
|
||||
|
||||
|
||||
@router.get("/role")
|
||||
async def get_role_config():
|
||||
"""获取当前角色配置"""
|
||||
return current_role_config
|
||||
|
||||
|
||||
@router.put("/role")
|
||||
async def update_role_config(role_config: RoleConfig):
|
||||
"""更新角色配置"""
|
||||
global current_role_config
|
||||
current_role_config = role_config
|
||||
return {"message": "角色配置已更新", "role_config": current_role_config}
|
||||
|
||||
|
||||
@router.post("/chat", response_model=ChatResponse)
|
||||
async def chat(request: ChatRequest):
|
||||
"""处理聊天请求"""
|
||||
# 创建或获取对话历史
|
||||
if request.conversation_id and request.conversation_id in conversations:
|
||||
conversation_history = conversations[request.conversation_id]
|
||||
else:
|
||||
conversation_history = []
|
||||
request.conversation_id = f"conv_{len(conversations) + 1}"
|
||||
conversations[request.conversation_id] = conversation_history
|
||||
|
||||
# 构建消息列表
|
||||
messages = [{"role": "system", "content": build_system_prompt(current_role_config)}]
|
||||
|
||||
# 添加历史消息
|
||||
for msg in conversation_history[-10:]: # 保留最近10条历史
|
||||
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
|
||||
try:
|
||||
response_text = await call_deepseek_api(messages)
|
||||
|
||||
# 添加助手回复到历史
|
||||
conversation_history.append({"role": "assistant", "content": response_text})
|
||||
|
||||
return ChatResponse(
|
||||
response=response_text, conversation_id=request.conversation_id
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/conversations/{conversation_id}")
|
||||
async def get_conversation(conversation_id: str):
|
||||
"""获取特定对话的历史"""
|
||||
if conversation_id not in conversations:
|
||||
raise HTTPException(status_code=404, detail="对话不存在")
|
||||
return {
|
||||
"conversation_id": conversation_id,
|
||||
"messages": conversations[conversation_id],
|
||||
}
|
||||
162
backend/app/routes/message_routes.py
Normal file
162
backend/app/routes/message_routes.py
Normal file
@@ -0,0 +1,162 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
消息API路由
|
||||
提供加载会话存档、查询消息等功能的API接口
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, HTTPException, Query, Depends
|
||||
import logging
|
||||
|
||||
from app.services.message_service import get_message_service, MessageService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/messages",
|
||||
tags=["messages"],
|
||||
responses={404: {"description": "Not found"}},
|
||||
)
|
||||
|
||||
|
||||
@router.post("/load")
|
||||
async def load_messages(
|
||||
seq: int = Query(0, description="起始seq值,首次使用0"),
|
||||
limit: int = Query(100, description="拉取数量限制", ge=1, le=1000),
|
||||
service: MessageService = Depends(get_message_service),
|
||||
):
|
||||
"""
|
||||
加载会话存档到数据库
|
||||
|
||||
完整流程:拉取 → 解密 → 保存
|
||||
|
||||
- 从企业微信拉取会话存档
|
||||
- 自动解密所有加密消息
|
||||
- 自动保存到数据库(去重处理)
|
||||
|
||||
参数说明:
|
||||
- seq: 起始序列号,首次拉取使用0,后续使用上次返回的max_seq
|
||||
- limit: 一次拉取的消息数量,最大1000
|
||||
|
||||
返回示例:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "消息加载完成",
|
||||
"data": {
|
||||
"total_fetched": 150,
|
||||
"encrypted_count": 120,
|
||||
"decrypted_success": 115,
|
||||
"decrypted_failed": 5,
|
||||
"saved_count": 145,
|
||||
"duplicates_skipped": 5,
|
||||
"failed_to_save": 0,
|
||||
"max_seq": 12345,
|
||||
"next_seq": 12346
|
||||
},
|
||||
"execution_time": "0:00:02.345678",
|
||||
"timestamp": "2025-12-10T16:44:22.123456"
|
||||
}
|
||||
```
|
||||
"""
|
||||
try:
|
||||
logger.info(f"API调用: 加载消息, seq={seq}, limit={limit}")
|
||||
result = await service.load_messages(seq=seq, limit=limit)
|
||||
|
||||
if not result.get("success", False):
|
||||
raise HTTPException(
|
||||
status_code=500, detail=result.get("message", "加载消息失败")
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"加载消息API调用失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"加载消息失败: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def get_messages(
|
||||
page: int = Query(1, description="页码", ge=1),
|
||||
page_size: int = Query(20, description="每页数量", ge=1, le=100),
|
||||
msgtype: Optional[str] = Query(None, description="消息类型过滤"),
|
||||
roomid: Optional[str] = Query(None, description="群聊ID过滤"),
|
||||
from_user: Optional[str] = Query(None, description="发送者过滤"),
|
||||
service: MessageService = Depends(get_message_service),
|
||||
):
|
||||
"""
|
||||
查询消息列表
|
||||
|
||||
支持分页和过滤条件查询
|
||||
"""
|
||||
try:
|
||||
logger.info(
|
||||
f"API调用: 查询消息列表, page={page}, page_size={page_size}, "
|
||||
f"msgtype={msgtype}, roomid={roomid}, from_user={from_user}"
|
||||
)
|
||||
|
||||
result = await service.get_messages(
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
msgtype=msgtype,
|
||||
roomid=roomid,
|
||||
from_user=from_user,
|
||||
)
|
||||
|
||||
if not result.get("success", False):
|
||||
raise HTTPException(
|
||||
status_code=500, detail=result.get("message", "查询消息列表失败")
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"查询消息列表失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"查询消息列表失败: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/stats")
|
||||
async def get_message_stats(service: MessageService = Depends(get_message_service)):
|
||||
"""
|
||||
获取消息统计信息
|
||||
|
||||
返回数据库中消息的统计信息
|
||||
"""
|
||||
try:
|
||||
# 这里可以添加统计逻辑
|
||||
# 暂时返回空统计,实际实现需要连接数据库统计
|
||||
return {
|
||||
"success": True,
|
||||
"data": {"total_messages": 0, "message_types": {}, "date_distribution": {}},
|
||||
}
|
||||
|
||||
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)
|
||||
):
|
||||
"""
|
||||
根据消息ID获取单个消息详情
|
||||
"""
|
||||
try:
|
||||
# 这里可以添加根据msgid查询消息的逻辑
|
||||
# 暂时返回空,实际实现需要连接数据库查询
|
||||
return {"success": True, "data": None, "message": "消息查询功能待实现"}
|
||||
|
||||
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("消息服务已关闭")
|
||||
208
backend/app/routes/wework_routes.py
Normal file
208
backend/app/routes/wework_routes.py
Normal file
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
企业微信会话存档API路由
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, HTTPException, Query, Depends, BackgroundTasks
|
||||
from fastapi.responses import FileResponse, JSONResponse
|
||||
import logging
|
||||
|
||||
from app.services.wework_service import get_wework_service, WeworkService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/wework",
|
||||
tags=["wework"],
|
||||
responses={404: {"description": "Not found"}},
|
||||
)
|
||||
|
||||
def get_service():
|
||||
"""依赖注入:获取企业微信服务实例"""
|
||||
return get_wework_service()
|
||||
|
||||
@router.get("/health")
|
||||
async def health_check(service: WeworkService = Depends(get_service)):
|
||||
"""健康检查端点"""
|
||||
return {
|
||||
"status": "healthy",
|
||||
"service": "wework",
|
||||
"corpid": service.corpid,
|
||||
"media_dir": str(service.media_dir)
|
||||
}
|
||||
|
||||
@router.get("/chat")
|
||||
async def get_chat(
|
||||
seq: int = Query(0, description="从指定的seq开始拉取消息,首次使用请使用0"),
|
||||
limit: int = Query(100, description="一次拉取的消息条数,最大值1000条", ge=1, le=1000),
|
||||
proxy: Optional[str] = Query(None, description="代理链接,如:socks5://10.0.0.1:8081 或 http://10.0.0.1:8081"),
|
||||
passwd: Optional[str] = Query(None, description="代理账号密码,如:user_name:passwd_123"),
|
||||
timeout: int = Query(5, description="超时时间,单位秒", ge=1, le=60),
|
||||
service: WeworkService = Depends(get_service)
|
||||
):
|
||||
"""
|
||||
拉取会话存档
|
||||
|
||||
从企业微信拉取聊天记录,支持代理和分页
|
||||
"""
|
||||
try:
|
||||
result = service.get_chat_data(
|
||||
seq=seq,
|
||||
limit=limit,
|
||||
proxy=proxy or "",
|
||||
passwd=passwd or "",
|
||||
timeout=timeout
|
||||
)
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(f"拉取会话存档失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"拉取会话存档失败: {str(e)}")
|
||||
|
||||
@router.post("/media")
|
||||
async def download_media(
|
||||
fileid: str = Query(..., description="媒体文件id,从解密后的会话存档中得到"),
|
||||
filename: Optional[str] = Query(None, description="保存的文件名,如果为空则自动生成"),
|
||||
proxy: Optional[str] = Query(None, description="代理链接"),
|
||||
passwd: Optional[str] = Query(None, description="代理账号密码"),
|
||||
timeout: int = Query(5, description="超时时间,单位秒", ge=1, le=60),
|
||||
background_tasks: BackgroundTasks = None,
|
||||
service: WeworkService = Depends(get_service)
|
||||
):
|
||||
"""
|
||||
拉取媒体文件
|
||||
|
||||
下载企业微信中的媒体文件(图片、语音、视频等),支持大文件分片下载
|
||||
"""
|
||||
try:
|
||||
result = service.get_media_data(
|
||||
sdk_fileid=fileid,
|
||||
filename=filename,
|
||||
proxy=proxy or "",
|
||||
passwd=passwd or "",
|
||||
timeout=timeout
|
||||
)
|
||||
|
||||
if result.get("success"):
|
||||
# 可以添加后台任务,比如发送下载完成通知等
|
||||
if background_tasks:
|
||||
background_tasks.add_task(
|
||||
logger.info,
|
||||
f"媒体文件下载完成: {result['filename']}, 大小: {result['filesize']} 字节"
|
||||
)
|
||||
|
||||
return result
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail=result.get("error", "下载失败"))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"拉取媒体文件失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"拉取媒体文件失败: {str(e)}")
|
||||
|
||||
@router.get("/media/files")
|
||||
async def list_media_files(
|
||||
service: WeworkService = Depends(get_service)
|
||||
):
|
||||
"""
|
||||
获取已下载的媒体文件列表
|
||||
|
||||
返回所有已下载的媒体文件信息
|
||||
"""
|
||||
try:
|
||||
files = service.get_media_files()
|
||||
return {
|
||||
"count": len(files),
|
||||
"files": files
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"获取媒体文件列表失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"获取媒体文件列表失败: {str(e)}")
|
||||
|
||||
@router.get("/media/download/{filename}")
|
||||
async def download_file(
|
||||
filename: str,
|
||||
service: WeworkService = Depends(get_service)
|
||||
):
|
||||
"""
|
||||
下载媒体文件
|
||||
|
||||
通过文件名下载已保存的媒体文件
|
||||
"""
|
||||
try:
|
||||
file_path = service.media_dir / filename
|
||||
if not file_path.exists():
|
||||
raise HTTPException(status_code=404, detail="文件不存在")
|
||||
|
||||
return FileResponse(
|
||||
path=file_path,
|
||||
filename=filename,
|
||||
media_type='application/octet-stream'
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"下载文件失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"下载文件失败: {str(e)}")
|
||||
|
||||
@router.delete("/media/cleanup")
|
||||
async def cleanup_media_files(
|
||||
days: int = Query(7, description="保留天数,早于此天数的文件将被删除", ge=1, le=365),
|
||||
service: WeworkService = Depends(get_service)
|
||||
):
|
||||
"""
|
||||
清理旧的媒体文件
|
||||
|
||||
删除指定天数之前的媒体文件
|
||||
"""
|
||||
try:
|
||||
deleted_count = service.cleanup_old_files(days)
|
||||
return {
|
||||
"message": f"成功删除 {deleted_count} 个旧文件",
|
||||
"deleted_count": deleted_count,
|
||||
"days": days
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"清理媒体文件失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"清理媒体文件失败: {str(e)}")
|
||||
|
||||
@router.post("/decrypt")
|
||||
async def decrypt_message(
|
||||
encrypt_key: str = Query(..., description="解密密钥,使用RSA私钥解密encrypt_random_key后得到"),
|
||||
encrypt_msg: str = Query(..., description="加密的消息内容"),
|
||||
service: WeworkService = Depends(get_service)
|
||||
):
|
||||
"""
|
||||
解密会话内容
|
||||
|
||||
使用企业自持的RSA私钥解密后的encrypt_key来解密encrypt_chat_msg
|
||||
"""
|
||||
try:
|
||||
result = service.decrypt_data(encrypt_key, encrypt_msg)
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(f"解密消息失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"解密消息失败: {str(e)}")
|
||||
|
||||
@router.get("/config")
|
||||
async def get_config(
|
||||
service: WeworkService = Depends(get_service)
|
||||
):
|
||||
"""
|
||||
获取当前配置
|
||||
|
||||
返回企业微信服务的配置信息
|
||||
"""
|
||||
return {
|
||||
"corpid": service.corpid,
|
||||
"corpid_masked": service.corpid[:8] + "..." + service.corpid[-4:] if len(service.corpid) > 12 else service.corpid,
|
||||
"media_dir": str(service.media_dir),
|
||||
"media_dir_exists": service.media_dir.exists()
|
||||
}
|
||||
|
||||
# 应用关闭时的清理
|
||||
@router.on_event("shutdown")
|
||||
async def shutdown_event():
|
||||
"""应用关闭时清理资源"""
|
||||
from app.services.wework_service import close_wework_service
|
||||
close_wework_service()
|
||||
logger.info("企业微信服务已关闭")
|
||||
Reference in New Issue
Block a user