多场景分析代码架构

This commit is contained in:
zhonghua1
2026-01-06 22:07:30 +08:00
parent 146d56fbd4
commit be1554cd9a
3 changed files with 218 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
package com.rj.common;
/**
* 音频文本分析场景类型
* 不同场景对应不同的系统/用户提示词以及大模型配置。
*/
public enum AudioAnalysisSceneType {
/**
* 家具销售/家居意向场景
*/
SCENARIO_FURNITURE_SALE(
"prompts/audio_text_analysis_furniture_system.txt",
"prompts/audio_text_analysis_furniture_user.txt",
"qwen-plus"
),
/**
* 会议纪要/会议分析场景
* 提示词文件和模型可根据实际需要进行调整。
*/
SCENARIO_MEETING_SUMMARY(
"prompts/audio_text_analysis_meeting_system.txt",
"prompts/audio_text_analysis_meeting_user.txt",
"qwen-plus"
),
/**
* 房产销售/置业顾问场景
*/
SCENARIO_CAR_SALE(
"prompts/audio_text_analysis_real_estate_system.txt",
"prompts/audio_text_analysis_real_estate_user.txt",
"qwen-plus"
);
private final String systemPromptPath;
private final String userPromptPath;
private final String modelName;
AudioAnalysisSceneType(String systemPromptPath, String userPromptPath, String modelName) {
this.systemPromptPath = systemPromptPath;
this.userPromptPath = userPromptPath;
this.modelName = modelName;
}
public String getSystemPromptPath() {
return systemPromptPath;
}
public String getUserPromptPath() {
return userPromptPath;
}
public String getModelName() {
return modelName;
}
}

View File

@@ -0,0 +1,24 @@
package com.rj.service;
import com.rj.common.AudioAnalysisSceneType;
/**
* 音频文本分析 - 大模型通用服务
* <p>
* 封装不同业务场景下的大模型调用逻辑(提示词加载、模型选择等),
* 控制层只需要关心场景类型和原始录音文本。
* </p>
*/
public interface IAudioTextAnalysisLlmService {
/**
* 调用大模型生成总结/结构化结果(通用方法)
*
* @param sceneType 业务场景类型(家具、会议、房产等)
* @param recordingText 录音转写文本
* @return 大模型返回的原始内容(一般是 JSON 字符串或结构化文本)
*/
String generateSummaryByLLM(AudioAnalysisSceneType sceneType, String recordingText);
}

View File

@@ -0,0 +1,134 @@
package com.rj.service.impl;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.rj.common.AudioAnalysisSceneType;
import com.rj.service.IAudioTextAnalysisLlmService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
/**
* 音频文本分析 - 大模型通用服务实现
*/
@Service
@Slf4j
public class AudioTextAnalysisLlmServiceImpl implements IAudioTextAnalysisLlmService {
private static final Map<String, String> SYSTEM_PROMPT_CACHE = new ConcurrentHashMap<>();
private static final Map<String, String> USER_PROMPT_CACHE = new ConcurrentHashMap<>();
@Override
public String generateSummaryByLLM(AudioAnalysisSceneType sceneType, String recordingText) {
long startTime = System.currentTimeMillis();
log.info("开始调用大模型生成总结,场景: {}", sceneType);
String systemPrompt = getSystemPrompt(sceneType);
String userPromptTemplate = getUserPromptTemplate(sceneType);
String userPrompt = buildPrompt(userPromptTemplate, recordingText);
Generation gen = new Generation();
Message systemMsg = Message.builder()
.role(Role.SYSTEM.getValue())
.content(systemPrompt)
.build();
Message userMsg = Message.builder()
.role(Role.USER.getValue())
.content(userPrompt)
.build();
GenerationParam param = GenerationParam.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(sceneType.getModelName())
.messages(Arrays.asList(systemMsg, userMsg))
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.build();
try {
GenerationResult call = gen.call(param);
String rawContent = call.getOutput().getChoices().get(0).getMessage().getContent();
log.info("大模型生成总结完成,场景: {}, 结果长度: {}", sceneType, rawContent != null ? rawContent.length() : 0);
return rawContent;
} catch (NoApiKeyException e) {
log.error("API密钥未配置", e);
throw new RuntimeException("API密钥未配置: " + e.getMessage(), e);
} catch (InputRequiredException e) {
log.error("输入参数错误", e);
throw new RuntimeException("输入参数错误: " + e.getMessage(), e);
} catch (Exception e) {
log.error("调用大模型生成总结失败, 场景: {}", sceneType, e);
throw new RuntimeException("调用大模型失败: " + e.getMessage(), e);
} finally {
long endTime = System.currentTimeMillis();
long durationMillis = endTime - startTime;
double durationSeconds = durationMillis / 1000.0;
double durationMinutes = durationSeconds / 60.0;
log.info("调用大模型耗时: {} 毫秒, {} 秒, {} 分钟, 场景: {}",
durationMillis,
String.format("%.2f", durationSeconds),
String.format("%.2f", durationMinutes),
sceneType);
}
}
private String buildPrompt(String template, String recordingText) {
if (template == null) {
return recordingText != null ? recordingText : "";
}
return template.replace("{RECORDING_TEXT}", recordingText != null ? recordingText : "");
}
private String getSystemPrompt(AudioAnalysisSceneType sceneType) {
return SYSTEM_PROMPT_CACHE.computeIfAbsent(sceneType.name(), key -> {
String path = sceneType.getSystemPromptPath();
String content = readResourceFile(path);
if (content == null || content.trim().isEmpty()) {
log.warn("无法读取系统提示词文件: {},场景: {},请检查资源文件是否存在", path, sceneType);
}
return content != null ? content : "";
});
}
private String getUserPromptTemplate(AudioAnalysisSceneType sceneType) {
return USER_PROMPT_CACHE.computeIfAbsent(sceneType.name(), key -> {
String path = sceneType.getUserPromptPath();
String content = readResourceFile(path);
if (content == null || content.trim().isEmpty()) {
log.warn("无法读取用户提示词模板文件: {},场景: {},请检查资源文件是否存在", path, sceneType);
}
return content != null ? content : "";
});
}
private String readResourceFile(String resourcePath) {
try {
ClassLoader classLoader = getClass().getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(resourcePath);
if (inputStream == null) {
log.error("无法找到资源文件: {}", resourcePath);
return null;
}
try (Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name()).useDelimiter("\\A")) {
String content = scanner.hasNext() ? scanner.next() : "";
log.info("成功读取提示词文件: {}, 长度: {}", resourcePath, content.length());
return content;
}
} catch (Exception e) {
log.error("读取资源文件失败: {}", resourcePath, e);
return null;
}
}
}