|
@@ -36,6 +36,7 @@ public class ChatController {
|
|
|
private final ChatPersistenceService persistenceService;
|
|
private final ChatPersistenceService persistenceService;
|
|
|
private final RerankerService rerankerService;
|
|
private final RerankerService rerankerService;
|
|
|
private final QACacheService qaCache;
|
|
private final QACacheService qaCache;
|
|
|
|
|
+ private final BrandRecommendService brandRecommendService;
|
|
|
private final JdbcTemplate jdbc;
|
|
private final JdbcTemplate jdbc;
|
|
|
private final QwenProperties props;
|
|
private final QwenProperties props;
|
|
|
private final HttpServletRequest request;
|
|
private final HttpServletRequest request;
|
|
@@ -43,6 +44,7 @@ public class ChatController {
|
|
|
public ChatController(RetrieverService rs, LLMService ls, PromptService ps,
|
|
public ChatController(RetrieverService rs, LLMService ls, PromptService ps,
|
|
|
ChatPersistenceService cps, RerankerService rrs,
|
|
ChatPersistenceService cps, RerankerService rrs,
|
|
|
QACacheService qaCache,
|
|
QACacheService qaCache,
|
|
|
|
|
+ BrandRecommendService brandRecommendService,
|
|
|
JdbcTemplate jdbc, QwenProperties props,
|
|
JdbcTemplate jdbc, QwenProperties props,
|
|
|
HttpServletRequest request) {
|
|
HttpServletRequest request) {
|
|
|
this.retrieverService = rs;
|
|
this.retrieverService = rs;
|
|
@@ -51,6 +53,7 @@ public class ChatController {
|
|
|
this.persistenceService = cps;
|
|
this.persistenceService = cps;
|
|
|
this.rerankerService = rrs;
|
|
this.rerankerService = rrs;
|
|
|
this.qaCache = qaCache;
|
|
this.qaCache = qaCache;
|
|
|
|
|
+ this.brandRecommendService = brandRecommendService;
|
|
|
this.jdbc = jdbc;
|
|
this.jdbc = jdbc;
|
|
|
this.props = props;
|
|
this.props = props;
|
|
|
this.request = request;
|
|
this.request = request;
|
|
@@ -72,11 +75,13 @@ public class ChatController {
|
|
|
String intent = (String) cached.getOrDefault("intent", "");
|
|
String intent = (String) cached.getOrDefault("intent", "");
|
|
|
@SuppressWarnings("unchecked")
|
|
@SuppressWarnings("unchecked")
|
|
|
List<Map<String, Object>> sources = (List<Map<String, Object>>) cached.getOrDefault("sources", List.of());
|
|
List<Map<String, Object>> sources = (List<Map<String, Object>>) cached.getOrDefault("sources", List.of());
|
|
|
|
|
+ List<Map<String, Object>> brandRecs = brandRecommendService.match(sources, answer);
|
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
|
- persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources);
|
|
|
|
|
|
|
+ persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources, brandRecs);
|
|
|
return ResponseEntity.ok(Map.of(
|
|
return ResponseEntity.ok(Map.of(
|
|
|
"answer", answer,
|
|
"answer", answer,
|
|
|
"sources", sources,
|
|
"sources", sources,
|
|
|
|
|
+ "brand_recommendations", brandRecs,
|
|
|
"intent", intent,
|
|
"intent", intent,
|
|
|
"conversation_id", cid,
|
|
"conversation_id", cid,
|
|
|
"cached", true
|
|
"cached", true
|
|
@@ -91,10 +96,13 @@ public class ChatController {
|
|
|
String intent = (String) waited.getOrDefault("intent", "");
|
|
String intent = (String) waited.getOrDefault("intent", "");
|
|
|
@SuppressWarnings("unchecked")
|
|
@SuppressWarnings("unchecked")
|
|
|
List<Map<String, Object>> sources = (List<Map<String, Object>>) waited.getOrDefault("sources", List.of());
|
|
List<Map<String, Object>> sources = (List<Map<String, Object>>) waited.getOrDefault("sources", List.of());
|
|
|
|
|
+ List<Map<String, Object>> brandRecs = brandRecommendService.match(sources, answer);
|
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
|
- persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources);
|
|
|
|
|
|
|
+ persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources, brandRecs);
|
|
|
return ResponseEntity.ok(Map.of(
|
|
return ResponseEntity.ok(Map.of(
|
|
|
- "answer", answer, "sources", sources, "intent", intent,
|
|
|
|
|
|
|
+ "answer", answer, "sources", sources,
|
|
|
|
|
+ "brand_recommendations", brandRecs,
|
|
|
|
|
+ "intent", intent,
|
|
|
"conversation_id", cid, "cached", true
|
|
"conversation_id", cid, "cached", true
|
|
|
));
|
|
));
|
|
|
}
|
|
}
|
|
@@ -118,8 +126,9 @@ public class ChatController {
|
|
|
throw e;
|
|
throw e;
|
|
|
}
|
|
}
|
|
|
String answer = llmAnswer;
|
|
String answer = llmAnswer;
|
|
|
|
|
+ List<Map<String, Object>> brandRecs = brandRecommendService.match(sources, answer);
|
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
|
- persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources);
|
|
|
|
|
|
|
+ persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources, brandRecs);
|
|
|
|
|
|
|
|
// 写入全局缓存
|
|
// 写入全局缓存
|
|
|
qaCache.put(normalized, answer, intent, sources);
|
|
qaCache.put(normalized, answer, intent, sources);
|
|
@@ -127,6 +136,7 @@ public class ChatController {
|
|
|
return ResponseEntity.ok(Map.of(
|
|
return ResponseEntity.ok(Map.of(
|
|
|
"answer", answer,
|
|
"answer", answer,
|
|
|
"sources", sources,
|
|
"sources", sources,
|
|
|
|
|
+ "brand_recommendations", brandRecs,
|
|
|
"intent", intent,
|
|
"intent", intent,
|
|
|
"conversation_id", cid
|
|
"conversation_id", cid
|
|
|
));
|
|
));
|
|
@@ -189,6 +199,7 @@ public class ChatController {
|
|
|
Flux<ServerSentEvent<String>> tailFlux = Flux.defer(() -> {
|
|
Flux<ServerSentEvent<String>> tailFlux = Flux.defer(() -> {
|
|
|
String finalAnswer = cleanAnswer(fullAnswerBuf.toString());
|
|
String finalAnswer = cleanAnswer(fullAnswerBuf.toString());
|
|
|
final List<Map<String, Object>> sources = buildSources(docs);
|
|
final List<Map<String, Object>> sources = buildSources(docs);
|
|
|
|
|
+ final List<Map<String, Object>> brandRecs = brandRecommendService.match(sources, finalAnswer);
|
|
|
String meta;
|
|
String meta;
|
|
|
try {
|
|
try {
|
|
|
meta = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(Map.of(
|
|
meta = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(Map.of(
|
|
@@ -202,10 +213,11 @@ public class ChatController {
|
|
|
long t4 = System.currentTimeMillis();
|
|
long t4 = System.currentTimeMillis();
|
|
|
log.info("[chatStream] chatStream done, llmElapsed={}ms, total={}ms", t4 - t3, t4 - t0);
|
|
log.info("[chatStream] chatStream done, llmElapsed={}ms, total={}ms", t4 - t3, t4 - t0);
|
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
|
- persistenceService.saveMessage(userKey, cid, "assistant", finalAnswer, intent, sources);
|
|
|
|
|
|
|
+ persistenceService.saveMessage(userKey, cid, "assistant", finalAnswer, intent, sources, brandRecs);
|
|
|
qaCache.put(normalized, finalAnswer, intent, sources);
|
|
qaCache.put(normalized, finalAnswer, intent, sources);
|
|
|
|
|
|
|
|
return Flux.just(
|
|
return Flux.just(
|
|
|
|
|
+ buildBrandRecommendEvent(brandRecs),
|
|
|
ServerSentEvent.<String>builder().event("meta").data(meta).build()
|
|
ServerSentEvent.<String>builder().event("meta").data(meta).build()
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
@@ -234,7 +246,8 @@ public class ChatController {
|
|
|
List<Map<String, Object>> sources = (List<Map<String, Object>>) cached.getOrDefault("sources", List.of());
|
|
List<Map<String, Object>> sources = (List<Map<String, Object>>) cached.getOrDefault("sources", List.of());
|
|
|
|
|
|
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
persistenceService.saveMessage(userKey, cid, "user", query, intent, null);
|
|
|
- persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources);
|
|
|
|
|
|
|
+ List<Map<String, Object>> brandRecs = brandRecommendService.match(sources, answer);
|
|
|
|
|
+ persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources, brandRecs);
|
|
|
|
|
|
|
|
return Flux.create(sink -> {
|
|
return Flux.create(sink -> {
|
|
|
sink.next(ServerSentEvent.<String>builder().event("intent").data(intent).build());
|
|
sink.next(ServerSentEvent.<String>builder().event("intent").data(intent).build());
|
|
@@ -244,6 +257,7 @@ public class ChatController {
|
|
|
for (String chunk : chunks) {
|
|
for (String chunk : chunks) {
|
|
|
sink.next(ServerSentEvent.<String>builder().data(chunk).build());
|
|
sink.next(ServerSentEvent.<String>builder().data(chunk).build());
|
|
|
}
|
|
}
|
|
|
|
|
+ sink.next(buildBrandRecommendEvent(brandRecs));
|
|
|
try {
|
|
try {
|
|
|
String meta = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(Map.of(
|
|
String meta = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(Map.of(
|
|
|
"intent", intent, "sources", sources, "conversation_id", cid, "cached", true
|
|
"intent", intent, "sources", sources, "conversation_id", cid, "cached", true
|
|
@@ -287,14 +301,16 @@ public class ChatController {
|
|
|
String answer = cleanAnswer(llmService.chat(messages, true));
|
|
String answer = cleanAnswer(llmService.chat(messages, true));
|
|
|
|
|
|
|
|
List<Map<String, Object>> sources = buildSources(docs);
|
|
List<Map<String, Object>> sources = buildSources(docs);
|
|
|
|
|
+ List<Map<String, Object>> brandRecs = brandRecommendService.match(sources, answer);
|
|
|
persistenceService.saveMessage(userKey, cid, "user",
|
|
persistenceService.saveMessage(userKey, cid, "user",
|
|
|
request.getMessage().isBlank() ? "[图片]" : "[图片] " + request.getMessage(),
|
|
request.getMessage().isBlank() ? "[图片]" : "[图片] " + request.getMessage(),
|
|
|
intent, null);
|
|
intent, null);
|
|
|
- persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources);
|
|
|
|
|
|
|
+ persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources, brandRecs);
|
|
|
|
|
|
|
|
return ResponseEntity.ok(Map.of(
|
|
return ResponseEntity.ok(Map.of(
|
|
|
"answer", answer,
|
|
"answer", answer,
|
|
|
"sources", sources,
|
|
"sources", sources,
|
|
|
|
|
+ "brand_recommendations", brandRecs,
|
|
|
"intent", intent,
|
|
"intent", intent,
|
|
|
"conversation_id", cid
|
|
"conversation_id", cid
|
|
|
));
|
|
));
|
|
@@ -350,6 +366,7 @@ public class ChatController {
|
|
|
Flux<ServerSentEvent<String>> tailFlux = Flux.defer(() -> {
|
|
Flux<ServerSentEvent<String>> tailFlux = Flux.defer(() -> {
|
|
|
String finalAnswer = cleanAnswer(fullAnswerBuf.toString());
|
|
String finalAnswer = cleanAnswer(fullAnswerBuf.toString());
|
|
|
final List<Map<String, Object>> sources = buildSources(docs);
|
|
final List<Map<String, Object>> sources = buildSources(docs);
|
|
|
|
|
+ final List<Map<String, Object>> brandRecs = brandRecommendService.match(sources, finalAnswer);
|
|
|
String meta;
|
|
String meta;
|
|
|
try {
|
|
try {
|
|
|
meta = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(Map.of(
|
|
meta = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(Map.of(
|
|
@@ -364,8 +381,9 @@ public class ChatController {
|
|
|
persistenceService.saveMessage(userKey, cid, "user",
|
|
persistenceService.saveMessage(userKey, cid, "user",
|
|
|
request.getMessage().isBlank() ? "[图片]" : "[图片] " + request.getMessage(),
|
|
request.getMessage().isBlank() ? "[图片]" : "[图片] " + request.getMessage(),
|
|
|
intent, null);
|
|
intent, null);
|
|
|
- persistenceService.saveMessage(userKey, cid, "assistant", finalAnswer, intent, sources);
|
|
|
|
|
|
|
+ persistenceService.saveMessage(userKey, cid, "assistant", finalAnswer, intent, sources, brandRecs);
|
|
|
return Flux.just(
|
|
return Flux.just(
|
|
|
|
|
+ buildBrandRecommendEvent(brandRecs),
|
|
|
ServerSentEvent.<String>builder().event("meta").data(meta).build()
|
|
ServerSentEvent.<String>builder().event("meta").data(meta).build()
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
@@ -429,14 +447,16 @@ public class ChatController {
|
|
|
String answer = cleanAnswer(llmService.chat(messages, enableSearch));
|
|
String answer = cleanAnswer(llmService.chat(messages, enableSearch));
|
|
|
|
|
|
|
|
List<Map<String, Object>> sources = buildSources(docs);
|
|
List<Map<String, Object>> sources = buildSources(docs);
|
|
|
|
|
+ List<Map<String, Object>> brandRecs = brandRecommendService.match(sources, answer);
|
|
|
String userMsg = !request.getMessage().isBlank() ? request.getMessage()
|
|
String userMsg = !request.getMessage().isBlank() ? request.getMessage()
|
|
|
: !ocrText.isEmpty() ? "[" + mediaLabel + "]" : request.getMessage();
|
|
: !ocrText.isEmpty() ? "[" + mediaLabel + "]" : request.getMessage();
|
|
|
persistenceService.saveMessage(userKey, cid, "user", userMsg, intent, null);
|
|
persistenceService.saveMessage(userKey, cid, "user", userMsg, intent, null);
|
|
|
- persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources);
|
|
|
|
|
|
|
+ persistenceService.saveMessage(userKey, cid, "assistant", answer, intent, sources, brandRecs);
|
|
|
|
|
|
|
|
return ResponseEntity.ok(Map.of(
|
|
return ResponseEntity.ok(Map.of(
|
|
|
"answer", answer,
|
|
"answer", answer,
|
|
|
"sources", sources,
|
|
"sources", sources,
|
|
|
|
|
+ "brand_recommendations", brandRecs,
|
|
|
"intent", intent,
|
|
"intent", intent,
|
|
|
"conversation_id", cid
|
|
"conversation_id", cid
|
|
|
));
|
|
));
|
|
@@ -534,18 +554,20 @@ public class ChatController {
|
|
|
|
|
|
|
|
Flux<ServerSentEvent<String>> tailFlux = Flux.defer(() -> {
|
|
Flux<ServerSentEvent<String>> tailFlux = Flux.defer(() -> {
|
|
|
final List<Map<String, Object>> sources = buildSources(docs);
|
|
final List<Map<String, Object>> sources = buildSources(docs);
|
|
|
|
|
+ String finalAnswer = cleanAnswer(fullAnswerBuf.toString());
|
|
|
|
|
+ final List<Map<String, Object>> brandRecs = brandRecommendService.match(sources, finalAnswer);
|
|
|
String meta;
|
|
String meta;
|
|
|
try {
|
|
try {
|
|
|
meta = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(Map.of(
|
|
meta = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(Map.of(
|
|
|
"intent", intent, "sources", sources, "conversation_id", cid,
|
|
"intent", intent, "sources", sources, "conversation_id", cid,
|
|
|
"ocr_text", ocrText != null ? ocrText : ""));
|
|
"ocr_text", ocrText != null ? ocrText : ""));
|
|
|
} catch (Exception e) { meta = "{}"; }
|
|
} catch (Exception e) { meta = "{}"; }
|
|
|
- String finalAnswer = cleanAnswer(fullAnswerBuf.toString());
|
|
|
|
|
String userMsg = (rawMsg != null && !rawMsg.isBlank()) ? rawMsg
|
|
String userMsg = (rawMsg != null && !rawMsg.isBlank()) ? rawMsg
|
|
|
: (ocrText != null && !ocrText.isEmpty()) ? "[" + mediaLabel + "]" : "";
|
|
: (ocrText != null && !ocrText.isEmpty()) ? "[" + mediaLabel + "]" : "";
|
|
|
persistenceService.saveMessage(userKey, cid, "user", userMsg, intent, null);
|
|
persistenceService.saveMessage(userKey, cid, "user", userMsg, intent, null);
|
|
|
- persistenceService.saveMessage(userKey, cid, "assistant", finalAnswer, intent, sources);
|
|
|
|
|
|
|
+ persistenceService.saveMessage(userKey, cid, "assistant", finalAnswer, intent, sources, brandRecs);
|
|
|
return Flux.just(
|
|
return Flux.just(
|
|
|
|
|
+ buildBrandRecommendEvent(brandRecs),
|
|
|
ServerSentEvent.<String>builder().event("meta").data(meta).build()
|
|
ServerSentEvent.<String>builder().event("meta").data(meta).build()
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
@@ -717,6 +739,17 @@ public class ChatController {
|
|
|
));
|
|
));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private ServerSentEvent<String> buildBrandRecommendEvent(List<Map<String, Object>> recs) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String data = new com.fasterxml.jackson.databind.ObjectMapper()
|
|
|
|
|
+ .writeValueAsString(Map.of("recommendations", recs != null ? recs : List.of()));
|
|
|
|
|
+ return ServerSentEvent.<String>builder().event("brand_recommend").data(data).build();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return ServerSentEvent.<String>builder().event("brand_recommend")
|
|
|
|
|
+ .data("{\"recommendations\":[]}").build();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private List<Map<String, Object>> buildSources(List<Map<String, Object>> docs) {
|
|
private List<Map<String, Object>> buildSources(List<Map<String, Object>> docs) {
|
|
|
Set<String> rawSeen = new HashSet<>();
|
|
Set<String> rawSeen = new HashSet<>();
|
|
|
Set<String> seen = new HashSet<>();
|
|
Set<String> seen = new HashSet<>();
|