25 changed files with 1398 additions and 610 deletions
-
42CLAUDE.md
-
44client/dist/chatbot-sdk.js
-
2client/dist/chatbot-sdk.js.map
-
2client/dist/chatbot-sdk.min.js
-
2client/dist/chatbot-sdk.min.js.map
-
33client/src/api.ts
-
10client/src/chat.ts
-
52src/main/java/com/wok/supportbot/config/ChatModelFactory.java
-
19src/main/java/com/wok/supportbot/config/DatabaseInitConfig.java
-
58src/main/java/com/wok/supportbot/config/DynamicEmbeddingModel.java
-
160src/main/java/com/wok/supportbot/config/EmbeddingConfigFixer.java
-
190src/main/java/com/wok/supportbot/config/EmbeddingModelFactory.java
-
52src/main/java/com/wok/supportbot/config/ModelConfigLoader.java
-
40src/main/java/com/wok/supportbot/controller/AiController.java
-
5src/main/java/com/wok/supportbot/controller/AiModelConfigController.java
-
16src/main/java/com/wok/supportbot/controller/ConversationController.java
-
14src/main/java/com/wok/supportbot/rag/load/InMemoryVectorStoreConfig.java
-
52src/main/java/com/wok/supportbot/rag/load/PgVectorStoreConfig.java
-
13src/main/resources/application.yml
-
58src/main/resources/static/components/ModelConfigManager.js
-
44src/main/resources/static/sdk/chatbot-sdk.js
-
2src/main/resources/static/sdk/chatbot-sdk.js.map
-
2src/main/resources/static/sdk/chatbot-sdk.min.js
-
2src/main/resources/static/sdk/chatbot-sdk.min.js.map
-
996src/main/resources/static/sdk/test.html
2
client/dist/chatbot-sdk.js.map
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
2
client/dist/chatbot-sdk.min.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
2
client/dist/chatbot-sdk.min.js.map
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,58 @@ |
|||
package com.wok.supportbot.config; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.ai.document.Document; |
|||
import org.springframework.ai.embedding.EmbeddingModel; |
|||
import org.springframework.ai.embedding.EmbeddingRequest; |
|||
import org.springframework.ai.embedding.EmbeddingResponse; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 动态 EmbeddingModel 代理 |
|||
* 实现 EmbeddingModel 接口,每次调用委托给 EmbeddingModelFactory 当前活跃的实例。 |
|||
* 这样 PgVectorStore / SimpleVectorStore 无需重建即可在运行时切换向量化模型。 |
|||
* |
|||
* 注意:每次调用都走 factory(factory 内部有缓存,开销很小, |
|||
* 仅在配置变更后第一次调用时才触发新实例创建)。 |
|||
*/ |
|||
@Slf4j |
|||
public class DynamicEmbeddingModel implements EmbeddingModel { |
|||
|
|||
private final EmbeddingModelFactory embeddingModelFactory; |
|||
|
|||
public DynamicEmbeddingModel(EmbeddingModelFactory embeddingModelFactory) { |
|||
this.embeddingModelFactory = embeddingModelFactory; |
|||
} |
|||
|
|||
private EmbeddingModel getDelegate() { |
|||
return embeddingModelFactory.getEmbeddingModel(); |
|||
} |
|||
|
|||
@Override |
|||
public float[] embed(Document document) { |
|||
return getDelegate().embed(document); |
|||
} |
|||
|
|||
@Override |
|||
public EmbeddingResponse embedForResponse(List<String> texts) { |
|||
return getDelegate().embedForResponse(texts); |
|||
} |
|||
|
|||
@Override |
|||
public EmbeddingResponse call(EmbeddingRequest request) { |
|||
return getDelegate().call(request); |
|||
} |
|||
|
|||
@Override |
|||
public int dimensions() { |
|||
return getDelegate().dimensions(); |
|||
} |
|||
|
|||
/** |
|||
* 返回当前委托的 EmbeddingModel 实例,供调试/日志使用 |
|||
*/ |
|||
public EmbeddingModel getCurrentDelegate() { |
|||
return getDelegate(); |
|||
} |
|||
} |
|||
@ -0,0 +1,160 @@ |
|||
package com.wok.supportbot.config; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.ai.embedding.EmbeddingModel; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.context.event.ApplicationReadyEvent; |
|||
import org.springframework.context.ApplicationListener; |
|||
import org.springframework.jdbc.core.JdbcTemplate; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* Embedding 配置检查器 |
|||
* 在应用启动完成后,检查 EMBEDDING 配置的合理性并记录日志。 |
|||
* 注意:不再强制修正非 DashScope 配置,尊重用户在 DB 中配置的提供商和模型。 |
|||
* 新增:检测 EmbeddingModel 返回的实际维度与 yml 配置的向量维度是否一致。 |
|||
*/ |
|||
@Component |
|||
@Slf4j |
|||
public class EmbeddingConfigFixer implements ApplicationListener<ApplicationReadyEvent> { |
|||
|
|||
@Autowired |
|||
private JdbcTemplate jdbcTemplate; |
|||
|
|||
@Autowired |
|||
private EmbeddingModelFactory embeddingModelFactory; |
|||
|
|||
@Value("${spring.ai.dashscope.api-key:}") |
|||
private String dashscopeApiKey; |
|||
|
|||
@Value("${knowledge.vector.dimension:1536}") |
|||
private int fallbackDimension; |
|||
|
|||
@Override |
|||
public void onApplicationEvent(ApplicationReadyEvent event) { |
|||
try { |
|||
checkEmbeddingConfig(); |
|||
checkDimensionConsistency(); |
|||
} catch (Exception e) { |
|||
log.warn("Embedding 配置检查异常(不影响启动): {}", e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
private void checkEmbeddingConfig() { |
|||
// 打印当前 EMBEDDING 所有配置 |
|||
List<Map<String, Object>> allConfigs = jdbcTemplate.queryForList( |
|||
"SELECT id, name, provider, model_name, api_key, base_url, is_active, is_delete " + |
|||
"FROM ai_model_config WHERE app_type = 'EMBEDDING' ORDER BY is_active DESC"); |
|||
log.info("========== EMBEDDING 配置检查 =========="); |
|||
for (Map<String, Object> row : allConfigs) { |
|||
String apiKey = (String) row.get("api_key"); |
|||
String maskedKey = apiKey != null && apiKey.length() > 8 |
|||
? apiKey.substring(0, 4) + "****" + apiKey.substring(apiKey.length() - 4) |
|||
: "****"; |
|||
log.info(" id={} name={} provider={} model={} apiKey={} baseUrl={} active={} deleted={}", |
|||
row.get("id"), row.get("name"), row.get("provider"), |
|||
row.get("model_name"), maskedKey, row.get("base_url"), |
|||
row.get("is_active"), row.get("is_delete")); |
|||
} |
|||
|
|||
// 查找活跃配置 |
|||
Map<String, Object> activeConfig = null; |
|||
for (Map<String, Object> row : allConfigs) { |
|||
if (Boolean.TRUE.equals(row.get("is_active")) |
|||
&& Boolean.FALSE.equals(row.get("is_delete"))) { |
|||
activeConfig = row; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (activeConfig == null) { |
|||
log.warn("EMBEDDING 类型无活跃配置,请在前端管理页面配置"); |
|||
return; |
|||
} |
|||
|
|||
String apiKey = (String) activeConfig.get("api_key"); |
|||
String modelName = (String) activeConfig.get("model_name"); |
|||
String provider = (String) activeConfig.get("provider"); |
|||
String baseUrl = (String) activeConfig.get("base_url"); |
|||
|
|||
// 仅记录警告,不再强制改写(用户可能有意使用非 DashScope 的 Embedding 提供商) |
|||
if (!"dashscope".equalsIgnoreCase(provider)) { |
|||
log.info("EMBEDDING 使用非 DashScope 提供商 [{}],model={}。" |
|||
+ "请确保前端「向量维度」与实际模型输出一致,否则需重建 vector_store 表", provider, modelName); |
|||
} |
|||
|
|||
// DashScope 用户的 API Key 一致性提示(不强制修正,尊重用户 DB 配置) |
|||
if ("dashscope".equalsIgnoreCase(provider) |
|||
&& dashscopeApiKey != null && !dashscopeApiKey.isBlank() |
|||
&& !dashscopeApiKey.equals(apiKey)) { |
|||
log.warn("EMBEDDING DashScope 配置的 API Key 与 application.yml 不一致,以 DB 配置为准。" |
|||
+ "如需统一管理,请在管理页面修改。"); |
|||
} |
|||
|
|||
if (baseUrl != null && !baseUrl.isBlank()) { |
|||
log.debug("EMBEDDING 配置了自定义 baseUrl={}", baseUrl); |
|||
} |
|||
|
|||
log.info("EMBEDDING 配置检查完成,当前使用 provider={} model={}", provider, modelName); |
|||
} |
|||
|
|||
/** |
|||
* 检测 EmbeddingModel 实际返回的维度与配置的向量维度是否一致。 |
|||
* 配置维度优先级:DB extraConfig.dimensions > application.yml knowledge.vector.dimension。 |
|||
*/ |
|||
private void checkDimensionConsistency() { |
|||
try { |
|||
int configuredDimension = resolveConfiguredDimension(); |
|||
EmbeddingModel model = embeddingModelFactory.getEmbeddingModel(); |
|||
int actualDimension = model.dimensions(); |
|||
if (actualDimension > 0 && actualDimension != configuredDimension) { |
|||
log.warn("========== ⚠️ 向量维度不匹配!=========="); |
|||
log.warn("Embedding 模型 {} 返回维度: {}", model, actualDimension); |
|||
log.warn("当前配置的向量维度: {}", configuredDimension); |
|||
log.warn("请执行以下步骤修复:"); |
|||
log.warn(" 1. 在前端「AI 大模型配置管理」中修改 EMBEDDING 配置的向量维度为 {}", actualDimension); |
|||
log.warn(" 2. 在 PostgreSQL 中执行: DROP TABLE IF EXISTS vector_store CASCADE"); |
|||
log.warn(" 3. 重启服务(PgVectorStore 会自动重建表)"); |
|||
log.warn(" 4. 重新上传所有知识库文档"); |
|||
log.warn("========================================"); |
|||
} else { |
|||
log.info("向量维度校验通过: Embedding 模型返回 {} 维,配置 {} 维,一致", |
|||
actualDimension, configuredDimension); |
|||
} |
|||
} catch (Exception e) { |
|||
log.warn("无法校验向量维度(EmbeddingModel 初始化可能失败): {}", e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 解析配置维度:DB extraConfig 优先,yml 兜底。 |
|||
*/ |
|||
private int resolveConfiguredDimension() { |
|||
try { |
|||
List<Map<String, Object>> activeConfigs = jdbcTemplate.queryForList( |
|||
"SELECT extra_config FROM ai_model_config WHERE app_type = 'EMBEDDING' AND is_active = true AND is_delete = false LIMIT 1"); |
|||
if (!activeConfigs.isEmpty()) { |
|||
Map<String, Object> row = activeConfigs.get(0); |
|||
String extraConfigJson = (String) row.get("extra_config"); |
|||
// 简单解析 JSONB 中的 dimensions 字段 |
|||
if (extraConfigJson != null && extraConfigJson.contains("\"dimensions\"")) { |
|||
java.util.regex.Pattern p = java.util.regex.Pattern.compile("\"dimensions\"\\s*:\\s*(\\d+)"); |
|||
java.util.regex.Matcher m = p.matcher(extraConfigJson); |
|||
if (m.find()) { |
|||
int dim = Integer.parseInt(m.group(1)); |
|||
log.info("从 DB EMBEDDING extraConfig 读取维度: {}", dim); |
|||
return dim; |
|||
} |
|||
} |
|||
} |
|||
} catch (Exception e) { |
|||
log.warn("从 DB 读取 EMBEDDING 维度失败: {}", e.getMessage()); |
|||
} |
|||
log.info("使用 application.yml fallback 维度: {}", fallbackDimension); |
|||
return fallbackDimension; |
|||
} |
|||
} |
|||
@ -0,0 +1,190 @@ |
|||
package com.wok.supportbot.config; |
|||
|
|||
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi; |
|||
import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingModel; |
|||
import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions; |
|||
import com.wok.supportbot.entity.AiModelConfig; |
|||
import com.wok.supportbot.service.AiModelConfigService; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.ai.document.MetadataMode; |
|||
import org.springframework.ai.embedding.EmbeddingModel; |
|||
import org.springframework.ai.openai.OpenAiEmbeddingModel; |
|||
import org.springframework.ai.openai.OpenAiEmbeddingOptions; |
|||
import org.springframework.ai.openai.api.OpenAiApi; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.retry.backoff.ExponentialBackOffPolicy; |
|||
import org.springframework.retry.support.RetryTemplate; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.Map; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
/** |
|||
* EmbeddingModel 工厂 |
|||
* 按 DB 活跃配置(EMBEDDING 类型)动态创建/缓存 EmbeddingModel 实例,支持运行时切换提供商。 |
|||
* - DashScope:手动构造 DashScopeApi + DashScopeEmbeddingModel |
|||
* - DeepSeek / Kimi / 豆包 / 智谱 / OpenAI 等:通过 spring-ai-openai 模块 + 自定义 baseUrl 创建 |
|||
*/ |
|||
@Component |
|||
@Slf4j |
|||
public class EmbeddingModelFactory { |
|||
|
|||
@Autowired |
|||
private AiModelConfigService configService; |
|||
|
|||
/** |
|||
* EmbeddingModel 缓存:key = "provider:apiKey:modelName" |
|||
*/ |
|||
private final ConcurrentHashMap<String, EmbeddingModel> cache = new ConcurrentHashMap<>(); |
|||
|
|||
/** |
|||
* 各提供商默认的 API 基础地址 |
|||
*/ |
|||
private static final Map<String, String> DEFAULT_BASE_URLS = Map.of( |
|||
"deepseek", "https://api.deepseek.com", |
|||
"moonshot", "https://api.moonshot.cn/v1", |
|||
"volcengine", "https://ark.cn-beijing.volces.com/api/v3", |
|||
"zhipu", "https://open.bigmodel.cn/api/paas/v4", |
|||
"openai", "https://api.openai.com" |
|||
); |
|||
|
|||
/** |
|||
* 各提供商的 Embedding API 路径(相对于 baseUrl) |
|||
* OpenAI 默认是 /v1/embeddings,但许多国产厂商在 baseUrl 中已包含版本号 |
|||
* (如 /v1、/api/v3、/api/paas/v4),因此只需 /embeddings 即可。 |
|||
* 豆包多模态模型需使用 /embeddings/multimodal(与 OpenAI 请求格式不兼容,另行处理)。 |
|||
*/ |
|||
private static final Map<String, String> EMBEDDINGS_PATHS = Map.of( |
|||
"deepseek", "/v1/embeddings", |
|||
"moonshot", "/embeddings", // baseUrl 已含 /v1 |
|||
"volcengine", "/embeddings", // baseUrl 已含 /api/v3 |
|||
"zhipu", "/embeddings", // baseUrl 已含 /api/paas/v4 |
|||
"openai", "/v1/embeddings" |
|||
); |
|||
|
|||
/** |
|||
* 获取当前活跃的 EmbeddingModel |
|||
* 查询 DB 中 app_type=EMBEDDING 的活跃配置,无配置时使用 DashScope text-embedding-v2 作为兜底 |
|||
* |
|||
* @return EmbeddingModel 实例 |
|||
*/ |
|||
public EmbeddingModel getEmbeddingModel() { |
|||
AiModelConfig config = configService.getActiveConfigWithFullKey("EMBEDDING"); |
|||
if (config == null || config.getApiKey() == null || config.getApiKey().isBlank()) { |
|||
log.warn("EMBEDDING 类型无活跃配置,请在管理页面配置向量化模型"); |
|||
throw new IllegalStateException("EMBEDDING 类型无活跃配置,请在管理页面配置向量化模型"); |
|||
} |
|||
log.debug("获取 EMBEDDING 活跃配置: provider={}, modelName={}, apiKey前4位={}", |
|||
config.getProvider(), config.getModelName(), |
|||
config.getApiKey().substring(0, Math.min(4, config.getApiKey().length()))); |
|||
return getOrCreateEmbeddingModel(config); |
|||
} |
|||
|
|||
/** |
|||
* 获取或创建 EmbeddingModel(带缓存) |
|||
* 缓存 key = provider:apiKey:modelName,配置不变则复用实例 |
|||
*/ |
|||
private EmbeddingModel getOrCreateEmbeddingModel(AiModelConfig config) { |
|||
String cacheKey = config.getProvider() + ":" + config.getApiKey() + ":" + config.getModelName(); |
|||
return cache.computeIfAbsent(cacheKey, k -> createEmbeddingModel(config)); |
|||
} |
|||
|
|||
/** |
|||
* 创建 EmbeddingModel 实例 |
|||
* - dashscope:手动构造 DashScopeApi + DashScopeEmbeddingModel |
|||
* - volcengine 豆包多模态模型:抛出异常提示选用纯文本模型 |
|||
* - 其他提供商:通过 OpenAI 兼容 API 创建 |
|||
*/ |
|||
private EmbeddingModel createEmbeddingModel(AiModelConfig config) { |
|||
RetryTemplate retryTemplate = createRetryTemplate(); |
|||
|
|||
if ("dashscope".equalsIgnoreCase(config.getProvider())) { |
|||
log.info("创建 DashScope EmbeddingModel: model={}", config.getModelName()); |
|||
DashScopeApi api = DashScopeApi.builder() |
|||
.apiKey(config.getApiKey()) |
|||
.build(); |
|||
DashScopeEmbeddingOptions options = DashScopeEmbeddingOptions.builder() |
|||
.withModel(config.getModelName()) |
|||
.build(); |
|||
return new DashScopeEmbeddingModel(api, MetadataMode.EMBED, options, retryTemplate); |
|||
} |
|||
|
|||
// 豆包多模态模型检测:doubao-embedding-vision* 使用 /embeddings/multimodal 端点, |
|||
// 请求/响应格式与 OpenAI 不兼容,无法通过 OpenAiEmbeddingModel 调用。 |
|||
// 提示用户改用纯文本模型。 |
|||
if ("volcengine".equalsIgnoreCase(config.getProvider()) |
|||
&& config.getModelName() != null |
|||
&& config.getModelName().contains("vision")) { |
|||
throw new IllegalArgumentException( |
|||
"豆包多模态向量模型 (" + config.getModelName() + ") 不支持当前使用的 OpenAI 兼容 API 格式。" |
|||
+ "请将 EMBEDDING 模型名称改为纯文本模型,如 doubao-embedding-text-240515(2048维)或 doubao-embedding-large(4096维)。" |
|||
+ "注意:切换向量维度后需调整 PgVectorStoreConfig.dimensions 并重建 vector_store 表。"); |
|||
} |
|||
|
|||
// OpenAI 兼容提供商 |
|||
String baseUrl = resolveBaseUrl(config); |
|||
String embeddingsPath = resolveEmbeddingsPath(config); |
|||
log.info("创建 OpenAI 兼容 EmbeddingModel: provider={}, baseUrl={}, embeddingsPath={}, model={}", |
|||
config.getProvider(), baseUrl, embeddingsPath, config.getModelName()); |
|||
|
|||
// 维度一致性提示 |
|||
log.info("⚠ 请确认模型 [{}] 的向量维度与 PgVectorStoreConfig.dimensions(1536) 一致,否则需调整并重建向量表", |
|||
config.getModelName()); |
|||
|
|||
OpenAiApi api = OpenAiApi.builder() |
|||
.apiKey(config.getApiKey()) |
|||
.baseUrl(baseUrl) |
|||
.embeddingsPath(embeddingsPath) |
|||
.build(); |
|||
|
|||
OpenAiEmbeddingOptions options = OpenAiEmbeddingOptions.builder() |
|||
.model(config.getModelName()) |
|||
.build(); |
|||
|
|||
return new OpenAiEmbeddingModel(api, MetadataMode.EMBED, options, retryTemplate); |
|||
} |
|||
|
|||
/** |
|||
* 解析 API 基础地址:优先使用 DB 配置的 baseUrl,否则使用提供商默认值 |
|||
*/ |
|||
private String resolveBaseUrl(AiModelConfig config) { |
|||
if (config.getBaseUrl() != null && !config.getBaseUrl().isBlank()) { |
|||
return config.getBaseUrl(); |
|||
} |
|||
String defaultUrl = DEFAULT_BASE_URLS.get(config.getProvider()); |
|||
if (defaultUrl != null) { |
|||
return defaultUrl; |
|||
} |
|||
throw new IllegalArgumentException( |
|||
"未知提供商 [" + config.getProvider() + "],请在配置中填写 API 基础地址 (baseUrl)"); |
|||
} |
|||
|
|||
/** |
|||
* 解析 Embedding API 路径:优先使用提供商已知路径,否则使用 OpenAI 默认 /v1/embeddings |
|||
*/ |
|||
private String resolveEmbeddingsPath(AiModelConfig config) { |
|||
String known = EMBEDDINGS_PATHS.get(config.getProvider()); |
|||
return known != null ? known : "/v1/embeddings"; |
|||
} |
|||
|
|||
/** |
|||
* 创建简单的重试模板(最多 3 次,指数退避) |
|||
*/ |
|||
private RetryTemplate createRetryTemplate() { |
|||
RetryTemplate retryTemplate = new RetryTemplate(); |
|||
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy(); |
|||
backOffPolicy.setInitialInterval(1000); |
|||
backOffPolicy.setMultiplier(2); |
|||
backOffPolicy.setMaxInterval(10000); |
|||
retryTemplate.setBackOffPolicy(backOffPolicy); |
|||
return retryTemplate; |
|||
} |
|||
|
|||
/** |
|||
* 清除 EmbeddingModel 缓存(配置变更时调用) |
|||
*/ |
|||
public void clearCache() { |
|||
cache.clear(); |
|||
log.info("EmbeddingModel 缓存已清除"); |
|||
} |
|||
} |
|||
@ -1,20 +1,26 @@ |
|||
package com.wok.supportbot.rag.load; |
|||
|
|||
import org.springframework.ai.embedding.EmbeddingModel; |
|||
import com.wok.supportbot.config.DynamicEmbeddingModel; |
|||
import com.wok.supportbot.config.EmbeddingModelFactory; |
|||
import org.springframework.ai.vectorstore.SimpleVectorStore; |
|||
import org.springframework.ai.vectorstore.VectorStore; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
/** |
|||
* 向量数据库配置(初始化基于内存的向量数据库 Bean) |
|||
* 使用 DynamicEmbeddingModel 代理,支持运行时切换向量化模型无需重启 |
|||
*/ |
|||
@Configuration |
|||
public class InMemoryVectorStoreConfig { |
|||
|
|||
@Autowired |
|||
private EmbeddingModelFactory embeddingModelFactory; |
|||
|
|||
@Bean |
|||
VectorStore inMemoryVectorStore(EmbeddingModel dashscopeEmbeddingModel) { |
|||
SimpleVectorStore simpleVectorStore = SimpleVectorStore.builder(dashscopeEmbeddingModel).build();; |
|||
return simpleVectorStore; |
|||
VectorStore inMemoryVectorStore() { |
|||
DynamicEmbeddingModel dynamicEmbeddingModel = new DynamicEmbeddingModel(embeddingModelFactory); |
|||
return SimpleVectorStore.builder(dynamicEmbeddingModel).build(); |
|||
} |
|||
} |
|||
2
src/main/resources/static/sdk/chatbot-sdk.js.map
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
2
src/main/resources/static/sdk/chatbot-sdk.min.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
2
src/main/resources/static/sdk/chatbot-sdk.min.js.map
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
996
src/main/resources/static/sdk/test.html
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue