diff --git a/neo/api.go b/neo/api.go index 5e7c46ca..04c2c70d 100644 --- a/neo/api.go +++ b/neo/api.go @@ -285,7 +285,12 @@ func (neo *DSL) handleChatList(c *gin.Context) { } } - response, err := neo.Store.GetChats(sid, filter) + locale := "en-us" + if loc := c.Query("locale"); loc != "" { + locale = strings.ToLower(strings.TrimSpace(loc)) + } + + response, err := neo.Store.GetChats(sid, filter, locale) if err != nil { c.JSON(500, gin.H{"message": err.Error(), "code": 500}) c.Done() @@ -483,19 +488,19 @@ func (neo *DSL) handleChatLatest(c *gin.Context) { return } + locale := "en-us" + if loc := c.Query("locale"); loc != "" { + locale = strings.ToLower(strings.TrimSpace(loc)) + } + // Get the chats - chats, err := neo.Store.GetChats(sid, store.ChatFilter{Page: 1}) + chats, err := neo.Store.GetChats(sid, store.ChatFilter{Page: 1}, locale) if err != nil { c.JSON(500, gin.H{"message": err.Error(), "code": 500}) c.Done() return } - locale := "en-us" - if loc := c.Query("locale"); loc != "" { - locale = strings.ToLower(strings.TrimSpace(loc)) - } - // Create a new chat if len(chats.Groups) == 0 || len(chats.Groups[0].Chats) == 0 { @@ -516,7 +521,7 @@ func (neo *DSL) handleChatLatest(c *gin.Context) { c.JSON(200, map[string]interface{}{"data": map[string]interface{}{ "placeholder": ast.GetPlaceholder(locale), "assistant_id": ast.ID, - "assistant_name": ast.Name, + "assistant_name": ast.GetName(locale), "assistant_avatar": ast.Avatar, "assistant_deleteable": neo.Use.Default != ast.ID, }}) @@ -532,7 +537,7 @@ func (neo *DSL) handleChatLatest(c *gin.Context) { return } - chat, err := neo.Store.GetChat(sid, chatID) + chat, err := neo.Store.GetChat(sid, chatID, locale) if err != nil { c.JSON(500, gin.H{"message": err.Error(), "code": 500}) c.Done() @@ -550,7 +555,7 @@ func (neo *DSL) handleChatLatest(c *gin.Context) { c.Done() return } - chat.Chat["assistant_name"] = ast.Name + chat.Chat["assistant_name"] = ast.GetName(locale) chat.Chat["assistant_avatar"] = ast.Avatar } @@ -575,7 +580,13 @@ func (neo *DSL) handleChatDetail(c *gin.Context) { return } - chat, err := neo.Store.GetChat(sid, chatID) + locale := "en-us" + if loc := c.Query("locale"); loc != "" { + locale = strings.ToLower(strings.TrimSpace(loc)) + } + + // Get the chat details + chat, err := neo.Store.GetChat(sid, chatID, locale) if err != nil { c.JSON(500, gin.H{"message": err.Error(), "code": 500}) c.Done() @@ -593,7 +604,7 @@ func (neo *DSL) handleChatDetail(c *gin.Context) { c.Done() return } - chat.Chat["assistant_name"] = ast.Name + chat.Chat["assistant_name"] = ast.GetName(locale) chat.Chat["assistant_avatar"] = ast.Avatar } @@ -611,6 +622,11 @@ func (neo *DSL) handleMentions(c *gin.Context) { return } + locale := "en-us" + if loc := c.Query("locale"); loc != "" { + locale = strings.ToLower(strings.TrimSpace(loc)) + } + // Get keywords from query parameter keywords := strings.ToLower(c.Query("keywords")) mentionable := true @@ -623,7 +639,7 @@ func (neo *DSL) handleMentions(c *gin.Context) { PageSize: 20, } - response, err := neo.Store.GetAssistants(filter) + response, err := neo.Store.GetAssistants(filter, locale) if err != nil { c.JSON(500, gin.H{"message": err.Error(), "code": 500}) c.Done() diff --git a/neo/assistant/api.go b/neo/assistant/api.go index 5028095e..240537c9 100644 --- a/neo/assistant/api.go +++ b/neo/assistant/api.go @@ -274,6 +274,16 @@ func (ast *Assistant) GetPlaceholder(locale string) *Placeholder { } } +// GetName returns the name of the assistant +func (ast *Assistant) GetName(locale string) string { + return i18n.Translate(ast.ID, locale, ast.Name).(string) +} + +// GetDescription returns the description of the assistant +func (ast *Assistant) GetDescription(locale string) string { + return i18n.Translate(ast.ID, locale, ast.Description).(string) +} + // Call implements the call functionality func (ast *Assistant) Call(c *gin.Context, payload APIPayload) (interface{}, error) { scriptCtx, err := ast.Script.NewContext(payload.Sid, nil) @@ -521,7 +531,7 @@ func (ast *Assistant) streamChat( output.Retry = ctx.Retry // Retry mode output.Silent = ctx.Silent // Silent mode if isFirst { - output.Assistant(ast.ID, ast.Name, ast.Avatar) + output.Assistant(ast.ID, ast.GetName(ctx.Locale), ast.Avatar) isFirst = false } @@ -542,7 +552,7 @@ func (ast *Assistant) streamChat( chatMessage.New(). Map(map[string]interface{}{ "assistant_id": ast.ID, - "assistant_name": ast.Name, + "assistant_name": ast.GetName(ctx.Locale), "assistant_avatar": ast.Avatar, "text": delta, "type": "text", @@ -731,7 +741,7 @@ func (ast *Assistant) saveChatHistory(ctx chatctx.Context, messages []chatMessag "content": contents.JSON(), "name": ast.ID, "assistant_id": ast.ID, - "assistant_name": ast.Name, + "assistant_name": ast.GetName(ctx.Locale), "assistant_avatar": ast.Avatar, }, } diff --git a/neo/assistant/load_test.go b/neo/assistant/load_test.go index 513f70af..17503e5b 100644 --- a/neo/assistant/load_test.go +++ b/neo/assistant/load_test.go @@ -370,17 +370,19 @@ func (m *mockStore) DeleteChat(id string, chatID string) error { return nil } func (m *mockStore) GetAssistants(filter store.AssistantFilter, locale ...string) (*store.AssistantResponse, error) { return nil, nil } -func (m *mockStore) GetChat(id string, chatID string) (*store.ChatInfo, error) { return nil, nil } -func (m *mockStore) GetChatWithFilter(id string, chatID string, filter store.ChatFilter) (*store.ChatInfo, error) { +func (m *mockStore) GetChat(id string, chatID string, locale ...string) (*store.ChatInfo, error) { return nil, nil } -func (m *mockStore) GetChats(id string, filter store.ChatFilter) (*store.ChatGroupResponse, error) { +func (m *mockStore) GetChatWithFilter(id string, chatID string, filter store.ChatFilter, locale ...string) (*store.ChatInfo, error) { return nil, nil } -func (m *mockStore) GetHistory(id string, chatID string) ([]map[string]interface{}, error) { +func (m *mockStore) GetChats(id string, filter store.ChatFilter, locale ...string) (*store.ChatGroupResponse, error) { return nil, nil } -func (m *mockStore) GetHistoryWithFilter(id string, chatID string, filter store.ChatFilter) ([]map[string]interface{}, error) { +func (m *mockStore) GetHistory(id string, chatID string, locale ...string) ([]map[string]interface{}, error) { + return nil, nil +} +func (m *mockStore) GetHistoryWithFilter(id string, chatID string, filter store.ChatFilter, locale ...string) ([]map[string]interface{}, error) { return nil, nil } func (m *mockStore) SaveAssistant(assistant map[string]interface{}) (interface{}, error) { diff --git a/neo/context/context.go b/neo/context/context.go index 979c7762..50ac2777 100644 --- a/neo/context/context.go +++ b/neo/context/context.go @@ -154,6 +154,12 @@ func WithClientType(ctx Context, clientType string) Context { return ctx } +// WithLocale set the locale +func WithLocale(ctx Context, locale string) Context { + ctx.Locale = locale + return ctx +} + // WithHistoryVisible set the history visible func WithHistoryVisible(ctx Context, historyVisible bool) Context { ctx.HistoryVisible = historyVisible diff --git a/neo/store/mongo.go b/neo/store/mongo.go index 2202d003..d5a150ad 100644 --- a/neo/store/mongo.go +++ b/neo/store/mongo.go @@ -9,27 +9,27 @@ func NewMongo() Store { } // GetChats retrieves a list of chats -func (m *Mongo) GetChats(sid string, filter ChatFilter) (*ChatGroupResponse, error) { +func (m *Mongo) GetChats(sid string, filter ChatFilter, locale ...string) (*ChatGroupResponse, error) { return &ChatGroupResponse{}, nil } // GetChat retrieves a single chat's information -func (m *Mongo) GetChat(sid string, cid string) (*ChatInfo, error) { +func (m *Mongo) GetChat(sid string, cid string, locale ...string) (*ChatInfo, error) { return &ChatInfo{}, nil } // GetChatWithFilter retrieves a single chat's information with filter options -func (m *Mongo) GetChatWithFilter(sid string, cid string, filter ChatFilter) (*ChatInfo, error) { +func (m *Mongo) GetChatWithFilter(sid string, cid string, filter ChatFilter, locale ...string) (*ChatInfo, error) { return &ChatInfo{}, nil } // GetHistory retrieves chat history -func (m *Mongo) GetHistory(sid string, cid string) ([]map[string]interface{}, error) { +func (m *Mongo) GetHistory(sid string, cid string, locale ...string) ([]map[string]interface{}, error) { return []map[string]interface{}{}, nil } // GetHistoryWithFilter retrieves chat history with filter options -func (m *Mongo) GetHistoryWithFilter(sid string, cid string, filter ChatFilter) ([]map[string]interface{}, error) { +func (m *Mongo) GetHistoryWithFilter(sid string, cid string, filter ChatFilter, locale ...string) ([]map[string]interface{}, error) { return []map[string]interface{}{}, nil } diff --git a/neo/store/redis.go b/neo/store/redis.go index 94f4b3eb..7054a3b3 100644 --- a/neo/store/redis.go +++ b/neo/store/redis.go @@ -9,27 +9,27 @@ func NewRedis() Store { } // GetChats retrieves a list of chats -func (r *Redis) GetChats(sid string, filter ChatFilter) (*ChatGroupResponse, error) { +func (r *Redis) GetChats(sid string, filter ChatFilter, locale ...string) (*ChatGroupResponse, error) { return &ChatGroupResponse{}, nil } // GetChat retrieves a single chat's information -func (r *Redis) GetChat(sid string, cid string) (*ChatInfo, error) { +func (r *Redis) GetChat(sid string, cid string, locale ...string) (*ChatInfo, error) { return &ChatInfo{}, nil } // GetChatWithFilter retrieves a single chat's information with filter options -func (r *Redis) GetChatWithFilter(sid string, cid string, filter ChatFilter) (*ChatInfo, error) { +func (r *Redis) GetChatWithFilter(sid string, cid string, filter ChatFilter, locale ...string) (*ChatInfo, error) { return &ChatInfo{}, nil } // GetHistory retrieves chat history -func (r *Redis) GetHistory(sid string, cid string) ([]map[string]interface{}, error) { +func (r *Redis) GetHistory(sid string, cid string, locale ...string) ([]map[string]interface{}, error) { return []map[string]interface{}{}, nil } // GetHistoryWithFilter retrieves chat history with filter options -func (r *Redis) GetHistoryWithFilter(sid string, cid string, filter ChatFilter) ([]map[string]interface{}, error) { +func (r *Redis) GetHistoryWithFilter(sid string, cid string, filter ChatFilter, locale ...string) ([]map[string]interface{}, error) { return []map[string]interface{}{}, nil } diff --git a/neo/store/types.go b/neo/store/types.go index abfc6477..45538897 100644 --- a/neo/store/types.go +++ b/neo/store/types.go @@ -86,33 +86,33 @@ type Store interface { // sid: Session ID // filter: Filter conditions // Returns: Grouped chat list and potential error - GetChats(sid string, filter ChatFilter) (*ChatGroupResponse, error) + GetChats(sid string, filter ChatFilter, locale ...string) (*ChatGroupResponse, error) // GetChat retrieves a single chat's information // sid: Session ID // cid: Chat ID // Returns: Chat information and potential error - GetChat(sid string, cid string) (*ChatInfo, error) + GetChat(sid string, cid string, locale ...string) (*ChatInfo, error) // GetChatWithFilter retrieves a single chat's information with filter options // sid: Session ID // cid: Chat ID // filter: Filter conditions // Returns: Chat information and potential error - GetChatWithFilter(sid string, cid string, filter ChatFilter) (*ChatInfo, error) + GetChatWithFilter(sid string, cid string, filter ChatFilter, locale ...string) (*ChatInfo, error) // GetHistory retrieves chat history // sid: Session ID // cid: Chat ID // Returns: History record list and potential error - GetHistory(sid string, cid string) ([]map[string]interface{}, error) + GetHistory(sid string, cid string, locale ...string) ([]map[string]interface{}, error) // GetHistoryWithFilter retrieves chat history with filter options // sid: Session ID // cid: Chat ID // filter: Filter conditions // Returns: History record list and potential error - GetHistoryWithFilter(sid string, cid string, filter ChatFilter) ([]map[string]interface{}, error) + GetHistoryWithFilter(sid string, cid string, filter ChatFilter, locale ...string) ([]map[string]interface{}, error) // SaveHistory saves chat history // sid: Session ID diff --git a/neo/store/xun.go b/neo/store/xun.go index c82c19bc..30766e72 100644 --- a/neo/store/xun.go +++ b/neo/store/xun.go @@ -322,18 +322,18 @@ func (conv *Xun) UpdateChatTitle(sid string, cid string, title string) error { } // GetChats get the chat list with grouping by date -func (conv *Xun) GetChats(sid string, filter ChatFilter) (*ChatGroupResponse, error) { +func (conv *Xun) GetChats(sid string, filter ChatFilter, locale ...string) (*ChatGroupResponse, error) { // Default behavior: exclude silent chats if filter.Silent == nil { silentFalse := false filter.Silent = &silentFalse } - return conv.getChatsWithFilter(sid, filter) + return conv.getChatsWithFilter(sid, filter, locale...) } // getChatsWithFilter get the chats with filter options -func (conv *Xun) getChatsWithFilter(sid string, filter ChatFilter) (*ChatGroupResponse, error) { +func (conv *Xun) getChatsWithFilter(sid string, filter ChatFilter, locale ...string) (*ChatGroupResponse, error) { userID, err := conv.getUserID(sid) if err != nil { return nil, err @@ -448,8 +448,13 @@ func (conv *Xun) getChatsWithFilter(sid string, filter ChatFilter) (*ChatGroupRe for _, assistant := range assistants { if id := assistant.Get("assistant_id"); id != nil { + name := assistant.Get("name") + if len(locale) > 0 { + lang := strings.ToLower(locale[0]) + name = i18n.Translate(id.(string), lang, name).(string) + } assistantMap[fmt.Sprintf("%v", id)] = map[string]interface{}{ - "name": assistant.Get("name"), + "name": name, "avatar": assistant.Get("avatar"), } } @@ -472,7 +477,12 @@ func (conv *Xun) getChatsWithFilter(sid string, filter ChatFilter) (*ChatGroupRe // Add assistant details if available if assistantID := row.Get("assistant_id"); assistantID != nil && assistantID != "" { if assistant, ok := assistantMap[fmt.Sprintf("%v", assistantID)]; ok { - chat["assistant_name"] = assistant["name"] + name := assistant["name"] + if len(locale) > 0 { + lang := strings.ToLower(locale[0]) + name = i18n.Translate(assistantID.(string), lang, name).(string) + } + chat["assistant_name"] = name chat["assistant_avatar"] = assistant["avatar"] } } @@ -516,12 +526,17 @@ func (conv *Xun) getChatsWithFilter(sid string, filter ChatFilter) (*ChatGroupRe } } - // Convert to ordered slice + // Convert to ordered slice and apply i18n result := []ChatGroup{} for _, label := range []string{"Today", "Yesterday", "This Week", "Last Week", "Even Earlier"} { if len(groups[label]) > 0 { + translatedLabel := label + if len(locale) > 0 { + lang := strings.ToLower(locale[0]) + translatedLabel = i18n.TranslateGlobal(lang, label).(string) + } result = append(result, ChatGroup{ - Label: label, + Label: translatedLabel, Chats: groups[label], }) } @@ -537,7 +552,7 @@ func (conv *Xun) getChatsWithFilter(sid string, filter ChatFilter) (*ChatGroupRe } // GetHistory get the history -func (conv *Xun) GetHistory(sid string, cid string) ([]map[string]interface{}, error) { +func (conv *Xun) GetHistory(sid string, cid string, locale ...string) ([]map[string]interface{}, error) { userID, err := conv.getUserID(sid) if err != nil { return nil, err @@ -568,13 +583,20 @@ func (conv *Xun) GetHistory(sid string, cid string) ([]map[string]interface{}, e res := []map[string]interface{}{} for _, row := range rows { + assistantName := row.Get("assistant_name") + assistantID := row.Get("assistant_id") + if len(locale) > 0 && assistantID != nil { + lang := strings.ToLower(locale[0]) + assistantName = i18n.Translate(assistantID.(string), lang, assistantName).(string) + } + message := map[string]interface{}{ "role": row.Get("role"), "name": row.Get("name"), "content": row.Get("content"), "context": row.Get("context"), "assistant_id": row.Get("assistant_id"), - "assistant_name": row.Get("assistant_name"), + "assistant_name": assistantName, "assistant_avatar": row.Get("assistant_avatar"), "mentions": row.Get("mentions"), "uid": row.Get("uid"), @@ -770,7 +792,7 @@ func (conv *Xun) SaveHistory(sid string, messages []map[string]interface{}, cid } // GetChat get the chat info and its history -func (conv *Xun) GetChat(sid string, cid string) (*ChatInfo, error) { +func (conv *Xun) GetChat(sid string, cid string, locale ...string) (*ChatInfo, error) { userID, err := conv.getUserID(sid) if err != nil { return nil, err @@ -809,14 +831,20 @@ func (conv *Xun) GetChat(sid string, cid string) (*ChatInfo, error) { return nil, err } + name := assistant.Get("name") + if len(locale) > 0 { + lang := strings.ToLower(locale[0]) + name = i18n.Translate(assistantID.(string), lang, name).(string) + } + if assistant != nil { - chat["assistant_name"] = assistant.Get("name") + chat["assistant_name"] = name chat["assistant_avatar"] = assistant.Get("avatar") } } // Get chat history with default filter (silent=false) - history, err := conv.GetHistory(sid, cid) + history, err := conv.GetHistory(sid, cid, locale...) if err != nil { return nil, err } @@ -828,7 +856,7 @@ func (conv *Xun) GetChat(sid string, cid string) (*ChatInfo, error) { } // GetChatWithFilter get the chat info and its history with filter options -func (conv *Xun) GetChatWithFilter(sid string, cid string, filter ChatFilter) (*ChatInfo, error) { +func (conv *Xun) GetChatWithFilter(sid string, cid string, filter ChatFilter, locale ...string) (*ChatInfo, error) { userID, err := conv.getUserID(sid) if err != nil { return nil, err @@ -874,7 +902,7 @@ func (conv *Xun) GetChatWithFilter(sid string, cid string, filter ChatFilter) (* } // Get chat history with filter - history, err := conv.GetHistoryWithFilter(sid, cid, filter) + history, err := conv.GetHistoryWithFilter(sid, cid, filter, locale...) if err != nil { return nil, err } @@ -1332,7 +1360,7 @@ func (conv *Xun) GetAssistantTags(locale ...string) ([]Tag, error) { } // GetHistoryWithFilter get the history with filter options -func (conv *Xun) GetHistoryWithFilter(sid string, cid string, filter ChatFilter) ([]map[string]interface{}, error) { +func (conv *Xun) GetHistoryWithFilter(sid string, cid string, filter ChatFilter, locale ...string) ([]map[string]interface{}, error) { userID, err := conv.getUserID(sid) if err != nil { return nil, err