feat: 2026-07-11 全量更新 - 代办集成+会议室预定+知识迭代修复+UI统一+Bug修复

== 已部署上线 (9项) ==
- 代办事项真实数据源集成 (企微审批API 8bug修复链)
- H5/坐席端 Logo样式统一+绿色背景
- 视频引导页修复 (localStorage key v2)
- 坐席端 v9 Vue版本修复 (ElMessage._context)
- 截图按钮 v10 修复 (getDisplayMedia user gesture)
- 扫码样式恢复+H5扫码登录跳转修复
- H5截图快捷键提示

== 代码完成待部署 (3项) ==
- 知识迭代3Bug修复 (#8 POST端点/#7 MERGE幂等/#6 过期检查)
- 会议室预定-小鱼易联终端 (40文件, 40/40测试通过)
- IT资产升级审批推送 (asset_service.py)

== 需求文档 (2项) ==
- 坐席端AI辅助消息框-PRD (4项新功能确认)
- 坐席端布局优化建议 v2.0 (7天计划)

== 新增文档 ==
- 日报-2026-07-11.md
- 知识迭代Bug修复报告-20260711.md
- 会议室预定-部署指南.md
- CHANGELOG.md 更新

== 测试 ==
- test_todo_integration.py: 40/40
- test_meetingroom.py: 40/40
- test_bugfix_ki_suggestions.py: 21/21
This commit is contained in:
Simon
2026-07-11 23:13:10 +08:00
parent 3d152fc8eb
commit bea288e414
928 changed files with 85169 additions and 54205 deletions
@@ -1,8 +1,10 @@
# =============================================================================
# 企微IT智能服务台 — 阶段5 自动化 意图识别
# 企微IT智能服务台 — 自动化 意图识别(含全局意图)
# =============================================================================
# 说明:调用 Dify 识别员工诉求命中哪个自动化场景;Dify 未配置时走关键词兜底,
# 保证 P0 四个场景在无真实 Dify 环境下也能跑通闭环。
# 复杂场景重构:新增全局意图检测(PAUSE/RESUME_TASK/CORRECT/SUPPLEMENT),
# detect() 内部先调全局意图检测,命中则返回全局意图,跳过场景识别。
# =============================================================================
from __future__ import annotations
@@ -17,17 +19,31 @@ logger = logging.getLogger(__name__)
class IntentRouter:
"""意图识别路由器。"""
"""意图识别路由器(含全局对话控制意图)"""
def __init__(self, db: Any = None, audit: Any = None):
self.db = db
self.audit = audit
async def detect(self, description: str, employee_id: str = "") -> Dict[str, Any]:
"""识别意图,返回 {scenario_key, confidence, raw, error}
"""识别意图,返回包含 global_intent 的完整结果
优先走 Dify;若 Dify 未配置或调用失败,使用关键词兜底。
优先检测全局对话控制意图(pause/resume_task/correct/supplement),
命中则直接返回全局意图,跳过场景识别;
未命中则走原有场景识别流程。
Returns:
Dict: {global_intent, scenario_key, confidence, corrected_field,
old_value, new_value, supplement_field, supplement_value,
raw, error}
"""
# 1. 先检测全局意图
global_result = await self.detect_global_intent(description)
if global_result.get("global_intent") is not None:
# 命中全局意图 → 直接返回,跳过场景识别
return global_result
# 2. 未命中全局意图 → 走原场景识别
client: Optional[DifyClient] = None
try:
client = await build_dify_client(audit=self.audit)
@@ -37,12 +53,97 @@ class IntentRouter:
if client is None:
fb = DifyClient._fallback_intent(description)
fb["error"] = "dify_not_configured"
# 确保全局意图字段存在
fb.setdefault("global_intent", None)
fb.setdefault("corrected_field", None)
fb.setdefault("old_value", None)
fb.setdefault("new_value", None)
fb.setdefault("supplement_field", None)
fb.setdefault("supplement_value", None)
return fb
try:
return await client.detect_intent(description, employee_id)
result = await client.detect_intent(description, employee_id)
# 确保全局意图字段存在(兼容旧版 Dify 返回)
result.setdefault("global_intent", None)
result.setdefault("corrected_field", None)
result.setdefault("old_value", None)
result.setdefault("new_value", None)
result.setdefault("supplement_field", None)
result.setdefault("supplement_value", None)
return result
except Exception as e: # noqa: BLE001
logger.warning(f"Dify 意图识别异常,转关键词兜底: {e}")
fb = DifyClient._fallback_intent(description)
fb["error"] = str(e)
fb.setdefault("global_intent", None)
fb.setdefault("corrected_field", None)
fb.setdefault("old_value", None)
fb.setdefault("new_value", None)
fb.setdefault("supplement_field", None)
fb.setdefault("supplement_value", None)
return fb
async def detect_global_intent(self, text: str) -> Dict[str, Any]:
"""检测全局对话控制意图(pause/resume_task/correct/supplement)。
优先调用 Dify(复用现有客户端),Prompt 中增加全局意图判断;
Dify 不可用时走关键词兜底(使用 GLOBAL_INTENT_KEYWORDS)。
Returns:
Dict: {global_intent, scenario_key, confidence, corrected_field,
old_value, new_value, supplement_field, supplement_value,
raw, error}
"""
# 尝试 Dify
client: Optional[DifyClient] = None
try:
client = await build_dify_client(audit=self.audit)
except Exception as e: # noqa: BLE001
logger.debug(f"构建 Dify 客户端失败,全局意图转关键词兜底: {e}")
if client is not None:
try:
result = await client.detect_intent(text, "")
# detect_intent 已返回 global_intent,直接使用
return result
except Exception as e: # noqa: BLE001
logger.warning(f"Dify 全局意图识别异常,转关键词兜底: {e}")
# 关键词兜底
return self._keyword_fallback_global(text)
def _keyword_fallback_global(self, text: str) -> Dict[str, Any]:
"""全局意图关键词兜底。"""
lower_text = (text or "").lower()
try:
from app.constants import GLOBAL_INTENT_KEYWORDS
for intent, keywords in GLOBAL_INTENT_KEYWORDS.items():
if any(kw.lower() in lower_text for kw in keywords):
return {
"global_intent": intent,
"scenario_key": None,
"confidence": 0.6,
"corrected_field": None,
"old_value": None,
"new_value": None,
"supplement_field": None,
"supplement_value": None,
"raw": "",
"error": "fallback",
}
except Exception: # noqa: BLE001
pass
return {
"global_intent": None,
"scenario_key": None,
"confidence": 0.0,
"corrected_field": None,
"old_value": None,
"new_value": None,
"supplement_field": None,
"supplement_value": None,
"raw": "",
"error": "fallback",
}