mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-06-30 16:01:58 +08:00
Go: add get chat (#14025)
### What problem does this PR solve? As title ### Type of change - [x] New Feature (non-breaking change which adds functionality) --------- Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
@@ -229,3 +229,12 @@ func (dao *ChatDAO) GetAllDialogIDsByTenantID(tenantID string) ([]string, error)
|
||||
Pluck("id", &dialogIDs).Error
|
||||
return dialogIDs, err
|
||||
}
|
||||
|
||||
// QueryByTenantIDAndID checks if a chat exists with given tenant_id and id
|
||||
// Reference: Python DialogService.query(tenant_id=tenant.tenant_id, id=chat_id, status=StatusEnum.VALID.value)
|
||||
// Used for permission verification in get_chat API
|
||||
func (dao *ChatDAO) QueryByTenantIDAndID(tenantID string, chatID string, status string) ([]*entity.Chat, error) {
|
||||
var chats []*entity.Chat
|
||||
err := DB.Where("tenant_id = ? AND id = ? AND status = ?", tenantID, chatID, status).Find(&chats).Error
|
||||
return chats, err
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func NewChatHandler(chatService *service.ChatService, userService *service.UserS
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} service.ListChatsResponse
|
||||
// @Router /v1/dialog/list [get]
|
||||
// @Router /api/v1/chats [get]
|
||||
func (h *ChatHandler) ListChats(c *gin.Context) {
|
||||
user, errorCode, errorMessage := GetUser(c)
|
||||
if errorCode != common.CodeSuccess {
|
||||
@@ -257,3 +257,96 @@ func (h *ChatHandler) RemoveChats(c *gin.Context) {
|
||||
"message": "success",
|
||||
})
|
||||
}
|
||||
|
||||
// GetChat get chat detail
|
||||
// @Summary Get Chat Detail
|
||||
// @Description Get detail of a chat by ID
|
||||
// @Tags chat
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param chat_id path string true "chat ID"
|
||||
// @Success 200 {object} service.GetChatResponse
|
||||
// @Router /api/v1/chats/{chat_id} [get]
|
||||
// Reference: api/apps/restful_apis/chat_api.py::get_chat
|
||||
// Python implementation details:
|
||||
// - Route: @manager.route("/chats/<chat_id>", methods=["GET"])
|
||||
func (h *ChatHandler) GetChat(c *gin.Context) {
|
||||
// Get current user from context (same as Python current_user)
|
||||
user, errorCode, errorMessage := GetUser(c)
|
||||
if errorCode != common.CodeSuccess {
|
||||
jsonError(c, errorCode, errorMessage)
|
||||
return
|
||||
}
|
||||
userID := user.ID
|
||||
|
||||
// Get chat_id from path parameter (same as Python <chat_id>)
|
||||
chatID := c.Param("chat_id")
|
||||
if chatID == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": common.CodeBadRequest,
|
||||
"data": nil,
|
||||
"message": "chat_id is required",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get chat detail with permission check
|
||||
chat, err := h.chatService.GetChat(userID, chatID)
|
||||
if err != nil {
|
||||
errMsg := err.Error()
|
||||
// Check if it's an authorization error
|
||||
if errMsg == "no authorization" {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": common.CodeAuthenticationError,
|
||||
"data": false,
|
||||
"message": "No authorization.",
|
||||
})
|
||||
return
|
||||
}
|
||||
// Not found error
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": common.CodeDataError,
|
||||
"data": nil,
|
||||
"message": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Build response (same as Python _build_chat_response)
|
||||
// The service already returns GetChatResponse with DatasetIDs and KBNames
|
||||
result := map[string]interface{}{
|
||||
"id": chat.ID,
|
||||
"tenant_id": chat.TenantID,
|
||||
"name": chat.Name,
|
||||
"description": chat.Description,
|
||||
"icon": chat.Icon,
|
||||
"language": chat.Language,
|
||||
"llm_id": chat.LLMID,
|
||||
"llm_setting": chat.LLMSetting,
|
||||
"prompt_type": chat.PromptType,
|
||||
"prompt_config": chat.PromptConfig,
|
||||
"meta_data_filter": chat.MetaDataFilter,
|
||||
"similarity_threshold": chat.SimilarityThreshold,
|
||||
"vector_similarity_weight": chat.VectorSimilarityWeight,
|
||||
"top_n": chat.TopN,
|
||||
"top_k": chat.TopK,
|
||||
"do_refer": chat.DoRefer,
|
||||
"rerank_id": chat.RerankID,
|
||||
"dataset_ids": chat.DatasetIDs,
|
||||
"kb_names": chat.KBNames,
|
||||
"status": chat.Status,
|
||||
"create_time": chat.CreateTime,
|
||||
"create_date": chat.CreateDate,
|
||||
"update_time": chat.UpdateTime,
|
||||
"update_date": chat.UpdateDate,
|
||||
"tenant_llm_id": chat.TenantLLMID,
|
||||
"tenant_rerank_id": chat.TenantRerankID,
|
||||
}
|
||||
|
||||
// Return success response
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": common.CodeSuccess,
|
||||
"data": result,
|
||||
"message": "success",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -187,10 +187,11 @@ func (r *Router) Setup(engine *gin.Engine) {
|
||||
// message.GET("/:memory_id/:message_id/content", r.memoryHandler.GetMessageContent)
|
||||
// }
|
||||
|
||||
chats := v1.Group("/chats")
|
||||
{
|
||||
chats.GET("", r.chatHandler.ListChats)
|
||||
}
|
||||
chats := v1.Group("/chats")
|
||||
{
|
||||
chats.GET("", r.chatHandler.ListChats)
|
||||
chats.GET("/:chat_id", r.chatHandler.GetChat)
|
||||
}
|
||||
|
||||
searches := v1.Group("/searches")
|
||||
{
|
||||
|
||||
@@ -621,3 +621,64 @@ func strPtr(s string) *string {
|
||||
func (s *ChatService) countRunes(str string) int {
|
||||
return utf8.RuneCountInString(str)
|
||||
}
|
||||
|
||||
// GetChatResponse get chat response with kb_names
|
||||
// Reference: Python _build_chat_response
|
||||
type GetChatResponse struct {
|
||||
*entity.Chat
|
||||
DatasetIDs []string `json:"dataset_ids"`
|
||||
KBNames []string `json:"kb_names"`
|
||||
}
|
||||
|
||||
// GetChat gets chat detail by ID with permission check
|
||||
func (s *ChatService) GetChat(userID string, chatID string) (*GetChatResponse, error) {
|
||||
// Step 1: Get user tenants (same as Python UserTenantService.query(user_id=current_user.id))
|
||||
tenants, err := s.userTenantDAO.GetByUserID(userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get user tenants: %w", err)
|
||||
}
|
||||
|
||||
// Step 2: Check if user has permission to access this chat
|
||||
// Python: for tenant in tenants: if DialogService.query(tenant_id=tenant.tenant_id, id=chat_id, status=StatusEnum.VALID.value): break
|
||||
hasPermission := false
|
||||
for _, tenant := range tenants {
|
||||
chats, err := s.chatDAO.QueryByTenantIDAndID(tenant.TenantID, chatID, "1")
|
||||
if err != nil {
|
||||
continue // Try next tenant
|
||||
}
|
||||
if len(chats) > 0 {
|
||||
hasPermission = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasPermission {
|
||||
return nil, fmt.Errorf("no authorization")
|
||||
}
|
||||
|
||||
// Step 3: Get chat detail (same as Python DialogService.get_by_id(chat_id))
|
||||
chat, err := s.chatDAO.GetByID(chatID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("chat not found")
|
||||
}
|
||||
|
||||
// Step 4: Build response with kb_names (same as Python _build_chat_response)
|
||||
// Resolve kb_ids to kb_names
|
||||
kbNames := s.getKBNames(chat.KBIDs)
|
||||
|
||||
// Build dataset_ids from kb_ids (same as Python _resolve_kb_names returns ids)
|
||||
var datasetIDs []string
|
||||
for _, kbID := range chat.KBIDs {
|
||||
datasetID, ok := kbID.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
datasetIDs = append(datasetIDs, datasetID)
|
||||
}
|
||||
|
||||
return &GetChatResponse{
|
||||
Chat: chat,
|
||||
DatasetIDs: datasetIDs,
|
||||
KBNames: kbNames,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user