Enhance chat update functionality and introduce chat title generation in Neo API

- Updated handleChatUpdate method to include content field in the request body, allowing for dynamic chat title generation based on user input.
- Implemented GenerateChatTitle method to create a concise title for chats, improving user experience and interaction.
- Modified JSON response structure in handleChatDetail and handleChatUpdate methods for better clarity and consistency.
- Enhanced error handling for chat updates, ensuring robust validation and feedback for users.
This commit is contained in:
Max 2024-12-16 19:59:23 +08:00
parent 869ed3717a
commit b3bc843235
2 changed files with 114 additions and 3 deletions

View file

@ -338,7 +338,7 @@ func (neo *DSL) handleChatDetail(c *gin.Context) {
return
}
c.JSON(200, chat)
c.JSON(200, map[string]interface{}{"data": chat})
c.Done()
}
@ -382,7 +382,8 @@ func (neo *DSL) handleChatUpdate(c *gin.Context) {
// Get title from request body
var body struct {
Title string `json:"title"`
Title string `json:"title"`
Content string `json:"content"`
}
if err := c.BindJSON(&body); err != nil {
c.JSON(400, gin.H{"message": "invalid request body", "code": 400})
@ -390,6 +391,20 @@ func (neo *DSL) handleChatUpdate(c *gin.Context) {
return
}
// If content is not empty, Generate the chat title
if body.Content != "" {
ctx, cancel := NewContextWithCancel(sid, c.Query("chat_id"), "")
defer cancel()
title, err := neo.GenerateChatTitle(ctx, body.Content, c)
if err != nil {
c.JSON(500, gin.H{"message": err.Error(), "code": 500})
c.Done()
return
}
body.Title = title
}
if body.Title == "" {
c.JSON(400, gin.H{"message": "title is required", "code": 400})
c.Done()
@ -403,6 +418,6 @@ func (neo *DSL) handleChatUpdate(c *gin.Context) {
return
}
c.JSON(200, gin.H{"message": "success"})
c.JSON(200, gin.H{"message": "ok", "title": body.Title, "chat_id": chatID})
c.Done()
}

View file

@ -58,6 +58,102 @@ func (neo *DSL) GetMentions(keywords string) ([]Mention, error) {
return neo.HookMention(context.Background(), keywords)
}
// GenerateChatTitle generate the chat title
func (neo *DSL) GenerateChatTitle(ctx Context, input string, c *gin.Context) (string, error) {
prompts := `
Help me generate a title for the chat
1. The title should be a short and concise description of the chat.
2. The title should be a single sentence.
3. The title should be in same language as the chat.
4. The title should be no more than 50 characters.
`
messages := []map[string]interface{}{
{"role": "system", "content": prompts},
{"role": "user", "content": input},
}
res, err := neo.HookCreate(ctx, messages, c)
if err != nil {
return "", err
}
// Select Assistant
ast, err := neo.selectAssistant(res.AssistantID)
if err != nil {
return "", err
}
if ast == nil {
msg := message.New().Error("assistant is not initialized").Done()
msg.Write(c.Writer)
return "", fmt.Errorf("assistant is not initialized")
}
clientBreak := make(chan bool, 1)
done := make(chan bool, 1)
fail := make(chan error, 1)
content := []byte{}
// Chat with AI in background
go func() {
err := ast.Chat(c.Request.Context(), messages, neo.Option, func(data []byte) int {
select {
case <-clientBreak:
return 0 // break
default:
msg := message.NewOpenAI(data)
if msg == nil {
return 1 // continue
}
// Handle error
if msg.Type == "error" {
fail <- fmt.Errorf("%s", msg.Message.Text)
return 0 // break
}
// Append content and send message
content = msg.Append(content)
// Complete the stream
if msg.Message.Done {
done <- true
return 0 // break
}
return 1 // continue
}
})
if err != nil {
log.Error("Chat error: %s", err.Error())
message.New().Error(err).Done().Write(c.Writer)
}
// Save chat history
if len(content) > 0 {
neo.saveHistory(ctx.Sid, ctx.ChatID, content, messages)
}
done <- true
}()
// Wait for completion or client disconnect
select {
case <-done:
return string(content), nil
case err := <-fail:
return "", err
case <-c.Writer.CloseNotify():
clientBreak <- true
return "", nil
}
}
// Upload upload a file
func (neo *DSL) Upload(ctx Context, c *gin.Context) (*assistant.File, error) {
// Get the file