jmal-cloud-server icon indicating copy to clipboard operation
jmal-cloud-server copied to clipboard

Integrate Spring AI for intelligent file search, summarization, and classification

Open Copilot opened this issue 3 months ago • 1 comments

  • [x] Analyze repository structure and existing codebase
  • [x] Add Spring AI dependencies to pom.xml
    • Added spring-ai-openai-spring-boot-starter and spring-ai-ollama-spring-boot-starter
    • Updated to Spring AI 1.0.0 stable release (from milestone 1.0.0-M4)
    • Removed Spring Milestones repository (no longer needed for stable release)
  • [x] Create AI configuration package (com.jmal.clouddisk.ai)
    • [x] Create AiProperties.java - AI configuration properties with provider, API key, model settings
    • [x] Create AiConfig.java - AI main configuration class supporting OpenAI and Ollama
  • [x] Implement Embedding Service
    • [x] Create EmbeddingService.java - Generate text vectors with chunking for large texts
  • [x] Implement Vector Store Service
    • [x] Create VectorStoreService.java - Store and search vectors with Lucene KnnVectorField
  • [x] Implement AI Search Service
    • [x] Create AiSearchService.java - Natural language and semantic/hybrid search
  • [x] Implement File Summary Service
    • [x] Create FileSummaryService.java - Generate file summaries with AI
  • [x] Implement File Classification Service
    • [x] Create FileClassificationService.java - Auto classify and tag files
  • [x] Create VO classes for API responses
    • [x] Create FileSummaryVO.java
    • [x] Create FileClassificationVO.java
    • [x] Create TagSuggestionVO.java
  • [x] Implement REST API Controller
    • [x] Create AiController.java with all endpoints under /api/ai
  • [x] Add default AI configuration to application.yml
  • [x] Update data models
    • [x] Add summary field to FileDocument
    • [x] Add summary field to FileMetadataDO
    • [x] Add new IFileDAO methods for search and summary operations
    • [x] Implement MongoDB and JPA DAO methods
  • [x] Code review and security check passed
Original prompt

需求概述

在现有的 JmalCloud 私有云存储项目中集成 Spring AI,实现以下 AI 智能功能:

  1. 自然语言搜索文件 - 用户可以使用自然语言描述来搜索文件
  2. 向量化 - 对文件内容进行向量化存储,支持语义搜索
  3. 文件总结 - 自动生成文件内容摘要
  4. 智能分类 - 自动对文件进行分类和打标签

技术实现要求

1. 添加 Spring AI 依赖配置

pom.xml 中添加以下依赖:

  • spring-ai-openai-spring-boot-starter - OpenAI 支持
  • spring-ai-ollama-spring-boot-starter - Ollama 本地部署支持
  • 相关的向量存储依赖

2. 创建 AI 配置类

创建 src/main/java/com/jmal/clouddisk/ai/ 包,包含:

  • AiConfig.java - AI 主配置类,支持多种 LLM 提供商切换
  • AiProperties.java - AI 配置属性类,包含:
    • provider - 提供商类型(openai/ollama)
    • apiKey - API 密钥
    • baseUrl - API 基础 URL
    • model - 模型名称
    • embeddingModel - 向量模型名称
    • temperature - 温度参数
    • maxTokens - 最大 token 数
    • enabled - 是否启用 AI 功能
    • vectorDimension - 向量维度(默认 1536)

3. 实现向量存储服务 - 基于 Lucene 的向量索引

创建以下类:

  • VectorStoreService.java - 向量存储服务

    • 使用 Lucene 的 KnnVectorField 存储文档向量
    • 在现有 LuceneService 的索引流程中集成向量化
    • 支持向量相似度搜索(使用 KnnVectorQuery
    • 方法:
      • storeVector(String fileId, float[] vector) - 存储向量
      • searchSimilar(float[] queryVector, int topK) - 相似度搜索
      • deleteVector(String fileId) - 删除向量
  • EmbeddingService.java - 向量生成服务

    • 调用 LLM 的 embedding API 生成向量
    • 支持文本分块处理(大文件内容分块后取平均向量)
    • 方法:
      • embed(String text) - 生成文本向量
      • embedBatch(List<String> texts) - 批量生成向量

4. 实现 AI 搜索服务 - 自然语言查询转换

创建 AiSearchService.java

  • 将用户的自然语言查询转换为结构化搜索条件
  • 结合向量搜索和关键词搜索实现混合搜索
  • 方法:
    • naturalLanguageSearch(String query, String userId) - 自然语言搜索
    • semanticSearch(String query, String userId, int topK) - 语义向量搜索
    • hybridSearch(String query, String userId) - 混合搜索(关键词+向量)

提示词模板示例:

你是一个文件搜索助手。用户会用自然语言描述他们要找的文件。
请分析用户的意图,提取关键信息:
- 文件类型(如:图片、文档、视频等)
- 时间范围(如:最近一周、上个月等)
- 关键词
- 其他条件

用户查询:{query}

请返回 JSON 格式:
{
  "fileTypes": ["image", "document"],
  "keywords": ["关键词1", "关键词2"],
  "timeRange": {"start": "2024-01-01", "end": "2024-12-31"},
  "sortBy": "updateDate",
  "sortOrder": "desc"
}

5. 实现文件总结服务 - 自动生成文件摘要

创建 FileSummaryService.java

  • 对文件内容生成摘要
  • 支持多种文件类型(利用现有 Tika 提取的内容)
  • 摘要存储在数据库中,避免重复生成
  • 方法:
    • generateSummary(String fileId) - 生成文件摘要
    • getSummary(String fileId) - 获取已有摘要
    • regenerateSummary(String fileId) - 重新生成摘要
    • batchGenerateSummary(List<String> fileIds) - 批量生成

提示词模板:

请对以下文件内容生成简洁的摘要(不超过200字):

文件名:{fileName}
文件类型:{fileType}
内容:
{content}

请用中文回复,摘要应该包含文件的主要内容和关键信息。

6. 实现智能分类服务 - 自动分类和标签

创建 FileClassificationService.java

  • 根据文件内容自动分类
  • 自动生成标签建议
  • 与现有的标签系统(TagService)集成
  • 方法:
    • classifyFile(String fileId) - 分类文件
    • suggestTags(String fileId) - 建议标签
    • autoTagFile(String fileId) - 自动打标签
    • batchClassify(List<String> fileIds) - 批量分类

预定义分类:

  • 工作文档
  • 个人照片
  • 视频媒体
  • 音乐音频
  • 代码项目
  • 学习资料
  • 财务文件
  • 其他

提示词模板:

请分析以下文件内容,给出分类和标签建议:

文件名:{fileName}
文件类型:{fileType}
内容摘要:
{contentSummary}

请返回 JSON 格式:
{
  "category": "分类名称",
  "tags": ["标签1", "标签2", "标签3"],
  "confidence": 0.95
}

可选分类:工作文档、个人照片、视频媒体、音乐音频、代码项目、学习资料、财务文件、其他

7. 添加 REST API 接口

创建 AiController.java(路径:/api/ai):

@RestController
@RequestMapping("/api/ai")
public class AiController {
    
    // 自然语言搜索
    @GetMapping("/search")
    public ResponseResult<List<FileIntroVO>> naturalLanguageSearch(
        @RequestParam String query,
        @RequestParam(required = false) Integer page,
        @RequestParam(required = false) Integer pageSize);
    
    // 语义搜索
    @GetMapping("/semantic-search")
    public ResponseResult<List<FileIntroVO>> semanticSearch(
        @RequestParam String query,
        @RequestParam(defaultValue = "10") Integer topK);
    
    // 获取文件摘要
    @GetMapping("/summary/{fileId}")
    public ResponseResult<FileSummaryVO> getFileSummary(@PathVariable String fileId);
    
    // 生成文件摘要
    @PostMapping("/summary/{fileId}")
    public ResponseResult<FileSummaryVO> generateFileSummary(@PathVariable String fileId);
    
    // 获取分类建议
    @GetMapping("/classify/{fileId}")
    public ResponseResult<FileClassificationVO> classifyFile(@PathVariable String fileId);
    
    // 获取标签建议
    @GetMapping("/suggest-tags/{fileId}")
    public ResponseResult<List<String>> suggestTags(@PathVariable String fileId);
    
    // 自动打标签
    @PostMapping("/auto-tag/{fileId}")
    public ResponseResult<Void> autoTagFile(@PathVariable String fileId);
    
    // 获取 AI 配置状态
    @GetMapping("/status")
    public ResponseResult<AiStatusVO> getAiStatus();
    
    // 更新 AI 配置
    @PutMapping("/config")
    public ResponseResult<Void> updateAiConfig(@RequestBody AiConfigDTO config);
}

8. 数据模型扩展

创建新的 VO/DTO 类:

  • FileSummaryVO.java - 文件摘要响应
  • FileClassificationVO.java - 文件分类响应
  • AiStatusVO.java - AI 状态响应
  • AiConfigDTO.java - AI 配置请求

在数据库中添加新字段(通过 MongoDB 文档或扩展现有模型):

  • summary - 文件摘要
  • aiCategory - AI 分类
  • aiTags - AI 建议的标签
  • embedding - 向量(可选,也可以存在 Lucene 中)

9. 在现有索引流程中集成向量化

修改 LuceneService.java

  • updateIndex 方法中,当读取文件内容后,调用 EmbeddingService 生成向量
  • 将向量存储到 Lucene 索引中(使用 KnnVectorField
  • 添加配置开关控制是否启用向量索引(考虑...

This pull request was created as a result of the following prompt from Copilot chat.

需求概述

在现有的 JmalCloud 私有云存储项目中集成 Spring AI,实现以下 AI 智能功能:

  1. 自然语言搜索文件 - 用户可以使用自然语言描述来搜索文件
  2. 向量化 - 对文件内容进行向量化存储,支持语义搜索
  3. 文件总结 - 自动生成文件内容摘要
  4. 智能分类 - 自动对文件进行分类和打标签

技术实现要求

1. 添加 Spring AI 依赖配置

pom.xml 中添加以下依赖:

  • spring-ai-openai-spring-boot-starter - OpenAI 支持
  • spring-ai-ollama-spring-boot-starter - Ollama 本地部署支持
  • 相关的向量存储依赖

2. 创建 AI 配置类

创建 src/main/java/com/jmal/clouddisk/ai/ 包,包含:

  • AiConfig.java - AI 主配置类,支持多种 LLM 提供商切换
  • AiProperties.java - AI 配置属性类,包含:
    • provider - 提供商类型(openai/ollama)
    • apiKey - API 密钥
    • baseUrl - API 基础 URL
    • model - 模型名称
    • embeddingModel - 向量模型名称
    • temperature - 温度参数
    • maxTokens - 最大 token 数
    • enabled - 是否启用 AI 功能
    • vectorDimension - 向量维度(默认 1536)

3. 实现向量存储服务 - 基于 Lucene 的向量索引

创建以下类:

  • VectorStoreService.java - 向量存储服务

    • 使用 Lucene 的 KnnVectorField 存储文档向量
    • 在现有 LuceneService 的索引流程中集成向量化
    • 支持向量相似度搜索(使用 KnnVectorQuery
    • 方法:
      • storeVector(String fileId, float[] vector) - 存储向量
      • searchSimilar(float[] queryVector, int topK) - 相似度搜索
      • deleteVector(String fileId) - 删除向量
  • EmbeddingService.java - 向量生成服务

    • 调用 LLM 的 embedding API 生成向量
    • 支持文本分块处理(大文件内容分块后取平均向量)
    • 方法:
      • embed(String text) - 生成文本向量
      • embedBatch(List<String> texts) - 批量生成向量

4. 实现 AI 搜索服务 - 自然语言查询转换

创建 AiSearchService.java

  • 将用户的自然语言查询转换为结构化搜索条件
  • 结合向量搜索和关键词搜索实现混合搜索
  • 方法:
    • naturalLanguageSearch(String query, String userId) - 自然语言搜索
    • semanticSearch(String query, String userId, int topK) - 语义向量搜索
    • hybridSearch(String query, String userId) - 混合搜索(关键词+向量)

提示词模板示例:

你是一个文件搜索助手。用户会用自然语言描述他们要找的文件。
请分析用户的意图,提取关键信息:
- 文件类型(如:图片、文档、视频等)
- 时间范围(如:最近一周、上个月等)
- 关键词
- 其他条件

用户查询:{query}

请返回 JSON 格式:
{
  "fileTypes": ["image", "document"],
  "keywords": ["关键词1", "关键词2"],
  "timeRange": {"start": "2024-01-01", "end": "2024-12-31"},
  "sortBy": "updateDate",
  "sortOrder": "desc"
}

5. 实现文件总结服务 - 自动生成文件摘要

创建 FileSummaryService.java

  • 对文件内容生成摘要
  • 支持多种文件类型(利用现有 Tika 提取的内容)
  • 摘要存储在数据库中,避免重复生成
  • 方法:
    • generateSummary(String fileId) - 生成文件摘要
    • getSummary(String fileId) - 获取已有摘要
    • regenerateSummary(String fileId) - 重新生成摘要
    • batchGenerateSummary(List<String> fileIds) - 批量生成

提示词模板:

请对以下文件内容生成简洁的摘要(不超过200字):

文件名:{fileName}
文件类型:{fileType}
内容:
{content}

请用中文回复,摘要应该包含文件的主要内容和关键信息。

6. 实现智能分类服务 - 自动分类和标签

创建 FileClassificationService.java

  • 根据文件内容自动分类
  • 自动生成标签建议
  • 与现有的标签系统(TagService)集成
  • 方法:
    • classifyFile(String fileId) - 分类文件
    • suggestTags(String fileId) - 建议标签
    • autoTagFile(String fileId) - 自动打标签
    • batchClassify(List<String> fileIds) - 批量分类

预定义分类:

  • 工作文档
  • 个人照片
  • 视频媒体
  • 音乐音频
  • 代码项目
  • 学习资料
  • 财务文件
  • 其他

提示词模板:

请分析以下文件内容,给出分类和标签建议:

文件名:{fileName}
文件类型:{fileType}
内容摘要:
{contentSummary}

请返回 JSON 格式:
{
  "category": "分类名称",
  "tags": ["标签1", "标签2", "标签3"],
  "confidence": 0.95
}

可选分类:工作文档、个人照片、视频媒体、音乐音频、代码项目、学习资料、财务文件、其他

7. 添加 REST API 接口

创建 AiController.java(路径:/api/ai):

@RestController
@RequestMapping("/api/ai")
public class AiController {
    
    // 自然语言搜索
    @GetMapping("/search")
    public ResponseResult<List<FileIntroVO>> naturalLanguageSearch(
        @RequestParam String query,
        @RequestParam(required = false) Integer page,
        @RequestParam(required = false) Integer pageSize);
    
    // 语义搜索
    @GetMapping("/semantic-search")
    public ResponseResult<List<FileIntroVO>> semanticSearch(
        @RequestParam String query,
        @RequestParam(defaultValue = "10") Integer topK);
    
    // 获取文件摘要
    @GetMapping("/summary/{fileId}")
    public ResponseResult<FileSummaryVO> getFileSummary(@PathVariable String fileId);
    
    // 生成文件摘要
    @PostMapping("/summary/{fileId}")
    public ResponseResult<FileSummaryVO> generateFileSummary(@PathVariable String fileId);
    
    // 获取分类建议
    @GetMapping("/classify/{fileId}")
    public ResponseResult<FileClassificationVO> classifyFile(@PathVariable String fileId);
    
    // 获取标签建议
    @GetMapping("/suggest-tags/{fileId}")
    public ResponseResult<List<String>> suggestTags(@PathVariable String fileId);
    
    // 自动打标签
    @PostMapping("/auto-tag/{fileId}")
    public ResponseResult<Void> autoTagFile(@PathVariable String fileId);
    
    // 获取 AI 配置状态
    @GetMapping("/status")
    public ResponseResult<AiStatusVO> getAiStatus();
    
    // 更新 AI 配置
    @PutMapping("/config")
    public ResponseResult<Void> updateAiConfig(@RequestBody AiConfigDTO config);
}

8. 数据模型扩展

创建新的 VO/DTO 类:

  • FileSummaryVO.java - 文件摘要响应
  • FileClassificationVO.java - 文件分类响应
  • AiStatusVO.java - AI 状态响应
  • AiConfigDTO.java - AI 配置请求

在数据库中添加新字段(通过 MongoDB 文档或扩展现有模型):

  • summary - 文件摘要
  • aiCategory - AI 分类
  • aiTags - AI 建议的标签
  • embedding - 向量(可选,也可以存在 Lucene 中)

9. 在现有索引流程中集成向量化

修改 LuceneService.java

  • updateIndex 方法中,当读取文件内容后,调用 EmbeddingService 生成向量
  • 将向量存储到 Lucene 索引中(使用 KnnVectorField
  • 添加配置开关控制是否启用向量索引(考虑性能和成本)

10. 配置文件示例

application.yml 中添加:

jmal:
  ai:
    enabled: true
    provider: openai  # openai 或 ollama
    api-key: ${AI_API_KEY:}
    base-url: ${AI_BASE_URL:https://api.openai.com}
    model: gpt-4o-mini
    embedding-model: text-embedding-3-small
    temperature: 0.7
    max-tokens: 2000
    vector-dimension: 1536
    # Ollama 配置
    ollama:
      base-url: http://localhost:11434
      model: llama3
      embedding-model: nomic-embed-text

注意事项

  1. 性能优化:向量化和 AI 调用应该异步处理,不阻塞主流程
  2. 成本控制:添加配置开关,允许用户选择性启用 AI 功能
  3. 错误处理:AI 服务不可用时应该优雅降级,不影响核心功能
  4. 缓存机制:摘要和分类结果应该缓存,避免重复调用
  5. 安全性:API 密钥应该通过环境变量配置,不硬编码
  6. 国际化:提示词应该支持中英文

文件结构

src/main/java/com/jmal/clouddisk/
├── ai/
│   ├── config/
│   │   ├── AiConfig.java
│   │   └── AiProperties.java
│   ├── service/
│   │   ├── EmbeddingService.java
│   │   ├── VectorStoreService.java
│   │   ├── AiSearchService.java
│   │   ├── FileSummaryService.java
│   │   └── FileClassificationService.java
│   ├── controller/
│   │   └── AiController.java
│   ├── dto/
│   │   ├── AiConfigDTO.java
│   │   ├── AiSearchResultDTO.java
│   │   └── NaturalLanguageQueryDTO.java
│   └── vo/
│       ├── FileSummaryVO.java
│       ├── FileClassificationVO.java
│       └── AiStatusVO.java

测试要求

  1. 单元测试覆盖所有 AI 服务类
  2. 集成测试验证与 LLM 的通信
  3. Mock 测试确保 AI 服务不可用时的降级处理

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot avatar Nov 26 '25 03:11 Copilot

springboot 已经升级至 <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-client-chat</artifactId> ...

Updated Spring AI from milestone 1.0.0-M4 to stable 1.0.0 release and removed the Spring Milestones repository since it's no longer needed. (01c6124)

Copilot avatar Nov 26 '25 04:11 Copilot