diff --git a/pom.xml b/pom.xml index a3f2635..6316ee6 100644 --- a/pom.xml +++ b/pom.xml @@ -125,6 +125,16 @@ + + org.apache.httpcomponents + httpclient + 4.5.13 + + + com.google.code.gson + gson + 2.8.6 + @@ -176,6 +186,7 @@ org.springframework.boot spring-boot-starter-websocket + org.springframework.boot spring-boot-starter-webflux diff --git a/src/main/java/com/example/venue_reservation_service/config/InterceptorConfig.java b/src/main/java/com/example/venue_reservation_service/config/InterceptorConfig.java index b4c42ed..8459220 100644 --- a/src/main/java/com/example/venue_reservation_service/config/InterceptorConfig.java +++ b/src/main/java/com/example/venue_reservation_service/config/InterceptorConfig.java @@ -21,6 +21,7 @@ public class InterceptorConfig implements WebMvcConfigurer { .excludePathPatterns("/user/test") .excludePathPatterns("/user/admin") .excludePathPatterns("/user/reset") + .excludePathPatterns("/chat/**") .excludePathPatterns("/reservation/excel") .excludePathPatterns("/reservation/payment") .excludePathPatterns("/swagger-ui/index.html") diff --git a/src/main/java/com/example/venue_reservation_service/controller/ChatController.java b/src/main/java/com/example/venue_reservation_service/controller/ChatController.java new file mode 100644 index 0000000..4df4df8 --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/controller/ChatController.java @@ -0,0 +1,39 @@ +package com.example.venue_reservation_service.controller; + + +import com.example.venue_reservation_service.entity.ChatRequest; +import com.example.venue_reservation_service.service.ChatService; +import jakarta.annotation.Resource; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + + +@RestController +@RequestMapping("/chat") +@CrossOrigin +public class ChatController { + + @Resource + private ChatService chatService; + + @PostMapping(value = "/ask", produces = MediaType.TEXT_PLAIN_VALUE) + public void chat(@RequestBody ChatRequest request, HttpServletRequest httpRequest, HttpServletResponse response) throws IOException { + + // 设置流式响应头 + response.setContentType("text/event-stream"); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setHeader("Cache-Control", "no-cache"); + + // 获取输出流 + ServletOutputStream outputStream = response.getOutputStream(); + + // 处理流式响应 + chatService.streamChatResponse(request, outputStream, httpRequest); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/venue_reservation_service/controller/DeviceController.java b/src/main/java/com/example/venue_reservation_service/controller/DeviceController.java index b1f4d48..e95b5c6 100644 --- a/src/main/java/com/example/venue_reservation_service/controller/DeviceController.java +++ b/src/main/java/com/example/venue_reservation_service/controller/DeviceController.java @@ -1,5 +1,6 @@ package com.example.venue_reservation_service.controller; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.example.venue_reservation_service.domain.Device; import com.example.venue_reservation_service.mapper.DeviceMapper; import com.example.venue_reservation_service.service.DeviceService; @@ -39,17 +40,10 @@ public class DeviceController { } // // 定时任务 - 每秒生成一条数据 -// @Scheduled(fixedRate = 1000) +// @Scheduled(fixedRate = 3000) // public void generateAndSendDeviceData() { // // 生成并保存新数据 -// Device newDevice = deviceService.generateDeviceData(); -// deviceService.save(newDevice); -// -// // 检查并清理旧数据 -// long count = deviceService.count(); -// if (count > 100) { -// deviceMapper.deleteOldestRecords(50); -// } +// Device newDevice = deviceService.getOne(Wrappers.query().orderByDesc("id").last("LIMIT 1")); // // // 推送新数据到前端 // messagingTemplate.convertAndSend("/topic/devices", newDevice); diff --git a/src/main/java/com/example/venue_reservation_service/controller/SessionController.java b/src/main/java/com/example/venue_reservation_service/controller/SessionController.java deleted file mode 100644 index 8735919..0000000 --- a/src/main/java/com/example/venue_reservation_service/controller/SessionController.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.example.venue_reservation_service.controller; - -import com.example.venue_reservation_service.domain.VeMessage; -import com.example.venue_reservation_service.domain.VeSession; -import com.example.venue_reservation_service.service.VeMessageService; -import com.example.venue_reservation_service.service.VeSessionService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import jakarta.annotation.Resource; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping("/session") -@Api("ai会话管理模块") -@CrossOrigin -public class SessionController { - - @Resource - private VeSessionService sessionService; - - @Resource - private VeMessageService messageService; - - @ApiOperation("创建新会话") - @PostMapping("/create") - public ResponseEntity createSession(@RequestBody VeSession session) { - VeSession savedSession = sessionService.saveSession(session); - return ResponseEntity.status(HttpStatus.CREATED).body(savedSession); - } - - @ApiOperation("获取用户会话历史") - @GetMapping("/list") - public ResponseEntity> getUserSessions(@RequestParam(name = "userId") Integer userId) { - List sessions = sessionService.getSessionsByUserId(userId); - return ResponseEntity.ok(sessions); - } - - @ApiOperation("获取会话详情") - @GetMapping("/{sessionId}") - public ResponseEntity getSession(@PathVariable("sessionId") Integer sessionId) { - VeSession session = sessionService.getById(sessionId); - if (session != null) { - return ResponseEntity.ok(session); - } else { - return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); - } - } - - @ApiOperation("获取指定会话的所有消息") - @GetMapping("/message/{sessionId}") - public ResponseEntity> getSessionMessages(@PathVariable("sessionId") Integer sessionId) { - List messages = messageService.getMessagesBySessionId(sessionId); - return ResponseEntity.ok(messages); - } - - @ApiOperation("创建新消息") - @PostMapping("/message/create") - public ResponseEntity createMessage(@RequestBody VeMessage message) { - VeMessage savedMessage = messageService.saveMessage(message); - return ResponseEntity.status(HttpStatus.CREATED).body(savedMessage); - } -} diff --git a/src/main/java/com/example/venue_reservation_service/controller/TypeController.java b/src/main/java/com/example/venue_reservation_service/controller/TypeController.java index 5fe7fcb..cc7545b 100644 --- a/src/main/java/com/example/venue_reservation_service/controller/TypeController.java +++ b/src/main/java/com/example/venue_reservation_service/controller/TypeController.java @@ -1,5 +1,6 @@ package com.example.venue_reservation_service.controller; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.example.venue_reservation_service.domain.Type; import com.example.venue_reservation_service.dto.PageDTO; import com.example.venue_reservation_service.service.TypeService; @@ -8,9 +9,12 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import jakarta.annotation.Resource; import org.apache.commons.io.FilenameUtils; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import java.util.Optional; + @RestController @RequestMapping("/type") @CrossOrigin @@ -20,10 +24,17 @@ public class TypeController { @Resource private TypeService typeService; + @Value("${access.url}") + private String imgPrefix; + @ApiOperation("查询某个场馆信息") @GetMapping("/select/{id}") public Result select(@PathVariable("id") Integer id){ - return Result.ok(typeService.getById(id)).message("查询成功"); + Type type = typeService.getById(id); + if(Optional.ofNullable(type).isPresent() && StringUtils.isNotBlank(type.getImgUrl())){ + type.setImgUrl(imgPrefix + type.getImgUrl()); + } + return Result.ok(type).message("查询成功"); } @ApiOperation("查看所有场馆信息") diff --git a/src/main/java/com/example/venue_reservation_service/domain/VeMessage.java b/src/main/java/com/example/venue_reservation_service/domain/VeMessage.java index d0886f0..8d5133f 100644 --- a/src/main/java/com/example/venue_reservation_service/domain/VeMessage.java +++ b/src/main/java/com/example/venue_reservation_service/domain/VeMessage.java @@ -38,7 +38,7 @@ public class VeMessage implements Serializable { /** * 发送者类型 */ - private Object sender; + private String sender; /** * 创建时间 diff --git a/src/main/java/com/example/venue_reservation_service/domain/VeSession.java b/src/main/java/com/example/venue_reservation_service/domain/VeSession.java index abf9469..a8c793e 100644 --- a/src/main/java/com/example/venue_reservation_service/domain/VeSession.java +++ b/src/main/java/com/example/venue_reservation_service/domain/VeSession.java @@ -8,7 +8,9 @@ import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serial; import java.io.Serializable; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; diff --git a/src/main/java/com/example/venue_reservation_service/entity/ChatRequest.java b/src/main/java/com/example/venue_reservation_service/entity/ChatRequest.java new file mode 100644 index 0000000..681f9b0 --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/entity/ChatRequest.java @@ -0,0 +1,11 @@ +package com.example.venue_reservation_service.entity; + +import lombok.Data; +@Data +public class ChatRequest { + + private String content; + + private String sessionToken; + +} \ No newline at end of file diff --git a/src/main/java/com/example/venue_reservation_service/entity/ChatResponse.java b/src/main/java/com/example/venue_reservation_service/entity/ChatResponse.java new file mode 100644 index 0000000..8e5dea0 --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/entity/ChatResponse.java @@ -0,0 +1,14 @@ +package com.example.venue_reservation_service.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class ChatResponse { + + private String content; + + private String sessionToken; + +} \ No newline at end of file diff --git a/src/main/java/com/example/venue_reservation_service/mapper/VeMessageMapper.java b/src/main/java/com/example/venue_reservation_service/mapper/VeMessageMapper.java index 30d0d0b..6fdde2a 100644 --- a/src/main/java/com/example/venue_reservation_service/mapper/VeMessageMapper.java +++ b/src/main/java/com/example/venue_reservation_service/mapper/VeMessageMapper.java @@ -2,6 +2,9 @@ package com.example.venue_reservation_service.mapper; import com.example.venue_reservation_service.domain.VeMessage; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.*; + +import java.util.List; /** * @author 31586 @@ -9,7 +12,10 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; * @createDate 2025-06-17 15:36:33 * @Entity generator.domain.VeMessage */ +@Mapper public interface VeMessageMapper extends BaseMapper { + @Select("SELECT * FROM venue_message WHERE session_id = #{sessionId} ORDER BY created_at ASC") + List selectMessagesBySessionId(@Param("sessionId") Integer sessionId); } diff --git a/src/main/java/com/example/venue_reservation_service/mapper/VeSessionMapper.java b/src/main/java/com/example/venue_reservation_service/mapper/VeSessionMapper.java index cb7f950..ae5d962 100644 --- a/src/main/java/com/example/venue_reservation_service/mapper/VeSessionMapper.java +++ b/src/main/java/com/example/venue_reservation_service/mapper/VeSessionMapper.java @@ -2,11 +2,9 @@ package com.example.venue_reservation_service.mapper; import com.example.venue_reservation_service.domain.VeSession; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.apache.ibatis.annotations.Insert; -import org.apache.ibatis.annotations.Options; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.*; +import java.time.LocalDateTime; import java.util.List; /** @@ -15,8 +13,12 @@ import java.util.List; * @createDate 2025-06-17 15:36:33 * @Entity generator.domain.VeSession */ +@Mapper public interface VeSessionMapper extends BaseMapper { + + @Select("SELECT * FROM venue_session WHERE session_token = #{sessionToken}") + VeSession selectBySessionToken(@Param("sessionToken") String sessionToken); } diff --git a/src/main/java/com/example/venue_reservation_service/service/ChatService.java b/src/main/java/com/example/venue_reservation_service/service/ChatService.java new file mode 100644 index 0000000..18b078d --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/service/ChatService.java @@ -0,0 +1,10 @@ +package com.example.venue_reservation_service.service; + +import com.example.venue_reservation_service.entity.ChatRequest; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; + +// ChatService.java +public interface ChatService { + void streamChatResponse(ChatRequest request, ServletOutputStream outputStream, HttpServletRequest httpRequest); +} diff --git a/src/main/java/com/example/venue_reservation_service/service/VeMessageService.java b/src/main/java/com/example/venue_reservation_service/service/VeMessageService.java index 31ade0a..dbaf201 100644 --- a/src/main/java/com/example/venue_reservation_service/service/VeMessageService.java +++ b/src/main/java/com/example/venue_reservation_service/service/VeMessageService.java @@ -12,7 +12,6 @@ import java.util.List; */ public interface VeMessageService extends IService { - VeMessage saveMessage(VeMessage message); + List getBySessionId(Integer sessionId); - List getMessagesBySessionId(Integer sessionId); } diff --git a/src/main/java/com/example/venue_reservation_service/service/VeSessionService.java b/src/main/java/com/example/venue_reservation_service/service/VeSessionService.java index f90e6b0..b8df891 100644 --- a/src/main/java/com/example/venue_reservation_service/service/VeSessionService.java +++ b/src/main/java/com/example/venue_reservation_service/service/VeSessionService.java @@ -3,8 +3,6 @@ package com.example.venue_reservation_service.service; import com.example.venue_reservation_service.domain.VeSession; import com.baomidou.mybatisplus.extension.service.IService; -import java.util.List; - /** * @author 31586 * @description 针对表【venue_session】的数据库操作Service @@ -12,7 +10,7 @@ import java.util.List; */ public interface VeSessionService extends IService { - VeSession saveSession(VeSession session); + VeSession createSession(Integer userId, String userIp); + VeSession getByToken(String token); - List getSessionsByUserId(Integer userId); } diff --git a/src/main/java/com/example/venue_reservation_service/service/impl/ChatServiceImpl.java b/src/main/java/com/example/venue_reservation_service/service/impl/ChatServiceImpl.java new file mode 100644 index 0000000..5ad9873 --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/service/impl/ChatServiceImpl.java @@ -0,0 +1,169 @@ +package com.example.venue_reservation_service.service.impl; + +import com.example.venue_reservation_service.domain.VeMessage; +import com.example.venue_reservation_service.domain.VeSession; +import com.example.venue_reservation_service.entity.ChatRequest; +import com.example.venue_reservation_service.mapper.VeMessageMapper; +import com.example.venue_reservation_service.mapper.VeSessionMapper; +import com.example.venue_reservation_service.service.ChatService; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class ChatServiceImpl implements ChatService { + + @Resource + private VeSessionMapper sessionMapper; + + @Resource + private VeMessageMapper messageMapper; + @Value("${internai.api-url}") + private String apiUrl; + @Value("${internai.api-key}") + private String apiKey; + + @Override + @Transactional + public void streamChatResponse(ChatRequest request, ServletOutputStream outputStream, HttpServletRequest httpRequest) { + // 获取或创建会话 + VeSession session = getOrCreateSession(request.getSessionToken(), httpRequest); + String sessionToken = session.getSessionToken(); + + // 保存用户消息 + saveMessage(request.getContent(), "user", session.getId()); + + // 构建完整对话历史 + List> messages = buildMessages(session.getId()); + + // 调用第三方API + streamApiResponse(messages, outputStream, sessionToken, session.getId()); + + // 更新会话结束时间 + updateSessionEndTime(session); + } + + private VeSession getOrCreateSession(String sessionToken, HttpServletRequest request) { + if (sessionToken != null && !sessionToken.isEmpty()) { + VeSession session = sessionMapper.selectBySessionToken(sessionToken); + if (session != null) { + return session; + } + } + + // 创建新会话 + VeSession newSession = new VeSession(); + newSession.setUserIp(request.getRemoteAddr()); + newSession.setStartTime(LocalDateTime.now()); + newSession.setSessionToken(UUID.randomUUID().toString()); + newSession.setTitle("New Chat"); + newSession.setUserId(1); + sessionMapper.insert(newSession); + return newSession; + } + + private void saveMessage(String content, String sender, Integer sessionId) { + VeMessage message = new VeMessage(); + message.setSessionId(sessionId); + message.setContent(content); + message.setSender(sender); + message.setCreatedAt(LocalDateTime.now()); + + messageMapper.insert(message); + } + + private List> buildMessages(Integer sessionId) { + List history = messageMapper.selectMessagesBySessionId(sessionId); + + return history.stream().map(msg -> { + Map messageMap = new HashMap<>(); + messageMap.put("role", msg.getSender().equals("user") ? "user" : "assistant"); + messageMap.put("content", msg.getContent()); + return messageMap; + }).collect(Collectors.toList()); + } + + private void streamApiResponse(List> messages, + ServletOutputStream outputStream, + String sessionToken, + Integer sessionId) { + + StringBuilder assistantResponse = new StringBuilder(); + + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost httpPost = new HttpPost(apiUrl); + httpPost.setHeader("Authorization", "Bearer " + apiKey); + httpPost.setHeader("Content-Type", "application/json"); + + // 构建请求体 + Map requestBody = new HashMap<>(); + requestBody.put("model", "internlm3-latest"); + requestBody.put("messages", messages); + requestBody.put("temperature", 0.8); + requestBody.put("top_p", 0.9); + requestBody.put("stream", true); + + httpPost.setEntity(new StringEntity(new ObjectMapper().writeValueAsString(requestBody))); + + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + InputStream contentStream = response.getEntity().getContent(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(contentStream))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.startsWith("data: ")) { + String json = line.substring(6).trim(); + if (json.equals("[DONE]")) break; + + JsonNode data = new ObjectMapper().readTree(json); + JsonNode choices = data.path("choices"); + if (!choices.isEmpty()) { + String chunk = choices.get(0).path("delta").path("content").asText(); + if (!chunk.isEmpty()) { + assistantResponse.append(chunk); + outputStream.write(chunk.getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + } + } + } + } + } + } + + // 保存助手回复 + if (!assistantResponse.isEmpty()) { + saveMessage(assistantResponse.toString(), "assistant", sessionId); + } + + } catch (Exception e) { + throw new RuntimeException("API call failed", e); + } + } + + private void updateSessionEndTime(VeSession session) { + session.setEndTime(LocalDateTime.now()); + sessionMapper.updateById(session); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/venue_reservation_service/service/impl/InformationServiceImpl.java b/src/main/java/com/example/venue_reservation_service/service/impl/InformationServiceImpl.java index 8d9059e..b6e6026 100644 --- a/src/main/java/com/example/venue_reservation_service/service/impl/InformationServiceImpl.java +++ b/src/main/java/com/example/venue_reservation_service/service/impl/InformationServiceImpl.java @@ -88,7 +88,6 @@ public class InformationServiceImpl extends ServiceImpl page = new Page<>(dto.getCurrent(), dto.getSize()); page = typeService.page(page, null); List types = new ArrayList<>(); - for (Type record : page.getRecords()) { // 获取场馆中的场地信息 QueryWrapper wrapper = new QueryWrapper<>(); @@ -98,6 +97,9 @@ public class InformationServiceImpl extends ServiceImpl (String) obj).toList(); record.setVenues(locations); + if(StringUtils.isNotBlank(record.getImgUrl())){ + record.setImgUrl(imgPrefix + record.getImgUrl()); + } types.add(record); } return Result.ok(types).message("查询成功"); diff --git a/src/main/java/com/example/venue_reservation_service/service/impl/VeMessageServiceImpl.java b/src/main/java/com/example/venue_reservation_service/service/impl/VeMessageServiceImpl.java index be54158..277da73 100644 --- a/src/main/java/com/example/venue_reservation_service/service/impl/VeMessageServiceImpl.java +++ b/src/main/java/com/example/venue_reservation_service/service/impl/VeMessageServiceImpl.java @@ -1,6 +1,5 @@ package com.example.venue_reservation_service.service.impl; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.venue_reservation_service.domain.VeMessage; import com.example.venue_reservation_service.service.VeMessageService; @@ -8,7 +7,6 @@ import com.example.venue_reservation_service.mapper.VeMessageMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; -import java.time.LocalDateTime; import java.util.List; /** @@ -20,22 +18,23 @@ import java.util.List; public class VeMessageServiceImpl extends ServiceImpl implements VeMessageService{ + @Resource - private VeMessageMapper messageMapper; + private VeMessageMapper messageMapper; @Override - public VeMessage saveMessage(VeMessage message) { - message.setCreatedAt(LocalDateTime.now()); - messageMapper.insert(message); - return message; + public boolean save(VeMessage message) { + if (message.getId() == null) { + messageMapper.insert(message); + } else { + messageMapper.updateById(message); + } + return false; } @Override - public List getMessagesBySessionId(Integer sessionId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("session_id", sessionId) - .orderByAsc("created_at"); - return messageMapper.selectList(queryWrapper); + public List getBySessionId(Integer sessionId) { + return messageMapper.selectMessagesBySessionId(sessionId); } } diff --git a/src/main/java/com/example/venue_reservation_service/service/impl/VeSessionServiceImpl.java b/src/main/java/com/example/venue_reservation_service/service/impl/VeSessionServiceImpl.java index 595e30a..75a6e6e 100644 --- a/src/main/java/com/example/venue_reservation_service/service/impl/VeSessionServiceImpl.java +++ b/src/main/java/com/example/venue_reservation_service/service/impl/VeSessionServiceImpl.java @@ -1,8 +1,5 @@ package com.example.venue_reservation_service.service.impl; -import cn.hutool.core.lang.UUID; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.venue_reservation_service.service.VeSessionService; import com.example.venue_reservation_service.domain.VeSession; @@ -10,9 +7,12 @@ import com.example.venue_reservation_service.mapper.VeSessionMapper; import jakarta.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.UUID; /** * @author 31586 @@ -26,20 +26,21 @@ public class VeSessionServiceImpl extends ServiceImpl getSessionsByUserId(Integer userId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("user_id", userId) - .orderByDesc("start_time"); - return sessionMapper.selectList(queryWrapper); + @Override + public VeSession getByToken(String token) { + return sessionMapper.selectBySessionToken(token); } } diff --git a/src/main/java/com/example/venue_reservation_service/utils/AIChatClient.java b/src/main/java/com/example/venue_reservation_service/utils/AIChatClient.java new file mode 100644 index 0000000..d3dbc86 --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/utils/AIChatClient.java @@ -0,0 +1,104 @@ +package com.example.venue_reservation_service.utils; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.Scanner; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.JsonNode; + +public class AIChatClient { + private static final String API_URL = "https://chat.intern-ai.org.cn/api/v1/chat/completions"; + private static final String BEARER_TOKEN = "eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFM1MTIifQ.eyJqdGkiOiI4NjMwNjcyNyIsInJvbCI6IlJPTEVfUkVHSVNURVIiLCJpc3MiOiJPcGVuWExhYiIsImlhdCI6MTc1MTUzOTEzNCwiY2xpZW50SWQiOiJlYm1ydm9kNnlvMG5semFlazF5cCIsInBob25lIjoiMTc4NzAzNDI2ODUiLCJvcGVuSWQiOm51bGwsInV1aWQiOiIzNDg5ZTJkOC04ZGI4LTQyNDUtOTFiZC03YmRkN2Y3MTI0ZDEiLCJlbWFpbCI6IiIsImV4cCI6MTc2NzA5MTEzNH0.-Bfg41q0v4RDjN6mgfLmga1isL02KF5DdoA1LoiNmUQg8I19FjEMz2w9dOJsql3-MavE6UB5QlECQiDvk4t6XQ"; // 替换为你的实际Token + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + // 初始化对话历史 + String conversationHistory = buildInitialHistory(); + + while (true) { + System.out.print("\n请输入你的问题 (输入 'exit' 退出): "); + String userInput = scanner.nextLine(); + + if ("exit".equalsIgnoreCase(userInput)) { + break; + } + + // 更新对话历史 + conversationHistory = updateHistory(conversationHistory, userInput); + + try { + // 发送请求并获取响应 + String response = sendChatRequest(conversationHistory); + + // 更新对话历史(添加AI回复) + conversationHistory = conversationHistory + + ",{\"role\":\"assistant\",\"content\":\"" + escapeJson(response) + "\"}"; + + System.out.println("\nAI回复: " + response); + } catch (Exception e) { + System.err.println("请求失败: " + e.getMessage()); + } + } + + scanner.close(); + } + + private static String sendChatRequest(String history) throws Exception { + // 构建完整的请求体 + String requestBody = String.format( + "{\"model\":\"internlm3-latest\",\"messages\":[%s],\"temperature\":0.8,\"top_p\":0.9,\"stream\":true}", + history + ); + + // 创建HTTP请求 + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(API_URL)) + .header("Authorization", "Bearer " + BEARER_TOKEN) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(requestBody)) + .build(); + + // 发送请求并处理流式响应 + StringBuilder fullResponse = new StringBuilder(); + client.send(request, HttpResponse.BodyHandlers.ofLines()).body() + .filter(line -> line.startsWith("data:") && !line.contains("[DONE]")) + .forEach(line -> { + try { + String json = line.substring(5).trim(); + if (!json.isEmpty()) { + JsonNode node = objectMapper.readTree(json); + String content = node.path("choices").get(0).path("delta").path("content").asText(); + if (content != null && !content.isEmpty()) { + System.out.print(content); // 实时输出 + fullResponse.append(content); + } + } + } catch (Exception e) { + System.err.println("\n解析错误: " + e.getMessage()); + } + }); + + return fullResponse.toString(); + } + + private static String buildInitialHistory() { + return "{\"role\":\"user\",\"content\":\"你知道刘慈欣吗?\"}," + + "{\"role\":\"assistant\",\"content\":\"为一个人工智能助手,我知道刘慈欣。他是一位著名的中国科幻小说家和工程师,曾经获得过多项奖项,包括雨果奖、星云奖等。\"}"; + } + + private static String updateHistory(String history, String newQuestion) { + return history + ",{\"role\":\"user\",\"content\":\"" + escapeJson(newQuestion) + "\"}"; + } + + private static String escapeJson(String input) { + return input.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t"); + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 072baa4..79d44e7 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -65,7 +65,7 @@ spring: boot: admin: client: - url: http://119.29.191.232:10020/monitor # 服务端地址 + url: http://119.29.191.232:10025/monitor # 服务端地址 username: admin # 服务端用户名 password: admin123! # 服务端密码 mail: @@ -136,3 +136,7 @@ access: logging: level: root: info +# AI API 配置 +internai: + api-url: https://chat.intern-ai.org.cn/api/v1/chat/completions + api-key: eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFM1MTIifQ.eyJqdGkiOiI4NjMwNjcyNyIsInJvbCI6IlJPTEVfUkVHSVNURVIiLCJpc3MiOiJPcGVuWExhYiIsImlhdCI6MTc1MTUzOTEzNCwiY2xpZW50SWQiOiJlYm1ydm9kNnlvMG5semFlazF5cCIsInBob25lIjoiMTc4NzAzNDI2ODUiLCJvcGVuSWQiOm51bGwsInV1aWQiOiIzNDg5ZTJkOC04ZGI4LTQyNDUtOTFiZC03YmRkN2Y3MTI0ZDEiLCJlbWFpbCI6IiIsImV4cCI6MTc2NzA5MTEzNH0.-Bfg41q0v4RDjN6mgfLmga1isL02KF5DdoA1LoiNmUQg8I19FjEMz2w9dOJsql3-MavE6UB5QlECQiDvk4t6XQ \ No newline at end of file