Files
X-Agents/server/internal/service/chat_service.go

185 lines
4.5 KiB
Go
Raw Normal View History

package service
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
"x-agents/server/internal/model"
"x-agents/server/internal/repository"
"github.com/google/uuid"
)
type ChatService struct {
pythonURL string
agentRepo *repository.AgentRepository
modelRepo *repository.ModelRepository
}
func NewChatService(pythonURL string, agentRepo *repository.AgentRepository, modelRepo *repository.ModelRepository) *ChatService {
return &ChatService{
pythonURL: pythonURL,
agentRepo: agentRepo,
modelRepo: modelRepo,
}
}
type ChatRequest struct {
AgentID string `json:"agent_id"`
Message string `json:"message"`
SessionID string `json:"session_id"`
ModelID string `json:"model_id"`
Context map[string]interface{} `json:"context"`
}
// ModelConfig 模型配置,用于传递给 Python 服务
type ModelConfig struct {
Provider string `json:"provider"`
Model string `json:"model"`
APIKey string `json:"api_key"`
BaseURL string `json:"base_url"`
APIEndpoint string `json:"api_endpoint"`
}
type ChatResponse struct {
Reply string `json:"reply"`
SessionID string `json:"session_id"`
ToolsUsed []string `json:"tools_used"`
Metadata map[string]interface{} `json:"metadata"`
}
// Chat 处理聊天请求
func (s *ChatService) Chat(ctx context.Context, userID string, req model.AgentRequest) (*model.AgentResponse, error) {
// 1. 检查 Agent 是否存在
agent, err := s.agentRepo.FindByID(req.AgentID)
if err != nil {
return nil, fmt.Errorf("agent not found: %w", err)
}
// 2. 检查用户权限
if !agent.IsActive {
return nil, fmt.Errorf("agent is not active")
}
// 3. 生成会话ID
sessionID := req.SessionID
if sessionID == "" {
sessionID = uuid.New().String()
}
// 4. 如果提供了 ModelID获取模型配置
var modelConfig *ModelConfig
if req.ModelID != "" {
modelInfo, err := s.modelRepo.FindByID(req.ModelID)
if err != nil {
return nil, fmt.Errorf("model not found: %w", err)
}
modelConfig = &ModelConfig{
Provider: modelInfo.Provider,
Model: modelInfo.Model,
APIKey: modelInfo.APIKey,
BaseURL: modelInfo.BaseURL,
APIEndpoint: modelInfo.APIEndpoint,
}
}
// 5. 调用 Python 服务
pythonReq := ChatRequest{
AgentID: req.AgentID,
Message: req.Message,
SessionID: sessionID,
ModelID: req.ModelID,
Context: req.Context,
}
// 将模型配置放入 Context 中传递给 Python 服务
if modelConfig != nil {
pythonReq.Context = make(map[string]interface{})
for k, v := range req.Context {
pythonReq.Context[k] = v
}
pythonReq.Context["model_config"] = modelConfig
}
pythonResp, err := s.callPythonChat(ctx, pythonReq)
if err != nil {
return nil, fmt.Errorf("failed to call python service: %w", err)
}
return &model.AgentResponse{
Reply: pythonResp.Reply,
SessionID: pythonResp.SessionID,
ToolsUsed: pythonResp.ToolsUsed,
Metadata: pythonResp.Metadata,
}, nil
}
func (s *ChatService) callPythonChat(ctx context.Context, req ChatRequest) (*ChatResponse, error) {
jsonData, err := json.Marshal(req)
if err != nil {
return nil, err
}
httpReq, err := http.NewRequestWithContext(
ctx,
"POST",
s.pythonURL+"/agent/chat",
bytes.NewBuffer(jsonData),
)
if err != nil {
return nil, err
}
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{
Timeout: 120 * time.Second, // Agent 可能需要较长时间
}
resp, err := client.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("python service returned status: %d", resp.StatusCode)
}
var chatResp ChatResponse
if err := json.NewDecoder(resp.Body).Decode(&chatResp); err != nil {
return nil, err
}
return &chatResp, nil
}
// ListAgents 获取用户可用的 Agent 列表
func (s *ChatService) ListAgents(userID string) ([]model.Agent, error) {
return s.agentRepo.FindByOwnerID(userID)
}
// CreateAgent 创建新的 Agent
func (s *ChatService) CreateAgent(userID string, name, description string) (*model.Agent, error) {
agent := &model.Agent{
ID: uuid.New().String(),
Name: name,
Description: description,
OwnerID: userID,
SecurityLevel: model.SecurityLevelSafe,
IsActive: true,
Timeout: 60,
MemoryLimit: 134217728, // 128MB
}
if err := s.agentRepo.Create(agent); err != nil {
return nil, err
}
return agent, nil
}