From 2a5ccb0e2d445c2df07722394a037c608b3ff1d8 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 25 Jan 2025 15:42:51 +0800 Subject: [PATCH] Add latest chat retrieval endpoint to Neo API - Implemented a new `/chats/latest` endpoint to fetch the most recent chat or generate a placeholder - Added `handleChatLatest` method in the DSL to support retrieving the latest chat for a given session - Introduced `GetPlaceholder()` method in the Assistant interface to support placeholder generation - Enhanced API flexibility by allowing optional assistant ID specification for placeholder retrieval This change improves the chat retrieval capabilities of the Neo API, providing a convenient way to access the most recent chat or generate a starting point for new conversations. --- neo/api.go | 59 ++++++++++++++++++++++++++++++++++++++++++ neo/assistant/api.go | 5 ++++ neo/assistant/types.go | 2 ++ 3 files changed, 66 insertions(+) diff --git a/neo/api.go b/neo/api.go index 4d9de7db..f047053f 100644 --- a/neo/api.go +++ b/neo/api.go @@ -95,6 +95,10 @@ func (neo *DSL) API(router *gin.Engine, path string) error { // curl -X GET 'http://localhost:5099/api/__yao/neo/chats?page=1&pagesize=20&keywords=search+term&order=desc&token=xxx' router.GET(path+"/chats", append(middlewares, neo.handleChatList)...) + // Get latest chat example: + // curl -X GET 'http://localhost:5099/api/__yao/neo/chats/latest?assistant_id=assistant_123&token=xxx' + router.GET(path+"/chats/latest", append(middlewares, neo.handleChatLatest)...) + // Get chat details example: // curl -X GET 'http://localhost:5099/api/__yao/neo/chats/chat_123?token=xxx' router.GET(path+"/chats/:id", append(middlewares, neo.handleChatDetail)...) @@ -447,6 +451,61 @@ func (neo *DSL) defaultGuard(c *gin.Context) { c.Next() } +// handleChatLatest handles getting the latest chat +func (neo *DSL) handleChatLatest(c *gin.Context) { + sid := c.GetString("__sid") + if sid == "" { + c.JSON(400, gin.H{"message": "sid is required", "code": 400}) + c.Done() + return + } + + // Get the chats + chats, err := neo.Store.GetChats(sid, store.ChatFilter{Page: 1}) + if err != nil { + c.JSON(500, gin.H{"message": err.Error(), "code": 500}) + c.Done() + return + } + + // Create a new chat + if len(chats.Groups) == 0 || len(chats.Groups[0].Chats) == 0 { + + ast := neo.Assistant + assistantID := c.Query("assistant_id") + if assistantID != "" { + ast, err = assistant.Get(assistantID) + if err != nil { + c.JSON(500, gin.H{"message": err.Error(), "code": 500}) + c.Done() + return + } + } + + c.JSON(200, map[string]interface{}{"data": map[string]interface{}{"placeholder": ast.GetPlaceholder()}}) + c.Done() + return + } + + // Get the chat_id + chatID, ok := chats.Groups[0].Chats[0]["chat_id"].(string) + if !ok { + c.JSON(404, gin.H{"message": "chat_id not found", "code": 404}) + c.Done() + return + } + + chat, err := neo.Store.GetChat(sid, chatID) + if err != nil { + c.JSON(500, gin.H{"message": err.Error(), "code": 500}) + c.Done() + return + } + + c.JSON(200, map[string]interface{}{"data": chat}) + c.Done() +} + // handleChatDetail handles getting a single chat's details func (neo *DSL) handleChatDetail(c *gin.Context) { sid := c.GetString("__sid") diff --git a/neo/assistant/api.go b/neo/assistant/api.go index 06a850e6..0c63e8a0 100644 --- a/neo/assistant/api.go +++ b/neo/assistant/api.go @@ -170,6 +170,11 @@ func (next *NextAction) Execute(c *gin.Context, ctx chatctx.Context) error { } } +// GetPlaceholder returns the placeholder of the assistant +func (ast *Assistant) GetPlaceholder() *Placeholder { + return ast.Placeholder +} + // Call implements the call functionality func (ast *Assistant) Call(c *gin.Context, payload APIPayload) (interface{}, error) { scriptCtx, err := ast.Script.NewContext(payload.Sid, nil) diff --git a/neo/assistant/types.go b/neo/assistant/types.go index ca3b24a2..76cc9158 100644 --- a/neo/assistant/types.go +++ b/neo/assistant/types.go @@ -24,6 +24,8 @@ type API interface { Upload(ctx context.Context, file *multipart.FileHeader, reader io.Reader, option map[string]interface{}) (*File, error) Download(ctx context.Context, fileID string) (*FileResponse, error) ReadBase64(ctx context.Context, fileID string) (string, error) + + GetPlaceholder() *Placeholder Execute(c *gin.Context, ctx chatctx.Context, input string, options map[string]interface{}) error Call(c *gin.Context, payload APIPayload) (interface{}, error) }