ai模块修改
This commit is contained in:
24
urbanLifelineServ/ai/src/main/java/org/xyzh/ai/AgentApp.java
Normal file
24
urbanLifelineServ/ai/src/main/java/org/xyzh/ai/AgentApp.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package org.xyzh.ai;
|
||||
|
||||
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableDubbo // 启用 Dubbo 服务
|
||||
@ComponentScan(basePackages = {
|
||||
"org.xyzh.agent", // 当前agent模块
|
||||
"org.xyzh.common" // 公共模块
|
||||
})
|
||||
public class AgentApp {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AgentApp.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
logger.info("======================== AgentApp 启动中 =========================");
|
||||
SpringApplication.run(AgentApp.class, args);
|
||||
logger.info("======================== AgentApp 启动成功 =========================");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
package org.xyzh.ai.client.callback;
|
||||
|
||||
/**
|
||||
* @description 流式响应回调接口
|
||||
* @filename StreamCallback.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
public interface StreamCallback {
|
||||
|
||||
/**
|
||||
* 接收到消息片段
|
||||
* @param message 消息内容
|
||||
*/
|
||||
void onMessage(String message);
|
||||
|
||||
/**
|
||||
* 消息结束(包含元数据)
|
||||
* @param metadata JSON格式的元数据
|
||||
*/
|
||||
void onMessageEnd(String metadata);
|
||||
|
||||
/**
|
||||
* 接收到Dify原始事件(用于转发完整事件数据)
|
||||
* @param eventType 事件类型(如workflow_started、node_started等)
|
||||
* @param eventData 完整的事件JSON数据
|
||||
*/
|
||||
default void onEvent(String eventType, String eventData) {
|
||||
// 默认实现:不处理
|
||||
}
|
||||
|
||||
/**
|
||||
* 流式响应完成
|
||||
*/
|
||||
void onComplete();
|
||||
|
||||
/**
|
||||
* 发生错误
|
||||
* @param error 错误对象
|
||||
*/
|
||||
void onError(Throwable error);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.xyzh.api.ai.dto.DifyFileInfo;
|
||||
|
||||
/**
|
||||
* @description 对话请求
|
||||
* @filename ChatRequest.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-12-15
|
||||
*/
|
||||
@Data
|
||||
public class ChatRequest {
|
||||
|
||||
/**
|
||||
* 输入变量
|
||||
*/
|
||||
private Map<String, Object> inputs;
|
||||
|
||||
/**
|
||||
* 用户问题
|
||||
*/
|
||||
private String query;
|
||||
|
||||
/**
|
||||
* 响应模式:streaming(流式)、blocking(阻塞)
|
||||
*/
|
||||
@JSONField(name = "response_mode")
|
||||
private String responseMode = "streaming";
|
||||
|
||||
/**
|
||||
* 对话ID(继续对话时传入)
|
||||
*/
|
||||
@JSONField(name = "conversation_id")
|
||||
private String conversationId;
|
||||
|
||||
/**
|
||||
* 用户标识
|
||||
*/
|
||||
private String user;
|
||||
|
||||
/**
|
||||
* 上传的文件列表
|
||||
*/
|
||||
private List<DifyFileInfo> files;
|
||||
|
||||
/**
|
||||
* 自动生成标题
|
||||
*/
|
||||
@JSONField(name = "auto_generate_name")
|
||||
private Boolean autoGenerateName = true;
|
||||
|
||||
/**
|
||||
* 指定的数据集ID列表(知识库检索)
|
||||
*/
|
||||
@JSONField(name = "dataset_ids")
|
||||
private List<String> datasetIds;
|
||||
|
||||
/**
|
||||
* 温度参数(0.0-1.0)
|
||||
*/
|
||||
private Double temperature;
|
||||
|
||||
/**
|
||||
* 最大token数
|
||||
*/
|
||||
@JSONField(name = "max_tokens")
|
||||
private Integer maxTokens;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description 对话响应(阻塞模式)
|
||||
* @filename ChatResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class ChatResponse {
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
@JSONField(name = "message_id")
|
||||
private String messageId;
|
||||
|
||||
/**
|
||||
* 对话ID
|
||||
*/
|
||||
@JSONField(name = "conversation_id")
|
||||
private String conversationId;
|
||||
|
||||
/**
|
||||
* 模式
|
||||
*/
|
||||
private String mode;
|
||||
|
||||
/**
|
||||
* 回答内容
|
||||
*/
|
||||
private String answer;
|
||||
|
||||
/**
|
||||
* 元数据
|
||||
*/
|
||||
private Map<String, Object> metadata;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JSONField(name = "created_at")
|
||||
private Long createdAt;
|
||||
|
||||
/**
|
||||
* Token使用情况
|
||||
*/
|
||||
private Usage usage;
|
||||
|
||||
/**
|
||||
* 检索信息
|
||||
*/
|
||||
@JSONField(name = "retrieval_info")
|
||||
private List<RetrievalInfo> retrievalInfo;
|
||||
|
||||
@Data
|
||||
public static class Usage {
|
||||
@JSONField(name = "prompt_tokens")
|
||||
private Integer promptTokens;
|
||||
|
||||
@JSONField(name = "prompt_unit_price")
|
||||
private String promptUnitPrice;
|
||||
|
||||
@JSONField(name = "prompt_price_unit")
|
||||
private String promptPriceUnit;
|
||||
|
||||
@JSONField(name = "prompt_price")
|
||||
private String promptPrice;
|
||||
|
||||
@JSONField(name = "completion_tokens")
|
||||
private Integer completionTokens;
|
||||
|
||||
@JSONField(name = "completion_unit_price")
|
||||
private String completionUnitPrice;
|
||||
|
||||
@JSONField(name = "completion_price_unit")
|
||||
private String completionPriceUnit;
|
||||
|
||||
@JSONField(name = "completion_price")
|
||||
private String completionPrice;
|
||||
|
||||
@JSONField(name = "total_tokens")
|
||||
private Integer totalTokens;
|
||||
|
||||
@JSONField(name = "total_price")
|
||||
private String totalPrice;
|
||||
|
||||
private String currency;
|
||||
|
||||
private Double latency;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class RetrievalInfo {
|
||||
@JSONField(name = "dataset_id")
|
||||
private String datasetId;
|
||||
|
||||
@JSONField(name = "dataset_name")
|
||||
private String datasetName;
|
||||
|
||||
@JSONField(name = "document_id")
|
||||
private String documentId;
|
||||
|
||||
@JSONField(name = "document_name")
|
||||
private String documentName;
|
||||
|
||||
@JSONField(name = "segment_id")
|
||||
private String segmentId;
|
||||
|
||||
private Double score;
|
||||
|
||||
private String content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
|
||||
/**
|
||||
* @description 对话列表响应
|
||||
* @filename ConversationListResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class ConversationListResponse {
|
||||
|
||||
private Integer limit;
|
||||
|
||||
@JSONField(name = "has_more")
|
||||
private Boolean hasMore;
|
||||
|
||||
private List<ConversationInfo> data;
|
||||
|
||||
@Data
|
||||
public static class ConversationInfo {
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private List<InputInfo> inputs;
|
||||
|
||||
private String status;
|
||||
|
||||
private String introduction;
|
||||
|
||||
@JSONField(name = "created_at")
|
||||
private Long createdAt;
|
||||
|
||||
@JSONField(name = "updated_at")
|
||||
private Long updatedAt;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class InputInfo {
|
||||
private String key;
|
||||
private String value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description 创建知识库请求
|
||||
* @filename DatasetCreateRequest.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class DatasetCreateRequest {
|
||||
|
||||
/**
|
||||
* 知识库名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 知识库描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 索引方式:high_quality(高质量)、economy(经济)
|
||||
*/
|
||||
@JSONField(name = "indexing_technique")
|
||||
private String indexingTechnique = "high_quality";
|
||||
|
||||
/**
|
||||
* Embedding模型
|
||||
*/
|
||||
@JSONField(name = "embedding_model")
|
||||
private String embeddingModel;
|
||||
|
||||
/**
|
||||
* Embedding模型提供商
|
||||
*/
|
||||
@JSONField(name = "embedding_model_provider")
|
||||
private String embeddingModelProvider;
|
||||
|
||||
/**
|
||||
* 检索模型配置(包含 Rerank、Top K、Score 阈值等)
|
||||
*/
|
||||
@JSONField(name = "retrieval_model")
|
||||
private RetrievalModel retrievalModel;
|
||||
|
||||
/**
|
||||
* 权限:only_me(仅自己)、all_team_members(团队所有成员)
|
||||
*/
|
||||
private String permission = "only_me";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description 创建知识库响应
|
||||
* @filename DatasetCreateResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class DatasetCreateResponse {
|
||||
|
||||
/**
|
||||
* 知识库ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 知识库名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 索引方式
|
||||
*/
|
||||
@JSONField(name = "indexing_technique")
|
||||
private String indexingTechnique;
|
||||
|
||||
/**
|
||||
* Embedding模型
|
||||
*/
|
||||
@JSONField(name = "embedding_model")
|
||||
private String embeddingModel;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JSONField(name = "created_at")
|
||||
private Long createdAt;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@JSONField(name = "created_by")
|
||||
private String createdBy;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description 知识库详情响应
|
||||
* @filename DatasetDetailResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class DatasetDetailResponse {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
@JSONField(name = "indexing_technique")
|
||||
private String indexingTechnique;
|
||||
|
||||
@JSONField(name = "embedding_model")
|
||||
private String embeddingModel;
|
||||
|
||||
@JSONField(name = "embedding_model_provider")
|
||||
private String embeddingModelProvider;
|
||||
|
||||
@JSONField(name = "embedding_available")
|
||||
private Boolean embeddingAvailable;
|
||||
|
||||
@JSONField(name = "retrieval_model_dict")
|
||||
private RetrievalModelDict retrievalModelDict;
|
||||
|
||||
@JSONField(name = "document_count")
|
||||
private Integer documentCount;
|
||||
|
||||
@JSONField(name = "word_count")
|
||||
private Integer wordCount;
|
||||
|
||||
@JSONField(name = "app_count")
|
||||
private Integer appCount;
|
||||
|
||||
@JSONField(name = "created_by")
|
||||
private String createdBy;
|
||||
|
||||
@JSONField(name = "created_at")
|
||||
private Long createdAt;
|
||||
|
||||
@JSONField(name = "updated_at")
|
||||
private Long updatedAt;
|
||||
|
||||
@Data
|
||||
public static class RetrievalModelDict {
|
||||
@JSONField(name = "search_method")
|
||||
private String searchMethod;
|
||||
|
||||
@JSONField(name = "reranking_enable")
|
||||
private Boolean rerankingEnable;
|
||||
|
||||
@JSONField(name = "reranking_model")
|
||||
private RerankingModel rerankingModel;
|
||||
|
||||
@JSONField(name = "top_k")
|
||||
private Integer topK;
|
||||
|
||||
@JSONField(name = "score_threshold_enabled")
|
||||
private Boolean scoreThresholdEnabled;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class RerankingModel {
|
||||
@JSONField(name = "reranking_provider_name")
|
||||
private String rerankingProviderName;
|
||||
|
||||
@JSONField(name = "reranking_model_name")
|
||||
private String rerankingModelName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 知识库列表响应
|
||||
* @filename DatasetListResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class DatasetListResponse {
|
||||
|
||||
/**
|
||||
* 知识库列表
|
||||
*/
|
||||
private List<DatasetInfo> data;
|
||||
|
||||
/**
|
||||
* 是否有更多
|
||||
*/
|
||||
@JSONField(name = "has_more")
|
||||
private Boolean hasMore;
|
||||
|
||||
/**
|
||||
* 分页限制
|
||||
*/
|
||||
private Integer limit;
|
||||
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
private Integer total;
|
||||
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
private Integer page;
|
||||
|
||||
@Data
|
||||
public static class DatasetInfo {
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
private String permission;
|
||||
@JSONField(name = "document_count")
|
||||
private Integer documentCount;
|
||||
@JSONField(name = "word_count")
|
||||
private Integer wordCount;
|
||||
@JSONField(name = "created_by")
|
||||
private String createdBy;
|
||||
@JSONField(name = "created_at")
|
||||
private Long createdAt;
|
||||
@JSONField(name = "updated_at")
|
||||
private Long updatedAt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description Dify知识库更新请求
|
||||
* @filename DatasetUpdateRequest.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class DatasetUpdateRequest {
|
||||
|
||||
/**
|
||||
* 知识库名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 知识库描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 索引方式(high_quality/economy)
|
||||
*/
|
||||
@JSONField(name = "indexing_technique")
|
||||
private String indexingTechnique;
|
||||
|
||||
/**
|
||||
* Embedding模型
|
||||
*/
|
||||
@JSONField(name = "embedding_model")
|
||||
private String embeddingModel;
|
||||
|
||||
/**
|
||||
* Embedding模型提供商
|
||||
*/
|
||||
@JSONField(name = "embedding_model_provider")
|
||||
private String embeddingModelProvider;
|
||||
|
||||
/**
|
||||
* 检索模型配置(包含 Rerank、Top K、Score 阈值等)
|
||||
*/
|
||||
@JSONField(name = "retrieval_model")
|
||||
private RetrievalModel retrievalModel;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description Dify文档列表响应
|
||||
* @filename DocumentListResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-07
|
||||
*/
|
||||
@Data
|
||||
public class DocumentListResponse {
|
||||
|
||||
private List<Document> data;
|
||||
|
||||
@JSONField(name = "has_more")
|
||||
private Boolean hasMore;
|
||||
|
||||
private Integer limit;
|
||||
|
||||
private Integer total;
|
||||
|
||||
private Integer page;
|
||||
|
||||
/**
|
||||
* 文档信息
|
||||
*/
|
||||
@Data
|
||||
public static class Document {
|
||||
private String id;
|
||||
|
||||
private Integer position;
|
||||
|
||||
@JSONField(name = "data_source_type")
|
||||
private String dataSourceType;
|
||||
|
||||
@JSONField(name = "data_source_info")
|
||||
private DataSourceInfo dataSourceInfo;
|
||||
|
||||
@JSONField(name = "dataset_process_rule_id")
|
||||
private String datasetProcessRuleId;
|
||||
|
||||
private String name;
|
||||
|
||||
@JSONField(name = "created_from")
|
||||
private String createdFrom;
|
||||
|
||||
@JSONField(name = "created_by")
|
||||
private String createdBy;
|
||||
|
||||
@JSONField(name = "created_at")
|
||||
private Long createdAt;
|
||||
|
||||
private Integer tokens;
|
||||
|
||||
@JSONField(name = "indexing_status")
|
||||
private String indexingStatus;
|
||||
|
||||
private String error;
|
||||
|
||||
private Boolean enabled;
|
||||
|
||||
@JSONField(name = "disabled_at")
|
||||
private Long disabledAt;
|
||||
|
||||
@JSONField(name = "disabled_by")
|
||||
private String disabledBy;
|
||||
|
||||
private Boolean archived;
|
||||
|
||||
@JSONField(name = "display_status")
|
||||
private String displayStatus;
|
||||
|
||||
@JSONField(name = "word_count")
|
||||
private Integer wordCount;
|
||||
|
||||
@JSONField(name = "hit_count")
|
||||
private Integer hitCount;
|
||||
|
||||
@JSONField(name = "doc_form")
|
||||
private String docForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据源信息
|
||||
*/
|
||||
@Data
|
||||
public static class DataSourceInfo {
|
||||
@JSONField(name = "upload_file_id")
|
||||
private String uploadFileId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 文档处理状态响应
|
||||
* @filename DocumentStatusResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class DocumentStatusResponse {
|
||||
|
||||
/**
|
||||
* 文档列表
|
||||
*/
|
||||
private List<DocumentStatus> data;
|
||||
|
||||
@Data
|
||||
public static class DocumentStatus {
|
||||
/**
|
||||
* 文档ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 索引状态:waiting、parsing、cleaning、splitting、indexing、completed、error
|
||||
*/
|
||||
@JSONField(name = "indexing_status")
|
||||
private String indexingStatus;
|
||||
|
||||
/**
|
||||
* 处理开始时间
|
||||
*/
|
||||
@JSONField(name = "processing_started_at")
|
||||
private Long processingStartedAt;
|
||||
|
||||
/**
|
||||
* 解析完成时间
|
||||
*/
|
||||
@JSONField(name = "parsing_completed_at")
|
||||
private Long parsingCompletedAt;
|
||||
|
||||
/**
|
||||
* 清洗完成时间
|
||||
*/
|
||||
@JSONField(name = "cleaning_completed_at")
|
||||
private Long cleaningCompletedAt;
|
||||
|
||||
/**
|
||||
* 分割完成时间
|
||||
*/
|
||||
@JSONField(name = "splitting_completed_at")
|
||||
private Long splittingCompletedAt;
|
||||
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
@JSONField(name = "completed_at")
|
||||
private Long completedAt;
|
||||
|
||||
/**
|
||||
* 暂停时间
|
||||
*/
|
||||
@JSONField(name = "paused_at")
|
||||
private Long pausedAt;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String error;
|
||||
|
||||
/**
|
||||
* 停止时间
|
||||
*/
|
||||
@JSONField(name = "stopped_at")
|
||||
private Long stoppedAt;
|
||||
|
||||
/**
|
||||
* 分段数量
|
||||
*/
|
||||
@JSONField(name = "completed_segments")
|
||||
private Integer completedSegments;
|
||||
|
||||
/**
|
||||
* 总分段数
|
||||
*/
|
||||
@JSONField(name = "total_segments")
|
||||
private Integer totalSegments;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description 文档上传请求
|
||||
* @filename DocumentUploadRequest.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class DocumentUploadRequest {
|
||||
|
||||
/**
|
||||
* 文档名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 索引方式
|
||||
*/
|
||||
@JSONField(name = "indexing_technique")
|
||||
private String indexingTechnique;
|
||||
|
||||
/**
|
||||
* 处理规则
|
||||
*/
|
||||
@JSONField(name = "process_rule")
|
||||
private ProcessRule processRule;
|
||||
|
||||
@Data
|
||||
public static class ProcessRule {
|
||||
/**
|
||||
* 分段模式:automatic(自动)、custom(自定义)
|
||||
*/
|
||||
private String mode = "automatic";
|
||||
|
||||
/**
|
||||
* 预处理规则
|
||||
*/
|
||||
private Rules rules;
|
||||
|
||||
@Data
|
||||
public static class Rules {
|
||||
/**
|
||||
* 自动分段配置
|
||||
*/
|
||||
@JSONField(name = "pre_processing_rules")
|
||||
private PreProcessingRules preProcessingRules;
|
||||
|
||||
/**
|
||||
* 分段配置
|
||||
*/
|
||||
private Segmentation segmentation;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class PreProcessingRules {
|
||||
/**
|
||||
* 移除额外空格
|
||||
*/
|
||||
@JSONField(name = "remove_extra_spaces")
|
||||
private Boolean removeExtraSpaces = true;
|
||||
|
||||
/**
|
||||
* 移除URL和邮箱
|
||||
*/
|
||||
@JSONField(name = "remove_urls_emails")
|
||||
private Boolean removeUrlsEmails = false;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Segmentation {
|
||||
/**
|
||||
* 分隔符
|
||||
*/
|
||||
private String separator = "\\n";
|
||||
|
||||
/**
|
||||
* 最大分段长度
|
||||
*/
|
||||
@JSONField(name = "max_tokens")
|
||||
private Integer maxTokens = 1000;
|
||||
|
||||
/**
|
||||
* 分段重叠长度
|
||||
*/
|
||||
@JSONField(name = "chunk_overlap")
|
||||
private Integer chunkOverlap = 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description 文档上传响应(根据 Dify API 返回结构)
|
||||
* @filename DocumentUploadResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class DocumentUploadResponse {
|
||||
|
||||
/**
|
||||
* 文档详细信息
|
||||
*/
|
||||
private Document document;
|
||||
|
||||
/**
|
||||
* 批次ID(用于查询处理状态)
|
||||
*/
|
||||
private String batch;
|
||||
|
||||
/**
|
||||
* 文档详细信息
|
||||
*/
|
||||
@Data
|
||||
public static class Document {
|
||||
/**
|
||||
* 文档ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 文档名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 位置(序号)
|
||||
*/
|
||||
private Integer position;
|
||||
|
||||
/**
|
||||
* 数据源类型
|
||||
*/
|
||||
@JSONField(name = "data_source_type")
|
||||
private String dataSourceType;
|
||||
|
||||
/**
|
||||
* 数据源信息
|
||||
*/
|
||||
@JSONField(name = "data_source_info")
|
||||
private Object dataSourceInfo;
|
||||
|
||||
/**
|
||||
* 数据集处理规则ID
|
||||
*/
|
||||
@JSONField(name = "dataset_process_rule_id")
|
||||
private String datasetProcessRuleId;
|
||||
|
||||
/**
|
||||
* 创建来源
|
||||
*/
|
||||
@JSONField(name = "created_from")
|
||||
private String createdFrom;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@JSONField(name = "created_by")
|
||||
private String createdBy;
|
||||
|
||||
/**
|
||||
* 创建时间(时间戳)
|
||||
*/
|
||||
@JSONField(name = "created_at")
|
||||
private Long createdAt;
|
||||
|
||||
/**
|
||||
* Token数量
|
||||
*/
|
||||
private Integer tokens;
|
||||
|
||||
/**
|
||||
* 索引状态
|
||||
*/
|
||||
@JSONField(name = "indexing_status")
|
||||
private String indexingStatus;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String error;
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 禁用时间
|
||||
*/
|
||||
@JSONField(name = "disabled_at")
|
||||
private Long disabledAt;
|
||||
|
||||
/**
|
||||
* 禁用人
|
||||
*/
|
||||
@JSONField(name = "disabled_by")
|
||||
private String disabledBy;
|
||||
|
||||
/**
|
||||
* 是否归档
|
||||
*/
|
||||
private Boolean archived;
|
||||
|
||||
/**
|
||||
* 显示状态
|
||||
*/
|
||||
@JSONField(name = "display_status")
|
||||
private String displayStatus;
|
||||
|
||||
/**
|
||||
* 字数
|
||||
*/
|
||||
@JSONField(name = "word_count")
|
||||
private Integer wordCount;
|
||||
|
||||
/**
|
||||
* 命中次数
|
||||
*/
|
||||
@JSONField(name = "hit_count")
|
||||
private Integer hitCount;
|
||||
|
||||
/**
|
||||
* 文档形式
|
||||
*/
|
||||
@JSONField(name = "doc_form")
|
||||
private String docForm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description Dify嵌入模型响应
|
||||
* @filename EmbeddingModelResponse.java
|
||||
* @author AI Assistant
|
||||
* @since 2025-11-06
|
||||
*/
|
||||
@Data
|
||||
public class EmbeddingModelResponse {
|
||||
|
||||
/**
|
||||
* 模型提供商列表
|
||||
*/
|
||||
@JSONField(name = "data")
|
||||
private List<ModelProvider> data;
|
||||
|
||||
/**
|
||||
* 模型提供商
|
||||
*/
|
||||
@Data
|
||||
public static class ModelProvider {
|
||||
/**
|
||||
* 提供商标识
|
||||
*/
|
||||
@JSONField(name = "provider")
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* 提供商标签
|
||||
*/
|
||||
@JSONField(name = "label")
|
||||
private Map<String, String> label;
|
||||
|
||||
/**
|
||||
* 小图标
|
||||
*/
|
||||
@JSONField(name = "icon_small")
|
||||
private Map<String, String> iconSmall;
|
||||
|
||||
/**
|
||||
* 大图标
|
||||
*/
|
||||
@JSONField(name = "icon_large")
|
||||
private Map<String, String> iconLarge;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@JSONField(name = "status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 模型列表
|
||||
*/
|
||||
@JSONField(name = "models")
|
||||
private List<Model> models;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模型详情
|
||||
*/
|
||||
@Data
|
||||
public static class Model {
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
@JSONField(name = "model")
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 模型标签
|
||||
*/
|
||||
@JSONField(name = "label")
|
||||
private Map<String, String> label;
|
||||
|
||||
/**
|
||||
* 模型类型
|
||||
*/
|
||||
@JSONField(name = "model_type")
|
||||
private String modelType;
|
||||
|
||||
/**
|
||||
* 特性列表
|
||||
*/
|
||||
@JSONField(name = "features")
|
||||
private List<Object> features;
|
||||
|
||||
/**
|
||||
* 获取来源
|
||||
*/
|
||||
@JSONField(name = "fetch_from")
|
||||
private String fetchFrom;
|
||||
|
||||
/**
|
||||
* 模型属性
|
||||
*/
|
||||
@JSONField(name = "model_properties")
|
||||
private ModelProperties modelProperties;
|
||||
|
||||
/**
|
||||
* 是否已弃用
|
||||
*/
|
||||
@JSONField(name = "deprecated")
|
||||
private Boolean deprecated;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@JSONField(name = "status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 是否启用负载均衡
|
||||
*/
|
||||
@JSONField(name = "load_balancing_enabled")
|
||||
private Boolean loadBalancingEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模型属性
|
||||
*/
|
||||
@Data
|
||||
public static class ModelProperties {
|
||||
/**
|
||||
* 上下文大小
|
||||
*/
|
||||
@JSONField(name = "context_size")
|
||||
private Integer contextSize;
|
||||
|
||||
/**
|
||||
* 最大分块数
|
||||
*/
|
||||
@JSONField(name = "max_chunks")
|
||||
private Integer maxChunks;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 消息历史响应
|
||||
* @filename MessageHistoryResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class MessageHistoryResponse {
|
||||
|
||||
private Integer limit;
|
||||
|
||||
@JSONField(name = "has_more")
|
||||
private Boolean hasMore;
|
||||
|
||||
private List<MessageInfo> data;
|
||||
|
||||
@Data
|
||||
public static class MessageInfo {
|
||||
private String id;
|
||||
|
||||
@JSONField(name = "conversation_id")
|
||||
private String conversationId;
|
||||
|
||||
private List<MessageContent> inputs;
|
||||
|
||||
private String query;
|
||||
|
||||
private String answer;
|
||||
|
||||
@JSONField(name = "message_files")
|
||||
private List<MessageFile> messageFiles;
|
||||
|
||||
private Feedback feedback;
|
||||
|
||||
@JSONField(name = "retriever_resources")
|
||||
private List<RetrieverResource> retrieverResources;
|
||||
|
||||
@JSONField(name = "created_at")
|
||||
private Long createdAt;
|
||||
|
||||
@JSONField(name = "agent_thoughts")
|
||||
private List<Object> agentThoughts;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MessageContent {
|
||||
private String key;
|
||||
private String value;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MessageFile {
|
||||
private String id;
|
||||
private String type;
|
||||
private String url;
|
||||
@JSONField(name = "belongs_to")
|
||||
private String belongsTo;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Feedback {
|
||||
private String rating;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class RetrieverResource {
|
||||
@JSONField(name = "dataset_id")
|
||||
private String datasetId;
|
||||
|
||||
@JSONField(name = "dataset_name")
|
||||
private String datasetName;
|
||||
|
||||
@JSONField(name = "document_id")
|
||||
private String documentId;
|
||||
|
||||
@JSONField(name = "document_name")
|
||||
private String documentName;
|
||||
|
||||
@JSONField(name = "segment_id")
|
||||
private String segmentId;
|
||||
|
||||
private Double score;
|
||||
|
||||
private String content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description Dify Rerank模型响应
|
||||
* @filename RerankModelResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-06
|
||||
*/
|
||||
@Data
|
||||
public class RerankModelResponse {
|
||||
private List<ModelProvider> data;
|
||||
|
||||
@Data
|
||||
public static class ModelProvider {
|
||||
private String provider;
|
||||
private Map<String, String> label; // e.g., {"en_US": "Cohere", "zh_Hans": "Cohere"}
|
||||
@JSONField(name = "icon_small")
|
||||
private String iconSmall;
|
||||
@JSONField(name = "icon_large")
|
||||
private String iconLarge;
|
||||
private String status; // e.g., "active"
|
||||
private List<Model> models;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Model {
|
||||
private String model; // e.g., "rerank-multilingual-v3.0"
|
||||
private Map<String, String> label;
|
||||
@JSONField(name = "model_type")
|
||||
private String modelType; // e.g., "rerank"
|
||||
private List<String> features;
|
||||
@JSONField(name = "fetch_from")
|
||||
private String fetchFrom;
|
||||
@JSONField(name = "model_properties")
|
||||
private ModelProperties modelProperties;
|
||||
private Boolean deprecated;
|
||||
private String status; // e.g., "active"
|
||||
private String provider; // 模型提供商(可能在 model 数据中)
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class ModelProperties {
|
||||
@JSONField(name = "context_size")
|
||||
private Integer contextSize;
|
||||
@JSONField(name = "max_chunks")
|
||||
private Integer maxChunks;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description Dify检索模型配置(Retrieval Model)
|
||||
* @filename RetrievalModel.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-06
|
||||
*/
|
||||
@Data
|
||||
public class RetrievalModel {
|
||||
|
||||
/**
|
||||
* 搜索方法:vector_search(向量搜索)、full_text_search(全文搜索)、hybrid_search(混合搜索)
|
||||
*/
|
||||
@JSONField(name = "search_method")
|
||||
private String searchMethod;
|
||||
|
||||
/**
|
||||
* Rerank是否启用
|
||||
*/
|
||||
@JSONField(name = "reranking_enable")
|
||||
private Boolean rerankingEnable;
|
||||
|
||||
/**
|
||||
* Rerank模式(字符串,值为 "reranking_model")
|
||||
*/
|
||||
@JSONField(name = "reranking_mode")
|
||||
private String rerankingMode;
|
||||
|
||||
/**
|
||||
* Rerank模型配置(当 reranking_enable=true 时必须设置)
|
||||
*/
|
||||
@JSONField(name = "reranking_model")
|
||||
private RerankingModel rerankingModel;
|
||||
|
||||
/**
|
||||
* Top K(返回前K个结果)
|
||||
*/
|
||||
@JSONField(name = "top_k")
|
||||
private Integer topK;
|
||||
|
||||
/**
|
||||
* 分数阈值(0.00-1.00)
|
||||
*/
|
||||
@JSONField(name = "score_threshold")
|
||||
private Double scoreThreshold;
|
||||
|
||||
/**
|
||||
* 是否启用分数阈值
|
||||
*/
|
||||
@JSONField(name = "score_threshold_enabled")
|
||||
private Boolean scoreThresholdEnabled;
|
||||
|
||||
/**
|
||||
* Rerank模型配置(嵌套对象)
|
||||
*/
|
||||
@Data
|
||||
public static class RerankingModel {
|
||||
/**
|
||||
* Rerank模型提供商
|
||||
*/
|
||||
@JSONField(name = "reranking_provider_name")
|
||||
private String rerankingProviderName;
|
||||
|
||||
/**
|
||||
* Rerank模型名称
|
||||
*/
|
||||
@JSONField(name = "reranking_model_name")
|
||||
private String rerankingModelName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @description 知识库检索请求
|
||||
* @filename RetrievalRequest.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class RetrievalRequest {
|
||||
|
||||
/**
|
||||
* 查询文本
|
||||
*/
|
||||
private String query;
|
||||
|
||||
/**
|
||||
* 返回的最相关结果数量
|
||||
*/
|
||||
@JSONField(name = "top_k")
|
||||
private Integer topK = 3;
|
||||
|
||||
/**
|
||||
* 相似度阈值(0-1)
|
||||
*/
|
||||
@JSONField(name = "score_threshold")
|
||||
private Double scoreThreshold = 0.7;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package org.xyzh.ai.client.dto;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description 知识库检索响应
|
||||
* @filename RetrievalResponse.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Data
|
||||
public class RetrievalResponse {
|
||||
|
||||
/**
|
||||
* 查询ID
|
||||
*/
|
||||
@JSONField(name = "query_id")
|
||||
private String queryId;
|
||||
|
||||
/**
|
||||
* 检索结果列表
|
||||
*/
|
||||
private List<RetrievalRecord> records;
|
||||
|
||||
@Data
|
||||
public static class RetrievalRecord {
|
||||
/**
|
||||
* 分段内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 相似度分数
|
||||
*/
|
||||
private Double score;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 元数据
|
||||
*/
|
||||
private Map<String, Object> metadata;
|
||||
|
||||
/**
|
||||
* 文档ID
|
||||
*/
|
||||
@JSONField(name = "document_id")
|
||||
private String documentId;
|
||||
|
||||
/**
|
||||
* 文档名称
|
||||
*/
|
||||
@JSONField(name = "document_name")
|
||||
private String documentName;
|
||||
|
||||
/**
|
||||
* 分段ID
|
||||
*/
|
||||
@JSONField(name = "segment_id")
|
||||
private String segmentId;
|
||||
|
||||
/**
|
||||
* 分段位置
|
||||
*/
|
||||
@JSONField(name = "segment_position")
|
||||
private Integer segmentPosition;
|
||||
|
||||
/**
|
||||
* 索引节点ID
|
||||
*/
|
||||
@JSONField(name = "index_node_id")
|
||||
private String indexNodeId;
|
||||
|
||||
/**
|
||||
* 索引节点哈希
|
||||
*/
|
||||
@JSONField(name = "index_node_hash")
|
||||
private String indexNodeHash;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
package org.xyzh.ai.config;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.xyzh.api.system.service.SysConfigService;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
/**
|
||||
* @description Dify配置类
|
||||
* @filename DifyConfig.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
@Slf4j
|
||||
@Data
|
||||
@Configuration
|
||||
public class DifyConfig {
|
||||
|
||||
@Autowired
|
||||
private SysConfigService sysConfigService;
|
||||
|
||||
/**
|
||||
* Dify API基础地址
|
||||
*/
|
||||
private String apiBaseUrl = "http://192.168.130.131/v1";
|
||||
|
||||
private String knowledgeApiKey="dataset-nupqKP4LONpzdXmGthIrbjeJ";
|
||||
|
||||
/**
|
||||
* 请求超时时间(秒)
|
||||
*/
|
||||
private Integer timeout = 60;
|
||||
|
||||
/**
|
||||
* 连接超时时间(秒)
|
||||
*/
|
||||
private Integer connectTimeout = 10;
|
||||
|
||||
/**
|
||||
* 读取超时时间(秒)
|
||||
*/
|
||||
private Integer readTimeout = 60;
|
||||
|
||||
/**
|
||||
* 流式响应超时时间(秒)
|
||||
*/
|
||||
private Integer streamTimeout = 300;
|
||||
|
||||
/**
|
||||
* 上传文件配置
|
||||
*/
|
||||
private Upload upload = new Upload();
|
||||
|
||||
/**
|
||||
* 知识库配置
|
||||
*/
|
||||
private Dataset dataset = new Dataset();
|
||||
|
||||
/**
|
||||
* 初始化配置,从数据库加载
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
try {
|
||||
log.info("开始从数据库加载Dify配置...");
|
||||
|
||||
// 基础配置
|
||||
loadStringConfig("dify.apiBaseUrl", val -> this.apiBaseUrl = val);
|
||||
loadStringConfig("dify.knowledgeApiKey", val -> this.knowledgeApiKey = val);
|
||||
loadIntegerConfig("dify.timeout", val -> this.timeout = val);
|
||||
loadIntegerConfig("dify.connectTimeout", val -> this.connectTimeout = val);
|
||||
loadIntegerConfig("dify.readTimeout", val -> this.readTimeout = val);
|
||||
loadIntegerConfig("dify.streamTimeout", val -> this.streamTimeout = val);
|
||||
|
||||
// Upload配置
|
||||
loadStringConfig("dify.upload.allowedTypes", val -> {
|
||||
if (val != null && !val.trim().isEmpty()) {
|
||||
this.upload.allowedTypes = val.split(",");
|
||||
}
|
||||
});
|
||||
loadIntegerConfig("dify.upload.maxSize", val -> this.upload.maxSize = val);
|
||||
|
||||
// Dataset配置
|
||||
loadStringConfig("dify.dataset.defaultIndexingTechnique", val -> this.dataset.defaultIndexingTechnique = val);
|
||||
loadStringConfig("dify.dataset.defaultEmbeddingModel", val -> this.dataset.defaultEmbeddingModel = val);
|
||||
|
||||
log.info("Dify配置加载完成 - API地址: {}", apiBaseUrl);
|
||||
} catch (Exception e) {
|
||||
log.error("加载Dify配置失败,将使用默认值", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载字符串配置
|
||||
*/
|
||||
private void loadStringConfig(String key, java.util.function.Consumer<String> setter) {
|
||||
try {
|
||||
String value = sysConfigService.getStringConfig(key);
|
||||
if (value != null && !value.trim().isEmpty()) {
|
||||
setter.accept(value);
|
||||
log.debug("加载配置: {} = {}", key, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("加载配置失败: {}, 错误: {}", key, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载整数配置
|
||||
*/
|
||||
private void loadIntegerConfig(String key, java.util.function.Consumer<Integer> setter) {
|
||||
try {
|
||||
Integer value = sysConfigService.getIntConfig(key);
|
||||
if (value != null) {
|
||||
setter.accept(value);
|
||||
log.debug("加载配置: {} = {}", key, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("加载配置失败: {}, 错误: {}", key, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Upload {
|
||||
/**
|
||||
* 支持的文件类型
|
||||
*/
|
||||
private String[] allowedTypes = {"pdf", "txt", "docx", "doc", "md", "html", "htm"};
|
||||
|
||||
/**
|
||||
* 最大文件大小(MB)
|
||||
*/
|
||||
private Integer maxSize = 50;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Dataset {
|
||||
/**
|
||||
* 默认索引方式(high_quality/economy)
|
||||
*/
|
||||
private String defaultIndexingTechnique = "high_quality";
|
||||
|
||||
/**
|
||||
* 默认Embedding模型
|
||||
*/
|
||||
private String defaultEmbeddingModel = "text-embedding-ada-002";
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证配置是否有效
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return apiBaseUrl != null && !apiBaseUrl.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整的API URL
|
||||
*/
|
||||
public String getFullApiUrl(String endpoint) {
|
||||
String baseUrl = apiBaseUrl.endsWith("/") ? apiBaseUrl.substring(0, apiBaseUrl.length() - 1) : apiBaseUrl;
|
||||
String path = endpoint.startsWith("/") ? endpoint : "/" + endpoint;
|
||||
return baseUrl + path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.xyzh.ai.exception;
|
||||
|
||||
/**
|
||||
* @description Dify API调用异常
|
||||
* @filename DifyException.java
|
||||
* @author AI Assistant
|
||||
* @copyright xyzh
|
||||
* @since 2025-11-04
|
||||
*/
|
||||
public class DifyException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer code;
|
||||
|
||||
public DifyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DifyException(Integer code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public DifyException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public DifyException(Integer code, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
89
urbanLifelineServ/ai/src/main/resources/application.yml
Normal file
89
urbanLifelineServ/ai/src/main/resources/application.yml
Normal file
@@ -0,0 +1,89 @@
|
||||
# ================== Server ==================
|
||||
server:
|
||||
port: 8190
|
||||
# servlet:
|
||||
# context-path: /urban-lifeline/agent # 微服务架构下,context-path由Gateway管理
|
||||
|
||||
# ================== Auth ====================
|
||||
urban-lifeline:
|
||||
auth:
|
||||
enabled: true
|
||||
whitelist:
|
||||
- /swagger-ui/**
|
||||
- /swagger-ui.html
|
||||
- /v3/api-docs/**
|
||||
- /webjars/**
|
||||
- /favicon.ico
|
||||
- /error
|
||||
- /actuator/health
|
||||
- /actuator/info
|
||||
|
||||
security:
|
||||
aes:
|
||||
secret-key: 1234567890qwer
|
||||
|
||||
# ================== Spring ==================
|
||||
spring:
|
||||
application:
|
||||
name: agent-service
|
||||
|
||||
# ================== Spring Cloud Nacos ==================
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
namespace: dev
|
||||
group: DEFAULT_GROUP
|
||||
|
||||
# ================== DataSource ==================
|
||||
datasource:
|
||||
url: jdbc:postgresql://127.0.0.1:5432/urban_lifeline
|
||||
username: postgres
|
||||
password: postgres
|
||||
driver-class-name: org.postgresql.Driver
|
||||
|
||||
# ================== Redis ==================
|
||||
data:
|
||||
redis:
|
||||
host: 127.0.0.1 # 如果是 docker 跑的 redis,按实际 host / 端口改
|
||||
port: 6379
|
||||
database: 0
|
||||
password: 123456 # 如果有密码就填上,没密码可以去掉这一行
|
||||
|
||||
# ================== SpringDoc ==================
|
||||
springdoc:
|
||||
api-docs:
|
||||
enabled: true
|
||||
path: /v3/api-docs
|
||||
swagger-ui:
|
||||
enabled: true
|
||||
path: /swagger-ui.html
|
||||
group-configs:
|
||||
- group: 'default'
|
||||
display-name: 'AI代理服务 API'
|
||||
paths-to-match: '/**'
|
||||
|
||||
# ================== Dubbo + Nacos ==================
|
||||
dubbo:
|
||||
application:
|
||||
name: urban-lifeline-agent
|
||||
qos-enable: false
|
||||
protocol:
|
||||
name: dubbo
|
||||
port: -1
|
||||
registry:
|
||||
address: nacos://127.0.0.1:8848
|
||||
scan:
|
||||
base-packages: org.xyzh.agent.service.impl
|
||||
|
||||
# ================== MyBatis ==================
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath:mapper/**/*.xml
|
||||
type-aliases-package: org.xyzh.common.dto, org.xyzh.api
|
||||
|
||||
# ================== Logging ==================
|
||||
logging:
|
||||
config: classpath:log4j2.xml
|
||||
charset:
|
||||
console: UTF-8
|
||||
file: UTF-8
|
||||
85
urbanLifelineServ/ai/src/main/resources/log4j2.xml
Normal file
85
urbanLifelineServ/ai/src/main/resources/log4j2.xml
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration status="WARN" monitorInterval="30">
|
||||
<Properties>
|
||||
<property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
|
||||
<property name="FILE_PATH" value="./logs" />
|
||||
<property name="FILE_NAME" value="agent-service" />
|
||||
<property name="file.encoding" value="UTF-8" />
|
||||
<property name="console.encoding" value="UTF-8" />
|
||||
</Properties>
|
||||
|
||||
<appenders>
|
||||
<console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
|
||||
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
</console>
|
||||
|
||||
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/${FILE_NAME}-info.log"
|
||||
filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
|
||||
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy interval="1"/>
|
||||
<SizeBasedTriggeringPolicy size="100MB"/>
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="30"/>
|
||||
</RollingFile>
|
||||
|
||||
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/${FILE_NAME}-warn.log"
|
||||
filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
|
||||
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy interval="1"/>
|
||||
<SizeBasedTriggeringPolicy size="100MB"/>
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="30"/>
|
||||
</RollingFile>
|
||||
|
||||
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/${FILE_NAME}-error.log"
|
||||
filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
|
||||
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy interval="1"/>
|
||||
<SizeBasedTriggeringPolicy size="100MB"/>
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="30"/>
|
||||
</RollingFile>
|
||||
</appenders>
|
||||
|
||||
<loggers>
|
||||
<logger name="com.alibaba.nacos" level="info" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
</logger>
|
||||
|
||||
<logger name="org.mybatis" level="debug" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
</logger>
|
||||
|
||||
<Logger name="org.springframework" level="info" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Logger>
|
||||
|
||||
<Logger name="org.xyzh.agent" level="debug" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
<AppenderRef ref="RollingFileInfo"/>
|
||||
<AppenderRef ref="RollingFileWarn"/>
|
||||
<AppenderRef ref="RollingFileError"/>
|
||||
</Logger>
|
||||
|
||||
<Logger name="org.xyzh.common" level="debug" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
<AppenderRef ref="RollingFileInfo"/>
|
||||
<AppenderRef ref="RollingFileWarn"/>
|
||||
<AppenderRef ref="RollingFileError"/>
|
||||
</Logger>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="Console"/>
|
||||
<appender-ref ref="RollingFileInfo"/>
|
||||
<appender-ref ref="RollingFileWarn"/>
|
||||
<appender-ref ref="RollingFileError"/>
|
||||
</root>
|
||||
</loggers>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user