This commit is contained in:
aruo
2026-05-31 21:45:14 +08:00
parent d4b5015beb
commit ac08345369
67 changed files with 11120 additions and 387 deletions
@@ -1,19 +1,11 @@
package org.example.service;
import com.alibaba.dashscope.embeddings.TextEmbedding;
import com.alibaba.dashscope.embeddings.TextEmbeddingParam;
import com.alibaba.dashscope.embeddings.TextEmbeddingResult;
import com.alibaba.dashscope.embeddings.TextEmbeddingOutput;
import com.alibaba.dashscope.embeddings.TextEmbeddingResultItem;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -27,44 +19,8 @@ public class VectorEmbeddingService {
private static final Logger logger = LoggerFactory.getLogger(VectorEmbeddingService.class);
@Value("${dashscope.api.key}")
private String apiKey;
@Value("${dashscope.embedding.model}")
private String model;
private TextEmbedding textEmbedding;
@PostConstruct
public void init() {
// 验证 API Key
if (apiKey == null || apiKey.trim().isEmpty() || apiKey.equals("your-api-key-here")) {
logger.error("API Key 未正确配置!当前值: {}", apiKey);
throw new IllegalStateException("请设置环境变量 DASHSCOPE_API_KEY 或在 application.yml 中配置正确的 API Key");
}
// 打印 API Key 前缀用于调试(不打印完整 Key 保证安全)
String maskedKey = apiKey.length() > 8 ?
apiKey.substring(0, 8) + "..." + apiKey.substring(apiKey.length() - 4) :
"***";
logger.info("API Key 已加载: {}", maskedKey);
// 设置全局 API Key(确保设置成功)
Constants.apiKey = apiKey;
// 验证 API Key 是否设置成功
if (Constants.apiKey == null || Constants.apiKey.isEmpty()) {
logger.error("Constants.apiKey 设置失败!");
throw new IllegalStateException("API Key 设置到 Constants 失败");
}
logger.info("Constants.apiKey 已设置: {}", Constants.apiKey.substring(0, Math.min(8, Constants.apiKey.length())) + "...");
// 创建 TextEmbedding 实例
textEmbedding = new TextEmbedding();
logger.info("阿里云 DashScope Embedding 服务初始化完成,模型: {}", model);
}
@Autowired
private EmbeddingModel embeddingModel;
/**
* 生成向量嵌入
@@ -81,73 +37,25 @@ public class VectorEmbeddingService {
}
logger.debug("开始生成向量嵌入, 内容长度: {} 字符", content.length());
// 确保 API Key 已设置(防止被其他地方覆盖)
if (Constants.apiKey == null || Constants.apiKey.isEmpty()) {
logger.warn("检测到 Constants.apiKey 为空,重新设置");
Constants.apiKey = apiKey;
float[] embedding = embeddingModel.embed(content);
List<Float> floatEmbedding = new ArrayList<>(embedding.length);
for (float v : embedding) {
floatEmbedding.add(v);
}
logger.debug("调用 API 前 Constants.apiKey: {}",
Constants.apiKey != null ? Constants.apiKey.substring(0, Math.min(8, Constants.apiKey.length())) + "..." : "null");
// 构建请求参数
TextEmbeddingParam param = TextEmbeddingParam
.builder()
.model(model)
.texts(Collections.singletonList(content))
.build();
// 调用 API
TextEmbeddingResult result = textEmbedding.call(param);
// 检查结果
List<Float> floatEmbedding = getFloats(result);
logger.info("成功生成向量嵌入, 内容长度: {} 字符, 向量维度: {}",
logger.info("成功生成向量嵌入, 内容长度: {} 字符, 向量维度: {}",
content.length(), floatEmbedding.size());
return floatEmbedding;
} catch (NoApiKeyException e) {
logger.error("API Key 未设置或无效", e);
throw new RuntimeException("API Key 未设置,请配置 dashscope.api.key", e);
} catch (Exception e) {
logger.error("生成向量嵌入失败, 内容长度: {}", content != null ? content.length() : 0, e);
throw new RuntimeException("生成向量嵌入失败: " + e.getMessage(), e);
}
}
@NotNull
private static List<Float> getFloats(TextEmbeddingResult result) {
if (result == null || result.getOutput() == null || result.getOutput().getEmbeddings() == null) {
throw new RuntimeException("DashScope API 返回空结果");
}
TextEmbeddingOutput output = result.getOutput();
List<TextEmbeddingResultItem> embeddings = output.getEmbeddings();
if (embeddings.isEmpty()) {
throw new RuntimeException("DashScope API 返回空向量列表");
}
// 获取第一个文本的向量
List<Double> embeddingDoubles = embeddings.get(0).getEmbedding();
// 转换为 List<Float>
List<Float> floatEmbedding = new ArrayList<>(embeddingDoubles.size());
for (Double value : embeddingDoubles) {
floatEmbedding.add(value.floatValue());
}
return floatEmbedding;
}
/**
* 批量生成向量嵌入
*
* @param contents 文本内容列表
* @return 向量嵌入列表
*/
public List<List<Float>> generateEmbeddings(List<String> contents) {
try {
if (contents == null || contents.isEmpty()) {
@@ -156,54 +64,24 @@ public class VectorEmbeddingService {
}
logger.info("开始批量生成向量嵌入, 数量: {}", contents.size());
// 确保 API Key 已设置
if (Constants.apiKey == null || Constants.apiKey.isEmpty()) {
logger.warn("检测到 Constants.apiKey 为空,重新设置");
Constants.apiKey = apiKey;
}
// 构建请求参数 - 批量输入
TextEmbeddingParam param = TextEmbeddingParam
.builder()
.model(model)
.texts(contents)
.build();
List<float[]> embeddings = embeddingModel.embed(contents);
// 调用 API
TextEmbeddingResult result = textEmbedding.call(param);
// 检查结果
if (result == null || result.getOutput() == null || result.getOutput().getEmbeddings() == null) {
throw new RuntimeException("批量 DashScope API 返回空结果");
}
List<TextEmbeddingResultItem> embeddingItems = result.getOutput().getEmbeddings();
if (embeddingItems.isEmpty()) {
throw new RuntimeException("批量 DashScope API 返回空向量列表");
}
// 转换结果
List<List<Float>> embeddings = new ArrayList<>();
for (TextEmbeddingResultItem item : embeddingItems) {
List<Double> embeddingDoubles = item.getEmbedding();
List<Float> embedding = new ArrayList<>(embeddingDoubles.size());
for (Double value : embeddingDoubles) {
embedding.add(value.floatValue());
List<List<Float>> result = new ArrayList<>();
for (float[] embedding : embeddings) {
List<Float> floatEmbedding = new ArrayList<>(embedding.length);
for (float v : embedding) {
floatEmbedding.add(v);
}
embeddings.add(embedding);
result.add(floatEmbedding);
}
logger.info("成功批量生成向量嵌入, 数量: {}, 维度: {}",
embeddings.size(),
embeddings.isEmpty() ? 0 : embeddings.get(0).size());
logger.info("成功批量生成向量嵌入, 数量: {}, 维度: {}",
result.size(),
result.isEmpty() ? 0 : result.get(0).size());
return embeddings;
return result;
} catch (NoApiKeyException e) {
logger.error("批量调用时 API Key 未设置或无效", e);
throw new RuntimeException("API Key 未设置,请配置 dashscope.api.key", e);
} catch (Exception e) {
logger.error("批量生成向量嵌入失败", e);
throw new RuntimeException("批量生成向量嵌入失败: " + e.getMessage(), e);