上传备份

flux
王兵 4 days ago
commit c585f9899b

21
.gitignore vendored

@ -0,0 +1,21 @@
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
/.idea
*.iml
/.settings
/bin
/gen
/build
/gradle
/classes
.classpath
.project
*.gradle
gradlew
local.properties
node_modules/
data/

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.13</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>xyz.wbsite.achat</groupId>
<artifactId>starter-achat</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>starter-achat</name>
<description>An abstract chat starter</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>8</java.version>
<maven.test.skip>true</maven.test.skip>
<spring-boot.version>2.7.13</spring-boot.version>
</properties>
<repositories>
<!-- 将中央仓库地址指向阿里云聚合仓库,提高下载速度 -->
<repository>
<id>aliyun</id>
<name>Aliyun Repository</name>
<layout>default</layout>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<pluginRepositories>
<!-- 将插件的仓库指向阿里云聚合仓库解决低版本maven下载插件异常或提高下载速度 -->
<pluginRepository>
<id>aliyun</id>
<name>Aliyun Repository</name>
<url>https://maven.aliyun.com/repository/public</url>
<layout>default</layout>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 依赖管理器 -->
<!-- 管理器中依赖都会有默认的版本号在pom中引用时即可省略<version>标签 -->
<!-- 注:当需要非默认版本或本地环境导致的无法继承管理器中版本时,此时可以使用<version>显式指定依赖版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<!-- 项目名称 -->
<finalName>${project.artifactId}</finalName>
<!-- 默认的主代码目录 -->
<sourceDirectory>src/main/java</sourceDirectory>
<!-- 默认的测试代码目录 -->
<testSourceDirectory>src/test/java</testSourceDirectory>
</build>
</project>

@ -0,0 +1,23 @@
package xyz.wbsite;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
@SpringBootApplication
public class Application {
/**
*
*/
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.run(args);
}
}

@ -0,0 +1,112 @@
package xyz.wbsite.achat;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import xyz.wbsite.achat.core.base.Message;
import xyz.wbsite.achat.core.base.Result;
import xyz.wbsite.achat.core.base.Session;
import xyz.wbsite.achat.core.message.UserMessage;
import xyz.wbsite.achat.core.prompt.MessagePrompt;
import xyz.wbsite.achat.core.service.SessionService;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
/**
* AI.
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
@RestController
public class ChatController {
@Resource
private SessionService sessionService;
/**
*
*/
@GetMapping("/chat")
public String chat() {
return "AChat is running!";
}
/**
*
*
* @return SSE
*/
@PostMapping(value = "/chat/send", produces = "text/event-stream;charset=UTF-8")
public SseEmitter send(@RequestBody MessagePrompt message) {
return sessionService.sendMessage(message);
}
/**
*
*
* @return
*/
@PostMapping("/chat/session")
public Result<Session> createSession() {
String sid = UUID.randomUUID().toString();
return sessionService.createSession(sid);
}
/**
*
*
* @return
*/
@ResponseBody
@GetMapping("/chat/session/list")
public Result<List<Session>> listSession() {
String sid = UUID.randomUUID().toString();
return sessionService.listSessions(sid);
}
/**
*
*
* @param sid ID
* @return
*/
@ResponseBody
@DeleteMapping("/chat/session/{sid}")
public Result deleteSession(@PathVariable("sid") String sid) {
return sessionService.deleteSession(sid);
}
/**
*
*
* @param sid ID
* @return
*/
@ResponseBody
@GetMapping("/chat/session/{sid}/history")
public Result<List<Message>> getSessionHistory(@PathVariable("sid") String sid) {
return sessionService.listMessage(sid);
}
/**
* AI
*
* @param sid ID
* @return
*/
@ResponseBody
@PostMapping("/chat/session/{sid}/stop")
public Result<Void> stopSession(@PathVariable("sid") String sid) {
return sessionService.stopSession(sid);
}
}

@ -0,0 +1,35 @@
package xyz.wbsite.achat.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Web(,).
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
*
*
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
// 注意,如果授权认认证未通过会直接返回,此跨域配置则不会生效,前端仍然会提示跨域
registry.addMapping("/chat/**")
//允许的域,不要写*否则cookie就无法使用了
.allowedOriginPatterns("http://localhost:5173")
.allowedHeaders("*")
//是否发送Cookie
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT")
.exposedHeaders("*")
.maxAge(3600);
}
}

@ -0,0 +1,30 @@
package xyz.wbsite.achat.core.base;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class Attachment {
private String filename;
private String fid;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getFid() {
return fid;
}
public void setFid(String fid) {
this.fid = fid;
}
}

@ -0,0 +1,59 @@
package xyz.wbsite.achat.core.base;
import java.util.Date;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class Event {
private String sid;
private Date time;
private String text;
private String type;
public Event(String sid) {
this.sid = sid;
this.time = new Date();
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

@ -0,0 +1,52 @@
package xyz.wbsite.achat.core.base;
import xyz.wbsite.achat.enums.Role;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class Message {
/**
*
*/
private Role role;
/**
* ID
*/
private String sid;
/**
*
*/
private String content;
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}

@ -0,0 +1,17 @@
package xyz.wbsite.achat.core.base;
public class Prompt {
/**
*
*/
private String prompt;
public String getPrompt() {
return prompt;
}
public void setPrompt(String prompt) {
this.prompt = prompt;
}
}

@ -0,0 +1,209 @@
package xyz.wbsite.achat.core.base;
import java.util.HashMap;
import java.util.Map;
/**
*
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class Result<T> {
/**
*
*/
private int code = 200;
/**
*
*/
private String message = "success";
/**
*
*/
private T data;
/**
*
*/
private boolean success = true;
/**
*
*/
private Map<String, String> errors;
/**
* ID
*/
private String requestId;
/**
*
*/
private long timestamp = System.currentTimeMillis();
public int getCode() {
return code;
}
public Result<T> setCode(int code) {
this.code = code;
return this;
}
public String getMessage() {
return message;
}
public Result<T> setMessage(String message) {
this.message = message;
return this;
}
public T getData() {
return data;
}
public Result<T> setData(T data) {
this.data = data;
return this;
}
public boolean isSuccess() {
return success;
}
public Result<T> setSuccess(boolean success) {
this.success = success;
return this;
}
public Map<String, String> getErrors() {
return errors;
}
public Result<T> setErrors(Map<String, String> errors) {
this.errors = errors;
return this;
}
public String getRequestId() {
return requestId;
}
public Result<T> setRequestId(String requestId) {
this.requestId = requestId;
return this;
}
public long getTimestamp() {
return timestamp;
}
public Result<T> setTimestamp(long timestamp) {
this.timestamp = timestamp;
return this;
}
/**
*
*
* @param field
* @param error
* @return
*/
public Result<T> addError(String field, String error) {
if (errors == null) {
errors = new HashMap<>();
}
errors.put(field, error);
return this;
}
/**
*
*
* @return
*/
public static <T> Result<T> success() {
return new Result<>();
}
/**
*
*
* @param data
* @return
*/
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setData(data);
return result;
}
/**
*
*
* @param message
* @return
*/
public static <T> Result<T> error(String message) {
Result<T> result = new Result<>();
result.message = message;
result.code = 500;
result.success = false;
return result;
}
/**
*
*
* @param code
* @param message
* @return
*/
public static <T> Result<T> error(int code, String message) {
Result<T> result = new Result<>();
result.code = code;
result.message = message;
result.success = false;
return result;
}
/**
*
*
* @param code
* @param message
* @param data
* @return
*/
public static <T> Result<T> error(int code, String message, T data) {
Result<T> result = new Result<>();
result.code = code;
result.message = message;
result.success = false;
result.data = data;
return result;
}
/**
*
*
* @param e
* @return
*/
public static <T> Result<T> error(Exception e) {
Result<T> result = new Result<>();
result.code = 500;
result.message = e.getMessage() != null ? e.getMessage() : "系统异常";
result.success = false;
return result;
}
}

@ -0,0 +1,126 @@
package xyz.wbsite.achat.core.base;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class Session {
/**
*
*/
private String id;
/**
* ID
*/
private String uid;
private String title;
private String model;
private String prompt;
private String temperature;
private String topP;
private String frequencyPenalty;
private String presencePenalty;
private String maxTokens;
private String lastTime;
private String lastMessage;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getPrompt() {
return prompt;
}
public void setPrompt(String prompt) {
this.prompt = prompt;
}
public String getTemperature() {
return temperature;
}
public void setTemperature(String temperature) {
this.temperature = temperature;
}
public String getTopP() {
return topP;
}
public void setTopP(String topP) {
this.topP = topP;
}
public String getFrequencyPenalty() {
return frequencyPenalty;
}
public void setFrequencyPenalty(String frequencyPenalty) {
this.frequencyPenalty = frequencyPenalty;
}
public String getPresencePenalty() {
return presencePenalty;
}
public void setPresencePenalty(String presencePenalty) {
this.presencePenalty = presencePenalty;
}
public String getMaxTokens() {
return maxTokens;
}
public void setMaxTokens(String maxTokens) {
this.maxTokens = maxTokens;
}
public String getLastTime() {
return lastTime;
}
public void setLastTime(String lastTime) {
this.lastTime = lastTime;
}
public String getLastMessage() {
return lastMessage;
}
public void setLastMessage(String lastMessage) {
this.lastMessage = lastMessage;
}
}

@ -0,0 +1,22 @@
package xyz.wbsite.achat.core.event;
import xyz.wbsite.achat.core.base.Event;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class CompleteEvent extends Event {
public CompleteEvent(String sid) {
super(sid);
setType("complete");
}
public static CompleteEvent of(String sid) {
return new CompleteEvent(sid);
}
}

@ -0,0 +1,29 @@
package xyz.wbsite.achat.core.event;
import xyz.wbsite.achat.core.base.Event;
/**
*
* <p>
* AI
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class PartialEvent extends Event {
public PartialEvent(String sid) {
super(sid);
setType("partial");
}
public PartialEvent(String sid, String partial) {
super(sid);
setType("partial");
setText(partial);
}
public static PartialEvent of(String sid, String partial) {
return new PartialEvent(sid, partial);
}
}

@ -0,0 +1,15 @@
package xyz.wbsite.achat.core.message;
import xyz.wbsite.achat.core.base.Message;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class AiMessage extends Message {
}

@ -0,0 +1,176 @@
package xyz.wbsite.achat.core.message;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import xyz.wbsite.achat.core.base.Event;
import xyz.wbsite.achat.core.event.CompleteEvent;
import xyz.wbsite.achat.core.event.PartialEvent;
import xyz.wbsite.achat.core.prompt.MessagePrompt;
import xyz.wbsite.achat.core.service.MessageGenerator;
import java.io.IOException;
/**
* SSE
* SSE
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class MessageSseEmitter extends SseEmitter {
/**
*
*/
private MessagePrompt messagePrompt;
/**
*
*/
private boolean complete;
/**
* AI
*/
private final StringBuilder answer = new StringBuilder();
/**
*
*/
private MessageGenerator messageGenerator;
/**
*
*
* @param message
*/
public MessageSseEmitter(MessagePrompt message, MessageGenerator processor) {
super(0L);
this.messagePrompt = message;
this.messageGenerator = processor;
// TaskUtil.taskAsync(task);
}
/**
*
*/
// public Runnable task = () -> {
// try {
// // 检查会话是否存在
// if (!messageProcessor.checkSessionExists(message.getChatId(), uid)) {
// this.sendMessage(createPartialMessage("当前会话不存在,请刷新后再试!"));
// return;
// }
//
// // 更新新会话的标题(如果为空)
// messageProcessor.updateSessionTitleIfEmpty(message.getChatId(), message.getText(), uid);
//
// // 保存本次用户消息
// messageProcessor.saveUserMessage(message.getChatId(), message.getText(), uid);
//
// // 根据是否有附件选择不同的处理方式
// TokenStream tokenStream;
// if (this.hasAttachment()) {
// String attachment = messageProcessor.parseAttachment(message.getAttachments(), uid);
// tokenStream = messageProcessor.createAssistantStreamWithAttachment(
// message.getChatId(), message.getText(), attachment, uid);
// } else {
// tokenStream = messageProcessor.createAssistantStream(
// message.getChatId(), message.getText(), uid);
// }
//
// // 设置流回调
// tokenStream
// .onPartialResponse(this::onPartialResponse)
// .onCompleteResponse(this::onCompleteResponse)
// .onError(this::onError)
// .start();
// } catch (Exception e) {
// onError(e);
// }
// };
/**
*
*/
private void onError(Throwable e) {
this.sendMessage(createPartialMessage("</think></think>" + e.getMessage()));
this.answer.append("</think></think>" + e.getMessage());
this.onCompleteResponse(null);
}
/**
*
*/
public void onPartialResponse(String msg) {
if (complete) {
return;
}
this.sendMessage(createPartialMessage(msg));
this.answer.append(msg);
}
/**
*
*/
public void onCompleteResponse(Object chatResponse) {
if (this.complete) {
return;
}
// 推送结束
this.sendMessage(createCompleteMessage());
// 关闭链接
this.complete();
}
/**
*
*/
private Event createPartialMessage(String partial) {
return new PartialEvent(messagePrompt.getSid(), partial);
}
/**
*
*/
private Event createCompleteMessage() {
return new CompleteEvent(messagePrompt.getSid());
}
/**
* send
*/
@Override
public void send(SseEventBuilder builder) throws IOException {
try {
super.send(builder);
} catch (Exception e) {
complete = true;
}
}
/**
*
*/
private void sendMessage(Event message) {
try {
this.send(message);
} catch (Exception e) {
complete = true;
}
}
/**
*
*/
public boolean isComplete() {
return complete;
}
/**
*
*/
public void setComplete(boolean complete) {
this.complete = complete;
}
}

@ -0,0 +1,42 @@
package xyz.wbsite.achat.core.message;
import xyz.wbsite.achat.core.base.Attachment;
import xyz.wbsite.achat.core.base.Message;
import java.util.List;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class UserMessage extends Message {
/**
* ID
*/
private String uid;
/**
*
*/
private List<Attachment> attachments;
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public List<Attachment> getAttachments() {
return attachments;
}
public void setAttachments(List<Attachment> attachments) {
this.attachments = attachments;
}
}

@ -0,0 +1,106 @@
package xyz.wbsite.achat.core.prompt;
import xyz.wbsite.achat.core.base.Message;
import xyz.wbsite.achat.core.base.Prompt;
import xyz.wbsite.achat.core.message.UserMessage;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class MessagePrompt extends Prompt {
/**
*
*/
private String model;
/**
*
*/
private List<Message> messages;
/**
*
*/
private Boolean stream;
/**
* token
*/
private Integer maxTokens;
/**
*
*/
private Double temperature;
/**
*
*/
private Map<String, Object> extraParams;
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public List<Message> getMessages() {
return messages;
}
public void setMessages(List<Message> messages) {
this.messages = messages;
}
public Boolean getStream() {
return stream;
}
public void setStream(Boolean stream) {
this.stream = stream;
}
public Integer getMaxTokens() {
return maxTokens;
}
public void setMaxTokens(Integer maxTokens) {
this.maxTokens = maxTokens;
}
public Double getTemperature() {
return temperature;
}
public void setTemperature(Double temperature) {
this.temperature = temperature;
}
public Map<String, Object> getExtraParams() {
return extraParams;
}
public void setExtraParams(Map<String, Object> extraParams) {
this.extraParams = extraParams;
}
public UserMessage getLastUserMessage() {
List<Message> messageList = messages.stream().filter(message -> message instanceof UserMessage).collect(Collectors.toList());
UserMessage userMessage = (UserMessage)messageList.get(messageList.size() - 1);
return userMessage;
}
public String getUid() {
return getLastUserMessage().getUid();
}
public String getSid(){
return getLastUserMessage().getSid();
}
}

@ -0,0 +1,18 @@
package xyz.wbsite.achat.core.service;
import xyz.wbsite.achat.core.message.MessageSseEmitter;
import xyz.wbsite.achat.core.base.Message;
/**
*
* <p>
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public interface MessageGenerator {
void on(MessageSseEmitter emitter, Message message);
}

@ -0,0 +1,85 @@
package xyz.wbsite.achat.core.service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import xyz.wbsite.achat.core.base.Message;
import xyz.wbsite.achat.core.base.Result;
import xyz.wbsite.achat.core.base.Session;
import xyz.wbsite.achat.core.message.UserMessage;
import xyz.wbsite.achat.core.prompt.MessagePrompt;
import java.util.List;
/**
*
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public interface SessionService {
/**
*
*
* @param uid
* @return
*/
Result<Session> createSession(String uid);
/**
*
*
* @param sid ID
* @return
*/
Result<Void> deleteSession(String sid);
/**
*
*
* @param uid
* @return
*/
Result<List<Session>> listSessions(String uid);
/**
*
*
* @param sid ID
* @return
*/
Result<Session> getSession(String sid);
/**
*
*
* @param sid ID
* @return
*/
Result<Void> stopSession(String sid);
/**
*
*
* @param message
* @return SSE
*/
SseEmitter sendMessage(MessagePrompt message);
/**
*
*
* @param sid ID
* @return
*/
Result<List<Message>> listMessage(String sid);
/**
*
*
* @param sid ID
* @return
*/
Result<Void> deleteMessage(String sid);
}

@ -0,0 +1,122 @@
package xyz.wbsite.achat.core.service.impl;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import xyz.wbsite.achat.core.message.MessageSseEmitter;
import xyz.wbsite.achat.core.base.Message;
import xyz.wbsite.achat.core.base.Result;
import xyz.wbsite.achat.core.base.Session;
import xyz.wbsite.achat.core.message.UserMessage;
import xyz.wbsite.achat.core.prompt.MessagePrompt;
import xyz.wbsite.achat.core.service.SessionService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
@Service
public class SessionServiceMemoryImpl implements SessionService {
private final Map<String, Session> sessionStore = new HashMap<>();
private final List<Message> messageStore = new ArrayList<>();
/**
*
*/
@Override
public Result<Session> createSession(String uid) {
Session session = new Session();
session.setId(String.valueOf(UUID.randomUUID().toString()));
session.setUid(uid);
session.setTitle("新对话");
sessionStore.put(session.getId(), session);
return Result.success(session);
}
/**
*
*/
@Override
public Result<Void> deleteSession(String sid) {
sessionStore.remove(sid);
return Result.success();
}
/**
*
*/
@Override
public Result<List<Session>> listSessions(String uid) {
List<Session> collect = sessionStore.values()
.stream()
.filter(item -> item.getUid().equals(uid))
.collect(Collectors.toList());
return Result.success(collect);
}
/**
*
*/
@Override
public Result<Session> getSession(String sid) {
Session session = sessionStore.get(sid);
if (session == null) {
return Result.error("会话不存在");
}
return Result.success(session);
}
/**
*
*/
@Override
public SseEmitter sendMessage(MessagePrompt message) {
// 创建VChatSseEmitter来处理流式响应
return new MessageSseEmitter(message, (emitter, message1) -> {
// 这边模拟LLM复述一遍用户问题
String text = message1.getContent();
for (char c : text.toCharArray()) {
if (emitter.isComplete()) {
return;
}
emitter.onPartialResponse(String.valueOf(c));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
emitter.onCompleteResponse(null);
});
}
@Override
public Result<Void> stopSession(String sid) {
// todo
return Result.success();
}
@Override
public Result<List<Message>> listMessage(String sid) {
List<Message> messages = messageStore.stream().filter(item -> item.getSid().equals(sid)).collect(Collectors.toList());
return Result.success(messages);
}
@Override
public Result<Void> deleteMessage(String sid) {
messageStore.forEach(item -> messageStore.remove(item));
return null;
}
}

@ -0,0 +1,41 @@
package xyz.wbsite.achat.enums;
import com.fasterxml.jackson.annotation.JsonValue;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public enum Role {
USER("user"),
ASSISTANT("assistant"),
SYSTEM("system"),
FUNCTION("function"),
TOOL("tool"),
UNKNOWN("unknown");
private final String value;
Role(String value) {
this.value = value;
}
// 序列化时返回小写字符串
@JsonValue
public String getValue() {
return value;
}
// 反序列化时根据字符串匹配枚举
public static Role fromValue(String value) {
for (Role role : Role.values()) {
if (role.value.equalsIgnoreCase(value)) {
return role;
}
}
throw new IllegalArgumentException("Invalid Role value: " + value);
}
}

@ -0,0 +1,23 @@
package xyz.wbsite.achat.enums;
/**
*
*/
public enum Status {
/**
*
*/
PENDING,
/**
*
*/
SUCCESS,
/**
*
*/
ERROR,
/**
*
*/
CANCELLED
}

@ -0,0 +1,2 @@
server.port=8080
spring.application.name=achat

@ -0,0 +1,19 @@
package xyz.wbsite.achat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
public class TestConfig {
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
public void initLocalData() {
}
}

@ -0,0 +1,96 @@
# 激活环境 dev:开发prod:生产
spring.profiles.active=dev
# 启动完成打开游览器
spring.profiles.open.web=false
# 应用名称
spring.application.name=aipro_sv
# 停机配置
# - 停机模式 graceful:优雅关机;immediate:立即关机
server.shutdown=graceful
# - 停机最大等待时间
spring.lifecycle.timeout-per-shutdown-phase=30s
# servlet配置
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
# - 编码配置
server.servlet.encoding.charset=UTF-8
# - 上下文配置
server.servlet.context-path=
# tomcat配置
server.tomcat.uri-encoding=UTF-8
server.tomcat.max-http-form-post-size=-1
# 允许循环引用,部分依赖因为存在循环依赖,暂时不能全局解决,暂时关闭循环检查
spring.main.allow-circular-references=true
# 路径匹配模式默认path_pattern_parser虽然高效但与ant不兼容由于项目中用到了ant语法暂时保留
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
# 性能优化配置
# - 开启Gzip压缩
server.compression.enabled=true
# - 路径匹配配置
spring.mvc.static-path-pattern=/static/**
# - 资源目录配置
spring.web.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${app.static.custom.path}
# - 启用静态资源
spring.web.resources.add-mappings=true
# - 启用客户端缓存
spring.web.resources.chain.enabled=true
spring.web.resources.chain.cache=true
spring.web.resources.chain.compressed=true
# - 客户端缓存时间
spring.web.resources.cache.period= 3600
# 序列化配置
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# - 时区配置
spring.jackson.time-zone=GMT+8
# - 属性为null时不序列化
spring.jackson.default-property-inclusion=non_null
# - 排序
spring.jackson.mapper.sort-properties-alphabetically=true
# - 忽略不对应属性错误
spring.jackson.deserialization.fail-on-unknown-properties=false
# 文件上传配置
# - 文件上传时禁止懒加载
spring.servlet.multipart.resolveLazily=false
# - 文件上传大小限制
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB
# 分页工具配置
pagehelper.autoRuntimeDialect=true
pagehelper.reasonable=false
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
# 页面模板配置
spring.freemarker.enabled=true
# - 模板资源路径
spring.freemarker.template-loader-path=classpath:/views/
# - 模板后缀
spring.freemarker.suffix=.ftl
spring.freemarker.allow-request-override=false
# - 模板可缓存
spring.freemarker.cache=true
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
spring.freemarker.settings.template_update_delay=1
spring.freemarker.settings.locale=zh_CN
# - 日期时间格式化
spring.freemarker.settings.datetime_format=yyyy-MM-dd HH:mm:ss
# - 日期格式化
spring.freemarker.settings.date_format=yyyy-MM-dd
# - 数字格式化
spring.freemarker.settings.number_format=#.##
# - 启用兼容模式
spring.freemarker.settings.classic_compatible=true
spring.freemarker.settings.whitespace_stripping=true
spring.freemarker.settings.url_escaping_charset=utf-8

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 控制台输出 -->
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
debug级别及以上
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<encoder>
<pattern>%highlight(%d{yyyy-MM-dd HH:mm:ss.SSS} [%-4level] [%thread] [%logger{36}-%method] %ex %msg%n)</pattern>
</encoder>
</appender>
<logger name="java.sql" level="INFO"></logger>
<!-- 日志总入口 -->
<root level="DEBUG">
<appender-ref ref="Console"/>
</root>
</configuration>
Loading…
Cancel
Save

Powered by TurnKey Linux.