欢迎光临
我们一直在努力

【Spring AI实战】第11章 多媒体AI能力实战

1. 图像识别、图文问答实战

我来分享一个完整的Spring AI图像识别与图文问答实战指南,包含代码示例和最佳实践。

项目环境搭建

1.1 依赖配置

<!– pom.xml –>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

# application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4-vision-preview
temperature: 0.7

基础图像识别

2.1 图像描述生成

@Service
public class ImageDescriptionService {

@Autowired
private OpenAiChatClient chatClient;

public String describeImage(String imageUrl) {
UserMessage userMessage = new UserMessage(
"请详细描述这张图片的内容",
List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageUrl))
);

ChatResponse response = chatClient.call(
new Prompt(List.of(userMessage))
);

return response.getResult().getOutput().getContent();
}

public String describeImage(MultipartFile imageFile) throws IOException {
String base64Image = Base64.getEncoder()
.encodeToString(imageFile.getBytes());

UserMessage userMessage = new UserMessage(
"描述这张图片",
List.of(new Media(MimeTypeUtils.IMAGE_PNG,
"data:image/png;base64," + base64Image))
);

ChatResponse response = chatClient.call(
new Prompt(List.of(userMessage))
);

return response.getResult().getOutput().getContent();
}
}

2.2 图像分类服务

@Service
public class ImageClassificationService {

private static final Map<String, String> CATEGORY_PROMPTS = Map.of(
"SCENE", "这是一张什么场景的照片?",
"OBJECT", "图片中的主要物体是什么?",
"EMOTION", "这张图片传达了什么情感?",
"ACTION", "图片中正在发生什么动作?"
);

public Map<String, String> classifyImage(String imageUrl) {
Map<String, String> results = new HashMap<>();

for (Map.Entry<String, String> entry : CATEGORY_PROMPTS.entrySet()) {
UserMessage userMessage = new UserMessage(
entry.getValue(),
List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageUrl))
);

ChatResponse response = chatClient.call(
new Prompt(List.of(userMessage))
);

results.put(entry.getKey(),
response.getResult().getOutput().getContent());
}

return results;
}
}

图文问答系统

3.1 问答服务实现

@Service
public class VisualQAService {

@Autowired
private OpenAiChatClient chatClient;

public String answerQuestion(String imageUrl, String question) {
// 构建包含图像和问题的消息
UserMessage userMessage = new UserMessage(
question,
List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageUrl))
);

ChatResponse response = chatClient.call(
new Prompt(List.of(userMessage))
);

return response.getResult().getOutput().getContent();
}

public VisualQAResponse analyzeWithContext(String imageUrl,
String question,
String context) {

String systemPrompt = """
你是一个视觉问答助手。请基于提供的图像和上下文信息回答问题。
上下文:%s
如果图像内容与上下文矛盾,以图像为准。
""".formatted(context);

SystemPrompt systemMessage = new SystemPrompt(systemPrompt);
UserMessage userMessage = new UserMessage(
question,
List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageUrl))
);

ChatResponse response = chatClient.call(
new Prompt(List.of(systemMessage, userMessage))
);

return VisualQAResponse.builder()
.question(question)
.answer(response.getResult().getOutput().getContent())
.confidence(extractConfidence(response))
.build();
}

private double extractConfidence(ChatResponse response) {
// 从响应中提取置信度(示例逻辑)
String content = response.getResult().getOutput().getContent();
if (content.contains("确定") || content.contains("肯定")) {
return 0.9;
} else if (content.contains("可能") || content.contains("大概")) {
return 0.7;
} else {
return 0.5;
}
}

@Data
@Builder
public static class VisualQAResponse {
private String question;
private String answer;
private double confidence;
private LocalDateTime timestamp;
}
}

3.2 多轮对话支持

@Service
public class MultiTurnVisualChatService {

private final Map<String, List<Message>> conversationHistory =
new ConcurrentHashMap<>();

public String chat(String sessionId, String imageUrl, String userMessage) {
List<Message> history = conversationHistory
.computeIfAbsent(sessionId, k -> new ArrayList<>());

// 如果是第一次消息,添加图像
if (history.isEmpty() && imageUrl != null) {
history.add(new UserMessage(
"这是我们要讨论的图片",
List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageUrl))
));
}

// 添加用户问题
history.add(new UserMessage(userMessage));

// 限制历史记录长度
if (history.size() > 10) {
history = history.subList(history.size() – 10, history.size());
}

ChatResponse response = chatClient.call(new Prompt(history));
String assistantResponse = response.getResult()
.getOutput().getContent();

// 保存助手回复
history.add(new AssistantMessage(assistantResponse));
conversationHistory.put(sessionId, history);

return assistantResponse;
}

public void clearHistory(String sessionId) {
conversationHistory.remove(sessionId);
}
}

REST API 控制器

@RestController
@RequestMapping("/api/vision")
public class VisionController {

@Autowired
private ImageDescriptionService descriptionService;

@Autowired
private VisualQAService qaService;

@Autowired
private MultiTurnVisualChatService chatService;

@PostMapping("/describe")
public ResponseEntity<String> describeImage(
@RequestParam("imageUrl") String imageUrl) {
return ResponseEntity.ok(
descriptionService.describeImage(imageUrl)
);
}

@PostMapping("/describe/upload")
public ResponseEntity<String> describeUploadedImage(
@RequestParam("file") MultipartFile file) throws IOException {
return ResponseEntity.ok(
descriptionService.describeImage(file)
);
}

@PostMapping("/qa")
public ResponseEntity<VisualQAResponse> visualQA(
@RequestBody VisualQARequest request) {
return ResponseEntity.ok(
qaService.answerQuestion(
request.getImageUrl(),
request.getQuestion()
)
);
}

@PostMapping("/chat")
public ResponseEntity<String> visualChat(
@RequestBody VisualChatRequest request) {
return ResponseEntity.ok(
chatService.chat(
request.getSessionId(),
request.getImageUrl(),
request.getMessage()
)
);
}

@Data
public static class VisualQARequest {
private String imageUrl;
private String question;
}

@Data
public static class VisualChatRequest {
private String sessionId;
private String imageUrl;
private String message;
}
}

高级功能:图像分析报告

@Service
public class ImageAnalysisReportService {

public AnalysisReport generateReport(String imageUrl) {
String description = describeImage(imageUrl);
Map<String, String> classifications = classifyImage(imageUrl);
List<String> tags = extractTags(imageUrl);
String summary = generateSummary(description, classifications);

return AnalysisReport.builder()
.description(description)
.classifications(classifications)
.tags(tags)
.summary(summary)
.analysisTime(LocalDateTime.now())
.build();
}

private List<String> extractTags(String imageUrl) {
UserMessage userMessage = new UserMessage(
"提取这张图片的关键标签,用逗号分隔",
List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageUrl))
);

ChatResponse response = chatClient.call(
new Prompt(List.of(userMessage))
);

String tagsStr = response.getResult().getOutput().getContent();
return Arrays.stream(tagsStr.split(","))
.map(String::trim)
.collect(Collectors.toList());
}

private String generateSummary(String description,
Map<String, String> classifications) {
String prompt = """
基于以下信息生成图片分析摘要:
描述:%s
分类:%s
请生成一段简洁的总结,不超过100字。
""".formatted(description, classifications);

ChatResponse response = chatClient.call(
new Prompt(prompt)
);

return response.getResult().getOutput().getContent();
}

@Data
@Builder
public static class AnalysisReport {
private String description;
private Map<String, String> classifications;
private List<String> tags;
private String summary;
private LocalDateTime analysisTime;
}
}

性能优化与缓存

@Service
public class CachedVisionService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

private static final long CACHE_TTL = 3600; // 1小时

public String describeImageWithCache(String imageUrl) {
String cacheKey = "image:desc:" + hashImageUrl(imageUrl);

// 尝试从缓存获取
String cached = (String) redisTemplate.opsForValue().get(cacheKey);
if (cached != null) {
return cached;
}

// 调用API
String description = descriptionService.describeImage(imageUrl);

// 存入缓存
redisTemplate.opsForValue().set(
cacheKey,
description,
CACHE_TTL,
TimeUnit.SECONDS
);

return description;
}

private String hashImageUrl(String url) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(url.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
} catch (NoSuchAlgorithmException e) {
return String.valueOf(url.hashCode());
}
}
}

错误处理与监控

@ControllerAdvice
public class VisionExceptionHandler {

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleVisionException(Exception ex) {
ErrorResponse error = ErrorResponse.builder()
.timestamp(LocalDateTime.now())
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
.error("Vision Processing Error")
.message(ex.getMessage())
.path(getRequestPath())
.build();

// 记录监控指标
Metrics.counter("vision.api.errors").increment();

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(error);
}

@Data
@Builder
public static class ErrorResponse {
private LocalDateTime timestamp;
private int status;
private String error;
private String message;
private String path;
}
}

测试用例

@SpringBootTest
class VisionServiceTest {

@Autowired
private VisualQAService qaService;

@Test
void testImageDescription() {
String imageUrl = "https://example.com/image.jpg";
String description = qaService.answerQuestion(
imageUrl,
"描述这张图片"
);

assertNotNull(description);
assertTrue(description.length() > 10);
}

@Test
void testComplexQuestion() {
String imageUrl = "https://example.com/chart.png";
String answer = qaService.answerQuestion(
imageUrl,
"这张图表展示了什么趋势?最大值和最小值分别是多少?"
);

assertNotNull(answer);
assertTrue(answer.contains("趋势") ||
answer.contains("增长") ||
answer.contains("下降"));
}
}

部署配置

# application-prod.yml
spring:
ai:
openai:
base-url: https://api.openai.com/v1
chat:
options:
model: gpt-4-vision-preview
max-tokens: 1000

management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
export:
prometheus:
enabled: true

resilience4j:
ratelimiter:
instances:
vision-api:
limit-for-period: 10
limit-refresh-period: 1s
timeout-duration: 0

最佳实践建议

  • 图像预处理 :压缩大图像,限制分辨率
  • 速率限制 :实现API调用频率控制
  • 成本控制 :监控token使用量
  • 异步处理 :对耗时操作使用异步调用
  • 结果缓存 :缓存常见图像的识别结果
  • 错误重试 :实现指数退避重试机制
  • 内容审核 :添加敏感内容检测
  • 这个实战指南提供了从基础到高级的完整实现,你可以根据具体需求进行调整和扩展。

    2. 文档解析、表格提取、智能总结

    我来为你详细介绍 Spring AI 在文档解析、表格提取和智能总结方面的功能。

    1. 文档解析

    Spring AI 提供了多种文档解析器,支持多种格式:

    支持的文档格式:

    // 常见解析器
    – PdfDocumentReader // PDF 文件
    – TikaDocumentReader // 多种格式(docx, pptx, xlsx, html等)
    – TextDocumentReader // 纯文本文件
    – MarkdownDocumentReader // Markdown 文件
    – JsonDocumentReader // JSON 文件

    使用示例:

    @Bean
    public VectorStore vectorStore(EmbeddingModel embeddingModel) {
    // 解析 PDF 文档
    DocumentReader pdfReader = new PdfDocumentReader("path/to/document.pdf");
    List<Document> documents = pdfReader.read();

    // 解析多种格式文档
    TikaDocumentReader tikaReader = new TikaDocumentReader(
    ResourceUtils.getFile("classpath:documents/")
    );

    return new SimpleVectorStore(embeddingModel);
    }

    2. 表格提取

    使用 Tika 提取表格:

    import org.springframework.ai.reader.tika.TikaDocumentReader;
    import org.springframework.ai.document.Document;

    public class TableExtractor {

    public List<TableData> extractTables(String filePath) {
    TikaDocumentReader reader = new TikaDocumentReader(filePath);
    List<Document> documents = reader.read();

    // 使用正则表达式或自定义逻辑提取表格
    return extractTableData(documents);
    }

    private List<TableData> extractTableData(List<Document> docs) {
    List<TableData> tables = new ArrayList<>();

    for (Document doc : docs) {
    String content = doc.getContent();
    // 提取表格内容(示例:简单的 CSV 格式表格)
    Pattern tablePattern = Pattern.compile("\\\\|.*?\\\\|", Pattern.DOTALL);
    Matcher matcher = tablePattern.matcher(content);

    while (matcher.find()) {
    tables.add(parseTable(matcher.group()));
    }
    }
    return tables;
    }
    }

    使用 DocumentTransformers 处理表格:

    @Bean
    public DocumentTransformer tableExtractorTransformer() {
    return documents -> {
    return documents.stream()
    .map(doc -> {
    String content = doc.getContent();
    // 提取并格式化表格数据
    String extractedTables = extractAndFormatTables(content);
    return new Document(
    doc.getContent() + "\\n\\n提取的表格数据:\\n" + extractedTables,
    doc.getMetadata()
    );
    })
    .collect(Collectors.toList());
    };
    }

    3. 智能总结

    使用 ChatClient 进行文档总结:

    @Service
    public class DocumentSummaryService {

    private final ChatClient chatClient;

    public DocumentSummaryService(ChatClient chatClient) {
    this.chatClient = chatClient;
    }

    public String summarizeDocument(String documentContent) {
    String prompt = """
    请对以下文档内容进行智能总结:

    要求:
    1. 提取核心要点
    2. 保持关键数据
    3. 总结主要结论
    4. 限制在300字以内

    文档内容:
    %s
    """.formatted(documentContent);

    return chatClient.call(prompt);
    }

    public Map<String, String> structuredSummary(Document document) {
    String prompt = """
    请以结构化格式总结以下文档:

    要求返回JSON格式:
    {
    "title": "文档标题",
    "keyPoints": ["要点1", "要点2", …],
    "summary": "详细总结",
    "keywords": ["关键词1", "关键词2", …],
    "actionItems": ["行动项1", "行动项2", …]
    }

    文档内容:
    %s
    """.formatted(document.getContent());

    String jsonResponse = chatClient.call(prompt);
    return parseJsonResponse(jsonResponse);
    }
    }

    批量文档处理管道:

    @Configuration
    public class DocumentProcessingPipeline {

    @Bean
    public Function<List<Document>, List<Document>> documentProcessingPipeline() {
    return documents -> {
    // 1. 文档解析和清理
    DocumentTransformer cleaner = new ContentFormattingTransformer();

    // 2. 表格提取
    DocumentTransformer tableExtractor = new TableExtractionTransformer();

    // 3. 文本分割(用于向量化)
    DocumentTransformer splitter = new TokenTextSplitter(
    1000, // 最大token数
    200 // 重叠token数
    );

    // 4. 应用转换链
    return documents.stream()
    .map(cleaner::apply)
    .map(tableExtractor::apply)
    .flatMap(doc -> splitter.apply(doc).stream())
    .collect(Collectors.toList());
    };
    }
    }

    4. 完整示例:端到端文档处理

    @Service
    public class CompleteDocumentProcessor {

    private final ChatClient chatClient;
    private final VectorStore vectorStore;
    private final EmbeddingModel embeddingModel;

    public CompleteDocumentProcessor(ChatClient chatClient,
    VectorStore vectorStore,
    EmbeddingModel embeddingModel) {
    this.chatClient = chatClient;
    this.vectorStore = vectorStore;
    this.embeddingModel = embeddingModel;
    }

    public ProcessingResult processDocument(String filePath) {
    // 1. 解析文档
    DocumentReader reader = new TikaDocumentReader(filePath);
    List<Document> documents = reader.read();

    // 2. 提取表格
    List<TableData> tables = extractTables(documents);

    // 3. 生成智能总结
    String fullText = documents.stream()
    .map(Document::getContent)
    .collect(Collectors.joining("\\n"));

    String summary = generateSummary(fullText);

    // 4. 向量化存储
    List<Document> processedDocs = new TokenTextSplitter(1000, 200)
    .apply(documents);

    vectorStore.add(processedDocs);

    // 5. 返回结果
    return new ProcessingResult(
    documents,
    tables,
    summary,
    processedDocs.size()
    );
    }

    private String generateSummary(String text) {
    String prompt = """
    你是一个专业的文档分析助手。请完成以下任务:

    1. 文档总结(不超过200字)
    2. 提取3-5个关键点
    3. 识别重要数据/数字
    4. 如果有表格,总结表格主要内容

    文档内容:
    %s
    """.formatted(text.substring(0, Math.min(text.length(), 4000)));

    return chatClient.call(prompt);
    }

    public String queryDocument(String question) {
    // 使用向量搜索找到相关文档片段
    List<Document> relevantDocs = vectorStore.similaritySearch(
    SearchRequest.query(question).withTopK(3)
    );

    String context = relevantDocs.stream()
    .map(Document::getContent)
    .collect(Collectors.joining("\\n\\n"));

    String prompt = """
    基于以下文档内容回答问题:

    文档内容:
    %s

    问题:%s

    要求:如果文档中有表格数据,请引用表格内容。
    """.formatted(context, question);

    return chatClient.call(prompt);
    }
    }

    5. 配置建议

    # application.yml
    spring:
    ai:
    openai:
    api-key: ${OPENAI_API_KEY}
    chat:
    options:
    model: gpt-4
    temperature: 0.1 # 降低创造性,提高准确性

    vectorstore:
    pgvector:
    enabled: true
    initialize-schema: true

    document:
    splitter:
    chunk-size: 1000
    chunk-overlap: 200

    6. 最佳实践

  • 分块策略 :根据文档类型调整分块大小
  • 技术文档:500-800 tokens
  • 法律文档:200-400 tokens
  • 普通文章:1000 tokens
  • 表格处理 :
  • 将表格转换为Markdown格式存储
  • 为表格添加描述性元数据
  • 考虑使用专门的表格识别库(如Tabula for PDF)
  • 总结优化 :
  • 使用few-shot提示提高总结质量
  • 为不同文档类型定制总结模板
  • 实现增量总结(用于长文档)
  • 性能考虑 :
  • 对大文档实现流式处理
  • 缓存处理结果
  • 并行处理多个文档
  • Spring AI 的这些功能可以很好地集成到企业文档处理流程中,实现自动化的文档解析、信息提取和智能分析。

    3. 文本翻译、内容润色、代码优化AI工具开发

    我来帮你设计一个基于Spring AI的AI工具开发方案,包含文本翻译、内容润色和代码优化三大功能。

    项目架构设计

    # Maven依赖
    dependencies:
    – Spring Boot 3.x
    – Spring AI (支持OpenAI/Azure OpenAI/本地模型)
    – Spring Web
    – Spring Validation

    核心功能实现

    2.1 统一AI服务接口

    @Service
    public class AIService {

    @Autowired
    private ChatClient chatClient;

    // 文本翻译
    public String translate(String text, String sourceLang, String targetLang) {
    String prompt = String.format("""
    请将以下%s文本翻译成%s:
    原文:%s

    要求:
    1. 保持原意准确
    2. 符合目标语言表达习惯
    3. 专业术语准确
    """, sourceLang, targetLang, text);

    return chatClient.call(prompt);
    }

    // 内容润色
    public String polishContent(String text, PolishStyle style) {
    String stylePrompt = switch(style) {
    case FORMAL -> "正式、专业的语气";
    case CASUAL -> "轻松、口语化的语气";
    case ACADEMIC -> "学术、严谨的语气";
    case CONCISE -> "简洁、精炼的表达";
    };

    String prompt = String.format("""
    请润色以下文本,要求:
    1. 保持原意不变
    2. 使用%s
    3. 优化语法和表达
    4. 提升可读性

    原文:%s
    """, stylePrompt, text);

    return chatClient.call(prompt);
    }

    // 代码优化
    public String optimizeCode(String code, String language, OptimizationGoal goal) {
    String goalPrompt = switch(goal) {
    case PERFORMANCE -> "提升性能,优化算法复杂度";
    case READABILITY -> "提高代码可读性和可维护性";
    case SECURITY -> "增强安全性,修复潜在漏洞";
    case BEST_PRACTICE -> "遵循最佳实践和设计模式";
    };

    String prompt = String.format("""
    请优化以下%s代码:
    %s

    优化目标:%s

    要求:
    1. 提供优化后的完整代码
    2. 说明优化点和原因
    3. 保持原有功能不变
    4. 添加必要的注释
    """, language, code, goalPrompt);

    return chatClient.call(prompt);
    }
    }

    2.2 RESTful API接口

    @RestController
    @RequestMapping("/api/ai")
    public class AIController {

    @PostMapping("/translate")
    public ResponseEntity<TranslationResponse> translate(
    @Valid @RequestBody TranslationRequest request) {
    String result = aiService.translate(
    request.getText(),
    request.getSourceLang(),
    request.getTargetLang()
    );
    return ResponseEntity.ok(new TranslationResponse(result));
    }

    @PostMapping("/polish")
    public ResponseEntity<PolishResponse> polish(
    @Valid @RequestBody PolishRequest request) {
    String result = aiService.polishContent(
    request.getText(),
    request.getStyle()
    );
    return ResponseEntity.ok(new PolishResponse(result));
    }

    @PostMapping("/optimize-code")
    public ResponseEntity<CodeOptimizationResponse> optimizeCode(
    @Valid @RequestBody CodeOptimizationRequest request) {
    String result = aiService.optimizeCode(
    request.getCode(),
    request.getLanguage(),
    request.getGoal()
    );
    return ResponseEntity.ok(new CodeOptimizationResponse(result));
    }
    }

    2.3 配置类

    @Configuration
    public class AIConfig {

    @Value("${spring.ai.openai.api-key}")
    private String apiKey;

    @Value("${spring.ai.openai.model}")
    private String model;

    @Bean
    public OpenAiChatClient openAiChatClient() {
    OpenAiApi openAiApi = new OpenAiApi("https://api.openai.com/v1", apiKey);
    return new OpenAiChatClient(openAiApi, model);
    }
    }

    高级功能扩展

    3.1 批量处理服务

    @Service
    public class BatchAIService {

    public List<TranslationResult> batchTranslate(
    List<String> texts,
    String sourceLang,
    String targetLang) {

    return texts.parallelStream()
    .map(text -> {
    try {
    String translated = aiService.translate(text, sourceLang, targetLang);
    return TranslationResult.success(text, translated);
    } catch (Exception e) {
    return TranslationResult.failure(text, e.getMessage());
    }
    })
    .collect(Collectors.toList());
    }
    }

    3.2 历史记录与缓存

    @Entity
    @Table(name = "ai_operations")
    public class AIOperation {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String operationType; // TRANSLATE, POLISH, OPTIMIZE
    private String input;
    private String output;
    private String modelUsed;
    private LocalDateTime createdAt;

    @PrePersist
    protected void onCreate() {
    createdAt = LocalDateTime.now();
    }
    }

    3.3 流式响应(SSE)

    @GetMapping(value = "/stream/translate", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamTranslate(
    @RequestParam String text,
    @RequestParam String targetLang) {

    return Flux.create(sink -> {
    // 模拟流式输出
    String[] words = text.split(" ");
    for (int i = 0; i < words.length; i++) {
    sink.next("翻译进度: " + (i + 1) + "/" + words.length);
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    sink.error(e);
    }
    }
    sink.complete();
    });
    }

    应用配置文件

    # application.yml
    spring:
    ai:
    openai:
    api-key: ${OPENAI_API_KEY}
    model: gpt-4
    temperature: 0.7
    max-tokens: 2000

    datasource:
    url: jdbc:mysql://localhost:3306/ai_tools
    username: root
    password: password

    jpa:
    hibernate:
    ddl-auto: update

    server:
    port: 8080

    # 自定义配置
    ai:
    tools:
    max-input-length: 5000
    enable-cache: true
    default-language: zh-CN
    rate-limit:
    requests-per-minute: 60

    前端示例(Vue.js)

    <template>
    <div class="ai-tools">
    <!– 翻译功能 –>
    <div class="tool-card">
    <h3>文本翻译</h3>
    <select v-model="sourceLang">
    <option value="zh">中文</option>
    <option value="en">英文</option>
    <option value="ja">日文</option>
    </select>
    <select v-model="targetLang">
    <option value="en">英文</option>
    <option value="zh">中文</option>
    <option value="ja">日文</option>
    </select>
    <textarea v-model="textToTranslate" placeholder="输入要翻译的文本"></textarea>
    <button @click="translate">翻译</button>
    <div class="result">{{ translationResult }}</div>
    </div>

    <!– 代码优化 –>
    <div class="tool-card">
    <h3>代码优化</h3>
    <select v-model="codeLanguage">
    <option value="java">Java</option>
    <option value="python">Python</option>
    <option value="javascript">JavaScript</option>
    </select>
    <textarea v-model="codeToOptimize" placeholder="输入代码"></textarea>
    <button @click="optimizeCode">优化代码</button>
    <pre class="code-result">{{ optimizedCode }}</pre>
    </div>
    </div>
    </template>

    <script setup>
    import { ref } from 'vue'
    import axios from 'axios'

    const textToTranslate = ref('')
    const translationResult = ref('')
    const codeToOptimize = ref('')
    const optimizedCode = ref('')

    const translate = async () => {
    const response = await axios.post('/api/ai/translate', {
    text: textToTranslate.value,
    sourceLang: 'zh',
    targetLang: 'en'
    })
    translationResult.value = response.data.result
    }

    const optimizeCode = async () => {
    const response = await axios.post('/api/ai/optimize-code', {
    code: codeToOptimize.value,
    language: 'java',
    goal: 'PERFORMANCE'
    })
    optimizedCode.value = response.data.result
    }
    </script>

    部署与监控

    # Dockerfile
    FROM openjdk:17-jdk-slim
    WORKDIR /app
    COPY target/ai-tools.jar app.jar
    EXPOSE 8080
    ENTRYPOINT ["java", "-jar", "app.jar"]

    # docker-compose.yml
    version: '3.8'
    services:
    ai-tools:
    build: .
    ports:
    – "8080:8080"
    environment:
    – OPENAI_API_KEY=${OPENAI_API_KEY}
    – SPRING_PROFILES_ACTIVE=prod
    depends_on:
    – mysql
    – redis

    mysql:
    image: mysql:8.0
    environment:
    MYSQL_ROOT_PASSWORD: password
    MYSQL_DATABASE: ai_tools

    redis:
    image: redis:alpine

    增强功能建议

  • 多模型支持 :集成多个AI提供商(OpenAI、Claude、本地模型)
  • 自定义提示词模板 :允许用户保存和重用提示词
  • API密钥管理 :多用户API密钥轮询使用
  • 质量评估 :对AI输出进行评分和反馈收集
  • 插件系统 :支持自定义功能扩展
  • 团队协作 :共享历史记录和模板
  • 这个方案提供了完整的Spring AI工具开发框架,你可以根据具体需求进行调整和扩展。

    赞(0)
    未经允许不得转载:171主机测评 » 【Spring AI实战】第11章 多媒体AI能力实战
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址