P1-2: 统一Dify调用点 - 删除detect-intent死链路(approval/byod) + routing_service共享client修复连接泄漏 + 前端死代码清理
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
# =============================================================================
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from typing import Optional
|
||||
@@ -332,34 +331,6 @@ class ApprovalUrgeRequest(BaseModel):
|
||||
sp_no: str
|
||||
|
||||
|
||||
class ApprovalDetectIntentRequest(BaseModel):
|
||||
"""审批意图检测请求"""
|
||||
text: str
|
||||
employee_id: Optional[str] = None
|
||||
|
||||
|
||||
class ApprovalDetectIntentResponse(BaseModel):
|
||||
"""审批意图检测响应
|
||||
|
||||
Attributes:
|
||||
is_approval_request: 是否为审批请求(原字段,语义不变)
|
||||
confidence: 置信度(0.0~1.0)(原字段,语义不变)
|
||||
approval_type: 审批类型(原字段,语义不变)
|
||||
source: 结果来源 — dify(Dify识别) / keyword_prefilter(关键词预过滤未命中) / fallback(降级兜底)
|
||||
intent_type: 意图大类(新增)— approval/it_consult/non_it_routing/chitchat
|
||||
business_category: 非IT业务类别(新增)— 行政/人力资源/财务/法务/行政-物业,仅 non_it_routing 时有值
|
||||
routing_confidence: 路由置信度(新增)— 0.0~1.0,≥0.7 触发名片推荐
|
||||
"""
|
||||
is_approval_request: bool
|
||||
confidence: float
|
||||
approval_type: Optional[str] = None
|
||||
source: str # "dify" | "keyword_prefilter" | "fallback"
|
||||
# 以下为 v3 统一意图识别新增字段(向后兼容:原审批逻辑只读取前4个字段)
|
||||
intent_type: str = "chitchat"
|
||||
business_category: Optional[str] = None
|
||||
routing_confidence: float = 0.0
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 企微API调用辅助函数
|
||||
# =============================================================================
|
||||
@@ -973,179 +944,3 @@ async def get_approval_keywords():
|
||||
return success_response(data=keywords)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 审批意图识别(Dify + 关键词预过滤 + 降级兜底)
|
||||
# =============================================================================
|
||||
|
||||
def _keyword_prefilter(text: str) -> bool:
|
||||
"""关键词预过滤:检查文本是否包含审批相关关键词(v2.0 收窄版)。
|
||||
|
||||
v2.0 变更(2026-07-13):
|
||||
- 不再合并 APPROVAL_TEMPLATES 的 keywords(包含"借用""升级""外联"等泛化词)
|
||||
- 仅使用 APPROVAL_PREFILTER_KEYWORDS(强意图词 + 复合专有词)
|
||||
- 模板 keywords 仍保留在 KEYWORD_TO_APPROVAL_TYPE 中,仅用于 Dify 不可用时的降级兜底
|
||||
|
||||
Args:
|
||||
text: 用户消息文本
|
||||
|
||||
Returns:
|
||||
bool: 是否包含审批关键词
|
||||
"""
|
||||
if not text:
|
||||
return False
|
||||
lower_text = text.lower()
|
||||
# v2.0: 仅使用预过滤关键词列表,不合并模板 keywords
|
||||
return any(kw.lower() in lower_text for kw in APPROVAL_PREFILTER_KEYWORDS)
|
||||
|
||||
|
||||
def _fallback_detect(text: str) -> tuple[bool, float, Optional[str]]:
|
||||
"""关键词兜底:Dify 不可用时通过关键词匹配判断审批意图。
|
||||
|
||||
遍历 KEYWORD_TO_APPROVAL_TYPE 映射,命中第一个关键词即返回对应审批类型。
|
||||
置信度取 0.6(略低于阈值,但预过滤已通过说明有审批关键词)。
|
||||
|
||||
Args:
|
||||
text: 用户消息文本
|
||||
|
||||
Returns:
|
||||
tuple: (is_approval_request, confidence, approval_type)
|
||||
"""
|
||||
lower_text = (text or "").lower()
|
||||
approval_type: Optional[str] = None
|
||||
for kw, atype in KEYWORD_TO_APPROVAL_TYPE.items():
|
||||
if kw.lower() in lower_text:
|
||||
approval_type = atype
|
||||
break
|
||||
# 预过滤已通过(说明有审批关键词),兜底返回 is_approval_request=True
|
||||
return True, 0.6, approval_type
|
||||
|
||||
|
||||
async def _call_dify_approval_intent(text: str, employee_id: str = "") -> dict:
|
||||
"""调用 Dify 审批意图识别应用(Dify 原生 API)。
|
||||
|
||||
直接调用 Dify 原生 /v1/chat-messages 接口,绕过 Dify2OpenAI 代理。
|
||||
Dify2OpenAI 代理会将 JSON 响应序列化为 "[object Object]" 字符串,
|
||||
导致后端无法解析。使用原生 API 可获得正确的 JSON 响应。
|
||||
|
||||
Dify 应用的 System Prompt 已在 Dify 后台配置好,后端只需把用户消息传过去。
|
||||
返回 JSON: {"is_approval_request": bool, "confidence": float, "approval_type": str|null}
|
||||
|
||||
Args:
|
||||
text: 用户消息文本
|
||||
employee_id: 员工 ID(可选,传给 Dify 的 user 字段)
|
||||
|
||||
Returns:
|
||||
dict: {"is_approval_request": bool, "confidence": float, "approval_type": str|None}
|
||||
|
||||
Raises:
|
||||
Exception: Dify 调用失败或响应解析失败
|
||||
"""
|
||||
base_url = settings.approval_dify_base_url
|
||||
api_key = settings.approval_dify_api_key
|
||||
timeout = settings.approval_dify_timeout
|
||||
|
||||
if not base_url or not api_key:
|
||||
raise ValueError("Dify 审批意图识别应用未配置(APPROVAL_DIFY_BASE_URL / APPROVAL_DIFY_API_KEY)")
|
||||
|
||||
# 构建请求 URL:base_url + /v1/chat-messages(Dify 原生 API)
|
||||
url = f"{base_url.rstrip('/')}/v1/chat-messages"
|
||||
|
||||
body = {
|
||||
"inputs": {}, # Dify 应用的输入变量(无自定义变量时为空)
|
||||
"query": text, # 用户消息文本
|
||||
"response_mode": "blocking", # 阻塞模式,等待完整响应
|
||||
"user": employee_id or "approval_detection", # 用户标识
|
||||
}
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
async with httpx.AsyncClient(timeout=httpx.Timeout(timeout)) as client:
|
||||
response = await client.post(url, json=body, headers=headers)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
# 解析 Dify 原生响应:answer 字段包含 AI 返回的文本(JSON 字符串)
|
||||
answer = data.get("answer", "")
|
||||
parsed = json.loads(answer)
|
||||
|
||||
return {
|
||||
"is_approval_request": bool(parsed.get("is_approval_request", False)),
|
||||
"confidence": float(parsed.get("confidence", 0.0)),
|
||||
"approval_type": parsed.get("approval_type"),
|
||||
# v3 统一意图识别新增字段(向后兼容:旧 Prompt 无这些字段时取默认值)
|
||||
"intent_type": str(parsed.get("intent_type", "chitchat")),
|
||||
"business_category": parsed.get("business_category"),
|
||||
"routing_confidence": float(parsed.get("routing_confidence", 0.0)),
|
||||
}
|
||||
|
||||
|
||||
@router.post("/approval/detect-intent")
|
||||
async def detect_approval_intent(request: ApprovalDetectIntentRequest):
|
||||
"""审批意图检测端点。
|
||||
|
||||
流程:
|
||||
1. 关键词预过滤 — 未命中直接返回 false(避免每条消息都调 Dify)
|
||||
2. 命中关键词 → 调用 Dify 审批意图识别应用
|
||||
3. Dify 调用失败 → 降级为关键词匹配(兜底)
|
||||
|
||||
Args:
|
||||
request: 包含 text(用户消息)和可选的 employee_id
|
||||
|
||||
Returns:
|
||||
ApprovalDetectIntentResponse: 检测结果
|
||||
"""
|
||||
text = request.text or ""
|
||||
|
||||
# 1. 关键词预过滤
|
||||
if not _keyword_prefilter(text):
|
||||
return success_response(data=ApprovalDetectIntentResponse(
|
||||
is_approval_request=False,
|
||||
confidence=0.0,
|
||||
approval_type=None,
|
||||
source="keyword_prefilter",
|
||||
intent_type="chitchat",
|
||||
business_category=None,
|
||||
routing_confidence=0.0,
|
||||
))
|
||||
|
||||
# 2. 调用 Dify 意图识别
|
||||
try:
|
||||
result = await _call_dify_approval_intent(text, request.employee_id or "")
|
||||
# 检查置信度阈值
|
||||
threshold = settings.approval_confidence_threshold
|
||||
is_approval = result["is_approval_request"] and result["confidence"] >= threshold
|
||||
logger.info(
|
||||
f"审批意图检测(Dify): is_approval={is_approval}, "
|
||||
f"confidence={result['confidence']}, type={result.get('approval_type')}, "
|
||||
f"intent_type={result.get('intent_type')}, "
|
||||
f"business_category={result.get('business_category')}, "
|
||||
f"routing_confidence={result.get('routing_confidence')}"
|
||||
)
|
||||
return success_response(data=ApprovalDetectIntentResponse(
|
||||
is_approval_request=is_approval,
|
||||
confidence=result["confidence"],
|
||||
approval_type=result.get("approval_type"),
|
||||
source="dify",
|
||||
intent_type=result.get("intent_type", "chitchat"),
|
||||
business_category=result.get("business_category"),
|
||||
routing_confidence=result.get("routing_confidence", 0.0),
|
||||
))
|
||||
except Exception as e:
|
||||
logger.warning(f"Dify 审批意图识别失败,降级为关键词匹配: {e}")
|
||||
# 3. 降级为关键词匹配
|
||||
is_approval, confidence, approval_type = _fallback_detect(text)
|
||||
logger.info(
|
||||
f"审批意图检测(兜底): is_approval={is_approval}, "
|
||||
f"confidence={confidence}, type={approval_type}"
|
||||
)
|
||||
return success_response(data=ApprovalDetectIntentResponse(
|
||||
is_approval_request=is_approval,
|
||||
confidence=confidence,
|
||||
approval_type=approval_type,
|
||||
source="fallback",
|
||||
intent_type="approval" if is_approval else "chitchat",
|
||||
business_category=None,
|
||||
routing_confidence=0.0,
|
||||
))
|
||||
|
||||
+3
-155
@@ -1,17 +1,15 @@
|
||||
# =============================================================================
|
||||
# IT智能服务台 — 自备电脑补贴(BYOD)资格查询 API
|
||||
# =============================================================================
|
||||
# 说明:提供自备电脑补贴资格的意图检测和资格检查功能
|
||||
# - 意图检测:关键词预过滤 → Dify → 关键词兜底(复用审批系统三级模式)
|
||||
# 说明:提供自备电脑补贴资格检查功能
|
||||
# - 资格检查:通过企微通讯录API获取员工岗位 → 与资格清单匹配 → 返回结果
|
||||
# - 岗位匹配支持精确匹配和模糊匹配(如"高级前端开发岗"匹配"前端开发岗")
|
||||
# - BYOD 意图检测已并入主 Dify 对话链路(v4.0 P1-2 删除独立 detect-intent 端点)
|
||||
# =============================================================================
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter, Depends
|
||||
from pydantic import BaseModel
|
||||
import redis.asyncio as aioredis
|
||||
@@ -144,17 +142,6 @@ BYOD_REGISTER_NOTES: list[str] = [
|
||||
# Schema 定义
|
||||
# =============================================================================
|
||||
|
||||
class ByodEligibilityRequest(BaseModel):
|
||||
"""BYOD 意图检测请求
|
||||
|
||||
Attributes:
|
||||
text: 用户消息文本
|
||||
employee_id: 员工ID(可选,传给 Dify 作为用户标识)
|
||||
"""
|
||||
text: str
|
||||
employee_id: Optional[str] = None
|
||||
|
||||
|
||||
class ByodCheckEligibilityRequest(BaseModel):
|
||||
"""BYOD 资格检查请求
|
||||
|
||||
@@ -234,74 +221,7 @@ def _match_position(position: str) -> tuple[bool, str, str]:
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Dify 意图识别(复用审批意图识别 Dify 应用)
|
||||
# =============================================================================
|
||||
# 说明:BYOD 意图识别复用审批系统的 Dify 应用(同一个 approval_dify_base_url /
|
||||
# approval_dify_api_key),Dify 后台的 System Prompt 已更新为同时支持
|
||||
# 审批意图和 BYOD 意图识别。Dify 返回的 JSON 中包含 is_byod_intent 字段。
|
||||
|
||||
async def _call_dify_byod_intent(text: str, employee_id: str = "") -> dict:
|
||||
"""调用 Dify 意图识别应用,检测 BYOD 意图。
|
||||
|
||||
复用审批意图识别的 Dify 应用(approval_dify_base_url / approval_dify_api_key),
|
||||
Dify 的 System Prompt 已更新为同时返回 is_byod_intent 字段。
|
||||
|
||||
Dify 原生 API 调用方式与 approval.py 中的 _call_dify_approval_intent 一致:
|
||||
POST {base_url}/v1/chat-messages,blocking 模式。
|
||||
|
||||
Args:
|
||||
text: 用户消息文本
|
||||
employee_id: 员工 ID(可选,传给 Dify 的 user 字段)
|
||||
|
||||
Returns:
|
||||
dict: {
|
||||
"is_byod_intent": bool,
|
||||
"confidence": float,
|
||||
}
|
||||
|
||||
Raises:
|
||||
Exception: Dify 调用失败或响应解析失败
|
||||
"""
|
||||
base_url = settings.approval_dify_base_url
|
||||
api_key = settings.approval_dify_api_key
|
||||
timeout = settings.approval_dify_timeout
|
||||
|
||||
if not base_url or not api_key:
|
||||
raise ValueError(
|
||||
"Dify 意图识别应用未配置(APPROVAL_DIFY_BASE_URL / APPROVAL_DIFY_API_KEY)"
|
||||
)
|
||||
|
||||
# 构建请求 URL:base_url + /v1/chat-messages(Dify 原生 API)
|
||||
url = f"{base_url.rstrip('/')}/v1/chat-messages"
|
||||
|
||||
body = {
|
||||
"inputs": {},
|
||||
"query": text,
|
||||
"response_mode": "blocking",
|
||||
"user": employee_id or "byod_detection",
|
||||
}
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
async with httpx.AsyncClient(timeout=httpx.Timeout(timeout)) as client:
|
||||
response = await client.post(url, json=body, headers=headers)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
# 解析 Dify 原生响应:answer 字段包含 AI 返回的文本(JSON 字符串)
|
||||
answer = data.get("answer", "")
|
||||
parsed = json.loads(answer)
|
||||
|
||||
return {
|
||||
"is_byod_intent": bool(parsed.get("is_byod_intent", False)),
|
||||
"confidence": float(parsed.get("confidence", 0.0)),
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 关键词预过滤 & 降级兜底
|
||||
# 关键词预过滤
|
||||
# =============================================================================
|
||||
|
||||
def _byod_keyword_prefilter(text: str) -> bool:
|
||||
@@ -322,82 +242,10 @@ def _byod_keyword_prefilter(text: str) -> bool:
|
||||
return any(kw.lower() in lower_text for kw in BYOD_PREFILTER_KEYWORDS)
|
||||
|
||||
|
||||
def _byod_fallback_detect(text: str) -> tuple[bool, float]:
|
||||
"""BYOD 关键词兜底:Dify 不可用时通过关键词匹配判断 BYOD 意图。
|
||||
|
||||
遍历 BYOD_PREFILTER_KEYWORDS,命中任意一个即认为有 BYOD 意图。
|
||||
置信度取 0.6(预过滤已通过说明有 BYOD 相关关键词)。
|
||||
|
||||
Args:
|
||||
text: 用户消息文本
|
||||
|
||||
Returns:
|
||||
tuple: (is_byod_intent, confidence)
|
||||
"""
|
||||
lower_text = (text or "").lower()
|
||||
for kw in BYOD_PREFILTER_KEYWORDS:
|
||||
if kw.lower() in lower_text:
|
||||
return True, 0.6
|
||||
return False, 0.0
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# API 端点
|
||||
# =============================================================================
|
||||
|
||||
@router.post("/byod/detect-intent")
|
||||
async def detect_byod_intent(request: ByodEligibilityRequest):
|
||||
"""BYOD 意图检测端点。
|
||||
|
||||
流程(复用审批系统三级模式):
|
||||
1. 关键词预过滤 — 未命中 BYOD 关键词直接返回 false(避免每条消息都调 Dify)
|
||||
2. 命中关键词 → 调用 Dify 意图识别应用(复用审批 Dify 应用)
|
||||
3. Dify 调用失败 → 降级为关键词匹配(兜底)
|
||||
|
||||
Args:
|
||||
request: 包含 text(用户消息)和可选的 employee_id
|
||||
|
||||
Returns:
|
||||
ByodEligibilityResponse: 检测结果(仅 is_byod_intent 和 source 字段有效)
|
||||
"""
|
||||
text = request.text or ""
|
||||
|
||||
# 1. 关键词预过滤
|
||||
if not _byod_keyword_prefilter(text):
|
||||
return success_response(data=ByodEligibilityResponse(
|
||||
is_byod_intent=False,
|
||||
eligible=False,
|
||||
source="keyword_prefilter",
|
||||
))
|
||||
|
||||
# 2. 调用 Dify 意图识别
|
||||
try:
|
||||
result = await _call_dify_byod_intent(text, request.employee_id or "")
|
||||
threshold = settings.approval_confidence_threshold
|
||||
is_byod = result["is_byod_intent"] and result["confidence"] >= threshold
|
||||
logger.info(
|
||||
f"BYOD意图检测(Dify): is_byod={is_byod}, "
|
||||
f"confidence={result['confidence']}"
|
||||
)
|
||||
return success_response(data=ByodEligibilityResponse(
|
||||
is_byod_intent=is_byod,
|
||||
eligible=False,
|
||||
source="dify",
|
||||
))
|
||||
except Exception as e:
|
||||
logger.warning(f"Dify BYOD 意图识别失败,降级为关键词匹配: {e}")
|
||||
# 3. 降级为关键词匹配
|
||||
is_byod, confidence = _byod_fallback_detect(text)
|
||||
logger.info(
|
||||
f"BYOD意图检测(兜底): is_byod={is_byod}, confidence={confidence}"
|
||||
)
|
||||
return success_response(data=ByodEligibilityResponse(
|
||||
is_byod_intent=is_byod,
|
||||
eligible=False,
|
||||
source="fallback",
|
||||
))
|
||||
|
||||
|
||||
@router.post("/byod/check-eligibility")
|
||||
async def check_byod_eligibility(
|
||||
request: ByodCheckEligibilityRequest,
|
||||
|
||||
@@ -215,6 +215,16 @@ async def cleanup_shared_services():
|
||||
logger.warning(f"AIService 连接池关闭异常: {e}")
|
||||
_shared_ai_handler = None
|
||||
|
||||
# v4.0 P1-2: 关闭 routing_service 的共享 httpx 连接池
|
||||
try:
|
||||
from app.services import routing_service
|
||||
if routing_service._routing_client and not routing_service._routing_client.is_closed:
|
||||
await routing_service._routing_client.aclose()
|
||||
routing_service._routing_client = None
|
||||
logger.info("routing_service httpx 连接池已关闭")
|
||||
except Exception as e:
|
||||
logger.warning(f"routing_service 连接池关闭异常: {e}")
|
||||
|
||||
|
||||
# Token 黑名单 Key 前缀(与 auth.py 中保持一致)
|
||||
TOKEN_BLACKLIST_PREFIX = "token:blacklist:"
|
||||
|
||||
@@ -35,6 +35,24 @@ from app.services.ws_manager import manager as ws_manager
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 共享 httpx 客户端(v4.0 P1-2:修复每次调用新建连接的泄漏问题)
|
||||
# =============================================================================
|
||||
_routing_client: Optional[httpx.AsyncClient] = None
|
||||
|
||||
|
||||
async def _get_routing_client(timeout: float) -> httpx.AsyncClient:
|
||||
"""获取共享的 httpx.AsyncClient(懒加载单例)。
|
||||
|
||||
为什么:之前每次 detect_routing_intent 调用都 `async with httpx.AsyncClient()`
|
||||
新建连接池,高并发下产生大量 TIME_WAIT 连接(与 AIService 修复前同源问题)。
|
||||
"""
|
||||
global _routing_client
|
||||
if _routing_client is None or _routing_client.is_closed:
|
||||
_routing_client = httpx.AsyncClient(timeout=httpx.Timeout(timeout))
|
||||
return _routing_client
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 路由关键词预过滤列表
|
||||
# =============================================================================
|
||||
@@ -169,24 +187,24 @@ async def detect_routing_intent(text: str, employee_id: str = "") -> dict:
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
async with httpx.AsyncClient(timeout=httpx.Timeout(timeout)) as client:
|
||||
response = await client.post(url, json=body, headers=headers)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
client = await _get_routing_client(timeout)
|
||||
response = await client.post(url, json=body, headers=headers)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
# 解析 Dify 原生响应:answer 字段包含 AI 返回的 JSON 字符串
|
||||
answer = data.get("answer", "")
|
||||
parsed = json.loads(answer)
|
||||
# 解析 Dify 原生响应:answer 字段包含 AI 返回的 JSON 字符串
|
||||
answer = data.get("answer", "")
|
||||
parsed = json.loads(answer)
|
||||
|
||||
# 解析统一意图识别的 6 个字段
|
||||
return {
|
||||
"is_approval_request": bool(parsed.get("is_approval_request", False)),
|
||||
"confidence": float(parsed.get("confidence", 0.0)),
|
||||
"approval_type": parsed.get("approval_type"),
|
||||
"intent_type": str(parsed.get("intent_type", "chitchat")),
|
||||
"business_category": parsed.get("business_category"),
|
||||
"routing_confidence": float(parsed.get("routing_confidence", 0.0)),
|
||||
}
|
||||
# 解析统一意图识别的 6 个字段
|
||||
return {
|
||||
"is_approval_request": bool(parsed.get("is_approval_request", False)),
|
||||
"confidence": float(parsed.get("confidence", 0.0)),
|
||||
"approval_type": parsed.get("approval_type"),
|
||||
"intent_type": str(parsed.get("intent_type", "chitchat")),
|
||||
"business_category": parsed.get("business_category"),
|
||||
"routing_confidence": float(parsed.get("routing_confidence", 0.0)),
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
@@ -439,33 +439,12 @@ export async function getAllCategoriesCard(): Promise<ApprovalCardData> {
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 审批意图检测 API(Dify 意图置信度 — 替代纯关键词匹配)
|
||||
// 审批意图检测 API —— v4.0 P1-2 已删除
|
||||
// =============================================================================
|
||||
|
||||
/** 审批意图检测响应 */
|
||||
export interface ApprovalDetectIntentResponse {
|
||||
/** 是否为审批请求 */
|
||||
is_approval_request: boolean
|
||||
/** 置信度(0.0~1.0) */
|
||||
confidence: number
|
||||
/** 审批类型(设备申请/账号权限申请/软件服务申请/资产处置申请/办公用品申请) */
|
||||
approval_type: string | null
|
||||
/** 结果来源:dify(Dify识别) / keyword_prefilter(关键词预过滤未命中) / fallback(降级兜底) */
|
||||
source: 'dify' | 'keyword_prefilter' | 'fallback'
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测审批意图
|
||||
* 员工发送消息后异步调用,后端先用关键词预过滤,命中后调 Dify 做意图识别。
|
||||
* 返回 is_approval_request === true 时,前端在消息列表中插入审批卡片消息。
|
||||
*
|
||||
* @param text 用户消息文本
|
||||
* @returns 审批意图检测结果
|
||||
*/
|
||||
export async function detectApprovalIntent(text: string): Promise<ApprovalDetectIntentResponse> {
|
||||
const response: any = await apiClient.post('/approval/detect-intent', { text })
|
||||
return response
|
||||
}
|
||||
// detectApprovalIntent / detectByodIntent 已删除:
|
||||
// - 前端自 v2.0 起不再独立调用 detect-intent(store 注释确认零调用)
|
||||
// - 后端 /approval/detect-intent 与 /byod/detect-intent 端点已同步删除
|
||||
// - 审批意图识别统一由主 Dify 对话链路(action 字段 + ApprovalMatcher)处理
|
||||
|
||||
/**
|
||||
* 获取软件下载列表
|
||||
@@ -482,9 +461,9 @@ export async function getSoftwareDownloads(): Promise<SoftwareDownload[]> {
|
||||
// =============================================================================
|
||||
// 自备电脑补贴(BYOD)资格查询 API
|
||||
// =============================================================================
|
||||
// 说明:提供自备电脑补贴的意图检测和资格检查功能
|
||||
// - detectByodIntent: 检测用户消息是否为 BYOD 意图(关键词预过滤 → Dify → 兜底)
|
||||
// 说明:提供自备电脑补贴的资格检查功能
|
||||
// - checkByodEligibility: 检查员工是否有资格申请自备电脑补贴
|
||||
// - BYOD 意图检测已并入主 Dify 对话链路(v4.0 P1-2 删除 detectByodIntent)
|
||||
// =============================================================================
|
||||
|
||||
/** BYOD 资格查询响应 */
|
||||
@@ -509,26 +488,6 @@ export interface ByodEligibilityResponse {
|
||||
source: 'dify' | 'keyword_prefilter' | 'fallback' | 'wecom'
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测自备电脑补贴意图
|
||||
* 员工发送消息后调用,后端先用 BYOD 关键词预过滤,命中后调 Dify 做意图识别。
|
||||
* 返回 is_byod_intent === true 时,前端应继续调用 checkByodEligibility 查询资格。
|
||||
*
|
||||
* @param text 用户消息文本
|
||||
* @param employeeId 员工ID(可选,传给 Dify 作为用户标识)
|
||||
* @returns BYOD 意图检测结果
|
||||
*/
|
||||
export async function detectByodIntent(
|
||||
text: string,
|
||||
employeeId?: string
|
||||
): Promise<ByodEligibilityResponse> {
|
||||
const response: any = await apiClient.post('/byod/detect-intent', {
|
||||
text,
|
||||
employee_id: employeeId,
|
||||
})
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查自备电脑补贴资格
|
||||
* 后端通过企微通讯录 API 获取员工岗位,与资格清单匹配后返回结果。
|
||||
|
||||
Reference in New Issue
Block a user