Skip to content

Commit 6060ce6

Browse files
add retry
1 parent 42240cb commit 6060ce6

File tree

16 files changed

+530
-262
lines changed

16 files changed

+530
-262
lines changed

Dockerfile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,25 @@ WORKDIR /app
5353

5454
# 安装运行时依赖 (证书 + nodejs + opus 运行库)
5555
RUN apt-get update && \
56-
apt-get install -y --no-install-recommends ca-certificates curl libopus0 && \
56+
apt-get install -y --no-install-recommends ca-certificates curl libopus0 supervisor && \
5757
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
5858
apt-get install -y --no-install-recommends nodejs && \
5959
rm -rf /var/lib/apt/lists/*
6060

6161
ENV PATH="/usr/share/nodejs/corepack/shims:$PATH"
6262

63+
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
64+
6365
# Create required directories
64-
RUN mkdir -p ./conf/i18n ./conf/mcp
66+
RUN mkdir -p ./conf/i18n ./conf/mcp ./conf/img/ ./adminui
6567

6668
# Copy compiled Go application
6769
COPY --from=builder /app/MuseBot .
6870
COPY --from=builder /app/MuseBotAdmin .
6971
COPY --from=builder /app/conf/i18n/ ./conf/i18n/
7072
COPY --from=builder /app/conf/mcp/ ./conf/mcp/
7173
COPY --from=builder /app/conf/img/ ./conf/img/
74+
COPY --from=builder /app/admin/adminui/ ./conf/adminui/
7275

7376
# Copy FFmpeg binaries
7477
COPY --from=ffmpeg-builder /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg

MuseAdmin

-37.7 MB
Binary file not shown.

admin/controller/bot.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -286,14 +286,6 @@ func SoftDeleteBot(w http.ResponseWriter, r *http.Request) {
286286
utils.Failure(ctx, w, r, param.CodeParamError, param.MsgParamError, err)
287287
return
288288
}
289-
290-
botInfo, err := db.GetBotByID(idStr)
291-
if err != nil {
292-
logger.ErrorCtx(ctx, "get bot error", "reason", "not found", "id", idStr, "err", err)
293-
utils.Failure(ctx, w, r, param.CodeDBQueryFail, param.MsgDBQueryFail, err)
294-
return
295-
}
296-
297289
err = db.SoftDeleteBot(id)
298290
if err != nil {
299291
logger.ErrorCtx(ctx, "soft delete bot error", "reason", "db fail", "id", id, "err", err)
@@ -302,10 +294,6 @@ func SoftDeleteBot(w http.ResponseWriter, r *http.Request) {
302294
}
303295

304296
checkpoint.BotMap.Delete(id)
305-
306-
adminUtils.GetCrtClient(botInfo).Do(GetRequest(ctx, http.MethodGet,
307-
strings.TrimSuffix(botInfo.Address, "/")+"/stop", bytes.NewBuffer(nil)))
308-
309297
utils.Success(ctx, w, r, "bot deleted")
310298
}
311299

admin/main.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package main
22

33
import (
4+
"bytes"
5+
"context"
6+
"embed"
47
"fmt"
8+
"io/fs"
59
"net/http"
610
_ "net/http/pprof"
11+
"time"
712

13+
"github.com/google/uuid"
814
"github.com/yincongcyincong/MuseBot/admin/checkpoint"
915
"github.com/yincongcyincong/MuseBot/admin/conf"
1016
"github.com/yincongcyincong/MuseBot/admin/controller"
@@ -77,3 +83,64 @@ func main() {
7783
panic(err)
7884
}
7985
}
86+
87+
//go:embed adminui/*
88+
var staticFiles embed.FS
89+
90+
func View() http.HandlerFunc {
91+
distFS, _ := fs.Sub(staticFiles, "adminui")
92+
93+
staticHandler := http.FileServer(http.FS(distFS))
94+
95+
return func(w http.ResponseWriter, r *http.Request) {
96+
if fileExists(distFS, r.URL.Path[1:]) {
97+
staticHandler.ServeHTTP(w, r)
98+
return
99+
}
100+
101+
fileBytes, err := fs.ReadFile(distFS, "index.html")
102+
if err != nil {
103+
http.Error(w, "index.html not found", http.StatusInternalServerError)
104+
return
105+
}
106+
107+
reader := bytes.NewReader(fileBytes)
108+
http.ServeContent(w, r, "index.html", time.Now(), reader)
109+
}
110+
}
111+
112+
func fileExists(fsys fs.FS, path string) bool {
113+
f, err := fsys.Open(path)
114+
if err != nil {
115+
return false
116+
}
117+
defer f.Close()
118+
info, err := f.Stat()
119+
if err != nil || info.IsDir() {
120+
return false
121+
}
122+
return true
123+
}
124+
125+
func WithRequestContext(next http.Handler) http.Handler {
126+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
127+
ctx := r.Context()
128+
logID := uuid.New().String()
129+
130+
isSSE := r.Header.Get("Accept") == "text/event-stream"
131+
132+
if !isSSE {
133+
var cancel context.CancelFunc
134+
ctx, cancel = context.WithTimeout(ctx, 1*time.Minute)
135+
defer cancel()
136+
}
137+
138+
// 通用的 context 值
139+
ctx = context.WithValue(ctx, "log_id", logID)
140+
ctx = context.WithValue(ctx, "start_time", time.Now())
141+
r = r.WithContext(ctx)
142+
143+
logger.InfoCtx(ctx, "request start", "path", r.URL.Path)
144+
next.ServeHTTP(w, r)
145+
})
146+
}

admin/view.go

Lines changed: 0 additions & 74 deletions
This file was deleted.

conf/conf.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ type BaseConf struct {
7373
Powered *string `json:"powered"`
7474
SendMcpRes *bool `json:"send_mcp_res"`
7575
DefaultModel *string `json:"default_model"`
76+
LLMRetryTimes *int `json:"llm_retry_times"`
7677

7778
CrtFile *string `json:"crt_file"`
7879
KeyFile *string `json:"key_file"`
@@ -151,6 +152,7 @@ func InitConf() {
151152
BaseConfInfo.CaFile = flag.String("ca_file", "", "ca file")
152153
BaseConfInfo.SendMcpRes = flag.Bool("send_mcp_res", false, "send mcp res")
153154
BaseConfInfo.DefaultModel = flag.String("default_model", "", "default model")
155+
BaseConfInfo.LLMRetryTimes = flag.Int("llm_retry_times", 3, "llm retry times")
154156

155157
adminUserIds := flag.String("admin_user_ids", "", "admin user ids")
156158
allowedUserIds := flag.String("allowed_user_ids", "", "allowed user ids")
@@ -415,6 +417,10 @@ func InitConf() {
415417
*BaseConfInfo.DefaultModel = os.Getenv("DEFAULT_MODEL")
416418
}
417419

420+
if os.Getenv("LLM_RETRY_TIMES") != "" {
421+
*BaseConfInfo.LLMRetryTimes, _ = strconv.Atoi(os.Getenv("LLM_RETRY_TIMES"))
422+
}
423+
418424
for _, userIdStr := range strings.Split(*allowedUserIds, ",") {
419425
if userIdStr == "" {
420426
continue
@@ -492,6 +498,7 @@ func InitConf() {
492498
logger.Info("CONF", "ContextExpireTime", *BaseConfInfo.ContextExpireTime)
493499
logger.Info("CONF", "SendMcpRes", *BaseConfInfo.SendMcpRes)
494500
logger.Info("CONF", "DefaultModel", *BaseConfInfo.DefaultModel)
501+
logger.Info("CONF", "LLMRetryTimes", *BaseConfInfo.LLMRetryTimes)
495502

496503
EnvAudioConf()
497504
EnvRagConf()

llm/aliyun.go

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,22 @@ func GenerateAliyunImg(ctx context.Context, prompt string, imageContent []byte)
122122
start := time.Now()
123123
metrics.APIRequestCount.WithLabelValues(model).Inc()
124124

125-
resp, err := client.Do(req)
126-
metrics.APIRequestDuration.WithLabelValues(model).Observe(time.Since(start).Seconds())
127-
if err != nil {
128-
logger.ErrorCtx(ctx, "create image fail", "err", err)
129-
return "", 0, err
125+
var resp *http.Response
126+
var err error
127+
for i := 0; i < *conf.BaseConfInfo.LLMRetryTimes; i++ {
128+
resp, err = client.Do(req)
129+
if err != nil {
130+
logger.ErrorCtx(ctx, "create image fail", "err", err)
131+
continue
132+
}
133+
break
134+
}
135+
if err != nil || resp == nil {
136+
return "", 0, fmt.Errorf("request fail %v %v", err, resp)
130137
}
131-
defer resp.Body.Close()
132138

139+
defer resp.Body.Close()
140+
metrics.APIRequestDuration.WithLabelValues(model).Observe(time.Since(start).Seconds())
133141
body, err := io.ReadAll(resp.Body)
134142
if err != nil {
135143
logger.ErrorCtx(ctx, "read response fail", "err", err)
@@ -220,9 +228,18 @@ func GenerateAliyunVideo(ctx context.Context, prompt string, image []byte) (stri
220228
metrics.APIRequestDuration.WithLabelValues(model).Observe(time.Since(start).Seconds())
221229
}()
222230

223-
resp, err := client.Do(req)
224-
if err != nil {
225-
return "", 0, err
231+
var resp *http.Response
232+
for i := 0; i < *conf.BaseConfInfo.LLMRetryTimes; i++ {
233+
resp, err = client.Do(req)
234+
if err != nil {
235+
logger.ErrorCtx(ctx, "create video fail", "err", err)
236+
continue
237+
}
238+
break
239+
}
240+
241+
if err != nil || resp == nil {
242+
return "", 0, fmt.Errorf("request fail %v %v", err, resp)
226243
}
227244
defer resp.Body.Close()
228245

@@ -232,34 +249,34 @@ func GenerateAliyunVideo(ctx context.Context, prompt string, image []byte) (stri
232249
}
233250

234251
var vr TaskStatusResponse
235-
if err := json.Unmarshal(body, &vr); err != nil {
252+
if err = json.Unmarshal(body, &vr); err != nil {
236253
return "", 0, err
237254
}
238255

239256
for i := 0; i < 100; i++ {
240257
time.Sleep(5 * time.Second)
241258

242-
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://dashscope.aliyuncs.com/api/v1/tasks/%s", vr.Output.TaskID), nil)
259+
req, err = http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://dashscope.aliyuncs.com/api/v1/tasks/%s", vr.Output.TaskID), nil)
243260
if err != nil {
244261
return "", 0, err
245262
}
246263

247264
req.Header.Set("Authorization", "Bearer "+*conf.BaseConfInfo.AliyunToken)
248265
req.Header.Set("Content-Type", "application/json")
249266

250-
resp, err := client.Do(req)
267+
resp, err = client.Do(req)
251268
if err != nil {
252269
return "", 0, err
253270
}
254271
defer resp.Body.Close()
255272

256-
body, err := io.ReadAll(resp.Body)
273+
body, err = io.ReadAll(resp.Body)
257274
if err != nil {
258275
return "", 0, err
259276
}
260277

261278
var vr videoResponse
262-
if err := json.Unmarshal(body, &vr); err != nil {
279+
if err = json.Unmarshal(body, &vr); err != nil {
263280
return "", 0, err
264281
}
265282

@@ -330,12 +347,21 @@ func GenerateAliyunText(ctx context.Context, audioContent []byte) (string, int,
330347
client := utils.GetLLMProxyClient()
331348
start := time.Now()
332349
metrics.APIRequestCount.WithLabelValues(recModel).Inc()
333-
resp, err := client.Do(req)
334350

335-
metrics.APIRequestDuration.WithLabelValues(recModel).Observe(time.Since(start).Seconds())
336-
if err != nil {
337-
return "", 0, fmt.Errorf("request failed: %w", err)
351+
var resp *http.Response
352+
for i := 0; i < *conf.BaseConfInfo.LLMRetryTimes; i++ {
353+
resp, err = client.Do(req)
354+
if err != nil {
355+
logger.ErrorCtx(ctx, "create video fail", "err", err)
356+
continue
357+
}
358+
break
338359
}
360+
361+
if err != nil || resp == nil {
362+
return "", 0, fmt.Errorf("request fail %v %v", err, resp)
363+
}
364+
metrics.APIRequestDuration.WithLabelValues(recModel).Observe(time.Since(start).Seconds())
339365
defer resp.Body.Close()
340366

341367
body, err := io.ReadAll(resp.Body)
@@ -405,11 +431,22 @@ func AliyunTTS(ctx context.Context, text, encoding string) ([]byte, int, int, er
405431
client := utils.GetLLMProxyClient()
406432
start := time.Now()
407433
metrics.APIRequestCount.WithLabelValues(model).Inc()
408-
resp, err := client.Do(req)
409-
metrics.APIRequestDuration.WithLabelValues(model).Observe(time.Since(start).Seconds())
410-
if err != nil {
411-
return nil, 0, 0, fmt.Errorf("request error: %w", err)
434+
435+
var resp *http.Response
436+
for i := 0; i < *conf.BaseConfInfo.LLMRetryTimes; i++ {
437+
resp, err = client.Do(req)
438+
if err != nil {
439+
logger.ErrorCtx(ctx, "create video fail", "err", err)
440+
continue
441+
}
442+
break
412443
}
444+
445+
if err != nil || resp == nil {
446+
return nil, 0, 0, fmt.Errorf("request fail %v %v", err, resp)
447+
}
448+
449+
metrics.APIRequestDuration.WithLabelValues(model).Observe(time.Since(start).Seconds())
413450
defer resp.Body.Close()
414451

415452
respData, err := io.ReadAll(resp.Body)

0 commit comments

Comments
 (0)