fix: 修复Python模块导入错误并优化Chat功能
- 修复 core/agents/api 模块导入问题 - 优化 ChatInput 组件交互体验 - 增强 agent_handler 和 agent_service 功能 - 调整 Chat 页面样式和布局 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,15 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"x-agents/server/internal/model"
|
||||
"x-agents/server/internal/repository"
|
||||
"x-agents/server/internal/service"
|
||||
"x-agents/server/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -12,22 +17,25 @@ import (
|
||||
// AgentHandler Agent 处理器
|
||||
type AgentHandler struct {
|
||||
agentService *service.AgentService
|
||||
agentRepo *repository.AgentRepository
|
||||
}
|
||||
|
||||
// NewAgentHandler 创建 Agent 处理器
|
||||
func NewAgentHandler(agentService *service.AgentService) *AgentHandler {
|
||||
func NewAgentHandler(agentService *service.AgentService, agentRepo *repository.AgentRepository) *AgentHandler {
|
||||
return &AgentHandler{
|
||||
agentService: agentService,
|
||||
agentRepo: agentRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// ChatRequest 对话请求
|
||||
type ChatRequest struct {
|
||||
AgentID string `json:"agent_id" binding:"required"` // 字符串类型
|
||||
Message string `json:"message" binding:"required"`
|
||||
SessionID string `json:"session_id"`
|
||||
ModelID string `json:"model_id"`
|
||||
UseXBot bool `json:"use_xbot"`
|
||||
AgentID string `json:"agent_id"` // 字符串类型,支持 UUID,可为空(当使用 mentioned_agent_ids 时)
|
||||
Message string `json:"message" binding:"required"`
|
||||
SessionID string `json:"session_id"`
|
||||
ModelID string `json:"model_id"`
|
||||
UseXBot bool `json:"use_xbot"`
|
||||
MentionedAgentIDs []string `json:"mentioned_agent_ids"` // @ 提及的智能体 ID 列表
|
||||
}
|
||||
|
||||
// ChatResponse 对话响应
|
||||
@@ -131,6 +139,29 @@ func (h *AgentHandler) ChatStream(c *gin.Context) {
|
||||
// 直接使用字符串类型的 agent_id,支持 UUID
|
||||
agentID := req.AgentID
|
||||
|
||||
// 优先使用前端传递的 mentioned_agent_ids
|
||||
if len(req.MentionedAgentIDs) > 0 {
|
||||
// 如果有多个 @ 提及,使用第一个
|
||||
mentionedAgentID := req.MentionedAgentIDs[0]
|
||||
log.Printf("[ChatStream] Using mentioned_agent_ids: %v", req.MentionedAgentIDs)
|
||||
agentID = mentionedAgentID
|
||||
// 清理消息,移除 @ 提及
|
||||
mentionParser := utils.NewMentionParser()
|
||||
req.Message = mentionParser.RemoveMentions(req.Message)
|
||||
} else if agentID == "" {
|
||||
// 兼容:解析消息中的 @ 提及(备用方案)
|
||||
mentionParser := utils.NewMentionParser()
|
||||
mentions := mentionParser.ParseMentions(req.Message)
|
||||
if len(mentions) > 0 {
|
||||
mentionedAgent := h.findAgentByName(mentions[0])
|
||||
if mentionedAgent != nil {
|
||||
log.Printf("[ChatStream] Detected @mention: %s, routing to agent: %s", mentions[0], mentionedAgent.ID)
|
||||
agentID = mentionedAgent.ID
|
||||
}
|
||||
req.Message = mentionParser.RemoveMentions(req.Message)
|
||||
}
|
||||
}
|
||||
|
||||
// 构建 SSE 流
|
||||
c.Header("Content-Type", "text/event-stream")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
@@ -144,6 +175,37 @@ func (h *AgentHandler) ChatStream(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// findAgentByName 根据用户名查找智能体
|
||||
func (h *AgentHandler) findAgentByName(name string) *model.Agent {
|
||||
log.Printf("[findAgentByName] Searching for agent: %s, agentRepo: %v", name, h.agentRepo)
|
||||
|
||||
if h.agentRepo == nil {
|
||||
log.Printf("[findAgentByName] ERROR: agentRepo is nil!")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 先尝试精确匹配
|
||||
agents, err := h.agentRepo.FindAll()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, agent := range agents {
|
||||
if agent.Name == name {
|
||||
return &agent
|
||||
}
|
||||
}
|
||||
|
||||
// 再尝试模糊匹配(忽略大小写)
|
||||
for _, agent := range agents {
|
||||
if strings.Contains(strings.ToLower(agent.Name), strings.ToLower(name)) {
|
||||
return &agent
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TeamChatRequest 多智能体群聊请求
|
||||
type TeamChatRequest struct {
|
||||
SupervisorAgentID int `json:"supervisor_agent_id" binding:"required"`
|
||||
@@ -236,6 +298,30 @@ func (h *AgentHandler) CreateAgent(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// InitTeamMembersResponse 初始化团队成员响应
|
||||
type InitTeamMembersResponse struct {
|
||||
Message string `json:"message"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
// InitTeamMembers 初始化团队成员智能体
|
||||
// @Summary 初始化团队成员智能体
|
||||
// @Tags 智能体管理
|
||||
// @Produce json
|
||||
// @Success 200 {object} InitTeamMembersResponse
|
||||
// @Router /api/agent/init-team [post]
|
||||
func (h *AgentHandler) InitTeamMembers(c *gin.Context) {
|
||||
if err := h.agentService.InitTeamMembers(); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, InitTeamMembersResponse{
|
||||
Message: "Team members initialized successfully",
|
||||
Count: 1, // 小荣
|
||||
})
|
||||
}
|
||||
|
||||
// ListAgents 获取智能体列表
|
||||
// @Summary 获取智能体列表
|
||||
// @Tags 智能体管理
|
||||
|
||||
@@ -117,7 +117,7 @@ func (s *AgentService) Chat(req AgentChatRequest) (*AgentChatResponse, error) {
|
||||
log.Printf("[AgentService] Sending to Python: model_id=%s, api_key=%s, base_url=%s, provider=%s, model=%s",
|
||||
req.ModelID, apiKeyPreview, req.BaseURL, req.ModelProvider, req.ModelName)
|
||||
|
||||
url := fmt.Sprintf("%s/api/v1/agent/chat", s.pythonURL)
|
||||
url := fmt.Sprintf("%s/agent/chat", s.pythonURL)
|
||||
|
||||
jsonData, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
@@ -155,7 +155,7 @@ func (s *AgentService) Chat(req AgentChatRequest) (*AgentChatResponse, error) {
|
||||
|
||||
// TeamChat 多智能体群聊
|
||||
func (s *AgentService) TeamChat(req TeamChatRequest) (*TeamChatResponse, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/agent/team/chat", s.pythonURL)
|
||||
url := fmt.Sprintf("%s/agent/team/chat", s.pythonURL)
|
||||
|
||||
// 设置默认策略
|
||||
if req.Strategy == "" {
|
||||
@@ -233,7 +233,7 @@ func (s *AgentService) ChatStream(c interface{}, agentID string, message, sessio
|
||||
log.Printf("[ChatStream] modelID is empty or modelRepo is nil: modelID=%s, modelRepo=%v", modelID, s.modelRepo != nil)
|
||||
}
|
||||
|
||||
streamURL := fmt.Sprintf("%s/api/v1/agent/chat/stream", s.pythonURL)
|
||||
streamURL := fmt.Sprintf("%s/agent/chat/stream", s.pythonURL)
|
||||
|
||||
jsonData, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
@@ -365,6 +365,89 @@ func (s *AgentService) CreateAgent(req CreateAgentRequest, userID int) (*CreateA
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TeamMemberInitRequest 团队成员初始化请求
|
||||
type TeamMemberInitRequest struct {
|
||||
Name string
|
||||
Description string
|
||||
Avatar string
|
||||
Skills []string
|
||||
RoleDescription string
|
||||
}
|
||||
|
||||
// InitTeamMembers 初始化团队成员智能体
|
||||
func (s *AgentService) InitTeamMembers() error {
|
||||
if s.agentRepo == nil {
|
||||
log.Printf("[AgentService] InitTeamMembers: agentRepo is nil!")
|
||||
return fmt.Errorf("agent repository not initialized")
|
||||
}
|
||||
|
||||
// 骚人开发组团队成员配置
|
||||
teamMembers := []TeamMemberInitRequest{
|
||||
{
|
||||
Name: "小荣",
|
||||
Description: "前端开发工程师 - 骚人开发组成员",
|
||||
Avatar: "👨💻",
|
||||
Skills: []string{"Vue 3", "TypeScript", "Element Plus", "Tailwind CSS"},
|
||||
RoleDescription: `你叫小荣,是骚人开发组的前端开发工程师。你细心认真,善于沟通。
|
||||
|
||||
技能专长:
|
||||
- Vue 3 框架开发
|
||||
- TypeScript 类型系统
|
||||
- Element Plus 组件库
|
||||
- Tailwind CSS 样式框架
|
||||
|
||||
性格特点:
|
||||
- 细心认真,注重代码质量
|
||||
- 善于与团队成员沟通协作
|
||||
- 积极解决前端技术难题`,
|
||||
},
|
||||
}
|
||||
|
||||
// 检查是否已存在同名智能体
|
||||
for _, member := range teamMembers {
|
||||
existingAgents, err := s.agentRepo.FindAll()
|
||||
if err != nil {
|
||||
log.Printf("[AgentService] InitTeamMembers: failed to list agents: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
exists := false
|
||||
for _, a := range existingAgents {
|
||||
if a.Name == member.Name {
|
||||
exists = true
|
||||
log.Printf("[AgentService] InitTeamMembers: agent %s already exists, skipping", member.Name)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !exists {
|
||||
// 创建智能体
|
||||
agent := &model.Agent{
|
||||
ID: uuid.New().String(),
|
||||
Name: member.Name,
|
||||
Description: member.Description,
|
||||
OwnerID: "1", // 系统管理员
|
||||
Avatar: member.Avatar,
|
||||
Skills: member.Skills,
|
||||
RoleDescription: member.RoleDescription,
|
||||
ModelProvider: "anthropic",
|
||||
ModelName: "claude-sonnet-4-20250514",
|
||||
IsActive: true,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
|
||||
if err := s.agentRepo.Create(agent); err != nil {
|
||||
log.Printf("[AgentService] InitTeamMembers: failed to create agent %s: %v", member.Name, err)
|
||||
continue
|
||||
}
|
||||
log.Printf("[AgentService] InitTeamMembers: created agent %s (ID: %s)", member.Name, agent.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListAgentsResponse 获取智能体列表响应
|
||||
type ListAgentsResponse struct {
|
||||
Agents []interface{} `json:"agents"`
|
||||
|
||||
Reference in New Issue
Block a user