新增ollama模型对话
This commit is contained in:
parent
1c936afe4c
commit
37c0f3feef
|
|
@ -141,6 +141,8 @@
|
|||
<!-- <version>1.18.30</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
//package cn.qihangerp.erp.config;
|
||||
//
|
||||
//import cn.qihangerp.erp.filter.UrlTokenFilter;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
//import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
//import org.springframework.security.web.SecurityFilterChain;
|
||||
//import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
//
|
||||
///**
|
||||
// * Spring Security配置
|
||||
// *
|
||||
// * @author qihang
|
||||
// */
|
||||
//@Configuration
|
||||
//@EnableWebSecurity
|
||||
//public class SecurityConfig {
|
||||
// @Autowired
|
||||
// private UrlTokenFilter urlTokenFilter;
|
||||
//
|
||||
// @Bean
|
||||
// public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// http
|
||||
// .csrf(AbstractHttpConfigurer::disable)
|
||||
// .authorizeRequests(authorizeRequests ->
|
||||
// authorizeRequests
|
||||
// .anyRequest().permitAll()
|
||||
// )
|
||||
// .addFilterBefore(urlTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
//
|
||||
// return http.build();
|
||||
// }
|
||||
//}
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
package cn.qihangerp.erp.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
|
@ -10,11 +9,9 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import cn.qihangerp.erp.serviceImpl.AiService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
|
|
@ -28,6 +25,9 @@ public class SseController {
|
|||
|
||||
private static final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();
|
||||
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
|
||||
|
||||
@Autowired
|
||||
private AiService aiService;
|
||||
|
||||
@GetMapping(value = "/connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public SseEmitter connect(@RequestParam String clientId) {
|
||||
|
|
@ -69,93 +69,22 @@ public class SseController {
|
|||
SseEmitter emitter = emitters.get(clientId);
|
||||
if (emitter != null) {
|
||||
try {
|
||||
// 调用opencode接口获取回复
|
||||
String response = callOpencodeApi(message);
|
||||
// 使用AiService处理消息
|
||||
String response = aiService.processMessage(message);
|
||||
|
||||
emitter.send(SseEmitter.event()
|
||||
.name("message")
|
||||
.data(response));
|
||||
|
||||
return "消息发送成功";
|
||||
} catch (Exception e) {
|
||||
log.error("消息处理失败: {}", e.getMessage());
|
||||
emitters.remove(clientId);
|
||||
return "消息发送失败";
|
||||
}
|
||||
}
|
||||
return "客户端不存在";
|
||||
}
|
||||
|
||||
private String callOpencodeApi(String message) throws Exception {
|
||||
// 创建HTTP客户端
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
|
||||
// 1. 创建新会话
|
||||
HttpRequest createSessionRequest = HttpRequest.newBuilder()
|
||||
.uri(URI.create("http://localhost:14967/session"))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString("{}"))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> createSessionResponse = client.send(createSessionRequest, HttpResponse.BodyHandlers.ofString());
|
||||
String sessionId = parseSessionId(createSessionResponse.body());
|
||||
|
||||
// 2. 构建消息请求体
|
||||
JSONObject requestBody = new JSONObject();
|
||||
JSONArray parts = new JSONArray();
|
||||
JSONObject part = new JSONObject();
|
||||
part.put("type", "text");
|
||||
part.put("text", message);
|
||||
parts.add(part);
|
||||
requestBody.put("parts", parts);
|
||||
|
||||
// 3. 向会话发送消息
|
||||
HttpRequest sendMessageRequest = HttpRequest.newBuilder()
|
||||
.uri(URI.create("http://localhost:14967/session/" + sessionId + "/message"))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(requestBody.toJSONString()))
|
||||
.build();
|
||||
|
||||
// 发送请求并获取响应
|
||||
HttpResponse<String> response = client.send(sendMessageRequest, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
// 解析响应,提取AI回复
|
||||
return parseAIResponse(response.body());
|
||||
}
|
||||
|
||||
private String parseSessionId(String responseBody) {
|
||||
// 简单解析JSON,提取sessionId
|
||||
// 实际项目中建议使用JSON库
|
||||
int idIndex = responseBody.indexOf("\"id\":\"");
|
||||
if (idIndex != -1) {
|
||||
int start = idIndex + 6;
|
||||
int end = responseBody.indexOf("\"", start);
|
||||
if (end != -1) {
|
||||
return responseBody.substring(start, end);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String parseAIResponse(String responseBody) {
|
||||
log.info("=================AI回复==========");
|
||||
log.info(responseBody);
|
||||
try {
|
||||
// 解析响应,提取AI回复
|
||||
JSONObject jsonObject = JSONObject.parseObject(responseBody);
|
||||
if (jsonObject.containsKey("info")) {
|
||||
JSONArray parts = jsonObject.getJSONArray("parts");
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
JSONObject part = parts.getJSONObject(i);
|
||||
if (part.containsKey("text")) {
|
||||
return part.getString("text");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "无法获取AI回复";
|
||||
}
|
||||
|
||||
@GetMapping("/disconnect")
|
||||
public String disconnect(@RequestParam String clientId) {
|
||||
|
|
|
|||
|
|
@ -1,115 +0,0 @@
|
|||
//package cn.qihangerp.erp.filter;
|
||||
//
|
||||
//import cn.qihangerp.common.AjaxResult;
|
||||
//import cn.qihangerp.common.enums.HttpStatus;
|
||||
//import cn.qihangerp.security.LoginUser;
|
||||
//import cn.qihangerp.security.TokenService;
|
||||
//import com.alibaba.fastjson2.JSON;
|
||||
//import jakarta.servlet.FilterChain;
|
||||
//import jakarta.servlet.ServletException;
|
||||
//import jakarta.servlet.http.HttpServletRequest;
|
||||
//import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
//import jakarta.servlet.http.HttpServletResponse;
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.http.MediaType;
|
||||
//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
//import org.springframework.security.core.context.SecurityContextHolder;
|
||||
//import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import org.springframework.web.filter.OncePerRequestFilter;
|
||||
//
|
||||
//import java.io.IOException;
|
||||
//import java.io.PrintWriter;
|
||||
//
|
||||
///**
|
||||
// * token过滤器 从URL参数中获取token并验证有效性
|
||||
// *
|
||||
// * @author qihang
|
||||
// */
|
||||
//@Component
|
||||
//public class UrlTokenFilter extends OncePerRequestFilter {
|
||||
// @Autowired
|
||||
// private TokenService tokenService;
|
||||
// private Logger log = LoggerFactory.getLogger(getClass());
|
||||
//
|
||||
// @Override
|
||||
// protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
// throws ServletException, IOException {
|
||||
// // 从URL参数中获取token
|
||||
// String token = request.getParameter("token");
|
||||
// String url = request.getRequestURI();
|
||||
//
|
||||
// // 跳过登录等不需要token的请求
|
||||
// if (url.contains("/login") || url.contains("/captchaImage")) {
|
||||
// chain.doFilter(request, response);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 如果URL参数中没有token,尝试从header中获取(保持兼容性)
|
||||
// if (token == null || token.isEmpty()) {
|
||||
// token = request.getHeader("Authorization");
|
||||
// }
|
||||
//
|
||||
// // 验证token
|
||||
// if (token != null && !token.isEmpty()) {
|
||||
// // 移除Bearer前缀
|
||||
// if (token.startsWith("Bearer ")) {
|
||||
// token = token.substring(7);
|
||||
// }
|
||||
//
|
||||
// // 将token声明为final,以便内部类可以引用
|
||||
// final String finalToken = token;
|
||||
//
|
||||
// // 将token设置到请求的header中,以便TokenService能够正常工作
|
||||
// final HttpServletRequest modifiedRequest = new HttpServletRequestWrapper(request) {
|
||||
// @Override
|
||||
// public String getHeader(String name) {
|
||||
// if ("Authorization".equals(name)) {
|
||||
// return "Bearer " + finalToken;
|
||||
// }
|
||||
// return super.getHeader(name);
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // 验证token并设置用户信息
|
||||
// try {
|
||||
// LoginUser loginUser = tokenService.getLoginUser(modifiedRequest);
|
||||
// if (loginUser != null) {
|
||||
// tokenService.verifyToken(loginUser);
|
||||
// UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
|
||||
// authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(modifiedRequest));
|
||||
// SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
||||
// chain.doFilter(modifiedRequest, response);
|
||||
// return;
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("Token validation failed: {}", e.getMessage());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // token无效或不存在
|
||||
// fallback("授权过期!", response);
|
||||
// }
|
||||
//
|
||||
// private void fallback(String message, HttpServletResponse response) {
|
||||
// response.setCharacterEncoding("UTF-8");
|
||||
// response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
// PrintWriter writer = null;
|
||||
// try {
|
||||
// if (message == null) {
|
||||
// message = "401 Forbidden";
|
||||
// }
|
||||
// AjaxResult res = AjaxResult.error(HttpStatus.UNAUTHORIZED, message);
|
||||
// writer = response.getWriter();
|
||||
// writer.append(JSON.toJSONString(res));
|
||||
// } catch (IOException e) {
|
||||
// log.error(e.getMessage());
|
||||
// } finally {
|
||||
// if (writer != null) {
|
||||
// writer.close();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package cn.qihangerp.erp.serviceImpl;
|
||||
|
||||
import cn.qihangerp.common.ResultVo;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
|
||||
/**
|
||||
* AI服务类,直接调用Ollama API处理聊天内容
|
||||
*/
|
||||
@Service
|
||||
public class AiService {
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final String ollamaUrl;
|
||||
|
||||
public AiService() {
|
||||
this.httpClient = HttpClient.newHttpClient();
|
||||
this.ollamaUrl = "http://localhost:11434/api/generate";
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理聊天消息
|
||||
* @param message 用户消息
|
||||
* @return AI回复
|
||||
*/
|
||||
public String processMessage(String message) {
|
||||
try {
|
||||
// 构建请求体
|
||||
JSONObject requestBody = new JSONObject();
|
||||
requestBody.put("model", "llama3");
|
||||
requestBody.put("prompt", message);
|
||||
requestBody.put("stream", false);
|
||||
requestBody.put("temperature", 0.7);
|
||||
|
||||
// 创建HTTP请求
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(ollamaUrl))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(requestBody.toJSONString()))
|
||||
.build();
|
||||
|
||||
// 发送请求并获取响应
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
// 解析响应
|
||||
JSONObject responseBody = JSONObject.parseObject(response.body());
|
||||
|
||||
// 检查是否有错误
|
||||
if (responseBody.containsKey("error")) {
|
||||
String errorMessage = responseBody.getString("error");
|
||||
return "错误: " + errorMessage;
|
||||
}
|
||||
|
||||
return responseBody.getString("response");
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return "抱歉,我暂时无法处理您的请求,请稍后重试。";
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue