This commit is contained in:
2025-12-16 13:31:21 +08:00
parent 8a03ede7dc
commit ded3eddc56
14 changed files with 430 additions and 326 deletions

View File

@@ -30,6 +30,7 @@ CREATE TABLE ai.tb_chat(
chat_id VARCHAR(50) NOT NULL, -- 对话ID chat_id VARCHAR(50) NOT NULL, -- 对话ID
agent_id VARCHAR(50) NOT NULL, -- 智能体ID agent_id VARCHAR(50) NOT NULL, -- 智能体ID
user_id VARCHAR(50) NOT NULL, -- 用户ID user_id VARCHAR(50) NOT NULL, -- 用户ID
user_type BOOLEAN NOT NULL DEFAULT true, -- 用户类型 true-系统内部人员 false-系统外部人员
title VARCHAR(500) NOT NULL, -- 对话标题 title VARCHAR(500) NOT NULL, -- 对话标题
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
@@ -45,9 +46,10 @@ CREATE TABLE ai.tb_chat_message(
optsn VARCHAR(50) NOT NULL, -- 流水号 optsn VARCHAR(50) NOT NULL, -- 流水号
message_id VARCHAR(50) NOT NULL, -- 消息ID message_id VARCHAR(50) NOT NULL, -- 消息ID
chat_id VARCHAR(50) NOT NULL, -- 对话ID chat_id VARCHAR(50) NOT NULL, -- 对话ID
role VARCHAR(50) NOT NULL, -- 角色user-用户/assistant-智能体/recipient-客 role VARCHAR(50) NOT NULL, -- 角色user-用户/assistant-智能体/recipient-
content TEXT NOT NULL, -- 消息内容 content TEXT NOT NULL, -- 消息内容
files VARCHAR(50)[] DEFAULT NULL, -- 文件id数组 files VARCHAR(50)[] DEFAULT NULL, -- 文件id数组
comment VARCHAR(50) DEFAULT NULL, -- 评价
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间 create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间 update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间

View File

@@ -1,289 +1,45 @@
-- =============================
-- 智能客服系统业务模块(工单系统)
-- 支持微信小程序客户咨询、智能问答、工单管理、CRM集成
-- =============================
CREATE SCHEMA IF NOT EXISTS workcase; CREATE SCHEMA IF NOT EXISTS workcase;
-- 客户信息表 -- 系统外部人员(来客)管理 用于给系统外人员创建id
DROP TABLE IF EXISTS workcase.tb_customer CASCADE; DROP TABLE IF EXISTS workcase.tb_receptionist CASCADE;
CREATE TABLE workcase.tb_customer ( CREATE TABLE workcase.tb_receptionist(
optsn VARCHAR(50) NOT NULL, -- 流水号 optsn VARCHAR(50) NOT NULL, -- 流水号
customer_id VARCHAR(50) NOT NULL, -- 客ID user_id VARCHAR(50) NOT NULL, -- 客ID
customer_no VARCHAR(100), -- 客户编号 name VARCHAR(50) NOT NULL, -- 姓名
customer_name VARCHAR(255), -- 客户姓名 phone VARCHAR(50) NOT NULL, -- 电话
customer_type VARCHAR(30) DEFAULT 'individual', -- 客户类型individual-个人/enterprise-企业 email VARCHAR(50) NOT NULL, -- 邮箱
company_name VARCHAR(255), -- 公司名称 wechat_id VARCHAR(50) NOT NULL, -- 微信号
phone VARCHAR(20), -- 电话 create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
email VARCHAR(100), -- 邮箱 delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
wechat_openid VARCHAR(100), -- 微信OpenID deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
wechat_unionid VARCHAR(100), -- 微信UnionID PRIMARY KEY (user_id),
avatar VARCHAR(500), -- 头像URL UNIQUE (wechat_id),
gender INTEGER DEFAULT 0, -- 性别0-未知/1-男/2-女 UNIQUE (phone),
address VARCHAR(500), -- 地址 UNIQUE (email)
customer_level VARCHAR(20) DEFAULT 'normal', -- 客户等级vip/important/normal/potential
customer_source VARCHAR(50), -- 客户来源wechat-微信/web-网站/phone-电话/referral-推荐
tags TEXT[], -- 客户标签数组
notes TEXT, -- 备注
crm_customer_id VARCHAR(50), -- CRM系统客户ID外部系统
last_contact_time TIMESTAMPTZ, -- 最后联系时间
total_consultations INTEGER DEFAULT 0, -- 咨询总次数
total_orders INTEGER DEFAULT 0, -- 订单总数
total_amount DECIMAL(18,2) DEFAULT 0, -- 总消费金额
satisfaction_score DECIMAL(3,2), -- 满意度评分1-5
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
status VARCHAR(20) DEFAULT 'active', -- 状态active-活跃/inactive-非活跃/blacklist-黑名单
creator VARCHAR(50) DEFAULT NULL, -- 创建者
updater VARCHAR(50) DEFAULT NULL, -- 更新者
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (customer_id),
UNIQUE (optsn),
UNIQUE (wechat_openid),
UNIQUE (phone),
UNIQUE (email)
); );
CREATE INDEX idx_customer_type ON workcase.tb_customer(customer_type) WHERE deleted = false;
CREATE INDEX idx_customer_level ON workcase.tb_customer(customer_level) WHERE deleted = false;
CREATE INDEX idx_customer_wechat ON workcase.tb_customer(wechat_openid) WHERE deleted = false;
COMMENT ON TABLE workcase.tb_customer IS '客户信息表'; -- 客服对话记录客服对话消息包含ai、员工回答和来客提问
COMMENT ON COLUMN workcase.tb_customer.customer_level IS '客户等级vip/important/normal/potential'; -- 直接使用ai.tb_chat和ai.tb_chat_messageuser_type为false表示该对话为来客对话
-- 这里需要把在微信客服上的聊天同步到ai.tb_chat_message
-- 会话表
DROP TABLE IF EXISTS workcase.tb_conversation CASCADE;
CREATE TABLE workcase.tb_conversation (
optsn VARCHAR(50) NOT NULL, -- 流水号
conversation_id VARCHAR(50) NOT NULL, -- 会话ID
customer_id VARCHAR(50) NOT NULL, -- 客户ID
conversation_type VARCHAR(30) DEFAULT 'ai', -- 会话类型ai-AI客服/human-人工客服/transfer-转接
channel VARCHAR(20) DEFAULT 'wechat', -- 渠道wechat-微信/web-网页/app-应用/phone-电话
agent_id VARCHAR(50), -- 智能体ID或客服人员ID
agent_type VARCHAR(20) DEFAULT 'ai', -- 座席类型ai-AI/human-人工
session_start_time TIMESTAMPTZ DEFAULT now(), -- 会话开始时间
session_end_time TIMESTAMPTZ, -- 会话结束时间
duration_seconds INTEGER, -- 会话时长(秒)
message_count INTEGER DEFAULT 0, -- 消息数量
conversation_status VARCHAR(20) DEFAULT 'active', -- 会话状态active-进行中/closed-已结束/transferred-已转接/timeout-超时
satisfaction_rating INTEGER, -- 满意度评分1-5星
satisfaction_feedback TEXT, -- 满意度反馈
summary TEXT, -- 会话摘要AI生成
tags TEXT[], -- 会话标签
metadata JSONB, -- 会话元数据
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
creator VARCHAR(50) DEFAULT NULL, -- 创建者
updater VARCHAR(50) DEFAULT NULL, -- 更新者
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (conversation_id),
UNIQUE (optsn),
FOREIGN KEY (customer_id) REFERENCES workcase.tb_customer(customer_id)
);
CREATE INDEX idx_conv_customer ON workcase.tb_conversation(customer_id, session_start_time DESC) WHERE deleted = false;
CREATE INDEX idx_conv_status ON workcase.tb_conversation(conversation_status) WHERE deleted = false;
CREATE INDEX idx_conv_agent ON workcase.tb_conversation(agent_id) WHERE deleted = false;
COMMENT ON TABLE workcase.tb_conversation IS '会话表';
COMMENT ON COLUMN workcase.tb_conversation.conversation_type IS '会话类型ai/human/transfer';
-- 会话消息表
DROP TABLE IF EXISTS workcase.tb_conversation_message CASCADE;
CREATE TABLE workcase.tb_conversation_message (
optsn VARCHAR(50) NOT NULL, -- 流水号
message_id VARCHAR(50) NOT NULL, -- 消息ID
conversation_id VARCHAR(50) NOT NULL, -- 所属会话ID
sender_type VARCHAR(20) NOT NULL, -- 发送者类型customer-客户/agent-座席/system-系统
sender_id VARCHAR(50), -- 发送者ID
message_type VARCHAR(30) NOT NULL DEFAULT 'text',-- 消息类型text-文本/image-图片/voice-语音/video-视频/file-文件/card-卡片
content TEXT, -- 消息内容
content_url VARCHAR(500), -- 内容URL图片、文件等
is_ai_generated BOOLEAN DEFAULT false, -- 是否AI生成
ai_model VARCHAR(100), -- 使用的AI模型
kb_references VARCHAR(50)[], -- 引用的知识库文档ID数组
confidence_score DECIMAL(5,4), -- AI回答置信度
sentiment VARCHAR(20), -- 情感分析positive-正面/neutral-中性/negative-负面
intent VARCHAR(100), -- 意图识别结果
is_sensitive BOOLEAN DEFAULT false, -- 是否敏感信息
read_status BOOLEAN DEFAULT false, -- 已读状态
read_time TIMESTAMPTZ, -- 阅读时间
metadata JSONB, -- 消息元数据
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间(发送时间)
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (message_id),
UNIQUE (optsn),
FOREIGN KEY (conversation_id) REFERENCES workcase.tb_conversation(conversation_id)
);
CREATE INDEX idx_msg_conversation ON workcase.tb_conversation_message(conversation_id, create_time) WHERE deleted = false;
CREATE INDEX idx_msg_sender ON workcase.tb_conversation_message(sender_id) WHERE deleted = false;
COMMENT ON TABLE workcase.tb_conversation_message IS '会话消息表';
COMMENT ON COLUMN workcase.tb_conversation_message.sentiment IS '情感分析positive/neutral/negative';
-- 工单表 -- 工单表
DROP TABLE IF EXISTS workcase.tb_ticket CASCADE; DROP TABLE IF EXISTS workcase.tb_workcase CASCADE;
CREATE TABLE workcase.tb_ticket ( CREATE TABLE workcase.tb_workcase(
optsn VARCHAR(50) NOT NULL, -- 流水号 optsn VARCHAR(50) NOT NULL, -- 流水号
ticket_id VARCHAR(50) NOT NULL, -- 工单ID workcase_id VARCHAR(50) NOT NULL, -- 工单ID
ticket_no VARCHAR(100) NOT NULL, -- 工单编号 user_id VARCHAR(50) NOT NULL, -- 来客ID
customer_id VARCHAR(50) NOT NULL, -- 客户ID username VARCHAR(200) NOT NULL, -- 来客姓名
conversation_id VARCHAR(50), -- 关联会话ID phone VARCHAR(20) NOT NULL, -- 来客电话
ticket_type VARCHAR(50) NOT NULL, -- 工单类型consultation-咨询/complaint-投诉/suggestion-建议/repair-维修/installation-安装/other-其他 type VARCHAR(50) NOT NULL, -- 故障类型
ticket_category VARCHAR(100), -- 工单分类(具体业务分类) device VARCHAR(50) NOT NULL, -- 设备型号
priority VARCHAR(20) DEFAULT 'normal', -- 优先级urgent-紧急/high-高/normal-普通/low-低 emergency VARCHAR(50) NOT NULL DEFAULT 'normal', -- 紧急程度 normal-普通 emergency-紧急
title VARCHAR(500) NOT NULL, -- 工单标题 status VARCHAR(50) NOT NULL DEFAULT 'pending', -- 状态 pending-待处理 processing-处理中 done-已完成
description TEXT NOT NULL, -- 问题描述 processor VARCHAR(50) DEFAULT NULL, -- 处理人
attachments VARCHAR(50)[], -- 附件ID数组 create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
ticket_source VARCHAR(30) DEFAULT 'ai', -- 工单来源ai-AI生成/manual-人工创建/system-系统自动 update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
assigned_to VARCHAR(50), -- 分配给(处理人) delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
assigned_dept VARCHAR(50), -- 分配部门 deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
ticket_status VARCHAR(30) DEFAULT 'pending', -- 工单状态pending-待处理/processing-处理中/resolved-已解决/closed-已关闭/cancelled-已取消 PRIMARY KEY (workcase_id),
resolution TEXT, -- 解决方案 UNIQUE (optsn)
resolution_time TIMESTAMPTZ, -- 解决时间
close_time TIMESTAMPTZ, -- 关闭时间
response_time TIMESTAMPTZ, -- 首次响应时间
sla_deadline TIMESTAMPTZ, -- SLA截止时间
is_overdue BOOLEAN DEFAULT false, -- 是否逾期
customer_rating INTEGER, -- 客户评分1-5星
customer_feedback TEXT, -- 客户反馈
crm_ticket_id VARCHAR(50), -- CRM系统工单ID外部系统
sync_status VARCHAR(20) DEFAULT 'pending', -- 同步状态pending-待同步/synced-已同步/failed-失败
tags TEXT[], -- 工单标签
metadata JSONB, -- 工单元数据
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
creator VARCHAR(50) DEFAULT NULL, -- 创建者
updater VARCHAR(50) DEFAULT NULL, -- 更新者
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (ticket_id),
UNIQUE (optsn),
UNIQUE (ticket_no),
FOREIGN KEY (customer_id) REFERENCES workcase.tb_customer(customer_id)
); );
CREATE INDEX idx_ticket_customer ON workcase.tb_ticket(customer_id) WHERE deleted = false;
CREATE INDEX idx_ticket_status ON workcase.tb_ticket(ticket_status) WHERE deleted = false;
CREATE INDEX idx_ticket_assigned ON workcase.tb_ticket(assigned_to) WHERE deleted = false;
CREATE INDEX idx_ticket_priority ON workcase.tb_ticket(priority) WHERE deleted = false;
CREATE INDEX idx_ticket_sla ON workcase.tb_ticket(sla_deadline) WHERE deleted = false AND is_overdue = false;
COMMENT ON TABLE workcase.tb_ticket IS '工单表';
COMMENT ON COLUMN workcase.tb_ticket.ticket_type IS '工单类型consultation/complaint/suggestion/repair/installation/other';
-- 工单处理记录表
DROP TABLE IF EXISTS workcase.tb_ticket_log CASCADE;
CREATE TABLE workcase.tb_ticket_log (
optsn VARCHAR(50) NOT NULL, -- 流水号
log_id VARCHAR(50) NOT NULL, -- 日志ID
ticket_id VARCHAR(50) NOT NULL, -- 工单ID
action_type VARCHAR(50) NOT NULL, -- 操作类型create-创建/assign-分配/update-更新/comment-评论/resolve-解决/close-关闭/reopen-重开
action_content TEXT, -- 操作内容
old_value TEXT, -- 旧值
new_value TEXT, -- 新值
operator_id VARCHAR(50), -- 操作人ID
operator_name VARCHAR(100), -- 操作人姓名
attachments VARCHAR(50)[], -- 附件ID数组
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
PRIMARY KEY (log_id),
UNIQUE (optsn),
FOREIGN KEY (ticket_id) REFERENCES workcase.tb_ticket(ticket_id)
);
CREATE INDEX idx_ticket_log_ticket ON workcase.tb_ticket_log(ticket_id, create_time DESC);
COMMENT ON TABLE workcase.tb_ticket_log IS '工单处理记录表';
-- FAQ表常见问题
DROP TABLE IF EXISTS workcase.tb_faq CASCADE;
CREATE TABLE workcase.tb_faq (
optsn VARCHAR(50) NOT NULL, -- 流水号
faq_id VARCHAR(50) NOT NULL, -- FAQ ID
knowledge_id VARCHAR(50), -- 关联知识库ID
category VARCHAR(100) NOT NULL, -- 分类
question TEXT NOT NULL, -- 问题
answer TEXT NOT NULL, -- 答案
similar_questions TEXT[], -- 相似问题数组
keywords TEXT[], -- 关键词数组
hit_count INTEGER DEFAULT 0, -- 命中次数
helpful_count INTEGER DEFAULT 0, -- 有帮助次数
unhelpful_count INTEGER DEFAULT 0, -- 无帮助次数
is_published BOOLEAN DEFAULT false, -- 是否发布
priority INTEGER DEFAULT 0, -- 优先级
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
creator VARCHAR(50) DEFAULT NULL, -- 创建者
updater VARCHAR(50) DEFAULT NULL, -- 更新者
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (faq_id),
UNIQUE (optsn)
);
CREATE INDEX idx_faq_category ON workcase.tb_faq(category) WHERE deleted = false;
CREATE INDEX idx_faq_published ON workcase.tb_faq(is_published) WHERE deleted = false AND is_published = true;
COMMENT ON TABLE workcase.tb_faq IS 'FAQ常见问题表';
-- 客服评价表
DROP TABLE IF EXISTS workcase.tb_service_evaluation CASCADE;
CREATE TABLE workcase.tb_service_evaluation (
optsn VARCHAR(50) NOT NULL, -- 流水号
evaluation_id VARCHAR(50) NOT NULL, -- 评价ID
customer_id VARCHAR(50) NOT NULL, -- 客户ID
conversation_id VARCHAR(50), -- 会话ID
ticket_id VARCHAR(50), -- 工单ID
evaluation_type VARCHAR(30) NOT NULL, -- 评价类型conversation-会话/ticket-工单/overall-整体服务
rating INTEGER NOT NULL, -- 评分1-5星
dimensions JSONB, -- 分维度评分JSON格式响应速度、专业性、态度等
feedback TEXT, -- 评价反馈
tags TEXT[], -- 评价标签
is_anonymous BOOLEAN DEFAULT false, -- 是否匿名
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (evaluation_id),
UNIQUE (optsn),
FOREIGN KEY (customer_id) REFERENCES workcase.tb_customer(customer_id)
);
CREATE INDEX idx_eval_customer ON workcase.tb_service_evaluation(customer_id) WHERE deleted = false;
CREATE INDEX idx_eval_rating ON workcase.tb_service_evaluation(rating) WHERE deleted = false;
COMMENT ON TABLE workcase.tb_service_evaluation IS '客服评价表';
-- CRM集成配置表
DROP TABLE IF EXISTS workcase.tb_crm_config CASCADE;
CREATE TABLE workcase.tb_crm_config (
optsn VARCHAR(50) NOT NULL, -- 流水号
config_id VARCHAR(50) NOT NULL, -- 配置ID
crm_system VARCHAR(50) NOT NULL, -- CRM系统名称
api_endpoint VARCHAR(500) NOT NULL, -- API端点
api_key VARCHAR(500), -- API密钥加密存储
auth_type VARCHAR(30) DEFAULT 'api_key', -- 认证类型api_key/oauth2/basic_auth
sync_interval INTEGER DEFAULT 3600, -- 同步间隔(秒)
sync_direction VARCHAR(30) DEFAULT 'bidirectional',-- 同步方向to_crm-单向到CRM/from_crm-单向从CRM/bidirectional-双向
field_mapping JSONB, -- 字段映射配置
sync_enabled BOOLEAN DEFAULT false, -- 是否启用同步
last_sync_time TIMESTAMPTZ, -- 最后同步时间
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
creator VARCHAR(50) DEFAULT NULL, -- 创建者
updater VARCHAR(50) DEFAULT NULL, -- 更新者
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (config_id),
UNIQUE (optsn)
);
COMMENT ON TABLE workcase.tb_crm_config IS 'CRM集成配置表';

View File

@@ -1,9 +0,0 @@
package org.xyzh.api.ai;
/**
* Agent服务接口
* 用于知识库和文档管理
*/
public interface AgentService {
}

View File

@@ -19,6 +19,9 @@ public class TbChat extends BaseDTO{
@Schema(description = "用户ID") @Schema(description = "用户ID")
private String userId; private String userId;
@Schema(description = "用户类型 true-系统内部人员 false-系统外部人员")
private Boolean userType;
@Schema(description = "对话标题") @Schema(description = "对话标题")
private String title; private String title;

View File

@@ -27,4 +27,7 @@ public class TbChatMessage extends BaseDTO{
@Schema(description = "文件ID数组") @Schema(description = "文件ID数组")
private List<String> files; private List<String> files;
@Schema(description = "评价")
private String comment;
} }

View File

@@ -0,0 +1,64 @@
package org.xyzh.api.ai.service;
import java.util.List;
import java.util.Map;
import org.springframework.web.multipart.MultipartFile;
import org.xyzh.api.ai.dto.TbKnowledgeFile;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageDomain;
import org.xyzh.common.core.page.PageParam;
public interface AIFileUploadService {
// ============================ 对话文件管理 ============================
/**
* 上传文件用于对话(图文多模态)
* @param file 上传的文件
* @param agentId 智能体ID
* @return Dify文件信息包含id、name、size等
*/
ResultDomain<Map<String, Object>> uploadFileForChat(
MultipartFile file,
String agentId
);
// ============================ 知识库文件管理 ============================
/**
* 上传文件到知识库同步到Dify
* @param knowledgeId 知识库ID
* @param file 上传的文件
* @param indexingTechnique 索引方式(可选)
* @return 上传结果
*/
ResultDomain<TbKnowledgeFile> uploadToKnowledge(
String knowledgeId,
MultipartFile file,
String indexingTechnique
);
/**
* 批量上传文件到知识库
* @param knowledgeId 知识库ID
* @param files 上传的文件列表
* @param indexingTechnique 索引方式(可选)
* @return 上传结果列表
*/
ResultDomain<TbKnowledgeFile> batchUploadToKnowledge(
String knowledgeId,
List<MultipartFile> files,
String indexingTechnique
);
/**
* 同时删除Dify中的文档
* @param fileId dify的文件ID
* @return 删除结果
*/
ResultDomain<Boolean> deleteKnowledgeFile(String fileId);
}

View File

@@ -0,0 +1,98 @@
package org.xyzh.api.ai.service;
import java.util.List;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.xyzh.api.ai.dto.DifyFileInfo;
import org.xyzh.api.ai.dto.TbChat;
import org.xyzh.api.ai.dto.TbChatMessage;
import org.xyzh.common.core.domain.ResultDomain;
public interface AgentChatService {
// ====================== 智能体会话管理 ======================
/**
* 创建新会话
* @param agentId 智能体ID
* @param title 会话标题(可选)
* @return 会话信息
*/
ResultDomain<TbChat> createChat(String agentId, String title);
/**
* 更新会话名称
* @param agentId 智能体ID
* @param chatId 会话ID
* @param title 会话标题(可选)
* @return 会话信息
*/
ResultDomain<TbChat> updateChat(String agentId, String chatId, String title);
/**
* 删除会话
* @param agentId 智能体ID
* @param chatId 会话ID
* @return 会话信息
*/
ResultDomain<TbChat> deleteChat(String agentId, String chatId);
/**
* 获取会话列表
* @param agentId 智能体ID
* @return 会话列表
*/
ResultDomain<TbChat> getChatList(String agentId);
// ====================== 智能体聊天管理 ======================
/**
* 获取会话消息列表
* @param agentId 智能体ID
* @param chatId 会话ID
* @return 会话消息列表
*/
ResultDomain<TbChatMessage> getChatMessageList(String agentId, String chatId);
/**
* 准备聊天数据POST传递复杂参数
* @param agentId 智能体ID
* @param chatId 会话ID可选为空则创建新会话
* @param query 用户问题
* @param filesData 上传的文件列表Dify文件信息
* @return ResultDomain<String> 返回sessionId
*/
ResultDomain<String> prepareChatMessageSession(
String agentId,
String chatId,
String query,
List<DifyFileInfo> filesData
);
/**
* 流式对话SSE- 使用sessionId建立SSE连接 产生chatMessage
* @param sessionId 会话标识
* @return SseEmitter 流式推送对象
*/
SseEmitter streamChatMessageWithSse(String sessionId);
/**
* 停止对话生成通过Dify TaskID
* @param taskId Dify任务ID
* @param agentId 智能体ID
* @return 停止结果
*/
ResultDomain<Boolean> stopChatMessageByTaskId(String taskId, String agentId);
/**
* 评价
* @param agentId 智能体ID
* @param chatId 会话ID
* @param messageId 消息ID
* @param comment 评价
* @return 评价结果
*/
ResultDomain<Boolean> commentChatMessage(String agentId, String chatId, String messageId, String comment);
}

View File

@@ -0,0 +1,32 @@
package org.xyzh.api.ai.service;
import org.xyzh.api.ai.dto.TbAgent;
import org.xyzh.common.core.domain.ResultDomain;
/**
* Agent服务接口
* 用于知识库和文档管理
*/
public interface AgentService {
/**
* 添加Agent, 用户自己在dify搭建发布后在本服务进行接入
* @param tbAgent
* @return
*/
ResultDomain<TbAgent> addAgent(TbAgent tbAgent);
/**
* 更新Agent
* @param tbAgent
* @return
*/
ResultDomain<TbAgent> updateAgent(TbAgent tbAgent);
/**
* 删除Agent
* @param tbAgent
* @return
*/
ResultDomain<TbAgent> deleteAgent(TbAgent tbAgent);
}

View File

@@ -0,0 +1,62 @@
package org.xyzh.api.ai.service;
import java.util.Map;
import org.xyzh.common.core.domain.ResultDomain;
import com.alibaba.fastjson2.JSONObject;
/**
* @description Dify代理服务接口
* @filename DifyProxyService.java
* @author yslg
* @copyright xyzh
* @since 2025-12-15
*/
public interface DifyProxyService {
/**
* 获取某个知识库的某个文档的所有分段
* @param datasetId 数据集ID
* @param documentId 文档ID
* @return 文档分段列表
*/
ResultDomain<JSONObject> getDocumentSegments(String datasetId, String documentId);
/**
* @description 更新某个知识库的某个文档的某个分段
* @param datasetId 数据集ID
* @param documentId 文档ID
* @param segmentId 分段ID
* @param requestBody 更新请求体
* @return 更新结果
*/
ResultDomain<String> updateSegment(String datasetId, String documentId, String segmentId, Map<String, Object> requestBody);
/**
* @description 创建某个知识库的某个文档的某个分段
* @param datasetId 数据集ID
* @param documentId 文档ID
* @param requestBody 创建请求体
* @return 创建结果
*/
ResultDomain<String> createSegment(String datasetId, String documentId, Map<String, Object> requestBody);
/**
* @description 删除某个知识库的某个文档的某个分段
* @param datasetId 数据集ID
* @param documentId 文档ID
* @param segmentId 分段ID
* @return 删除结果
*/
ResultDomain<String> deleteSegment(String datasetId, String documentId, String segmentId);
/**
* @description 更新文档启用/禁用状态
* @param datasetId Dify数据集ID
* @param action 操作类型enable/disable/archive/un_archive
* @param requestBody 请求体包含document_ids数组
* @return ResultDomain<String> 更新结果
*/
ResultDomain<String> updateDocumentStatus(String datasetId, String action, Map<String, Object> requestBody);
}

View File

@@ -0,0 +1,124 @@
package org.xyzh.api.ai.service;
import java.util.List;
import java.util.Map;
import org.xyzh.api.ai.dto.TbKnowledge;
import org.xyzh.api.ai.dto.TbKnowledgeFile;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageParam;
public interface KnowledgeService {
// ================================= 知识库管理 =================================
/**
* 创建知识库同步到Dify
* @param knowledge 知识库信息
* @param permissionType 权限类型PUBLIC-公开DEPARTMENT-部门ROLE-角色PRIVATE-私有
* @param deptIds 部门ID列表DEPARTMENT类型需要
* @param roleIds 角色ID列表ROLE/PRIVATE类型需要
* @return 创建结果
*/
ResultDomain<TbKnowledge> createKnowledge(
TbKnowledge knowledge,
String permissionType,
List<String> deptIds,
List<String> roleIds
);
/**
* 更新知识库
* @param knowledge 知识库信息
* @return 更新结果
*/
ResultDomain<TbKnowledge> updateKnowledge(TbKnowledge knowledge);
/**
* 删除知识库同时删除Dify中的知识库
* @param knowledgeId 知识库ID
* @return 删除结果
*/
ResultDomain<Boolean> deleteKnowledge(String knowledgeId);
/**
* 根据ID查询知识库带权限校验
* @param knowledgeId 知识库ID
* @return 知识库信息
*/
ResultDomain<TbKnowledge> getKnowledgeById(String knowledgeId);
/**
* 查询用户有权限的知识库列表
* @param filter 过滤条件
* @return 知识库列表
*/
ResultDomain<TbKnowledge> listKnowledges(TbKnowledge filter);
/**
* 分页查询知识库
* @param filter 过滤条件
* @param pageParam 分页参数
* @return 分页结果
*/
ResultDomain<TbKnowledge> pageKnowledges(TbKnowledge filter, PageParam pageParam);
/**
* 查询知识库的文档数量和分段数量从Dify同步
* @param knowledgeId 知识库ID
* @return 统计信息
*/
ResultDomain<TbKnowledge> getKnowledgeStats(String knowledgeId);
/**
* 获取可用的嵌入模型列表
* @return 嵌入模型列表
*/
ResultDomain<Map<String, Object>> getAvailableEmbeddingModels();
/**
* 获取可用的Rerank模型列表
* @return Rerank模型列表
*/
ResultDomain<Map<String, Object>> getAvailableRerankModels();
/**
* 获取Dify知识库文档列表
* @param knowledgeId 知识库ID
* @param page 页码从1开始
* @param limit 每页数量
* @return 文档列表
*/
ResultDomain<Map<String, Object>> getDocumentList(String knowledgeId, Integer page, Integer limit);
// ================================= 文件管理 =================================
/**
* 添加知识库文件
* @param knowledgeFile 文件信息
* @return 添加结果
*/
ResultDomain<TbKnowledgeFile> addKnowledgeFile(TbKnowledgeFile knowledgeFile);
/**
* 更新知识库文件, 产生一个新version 删除dify中旧版本的文件的document并上传新文件重新索引
* @param knowledgeFile 文件信息
* @return 更新结果
*/
ResultDomain<TbKnowledgeFile> updateKnowledgeFile(TbKnowledgeFile knowledgeFile);
/**
* 删除知识库文件
* @param knowledgeFile 文件信息
* @return 删除结果
*/
ResultDomain<TbKnowledgeFile> deleteKnowledgeFile(TbKnowledgeFile knowledgeFile);
/**
* @description 获取一个文件的所有历史版本
* @param fileId 文件ID
* @author yslg
* @since 2025-12-15
*/
ResultDomain<TbKnowledgeFile> getKnowledgeFileHistory(String fileId);
}

View File

@@ -1,12 +0,0 @@
package org.xyzh.api.ai.vo;
import org.xyzh.common.vo.BaseVO;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
@Data
@Schema(description = "智能体VO")
public class AgentVO extends BaseVO{
}

View File

@@ -5399,7 +5399,7 @@
"vue-router": "^4.5.0" "vue-router": "^4.5.0"
}, },
"devDependencies": { "devDependencies": {
"@module-federation/vite": "^1.0.10", "@module-federation/vite": "^1.9.3",
"@types/node": "^22.0.0", "@types/node": "^22.0.0",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
"@vitejs/plugin-vue-jsx": "^4.1.1", "@vitejs/plugin-vue-jsx": "^4.1.1",
@@ -6901,6 +6901,7 @@
"vue-router": "^4.5.0" "vue-router": "^4.5.0"
}, },
"devDependencies": { "devDependencies": {
"@module-federation/vite": "^1.9.3",
"@types/node": "^22.0.0", "@types/node": "^22.0.0",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
"@vitejs/plugin-vue-jsx": "^4.1.1", "@vitejs/plugin-vue-jsx": "^4.1.1",

View File

@@ -48,16 +48,6 @@
<main class="main-content"> <main class="main-content">
<!-- iframe 模式 --> <!-- iframe 模式 -->
<div v-if="currentIframeUrl" class="iframe-container"> <div v-if="currentIframeUrl" class="iframe-container">
<div class="iframe-header">
<span class="iframe-title">{{ currentMenuItem?.label }}</span>
<el-button
text
@click="handleRefreshIframe"
:icon="Refresh"
>
刷新
</el-button>
</div>
<iframe <iframe
ref="iframeRef" ref="iframeRef"
:src="currentIframeUrl" :src="currentIframeUrl"
@@ -200,7 +190,7 @@ const handleMenuClick = (item: MenuItem) => {
// 所有菜单都通过路由跳转 // 所有菜单都通过路由跳转
if (item.url) { if (item.url) {
router.push(item.url) router.push(item.url)
if (item.type === 'iframe') { if (item.viewType === 'iframe') {
iframeLoading.value = true iframeLoading.value = true
} }
} }

View File

@@ -61,16 +61,6 @@
<main class="main-content"> <main class="main-content">
<!-- iframe 模式 --> <!-- iframe 模式 -->
<div v-if="currentIframeUrl" class="iframe-container"> <div v-if="currentIframeUrl" class="iframe-container">
<div class="iframe-header">
<span class="iframe-title">{{ currentMenuItem?.label }}</span>
<el-button
text
@click="handleRefreshIframe"
:icon="Refresh"
>
刷新
</el-button>
</div>
<iframe <iframe
ref="iframeRef" ref="iframeRef"
:src="currentIframeUrl" :src="currentIframeUrl"