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 )