Enhance localization support in chat and assistant functionalities

- Added locale parameter to GetChats, GetChat, and GetAssistants methods across various store implementations for improved localization.
- Updated handleChatList, handleChatLatest, and handleChatDetail functions to utilize the new locale handling for better user experience.
- Refactored assistant methods to support localized names and descriptions based on user input.
- Introduced WithLocale function in context to manage locale settings effectively.
This commit is contained in:
Max 2025-05-27 11:49:19 +08:00
parent 4ab7a1056e
commit 1058598be3
8 changed files with 113 additions and 51 deletions

View file

@ -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()

View file

@ -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,
},
}

View file

@ -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) {

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -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

View file

@ -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