|
@@ -1,198 +0,0 @@
|
|
|
-/*
|
|
|
- * Copyright (c) 2025 GaoKunW
|
|
|
- *
|
|
|
- */
|
|
|
-
|
|
|
-package org.eco.vip.ai.ollama.service;
|
|
|
-
|
|
|
-
|
|
|
-import cn.hutool.json.JSONArray;
|
|
|
-import cn.hutool.json.JSONObject;
|
|
|
-import io.github.pigmesh.ai.deepseek.core.DeepSeekClient;
|
|
|
-import io.github.pigmesh.ai.deepseek.core.Json;
|
|
|
-import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionChoice;
|
|
|
-import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionRequest;
|
|
|
-import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse;
|
|
|
-import jakarta.annotation.Resource;
|
|
|
-import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.eco.vip.text2sql.api.IText2sqlApi;
|
|
|
-import org.eco.vip.text2sql.domain.ContentVo;
|
|
|
-import org.springframework.stereotype.Service;
|
|
|
-import reactor.core.publisher.Flux;
|
|
|
-
|
|
|
-import java.util.Arrays;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.function.Function;
|
|
|
-import java.util.stream.Collectors;
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * @description OllamaService
|
|
|
- *
|
|
|
- * @author GaoKunW
|
|
|
- * @date 2025/3/12 23:02
|
|
|
- */
|
|
|
-@Slf4j
|
|
|
-@Service
|
|
|
-public class OllamaService implements IOllamaService {
|
|
|
-
|
|
|
- public final static HashMap<String, String> CACHE = new HashMap<>();
|
|
|
-
|
|
|
- Function<String, String> elt = s -> s.replaceAll("<think>[\\s\\S]*?</think>", "").replaceAll("\n", "");
|
|
|
-
|
|
|
- Function<List<ChatCompletionChoice>, String> choicesProcess = list -> list.stream().map(e -> e.delta().content())
|
|
|
- .collect(Collectors.joining());
|
|
|
-
|
|
|
- @Resource
|
|
|
- private DeepSeekClient deepSeekClient;
|
|
|
-
|
|
|
- @Resource
|
|
|
- private IText2sqlApi text2sqlApi;
|
|
|
-
|
|
|
- @Override
|
|
|
- public String syncChatContent(String prompt) {
|
|
|
- ChatCompletionRequest request = ChatCompletionRequest.builder()
|
|
|
- // 根据渠道模型名称动态修改这个参数
|
|
|
-// .model("qwen2.5:1.5b")
|
|
|
-// .addAssistantMessage("我是一个sql生成专家,根据用户需求,生成mysql可执行的sql语句,只输出sql语句不需要任何格式")
|
|
|
- .addUserMessage(prompt).build();
|
|
|
- ChatCompletionResponse response = deepSeekClient.chatCompletion(request).execute();
|
|
|
- ChatCompletionChoice completionChoice = response.choices().getFirst();
|
|
|
- return completionChoice.message().content();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public String syncChat(String prompt) {
|
|
|
- ContentVo contentVo = text2sqlApi.getQuestion(prompt);
|
|
|
- if (contentVo != null) {
|
|
|
- String content = this.syncChatContent(contentVo.getContent());
|
|
|
- contentVo.setContent(content);
|
|
|
- JSONArray answer = text2sqlApi.getAnswer(contentVo);
|
|
|
- log.info("\nanswer: {}", answer);
|
|
|
- String md = convertJsonArrayToMd(answer);
|
|
|
- log.info("\nmd {}", md);
|
|
|
- return md;
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public JSONArray syncChatArr(String prompt) {
|
|
|
- ContentVo contentVo = text2sqlApi.getQuestion(prompt);
|
|
|
- if (contentVo != null) {
|
|
|
- String content = this.syncChatContent(contentVo.getContent());
|
|
|
- contentVo.setContent(content);
|
|
|
- return text2sqlApi.getAnswer(contentVo);
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Flux<ChatCompletionResponse> multipleRoundChatAdvanced(String prompt, String cacheCode) {
|
|
|
- log.info("cacheCode {}", cacheCode);
|
|
|
- ChatCompletionRequest request = ChatCompletionRequest.builder()
|
|
|
- .addUserMessage(prompt)
|
|
|
- .addAssistantMessage(elt.apply(CACHE.getOrDefault(cacheCode, "")))
|
|
|
- .addSystemMessage("你是一个专业的助手").maxCompletionTokens(5000).build();
|
|
|
- log.info("request {}", Json.toJson(request));
|
|
|
- // 只保留上一次回答内容
|
|
|
- CACHE.remove(cacheCode);
|
|
|
- return deepSeekClient.chatFluxCompletion(request).doOnNext(i -> {
|
|
|
- String content = choicesProcess.apply(i.choices());
|
|
|
- // 其他ELT流程
|
|
|
- CACHE.merge(cacheCode, content, String::concat);
|
|
|
- }).doOnError(e -> log.error("chatAdvanced error:{}", e.getMessage()));
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Flux<ChatCompletionResponse> chatBase(String prompt) {
|
|
|
- return deepSeekClient.chatFluxCompletion(prompt);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Flux<ChatCompletionResponse> chat(String prompt) {
|
|
|
- ContentVo contentVo = text2sqlApi.getQuestion(prompt);
|
|
|
- if (contentVo != null) {
|
|
|
- String content = this.syncChatContent(contentVo.getContent());
|
|
|
- contentVo.setContent(content);
|
|
|
- JSONArray answer = text2sqlApi.getAnswer(contentVo);
|
|
|
- log.info("\nanswer {}", answer);
|
|
|
- String md = convertJsonArrayToMd(answer);
|
|
|
- log.info("\nmd {}", md);
|
|
|
-// Flux<ChatCompletionResponse> flux = deepSeekClient.c
|
|
|
-// return deepSeekClient.chatFluxCompletion("问题:" + prompt + ";\n答案:" + answer.toString() + "\n" + "请将问题和答案汇总,答案按照列表格式完整输出,不要输出其他内容");
|
|
|
-// return deepSeekClient.chatFluxCompletion(answer.toString() + "\n" + "以上内容转换表格格式输出,不要输出其他内容");
|
|
|
- return deepSeekClient.chatFluxCompletion(md + "\n直接输出以上内容,不要输出其他内容");
|
|
|
-// return deepSeekClient.chatFluxCompletion(answer.toString() + "\n" + "请将以上 JSON 数据转换为规范的 Markdown 表格格式,要求:" +
|
|
|
-// "\n1. 第一行为表头(自动提取 JSON 的键名)\n" +
|
|
|
-// "2. 第二行为分隔符行(|---|---|...)\n" +
|
|
|
-// "3. 后续行展示数据内容\n" +
|
|
|
-// "4. 所有列保持左对齐\n" +
|
|
|
-// "5. 如果值为空则显示为 -" +
|
|
|
-// "6. 只输出数据内容,不要输出其他内容" +
|
|
|
-// "7. 以```Markdown 代码格式展示");
|
|
|
-// return deepSeekClient.chatFluxCompletion(answer.toString() + "\n" + "请将以上 JSON 数据转换为规范的 Markdown 表格格式,要求:\n" +
|
|
|
-// "1. 所有列保持左对齐\n" +
|
|
|
-// "2. 不要修改原数据的值" +
|
|
|
-// "3. 如果值为空则''显示为 -" +
|
|
|
-// "4. 只输出数据内容,不要输出其他内容" +
|
|
|
-// "5. 以```Markdown 代码格式展示");
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- public String convertJsonArrayToMd(JSONArray array) {
|
|
|
- if (array.isEmpty()) {
|
|
|
- return "";
|
|
|
- }
|
|
|
-
|
|
|
- // 2. 提取表头(假设所有对象的键相同)
|
|
|
- JSONObject firstObj = array.getJSONObject(0);
|
|
|
- String[] headers = firstObj.keySet().toArray(new String[0]);
|
|
|
-
|
|
|
- // 3. 构建Markdown表格
|
|
|
- StringBuilder md = new StringBuilder();
|
|
|
-
|
|
|
- // 3.1 表头行
|
|
|
- md.append("|").append(String.join("|", headers)).append("|\n");
|
|
|
-
|
|
|
- // 3.2 分隔线行(左对齐)
|
|
|
- md.append("|").append(String.join("|", Arrays.stream(headers)
|
|
|
- .map(h -> "---")
|
|
|
- .toArray(String[]::new))).append("|\n");
|
|
|
-
|
|
|
- // 3.3 数据行
|
|
|
- for (int i = 0; i < array.size(); i++) {
|
|
|
- JSONObject obj = array.getJSONObject(i);
|
|
|
- String[] row = Arrays.stream(headers)
|
|
|
- // 空值默认显示为 "-"
|
|
|
- .map(key -> obj.getStr(key, "-")
|
|
|
-// .replace("|", "\\|")
|
|
|
-// .replace("\n", "<br>")
|
|
|
- )
|
|
|
- .toArray(String[]::new);
|
|
|
- md.append("|").append(String.join("|", row)).append("|\n");
|
|
|
- }
|
|
|
-
|
|
|
- return md.toString();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Flux<ChatCompletionResponse> chatAdvanced(String prompt) {
|
|
|
- ChatCompletionRequest request = ChatCompletionRequest.builder()
|
|
|
- // 模型选择,支持 DEEPSEEK_CHAT、DEEPSEEK_REASONER 等
|
|
|
-// .model("qwen2.5:1.5b")
|
|
|
- // 添加用户消息
|
|
|
- .addUserMessage(prompt)
|
|
|
- // 设置最大生成 token 数,默认 2048
|
|
|
- .maxCompletionTokens(1000)
|
|
|
- // 设置响应格式,支持 JSON 结构化输出
|
|
|
-// .responseFormat(...) // 可选
|
|
|
- // function calling
|
|
|
-// .tools(...) // 可选
|
|
|
- .build();
|
|
|
-
|
|
|
- return deepSeekClient.chatFluxCompletion(request);
|
|
|
- }
|
|
|
-}
|