Some checks failed
CI / test (push) Failing after 3s
CI / frontend (push) Failing after 3s
CI / golangci-lint (push) Failing after 3s
Security Scan / backend-security (push) Failing after 3s
Security Scan / frontend-security (push) Failing after 5s
CI / windsurf-platform (macos-latest) (push) Has been cancelled
CI / windsurf-platform (windows-latest) (push) Has been cancelled
193 lines
5.2 KiB
Go
193 lines
5.2 KiB
Go
package routes
|
||
|
||
import (
|
||
"encoding/json"
|
||
"log/slog"
|
||
"net/http"
|
||
|
||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// RegisterAntigravityHTTPRoutes 注册 Antigravity HTTP API 路由
|
||
func RegisterAntigravityHTTPRoutes(v1 *gin.RouterGroup, langServerService *service.LanguageServerService) {
|
||
logger := slog.Default()
|
||
|
||
// 创建处理器
|
||
cascadeGroup := v1.Group("/cascade")
|
||
{
|
||
// 启动 Cascade 会话
|
||
cascadeGroup.POST("/start", func(c *gin.Context) {
|
||
handleStartCascade(c, langServerService, logger)
|
||
})
|
||
|
||
// 发送消息到 Cascade(流式响应)
|
||
cascadeGroup.POST("/message", func(c *gin.Context) {
|
||
handleSendMessage(c, langServerService, logger)
|
||
})
|
||
|
||
// 取消 Cascade 会话
|
||
cascadeGroup.POST("/cancel", func(c *gin.Context) {
|
||
handleCancelCascade(c, langServerService, logger)
|
||
})
|
||
}
|
||
|
||
// 模型列表
|
||
v1.GET("/models", func(c *gin.Context) {
|
||
handleGetModels(c, langServerService, logger)
|
||
})
|
||
|
||
// 健康检查
|
||
v1.GET("/health", func(c *gin.Context) {
|
||
handleHealth(c, logger)
|
||
})
|
||
}
|
||
|
||
// handleStartCascade 处理启动 Cascade 请求
|
||
func handleStartCascade(c *gin.Context, svc *service.LanguageServerService, logger *slog.Logger) {
|
||
type StartCascadeRequest struct {
|
||
Model string `json:"model" binding:"required"`
|
||
SystemPrompt string `json:"system_prompt"`
|
||
Metadata map[string]string `json:"metadata"`
|
||
}
|
||
|
||
var req StartCascadeRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
logger.Error("invalid start cascade request", "error", err)
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||
return
|
||
}
|
||
|
||
// 获取 OAuth token
|
||
token := c.GetHeader("Authorization")
|
||
if token == "" {
|
||
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing authorization header"})
|
||
return
|
||
}
|
||
|
||
// 调用服务
|
||
cascadeID, err := svc.StartCascade(
|
||
c.Request.Context(),
|
||
req.Model,
|
||
req.SystemPrompt,
|
||
req.Metadata,
|
||
token,
|
||
)
|
||
if err != nil {
|
||
logger.Error("start cascade failed", "error", err)
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{"cascade_id": cascadeID})
|
||
}
|
||
|
||
// handleSendMessage 处理发送消息请求(流式)
|
||
func handleSendMessage(c *gin.Context, svc *service.LanguageServerService, logger *slog.Logger) {
|
||
type SendMessageRequest struct {
|
||
CascadeID string `json:"cascade_id" binding:"required"`
|
||
Message string `json:"message" binding:"required"`
|
||
}
|
||
|
||
var req SendMessageRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
logger.Error("invalid send message request", "error", err)
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||
return
|
||
}
|
||
|
||
// 获取 OAuth token
|
||
token := c.GetHeader("Authorization")
|
||
if token == "" {
|
||
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing authorization header"})
|
||
return
|
||
}
|
||
|
||
// 调用服务并获取流式更新通道
|
||
updateChan, err := svc.SendUserMessage(c.Request.Context(), req.CascadeID, req.Message, token)
|
||
if err != nil {
|
||
logger.Error("send message failed", "error", err)
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
// 设置 SSE 响应头
|
||
c.Header("Content-Type", "text/event-stream")
|
||
c.Header("Cache-Control", "no-cache")
|
||
c.Header("Connection", "keep-alive")
|
||
c.Header("X-Accel-Buffering", "no")
|
||
c.Status(http.StatusOK)
|
||
|
||
// 流式发送更新到客户端
|
||
flusher, ok := c.Writer.(http.Flusher)
|
||
if !ok {
|
||
logger.Error("response writer does not support flushing")
|
||
return
|
||
}
|
||
|
||
for event := range updateChan {
|
||
if event == nil {
|
||
break
|
||
}
|
||
|
||
// 将事件序列化为 JSON
|
||
eventJSON, err := marshalJSON(event)
|
||
if err != nil {
|
||
logger.Error("failed to marshal event", "error", err)
|
||
continue
|
||
}
|
||
|
||
// 发送 SSE 格式的数据
|
||
_, _ = c.Writer.WriteString("data: " + string(eventJSON) + "\n\n")
|
||
flusher.Flush()
|
||
}
|
||
}
|
||
|
||
// handleCancelCascade 处理取消 Cascade 请求
|
||
func handleCancelCascade(c *gin.Context, svc *service.LanguageServerService, logger *slog.Logger) {
|
||
type CancelRequest struct {
|
||
CascadeID string `json:"cascade_id" binding:"required"`
|
||
}
|
||
|
||
var req CancelRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
logger.Error("invalid cancel request", "error", err)
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||
return
|
||
}
|
||
|
||
err := svc.CancelCascade(c.Request.Context(), req.CascadeID)
|
||
if err != nil {
|
||
logger.Error("cancel cascade failed", "error", err)
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{"message": "cascade cancelled"})
|
||
}
|
||
|
||
// handleGetModels 处理获取模型列表请求
|
||
func handleGetModels(c *gin.Context, svc *service.LanguageServerService, logger *slog.Logger) {
|
||
models, err := svc.GetAvailableModels(c.Request.Context())
|
||
if err != nil {
|
||
logger.Error("get models failed", "error", err)
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"models": models,
|
||
"default_model": "claude-opus-4-6",
|
||
})
|
||
}
|
||
|
||
// handleHealth 处理健康检查请求
|
||
func handleHealth(c *gin.Context, logger *slog.Logger) {
|
||
c.JSON(http.StatusOK, gin.H{"status": "healthy"})
|
||
}
|
||
|
||
// marshalJSON 辅助函数用于序列化事件
|
||
func marshalJSON(v interface{}) ([]byte, error) {
|
||
return json.Marshal(v)
|
||
}
|