feat(chat): auto-generate titles for chat sessions
This commit is contained in:
parent
4dc1493473
commit
6cbe81f425
@ -143,6 +143,8 @@ public class ChatController {
|
||||
oldName,
|
||||
"newName",
|
||||
(Object) newName);
|
||||
case StreamEvent.TitleGenerated(var title, var sessionId) ->
|
||||
Map.of("type", "title_generated", "title", title, "sessionId", sessionId);
|
||||
};
|
||||
return ServerSentEvent.<String>builder().data(toJson(data)).build();
|
||||
}
|
||||
|
||||
@ -10,7 +10,8 @@ public sealed interface StreamEvent
|
||||
StreamEvent.Done,
|
||||
StreamEvent.Error,
|
||||
StreamEvent.RenameSuggestion,
|
||||
StreamEvent.FunctionRenamed {
|
||||
StreamEvent.FunctionRenamed,
|
||||
StreamEvent.TitleGenerated {
|
||||
|
||||
record Chunk(String content) implements StreamEvent {}
|
||||
|
||||
@ -28,4 +29,6 @@ public sealed interface StreamEvent
|
||||
implements StreamEvent {}
|
||||
|
||||
record FunctionRenamed(UUID functionId, String oldName, String newName) implements StreamEvent {}
|
||||
|
||||
record TitleGenerated(String title, UUID sessionId) implements StreamEvent {}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import lombok.extern.log4j.Log4j2;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.ai.chat.client.ChatClient;
|
||||
import org.springframework.ai.chat.messages.Message;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.model.ChatModel;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.support.ToolCallbacks;
|
||||
@ -86,6 +87,12 @@ public class ChatService {
|
||||
() -> {
|
||||
log.debug("Chat completed for session {}", sessionId);
|
||||
saveAssistantMessage(session, assistantContent.toString());
|
||||
generateAndSetTitle(
|
||||
session,
|
||||
chatModel,
|
||||
request.content(),
|
||||
assistantContent.toString(),
|
||||
eventSink);
|
||||
eventSink.tryEmitComplete();
|
||||
})
|
||||
.doOnError(
|
||||
@ -131,6 +138,52 @@ public class ChatService {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateAndSetTitle(
|
||||
ChatSession session,
|
||||
ChatModel chatModel,
|
||||
String userMessage,
|
||||
String assistantResponse,
|
||||
Sinks.Many<StreamEvent> eventSink) {
|
||||
|
||||
if (Objects.isNull(session.getTitle()) || !session.getTitle().endsWith(" — Chat")) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var truncatedResponse = AiUtils.truncate(assistantResponse, 500);
|
||||
var prompt =
|
||||
String.format(
|
||||
"""
|
||||
Generate a very short title for a chat conversation
|
||||
(maximum 6 words, 50 characters). Output ONLY the title text.
|
||||
No quotes, no punctuation, no explanation.
|
||||
|
||||
User message: %s
|
||||
|
||||
Assistant response: %s
|
||||
|
||||
Title:""",
|
||||
userMessage, truncatedResponse);
|
||||
|
||||
var response = chatModel.call(new Prompt(new UserMessage(prompt)));
|
||||
var title = response.getResult().getOutput().getText();
|
||||
|
||||
if (Objects.nonNull(title) && !title.isBlank()) {
|
||||
title = title.trim().replaceAll("^[\"'\\[\\]]+|[\"'\\[\\]]+$", "");
|
||||
|
||||
if (title.length() > 50) {
|
||||
title = title.substring(0, 50);
|
||||
}
|
||||
|
||||
sessionService.updateTitle(session.getId(), title);
|
||||
eventSink.tryEmitNext(new StreamEvent.TitleGenerated(title, session.getId()));
|
||||
log.info("Auto-generated title '{}' for session {}", title, session.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to auto-generate title for session {}: {}", session.getId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private class ObservedToolCallback implements ToolCallback {
|
||||
private final ToolCallback delegate;
|
||||
private final Sinks.Many<StreamEvent> eventSink;
|
||||
|
||||
@ -96,4 +96,16 @@ public class ChatSessionService {
|
||||
|
||||
messageRepository.save(msg);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void updateTitle(UUID sessionId, String title) {
|
||||
var session =
|
||||
sessionRepository
|
||||
.findById(sessionId)
|
||||
.orElseThrow(
|
||||
() -> new NotFoundException("Chat session with id '" + sessionId + "' not found"));
|
||||
|
||||
session.setTitle(title);
|
||||
sessionRepository.save(session);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user