mirror of
https://github.com/ccmjga/zhilu-admin
synced 2026-04-05 11:47:32 +00:00
init action
This commit is contained in:
@@ -61,6 +61,7 @@ dependencies {
|
|||||||
implementation("org.springframework.boot:spring-boot-starter-quartz")
|
implementation("org.springframework.boot:spring-boot-starter-quartz")
|
||||||
implementation("dev.langchain4j:langchain4j:1.0.0")
|
implementation("dev.langchain4j:langchain4j:1.0.0")
|
||||||
implementation("dev.langchain4j:langchain4j-open-ai:1.0.0")
|
implementation("dev.langchain4j:langchain4j-open-ai:1.0.0")
|
||||||
|
implementation("dev.langchain4j:langchain4j-pgvector:1.0.1-beta6")
|
||||||
implementation("dev.langchain4j:langchain4j-community-zhipu-ai:1.0.1-beta6")
|
implementation("dev.langchain4j:langchain4j-community-zhipu-ai:1.0.1-beta6")
|
||||||
implementation("io.projectreactor:reactor-core:3.7.6")
|
implementation("io.projectreactor:reactor-core:3.7.6")
|
||||||
testImplementation("org.testcontainers:junit-jupiter:$testcontainersVersion")
|
testImplementation("org.testcontainers:junit-jupiter:$testcontainersVersion")
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.zl.mjga.config.ai;
|
||||||
|
|
||||||
|
import dev.langchain4j.community.model.zhipu.ZhipuAiEmbeddingModel;
|
||||||
|
import dev.langchain4j.data.segment.TextSegment;
|
||||||
|
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||||
|
import dev.langchain4j.store.embedding.pgvector.PgVectorEmbeddingStore;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.DependsOn;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class EmbeddingConfig {
|
||||||
|
|
||||||
|
@Resource private Environment env;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@DependsOn("flywayInitializer")
|
||||||
|
public EmbeddingModel zhipuEmbeddingModel(ZhiPuConfiguration zhiPuConfiguration) {
|
||||||
|
return ZhipuAiEmbeddingModel.builder()
|
||||||
|
.apiKey(zhiPuConfiguration.getApiKey())
|
||||||
|
.model(zhiPuConfiguration.getEmbeddingModel())
|
||||||
|
.dimensions(2048)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EmbeddingStore<TextSegment> zhiPuEmbeddingStore(EmbeddingModel zhipuEmbeddingModel) {
|
||||||
|
String hostPort = env.getProperty("DATABASE_HOST_PORT");
|
||||||
|
String host = hostPort.split(":")[0];
|
||||||
|
return PgVectorEmbeddingStore.builder()
|
||||||
|
.host(host)
|
||||||
|
.port(env.getProperty("DATABASE_EXPOSE_PORT", Integer.class))
|
||||||
|
.database(env.getProperty("DATABASE_DB"))
|
||||||
|
.user(env.getProperty("DATABASE_USER"))
|
||||||
|
.password(env.getProperty("DATABASE_PASSWORD"))
|
||||||
|
.table("mjga.zhipu_embedding_store")
|
||||||
|
.dimension(2048)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,10 +11,12 @@ public class ZhiPuConfiguration {
|
|||||||
private String baseUrl;
|
private String baseUrl;
|
||||||
private String apiKey;
|
private String apiKey;
|
||||||
private String modelName;
|
private String modelName;
|
||||||
|
private String embeddingModel;
|
||||||
|
|
||||||
public void init(AiLlmConfig config) {
|
public void init(AiLlmConfig config) {
|
||||||
this.baseUrl = config.getUrl();
|
this.baseUrl = config.getUrl();
|
||||||
this.apiKey = config.getApiKey();
|
this.apiKey = config.getApiKey();
|
||||||
this.modelName = config.getModelName();
|
this.modelName = config.getModelName();
|
||||||
|
this.embeddingModel = config.getEmbeddingModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,20 @@ import com.zl.mjga.dto.PageRequestDto;
|
|||||||
import com.zl.mjga.dto.PageResponseDto;
|
import com.zl.mjga.dto.PageResponseDto;
|
||||||
import com.zl.mjga.dto.ai.LlmQueryDto;
|
import com.zl.mjga.dto.ai.LlmQueryDto;
|
||||||
import com.zl.mjga.dto.ai.LlmVm;
|
import com.zl.mjga.dto.ai.LlmVm;
|
||||||
|
import com.zl.mjga.exception.BusinessException;
|
||||||
import com.zl.mjga.service.AiChatService;
|
import com.zl.mjga.service.AiChatService;
|
||||||
|
import com.zl.mjga.service.EmbeddingService;
|
||||||
import com.zl.mjga.service.LlmService;
|
import com.zl.mjga.service.LlmService;
|
||||||
import dev.langchain4j.service.TokenStream;
|
import dev.langchain4j.service.TokenStream;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jooq.generated.mjga.enums.LlmCodeEnum;
|
||||||
|
import org.jooq.generated.mjga.tables.pojos.AiLlmConfig;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@@ -28,6 +33,7 @@ public class AiController {
|
|||||||
|
|
||||||
private final AiChatService aiChatService;
|
private final AiChatService aiChatService;
|
||||||
private final LlmService llmService;
|
private final LlmService llmService;
|
||||||
|
private final EmbeddingService embeddingService;
|
||||||
|
|
||||||
@PostMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
@PostMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
public Flux<String> chat(Principal principal, @RequestBody String userMessage) {
|
public Flux<String> chat(Principal principal, @RequestBody String userMessage) {
|
||||||
@@ -57,4 +63,13 @@ public class AiController {
|
|||||||
@ModelAttribute PageRequestDto pageRequestDto, @ModelAttribute LlmQueryDto llmQueryDto) {
|
@ModelAttribute PageRequestDto pageRequestDto, @ModelAttribute LlmQueryDto llmQueryDto) {
|
||||||
return llmService.pageQueryLlm(pageRequestDto, llmQueryDto);
|
return llmService.pageQueryLlm(pageRequestDto, llmQueryDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/action/chat")
|
||||||
|
public Map<String, Object> actionChat(@RequestBody String message) {
|
||||||
|
AiLlmConfig aiLlmConfig = llmService.loadConfig(LlmCodeEnum.ZHI_PU);
|
||||||
|
if (!aiLlmConfig.getEnable()) {
|
||||||
|
throw new BusinessException("命令模型未启用,请开启后再试。");
|
||||||
|
}
|
||||||
|
return embeddingService.searchAction(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
backend/src/main/java/com/zl/mjga/model/urp/Actions.java
Normal file
14
backend/src/main/java/com/zl/mjga/model/urp/Actions.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package com.zl.mjga.model.urp;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum Actions {
|
||||||
|
CREATE_USER("CREATE_USER", "创建新用户"),
|
||||||
|
DELETE_USER("DELETE_USER", "删除用户");
|
||||||
|
public static final String INDEX_KEY = "action";
|
||||||
|
private final String code;
|
||||||
|
private final String content;
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.zl.mjga.service;
|
||||||
|
|
||||||
|
import static dev.langchain4j.store.embedding.filter.MetadataFilterBuilder.metadataKey;
|
||||||
|
|
||||||
|
import com.zl.mjga.model.urp.Actions;
|
||||||
|
import dev.langchain4j.data.document.Metadata;
|
||||||
|
import dev.langchain4j.data.embedding.Embedding;
|
||||||
|
import dev.langchain4j.data.segment.TextSegment;
|
||||||
|
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingSearchResult;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||||
|
import dev.langchain4j.store.embedding.filter.Filter;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class EmbeddingService {
|
||||||
|
|
||||||
|
private final EmbeddingModel zhipuEmbeddingModel;
|
||||||
|
|
||||||
|
private final EmbeddingStore<TextSegment> zhiPuEmbeddingStore;
|
||||||
|
|
||||||
|
public Map<String, Object> searchAction(String message) {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
EmbeddingSearchRequest embeddingSearchRequest =
|
||||||
|
EmbeddingSearchRequest.builder()
|
||||||
|
.queryEmbedding(zhipuEmbeddingModel.embed(message).content())
|
||||||
|
.build();
|
||||||
|
EmbeddingSearchResult<TextSegment> embeddingSearchResult =
|
||||||
|
zhiPuEmbeddingStore.search(embeddingSearchRequest);
|
||||||
|
if (!embeddingSearchResult.matches().isEmpty()) {
|
||||||
|
result = embeddingSearchResult.matches().getFirst().embedded().metadata().toMap();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void initActionIndex() {
|
||||||
|
for (Actions action : Actions.values()) {
|
||||||
|
Embedding queryEmbedding = zhipuEmbeddingModel.embed(action.getContent()).content();
|
||||||
|
Filter createUserFilter = metadataKey(Actions.INDEX_KEY).isEqualTo(action.getCode());
|
||||||
|
EmbeddingSearchRequest embeddingSearchRequest =
|
||||||
|
EmbeddingSearchRequest.builder()
|
||||||
|
.queryEmbedding(queryEmbedding)
|
||||||
|
.filter(createUserFilter)
|
||||||
|
.build();
|
||||||
|
EmbeddingSearchResult<TextSegment> embeddingSearchResult =
|
||||||
|
zhiPuEmbeddingStore.search(embeddingSearchRequest);
|
||||||
|
if (embeddingSearchResult.matches().isEmpty()) {
|
||||||
|
TextSegment segment =
|
||||||
|
TextSegment.from(
|
||||||
|
action.getContent(), Metadata.metadata(Actions.INDEX_KEY, action.getCode()));
|
||||||
|
Embedding embedding = zhipuEmbeddingModel.embed(segment).content();
|
||||||
|
zhiPuEmbeddingStore.add(embedding, segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -77,6 +77,7 @@ CREATE TABLE mjga.ai_llm_config (
|
|||||||
name VARCHAR(255) NOT NULL UNIQUE,
|
name VARCHAR(255) NOT NULL UNIQUE,
|
||||||
code mjga.llm_code_enum NOT NULL UNIQUE,
|
code mjga.llm_code_enum NOT NULL UNIQUE,
|
||||||
model_name VARCHAR(255) NOT NULL,
|
model_name VARCHAR(255) NOT NULL,
|
||||||
|
embedding_model VARCHAR(255) NOT NULL,
|
||||||
api_key VARCHAR(255) NOT NULL,
|
api_key VARCHAR(255) NOT NULL,
|
||||||
url VARCHAR(255) NOT NULL,
|
url VARCHAR(255) NOT NULL,
|
||||||
enable BOOLEAN NOT NULL DEFAULT true,
|
enable BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ VALUES (1, 1),
|
|||||||
(1, 9),
|
(1, 9),
|
||||||
(1, 10);
|
(1, 10);
|
||||||
|
|
||||||
INSERT INTO mjga.ai_llm_config (name,code,model_name, api_key, url, enable, priority)
|
INSERT INTO mjga.ai_llm_config (name,code,model_name,embedding_model, api_key, url, enable, priority)
|
||||||
VALUES
|
VALUES
|
||||||
('DeepSeek','DEEP_SEEK','deepseek-chat','your_api_key', 'https://api.deepseek.com', false, 0),
|
('DeepSeek','DEEP_SEEK','deepseek-chat','embedding-model-name','your_api_key', 'https://api.deepseek.com', false, 0),
|
||||||
('智谱清言','ZHI_PU','glm-4-flash', 'your_api_key', 'https://open.bigmodel.cn/', false, 1);
|
('智谱清言','ZHI_PU','glm-4-flash','embedding-model-name', 'your_api_key', 'https://open.bigmodel.cn/', false, 1);
|
||||||
Reference in New Issue
Block a user