Files
team-api/relay/handler/claude_handler.go
T
fa053529af 图片请求统一异步处理 (#11)
* fix:未导入unicode包

* feat:图片异步转换

* feat:添加R2支持

* feat:新增文件管理

* fix:修复错误信息双写导致响应异常

* chore:渠道列表中添加快捷启用停止按钮

* fix:修复模型异常终端导致报错的问题

* improve:优化无可用渠道的日志打印,减少日志污染

* fix:在线体验出错缺少提示信息

* fix:修复日志库问题,只有请求日志保存到独立的库中

* feat:新增阿里图片模型说明文档

* fix:阿里千问图片生成

* fix:修复图片异步控制无效问题

* improve:优化文件展示,支持缩略图查看

* feat:实时监控中添加图片异步转换池状态信息

* improve:优化在线体验页面布局

* fix:修复异步任务状态显示异常问题

* feat:图片异步任务停止时等待任务完成后再退出程序

* chore:调整存储路径

---------

Co-authored-by: qian <wuchengqian5@163.com>
Co-authored-by: chengqian <wuchengqian@kkidc.com>
2026-07-18 00:26:13 +08:00

76 lines
2.5 KiB
Go

package handler
import (
"context"
"encoding/json"
"errors"
"net/http"
"github.com/gogf/gf/v2/frame/g"
"github.com/qianfree/team-api/relay/common"
"github.com/qianfree/team-api/relay/constant"
)
// HandleClaudeMessages 处理 /v1/messages 请求(Claude 原生格式)
func HandleClaudeMessages(ctx context.Context, body []byte, path string, headers http.Header, rc *RelayContext, provider common.DataProvider, billing common.BillingProvider) (*common.Usage, *BillingResult, error) {
return RelayHandler(ctx, body, path, headers, rc, provider, billing)
}
// WriteClaudeRelayError 写入 Claude 格式的错误响应
func WriteClaudeRelayError(w http.ResponseWriter, err error) {
// 流式中断(客户端已断开):降级为 INFO,跳过写响应(客户端已不在)
if errors.Is(err, common.ErrStreamInterrupted) {
g.Log().Infof(context.Background(), "[ClaudeRelayError] Client disconnected during stream")
return
}
// adaptor 已直接写入响应体(如 Gemini 原生格式透传),跳过二次写入
var prewritten *constant.RelayError
if errors.As(err, &prewritten) && prewritten.ResponseWritten {
return
}
var relayErr *constant.RelayError
var rateLimitErr *RelayErrorWithRateLimit
statusCode := http.StatusInternalServerError
errMsg := err.Error()
errType := "api_error"
if errors.As(err, &rateLimitErr) {
statusCode = rateLimitErr.StatusCode
errMsg = rateLimitErr.Message
errType = "rate_limit_error"
} else if errors.As(err, &relayErr) {
statusCode = relayErr.StatusCode
errMsg = relayErr.Message
if relayErr.Cause != nil {
errMsg = relayErr.Message + ": " + relayErr.Cause.Error()
}
errType = relayErr.Type
}
if statusCode < 100 || statusCode > 599 {
statusCode = http.StatusInternalServerError
}
// 无可用渠道是正常业务条件,已在 handleChannelUnavailable 中以 Warning 记录,此处跳过避免重复日志;
// 其余 5xx 为真实错误,保留 ERROR 但禁用堆栈打印(此处调用栈固定,无调试价值)
if statusCode >= 500 && !errors.Is(err, common.ErrChannelUnavailable) {
g.Log().Stack(false).Errorf(context.Background(), "[ClaudeRelayError] statusCode=%d type=%s message=%s originalError=%v",
statusCode, errType, errMsg, err)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
errBody, _ := json.Marshal(map[string]any{
"type": "error",
"error": map[string]any{
"type": errType,
"message": errMsg,
},
})
_, _ = w.Write(errBody)
}