refactor(ai): 重构AI接口算力点扣费逻辑并添加失败返还机制

- 移除预检查算力点步骤,改为请求前预扣算力点
- 添加请求失败时自动返还算力点的功能
- 修改copyAIResponse函数参数以支持失败回调处理
- 在响应状态异常时也执行算力点返还操作
- 从auth服务中移除EnsureUserCredits方法
- 新增RefundUserCredits方法用于返还用户算力点
- 添加AI_REFUND算力点日志类型常量
- 更新算力点日志类型说明及展示标签
This commit is contained in:
HouYunFei
2026-05-25 15:23:51 +08:00
parent 01f2a4d9d5
commit 2934b1d0bc
10 changed files with 98 additions and 178 deletions
+15 -14
View File
@@ -77,10 +77,6 @@ func proxyAIRequest(w http.ResponseWriter, r *http.Request, path string) {
return
}
credits *= readAIRequestCount(body, contentType)
if err := service.EnsureUserCredits(user.ID, credits); err != nil {
FailError(w, err)
return
}
channel, err := service.SelectModelChannel(modelName)
if err != nil {
log.Printf("AI proxy select channel failed: model=%s err=%v", modelName, err)
@@ -97,15 +93,24 @@ func proxyAIRequest(w http.ResponseWriter, r *http.Request, path string) {
if contentType != "" {
request.Header.Set("Content-Type", contentType)
}
copyAIResponse(w, request, func() error {
return service.ConsumeUserCredits(user.ID, modelName, credits, path)
if err := service.ConsumeUserCredits(user.ID, modelName, credits, path); err != nil {
FailError(w, err)
return
}
copyAIResponse(w, request, func() {
if err := service.RefundUserCredits(user.ID, modelName, credits, path); err != nil {
log.Printf("AI proxy refund credits failed: user=%s model=%s credits=%d err=%v", user.ID, modelName, credits, err)
}
})
}
func copyAIResponse(w http.ResponseWriter, request *http.Request, beforeWrite func() error) {
func copyAIResponse(w http.ResponseWriter, request *http.Request, onFailure func()) {
response, err := http.DefaultClient.Do(request)
if err != nil {
log.Printf("AI proxy request failed: url=%s err=%v", request.URL.String(), err)
if onFailure != nil {
onFailure()
}
Fail(w, "AI 接口请求失败")
return
}
@@ -114,16 +119,12 @@ func copyAIResponse(w http.ResponseWriter, request *http.Request, beforeWrite fu
if response.StatusCode >= http.StatusBadRequest {
payload, _ := io.ReadAll(io.LimitReader(response.Body, 4096))
log.Printf("AI upstream error: url=%s status=%d body=%s", request.URL.String(), response.StatusCode, strings.TrimSpace(string(payload)))
if onFailure != nil {
onFailure()
}
Fail(w, "AI 接口请求失败")
return
}
if beforeWrite != nil {
if err := beforeWrite(); err != nil {
log.Printf("AI proxy before write failed: url=%s err=%v", request.URL.String(), err)
FailError(w, err)
return
}
}
for key, values := range response.Header {
if strings.EqualFold(key, "Content-Length") {