jeecgboot/JeecgBoot · error · RuntimeException

旁白生成失败,状态码: {statusCode}

Error message

旁白生成失败,状态码: {statusCode}

What it means

Thrown by VideoGenerationServiceImpl.generateNarration() when the HTTP response from the GLM chat completions API (baseUrl + '/chat/completions') returns a status code other than 200. The method sends a POST request with a system+user message to generate a short narration script and checks the status code before parsing the response body.

Source

Thrown at jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/video/service/impl/VideoGenerationServiceImpl.java:526

        JSONObject userMsg = new JSONObject();
        userMsg.put("role", "user");
        userMsg.put("content", "视频画面:" + videoPrompt);

        messages.add(systemMsg);
        messages.add(userMsg);
        body.put("messages", messages);

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(baseUrl + "/chat/completions"))
                .header("Authorization", "Bearer " + apiKey)
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(body.toJSONString()))
                .timeout(Duration.ofSeconds(30))
                .build();

        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() != 200) {
            throw new RuntimeException("旁白生成失败,状态码: " + response.statusCode());
        }

        JSONObject respJson = JSON.parseObject(response.body());
        return respJson.getJSONArray("choices")
                .getJSONObject(0)
                .getJSONObject("message")
                .getString("content")
                .trim();
    }

    /**
     * 使用 edge-tts 将文本转为语音
     */
    private void generateTtsAudio(String text, Path audioPath) throws IOException, InterruptedException {
        ProcessBuilder pb = new ProcessBuilder(
                edgeTtsPath,
                "--voice", "zh-CN-YunyangNeural",
                "--text", text,

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Check the aiChatConfig.aiModelVideo configuration (apiKey, apiHost) in application.yml or the database config table.
  2. Test the API key and endpoint manually with curl to identify the specific HTTP error.
  3. Verify the model name 'glm-4-flash' is available and the account has access to it.
  4. For 429 rate-limit errors, reduce the frequency of video generation requests or upgrade the API plan.

Example fix

// before
if (response.statusCode() != 200) {
    throw new RuntimeException("旁白生成失败,状态码: " + response.statusCode());
}

// after
if (response.statusCode() != 200) {
    log.error("GLM narration API failed. Status: {}, Body: {}", response.statusCode(), response.body());
    throw new RuntimeException("旁白生成失败,状态码: " + response.statusCode() + ", 响应: " + response.body());
}
Defensive patterns

Strategy: retry

Validate before calling

// Validate config before calling generateNarration
AiChatConfig.ModelConfig config = aiChatConfig.getAiModelVideo();
if (config == null || oConvertUtils.isEmpty(config.getApiKey()) || oConvertUtils.isEmpty(config.getApiHost())) {
    throw new JeecgBootException("视频旁白AI模型未配置,请检查apiKey和apiHost");
}

Type guard

private static boolean isVideoModelConfigured(AiChatConfig.ModelConfig config) {
    return config != null
        && oConvertUtils.isNotEmpty(config.getApiKey())
        && oConvertUtils.isNotEmpty(config.getApiHost());
}

Try / catch

int maxRetries = 2;
for (int attempt = 0; attempt <= maxRetries; attempt++) {
    try {
        return generateNarration(videoPrompt);
    } catch (RuntimeException e) {
        if (e.getMessage().contains("旁白生成失败") && attempt < maxRetries) {
            log.warn("Narration generation attempt {} failed, retrying...", attempt + 1);
            continue;
        }
        log.error("Narration generation failed after retries");
        throw e;
    }
}

Prevention

When it happens

Trigger: The GLM API (configured via aiChatConfig.aiModelVideo) returns any non-200 status: 401 (invalid API key), 403 (forbidden/quota exceeded), 429 (rate limited), 500/502/503 (server error), or 404 (wrong base URL). The method uses a 30-second timeout, so gateway timeouts may surface as a different exception (HttpTimeoutException).

Common situations: API key for the video narration model is missing, invalid, or expired; the apiHost configuration points to the wrong base URL; the model 'glm-4-flash' is not available on the configured endpoint; rate limiting or quota exhaustion; GLM service outage.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/d18791256508cedc. Report an issue: GitHub.