diff --git a/backend/go-service/app/transcribe/service/openai_compat_client.go b/backend/go-service/app/transcribe/service/openai_compat_client.go index 08d5efc..00bf98f 100644 --- a/backend/go-service/app/transcribe/service/openai_compat_client.go +++ b/backend/go-service/app/transcribe/service/openai_compat_client.go @@ -107,17 +107,20 @@ func (c *OpenAICompatibleClient) Transcribe(ctx context.Context, cfg *dao.STTCon } // 3) 构造请求 - endpoint := strings.TrimRight(cfg.Provider.BaseURL, "/") + "/audio/transcriptions" + endpoint := buildTranscriptionEndpoint(cfg.Provider.BaseURL) + if endpoint == "" { + return nil, fmt.Errorf("STT provider base_url is empty: provider=%s model=%s", cfg.Provider.ProviderCode, cfg.Model.ModelCode) + } req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, body) if err != nil { - return nil, fmt.Errorf("构造 STT 请求失败: %w", err) + return nil, fmt.Errorf("构造 STT 请求失败: endpoint=%s provider=%s model=%s: %w", endpoint, cfg.Provider.ProviderCode, cfg.Model.ModelCode, err) } req.Header.Set("Authorization", "Bearer "+cfg.Key.APIKey) req.Header.Set("Content-Type", writer.FormDataContentType()) resp, err := c.httpClient.Do(req) if err != nil { - return nil, fmt.Errorf("调用 STT 接口失败: %w", err) + return nil, fmt.Errorf("调用 STT 接口失败: endpoint=%s provider=%s model=%s: %w", endpoint, cfg.Provider.ProviderCode, cfg.Model.ModelCode, err) } defer resp.Body.Close() @@ -132,7 +135,7 @@ func (c *OpenAICompatibleClient) Transcribe(ctx context.Context, cfg *dao.STTCon if len(preview) > 300 { preview = preview[:300] + "..." } - return nil, fmt.Errorf("STT 接口返回 %d: %s", resp.StatusCode, preview) + return nil, fmt.Errorf("STT 接口返回 %d: endpoint=%s provider=%s model=%s body=%s", resp.StatusCode, endpoint, cfg.Provider.ProviderCode, cfg.Model.ModelCode, preview) } // 4) 解析 @@ -151,6 +154,17 @@ func (c *OpenAICompatibleClient) Transcribe(ctx context.Context, cfg *dao.STTCon return &result, nil } +func buildTranscriptionEndpoint(baseURL string) string { + base := strings.TrimRight(strings.TrimSpace(baseURL), "/") + if base == "" { + return "" + } + if strings.HasSuffix(base, "/audio/transcriptions") { + return base + } + return base + "/audio/transcriptions" +} + // downloadAudio 从给定 URL 拉取音频内容,返回字节流 + 推断的文件名 // // 文件名仅作为 multipart 的 filename 参数,主要决定 Content-Type 推断; diff --git a/backend/go-service/app/transcribe/service/transcribe_service.go b/backend/go-service/app/transcribe/service/transcribe_service.go index 42683d1..23f7e0f 100644 --- a/backend/go-service/app/transcribe/service/transcribe_service.go +++ b/backend/go-service/app/transcribe/service/transcribe_service.go @@ -165,6 +165,12 @@ func (s *TranscribeService) runJob(transcriptID int64, rec meetingModel.MeetingR "model_code": cfg.Model.ModelCode, "key_id": cfg.Key.ID, }).Error + logs.Info(ctx, funcName, "已选择 STT 配置", + zap.Int64("transcript_id", transcriptID), + zap.String("provider_code", cfg.Provider.ProviderCode), + zap.String("model_code", cfg.Model.ModelCode), + zap.String("base_url", cfg.Provider.BaseURL), + zap.String("file_url", rec.FileURL)) result, err := s.sttClient.Transcribe(ctx, cfg, rec.FileURL, language) if err != nil { diff --git a/backend/go-service/config/config.dev.yaml b/backend/go-service/config/config.dev.yaml index 039617b..16831ee 100644 --- a/backend/go-service/config/config.dev.yaml +++ b/backend/go-service/config/config.dev.yaml @@ -53,7 +53,7 @@ minio: secret_key: "echochat_2026-1s32dswW@#" # 密钥(与 docker-compose 中的 MINIO_ROOT_PASSWORD 一致) bucket: "echochat" # 存储桶名称 use_ssl: false # 开发环境不使用 HTTPS - public_base_url: "http://yl.z64.cn/echochat" + public_base_url: "https://yl.z64.cn/echochat" # Node media-server 接入配置(Phase 2e-2 Task 7 HTTPMediaOrchestrator) # 对应 media-server/.env 的 MEDIA_INTERNAL_TOKEN + HTTP_PORT(默认 3300) diff --git a/backend/go-service/config/config.docker.yaml b/backend/go-service/config/config.docker.yaml index 6df85b9..21329fc 100644 --- a/backend/go-service/config/config.docker.yaml +++ b/backend/go-service/config/config.docker.yaml @@ -47,7 +47,7 @@ minio: secret_key: "echochat_2026-1s32dswW@#" bucket: "echochat" use_ssl: false - public_base_url: "http://yl.z64.cn/echochat" + public_base_url: "https://yl.z64.cn/echochat" # Node media-server 接入配置(Phase 2e-2 Task 7) media_server: diff --git a/deploy/.env.public.example b/deploy/.env.public.example index 32212ba..61490c5 100644 --- a/deploy/.env.public.example +++ b/deploy/.env.public.example @@ -18,7 +18,7 @@ REDIS_PASSWORD=echochat_2026-1s32dswW@# MINIO_ROOT_USER=echochat MINIO_ROOT_PASSWORD=echochat_2026-1s32dswW@# -MINIO_PUBLIC_BASE_URL=http://yl.z64.cn/echochat +MINIO_PUBLIC_BASE_URL=https://yl.z64.cn/echochat # ============================================================ # Go backend diff --git a/deploy/docker-compose.dev.yml b/deploy/docker-compose.dev.yml index adfad3d..40c4a98 100644 --- a/deploy/docker-compose.dev.yml +++ b/deploy/docker-compose.dev.yml @@ -69,7 +69,7 @@ services: ECHOCHAT_MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:-echochat} ECHOCHAT_MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:-echochat123456} ECHOCHAT_MEDIA_SERVER_INTERNAL_TOKEN: ${MEDIA_INTERNAL_TOKEN:-internal-token-22xqs} - ECHOCHAT_MINIO_PUBLIC_BASE_URL: ${MINIO_PUBLIC_BASE_URL:-http://yl.z64.cn/echochat} + ECHOCHAT_MINIO_PUBLIC_BASE_URL: ${MINIO_PUBLIC_BASE_URL:-https://yl.z64.cn/echochat} # media-server 失败回调共享密钥:与 media-server 服务的 INTERNAL_WEBHOOK_SECRET 保持一致 # 未配置时 go-service 会拒绝所有 webhook(Forbidden),录制失败状态将无法及时落 failed ECHOCHAT_MEETING_INTERNAL_WEBHOOK_SECRET: ${INTERNAL_WEBHOOK_SECRET:-internal-webhook-12xqs}