You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

196 lines
7.0 KiB

import uuid
import json
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from database import get_db
from models import User, ChatSession, ChatMessage
from modules.org.router import _get_subordinate_ids, _user_to_out
from schemas import EmployeeAnalysis, UserOut
router = APIRouter(prefix="/api/monitor", tags=["monitor"])
@router.get("/employees", response_model=list[UserOut])
async def get_monitor_employees(request: Request, db: AsyncSession = Depends(get_db)):
user_ctx = request.state.user
cur_id = uuid.UUID(user_ctx["id"])
if user_ctx["data_scope"] == "all":
result = await db.execute(select(User).where(User.status == "active"))
return [await _user_to_out(db, u) for u in result.scalars().all()]
elif user_ctx["data_scope"] == "subordinate_only":
sub_ids = await _get_subordinate_ids(db, cur_id)
sub_ids.add(cur_id)
result = await db.execute(select(User).where(User.id.in_(sub_ids)))
return [await _user_to_out(db, u) for u in result.scalars().all()]
else:
result = await db.execute(select(User).where(User.id == cur_id))
return [await _user_to_out(db, u) for u in result.scalars().all()]
@router.get("/employee/{emp_id}/dashboard")
async def get_employee_dashboard(
emp_id: uuid.UUID, request: Request, db: AsyncSession = Depends(get_db)
):
user_ctx = request.state.user
cur_id = uuid.UUID(user_ctx["id"])
if user_ctx["data_scope"] != "all":
if user_ctx["data_scope"] == "self_only" and str(emp_id) != user_ctx["id"]:
raise HTTPException(403, "无权查看此员工数据")
elif user_ctx["data_scope"] == "subordinate_only":
sub_ids = await _get_subordinate_ids(db, cur_id)
sub_ids.add(cur_id)
if emp_id not in sub_ids:
raise HTTPException(403, "无权查看此员工数据")
emp_result = await db.execute(select(User).where(User.id == emp_id))
emp = emp_result.scalar_one_or_none()
if not emp:
raise HTTPException(404, "员工不存在")
total_msgs_result = await db.execute(
select(func.count(ChatMessage.id)).where(ChatMessage.user_id == emp_id)
)
total_messages = total_msgs_result.scalar() or 0
session_result = await db.execute(
select(func.count(ChatSession.id)).where(ChatSession.user_id == emp_id)
)
total_sessions = session_result.scalar() or 0
recent_msgs_result = await db.execute(
select(ChatMessage)
.where(ChatMessage.user_id == emp_id)
.order_by(ChatMessage.created_at.desc())
.limit(50)
)
recent = recent_msgs_result.scalars().all()
topics = {}
active_days = set()
for msg in recent:
if msg.created_at:
active_days.add(msg.created_at.strftime("%Y-%m-%d"))
role = msg.role
topics[role] = topics.get(role, 0) + 1
return {
"code": 200,
"data": {
"employee": {
"id": str(emp.id),
"name": emp.display_name,
"department": str(emp.department_id) if emp.department_id else "",
"position": emp.position or "",
},
"stats": {
"total_messages": total_messages,
"total_sessions": total_sessions,
"active_days": len(active_days),
"message_breakdown": topics,
"recent_interactions": [
{"role": m.role, "content": m.content[:200], "created_at": str(m.created_at)}
for m in recent[:10]
],
},
},
}
@router.get("/employee/{emp_id}/analysis", response_model=EmployeeAnalysis)
async def get_employee_analysis(
emp_id: uuid.UUID, request: Request, db: AsyncSession = Depends(get_db)
):
user_ctx = request.state.user
cur_id = uuid.UUID(user_ctx["id"])
if user_ctx["data_scope"] != "all":
if user_ctx["data_scope"] == "self_only" and str(emp_id) != user_ctx["id"]:
raise HTTPException(403, "无权查看此员工数据")
elif user_ctx["data_scope"] == "subordinate_only":
sub_ids = await _get_subordinate_ids(db, cur_id)
sub_ids.add(cur_id)
if emp_id not in sub_ids:
raise HTTPException(403, "无权查看此员工数据")
emp_result = await db.execute(select(User).where(User.id == emp_id))
emp = emp_result.scalar_one_or_none()
if not emp:
raise HTTPException(404, "员工不存在")
from config import settings
from agentscope.model import OpenAIChatModel
from agentscope.formatter import OpenAIChatFormatter
from agentscope.message import Msg
msgs_result = await db.execute(
select(ChatMessage)
.where(ChatMessage.user_id == emp_id)
.order_by(ChatMessage.created_at.desc())
.limit(100)
)
messages = msgs_result.scalars().all()
interaction_log = "\n".join([
f"[{m.role}] {m.content[:300]}" for m in messages
])
model = OpenAIChatModel(
config_name="analysis_model",
model_name=settings.LLM_MODEL,
api_key=settings.LLM_API_KEY,
api_base=settings.LLM_API_BASE,
)
formatter = OpenAIChatFormatter()
prompt = formatter.format([
Msg("system", f"""你是一个企业管理者分析助手。请根据员工与AI的交互记录,生成一个JSON格式的分析报告。
要求:
1. 分析员工的task_completion_rate (0-1的浮点数)
2. 统计active_days和total_interactions
3. 提取main_topics (最多5个关键词)
4. 评估efficiency_trend ("提升" / "稳定" / "下降")
5. 给出efficiency_detail (一句话说明)
6. 列出strengths (2-3个优点)
7. 给出growth_suggestions (2-3条建议)
8. 总结personality_traits (一句话)
输出严格JSON格式,不要包含markdown代码块标记。""", "system"),
Msg("user", f"员工姓名: {emp.display_name}\n交互记录:\n{interaction_log}", "user"),
])
try:
res = await model(prompt)
res_text = ""
if isinstance(res, list):
res_text = res[0].get_text_content() if hasattr(res[0], 'get_text_content') else str(res[0])
elif hasattr(res, 'get_text_content'):
res_text = res.get_text_content()
else:
res_text = str(res)
analysis_data = json.loads(res_text)
except Exception:
analysis_data = {
"task_completion_rate": 0.7,
"active_days": 0,
"total_interactions": len(messages),
"main_topics": [],
"efficiency_trend": "稳定",
"efficiency_detail": "暂无足够数据",
"strengths": [],
"growth_suggestions": [],
"personality_traits": "暂未收集足够人格特征数据",
}
return EmployeeAnalysis(
employee_name=emp.display_name,
department=str(emp.department_id) if emp.department_id else "",
period=f"最近数据",
**analysis_data
)