修复帧提取BUG

This commit is contained in:
Connor
2026-01-18 05:44:14 +08:00
parent 7ff1ff95a3
commit ae4fcfc970
2 changed files with 98 additions and 42 deletions

View File

@@ -0,0 +1,38 @@
package services
import (
"encoding/json"
"regexp"
"strings"
)
// parseFramePromptJSON 解析AI返回的JSON格式提示词
func (s *FramePromptService) parseFramePromptJSON(aiResponse string) *SingleFramePrompt {
// 清理可能的markdown代码块标记
cleaned := strings.TrimSpace(aiResponse)
// 移除 ```json 和 ``` 标记
re := regexp.MustCompile("(?s)```json\\s*(.+?)\\s*```")
if matches := re.FindStringSubmatch(cleaned); len(matches) > 1 {
cleaned = strings.TrimSpace(matches[1])
} else {
// 移除单独的 ``` 标记
cleaned = strings.Trim(cleaned, "`")
cleaned = strings.TrimSpace(cleaned)
}
// 尝试解析JSON
var result SingleFramePrompt
if err := json.Unmarshal([]byte(cleaned), &result); err != nil {
s.log.Warnw("Failed to parse JSON", "error", err, "cleaned_response", cleaned)
return nil
}
// 验证必需字段
if result.Prompt == "" {
s.log.Warnw("Parsed JSON missing prompt field", "response", cleaned)
return nil
}
return &result
}

View File

@@ -171,38 +171,44 @@ func (s *FramePromptService) generateFirstFrame(sb models.Storyboard, scene *mod
userPrompt := s.promptI18n.FormatUserPrompt("frame_info", contextInfo) userPrompt := s.promptI18n.FormatUserPrompt("frame_info", contextInfo)
// 调用AI生成如果指定了模型则使用指定的模型 // 调用AI生成如果指定了模型则使用指定的模型
var prompt string var aiResponse string
var err error var err error
if model != "" { if model != "" {
client, getErr := s.aiService.GetAIClientForModel("text", model) client, getErr := s.aiService.GetAIClientForModel("text", model)
if getErr != nil { if getErr != nil {
s.log.Warnw("Failed to get client for specified model, using default", "model", model, "error", getErr) s.log.Warnw("Failed to get client for specified model, using default", "model", model, "error", getErr)
prompt, err = s.aiService.GenerateText(userPrompt, systemPrompt) aiResponse, err = s.aiService.GenerateText(userPrompt, systemPrompt)
} else { } else {
prompt, err = client.GenerateText(userPrompt, systemPrompt) aiResponse, err = client.GenerateText(userPrompt, systemPrompt)
} }
} else { } else {
prompt, err = s.aiService.GenerateText(userPrompt, systemPrompt) aiResponse, err = s.aiService.GenerateText(userPrompt, systemPrompt)
} }
if err != nil { if err != nil {
s.log.Warnw("AI generation failed, using fallback", "error", err) s.log.Warnw("AI generation failed, using fallback", "error", err)
// 降级方案:使用简单拼接 // 降级方案:使用简单拼接
prompt = s.buildFallbackPrompt(sb, scene, "first frame, static shot") fallbackPrompt := s.buildFallbackPrompt(sb, scene, "first frame, static shot")
}
// 如果AI返回空字符串使用降级方案
prompt = strings.TrimSpace(prompt)
if prompt == "" {
s.log.Warnw("AI returned empty prompt, using fallback", "storyboard_id", sb.ID)
prompt = s.buildFallbackPrompt(sb, scene, "first frame, static shot")
}
return &SingleFramePrompt{ return &SingleFramePrompt{
Prompt: prompt, Prompt: fallbackPrompt,
Description: "镜头开始的静态画面,展示初始状态", Description: "镜头开始的静态画面,展示初始状态",
} }
} }
// 解析AI返回的JSON
result := s.parseFramePromptJSON(aiResponse)
if result == nil {
// JSON解析失败使用降级方案
s.log.Warnw("Failed to parse AI JSON response, using fallback", "storyboard_id", sb.ID, "response", aiResponse)
fallbackPrompt := s.buildFallbackPrompt(sb, scene, "first frame, static shot")
return &SingleFramePrompt{
Prompt: fallbackPrompt,
Description: "镜头开始的静态画面,展示初始状态",
}
}
return result
}
// generateKeyFrame 生成关键帧提示词 // generateKeyFrame 生成关键帧提示词
func (s *FramePromptService) generateKeyFrame(sb models.Storyboard, scene *models.Scene, model string) *SingleFramePrompt { func (s *FramePromptService) generateKeyFrame(sb models.Storyboard, scene *models.Scene, model string) *SingleFramePrompt {
// 构建上下文信息 // 构建上下文信息
@@ -213,37 +219,43 @@ func (s *FramePromptService) generateKeyFrame(sb models.Storyboard, scene *model
userPrompt := s.promptI18n.FormatUserPrompt("key_frame_info", contextInfo) userPrompt := s.promptI18n.FormatUserPrompt("key_frame_info", contextInfo)
// 调用AI生成如果指定了模型则使用指定的模型 // 调用AI生成如果指定了模型则使用指定的模型
var prompt string var aiResponse string
var err error var err error
if model != "" { if model != "" {
client, getErr := s.aiService.GetAIClientForModel("text", model) client, getErr := s.aiService.GetAIClientForModel("text", model)
if getErr != nil { if getErr != nil {
s.log.Warnw("Failed to get client for specified model, using default", "model", model, "error", getErr) s.log.Warnw("Failed to get client for specified model, using default", "model", model, "error", getErr)
prompt, err = s.aiService.GenerateText(userPrompt, systemPrompt) aiResponse, err = s.aiService.GenerateText(userPrompt, systemPrompt)
} else { } else {
prompt, err = client.GenerateText(userPrompt, systemPrompt) aiResponse, err = client.GenerateText(userPrompt, systemPrompt)
} }
} else { } else {
prompt, err = s.aiService.GenerateText(userPrompt, systemPrompt) aiResponse, err = s.aiService.GenerateText(userPrompt, systemPrompt)
} }
if err != nil { if err != nil {
s.log.Warnw("AI generation failed, using fallback", "error", err) s.log.Warnw("AI generation failed, using fallback", "error", err)
prompt = s.buildFallbackPrompt(sb, scene, "key frame, dynamic action") fallbackPrompt := s.buildFallbackPrompt(sb, scene, "key frame, dynamic action")
}
// 如果AI返回空字符串使用降级方案
prompt = strings.TrimSpace(prompt)
if prompt == "" {
s.log.Warnw("AI returned empty prompt, using fallback", "storyboard_id", sb.ID)
prompt = s.buildFallbackPrompt(sb, scene, "key frame, dynamic action")
}
return &SingleFramePrompt{ return &SingleFramePrompt{
Prompt: prompt, Prompt: fallbackPrompt,
Description: "动作高潮瞬间,展示关键动作", Description: "动作高潮瞬间,展示关键动作",
} }
} }
// 解析AI返回的JSON
result := s.parseFramePromptJSON(aiResponse)
if result == nil {
// JSON解析失败使用降级方案
s.log.Warnw("Failed to parse AI JSON response, using fallback", "storyboard_id", sb.ID, "response", aiResponse)
fallbackPrompt := s.buildFallbackPrompt(sb, scene, "key frame, dynamic action")
return &SingleFramePrompt{
Prompt: fallbackPrompt,
Description: "动作高潮瞬间,展示关键动作",
}
}
return result
}
// generateLastFrame 生成尾帧提示词 // generateLastFrame 生成尾帧提示词
func (s *FramePromptService) generateLastFrame(sb models.Storyboard, scene *models.Scene, model string) *SingleFramePrompt { func (s *FramePromptService) generateLastFrame(sb models.Storyboard, scene *models.Scene, model string) *SingleFramePrompt {
// 构建上下文信息 // 构建上下文信息
@@ -254,37 +266,43 @@ func (s *FramePromptService) generateLastFrame(sb models.Storyboard, scene *mode
userPrompt := s.promptI18n.FormatUserPrompt("last_frame_info", contextInfo) userPrompt := s.promptI18n.FormatUserPrompt("last_frame_info", contextInfo)
// 调用AI生成如果指定了模型则使用指定的模型 // 调用AI生成如果指定了模型则使用指定的模型
var prompt string var aiResponse string
var err error var err error
if model != "" { if model != "" {
client, getErr := s.aiService.GetAIClientForModel("text", model) client, getErr := s.aiService.GetAIClientForModel("text", model)
if getErr != nil { if getErr != nil {
s.log.Warnw("Failed to get client for specified model, using default", "model", model, "error", getErr) s.log.Warnw("Failed to get client for specified model, using default", "model", model, "error", getErr)
prompt, err = s.aiService.GenerateText(userPrompt, systemPrompt) aiResponse, err = s.aiService.GenerateText(userPrompt, systemPrompt)
} else { } else {
prompt, err = client.GenerateText(userPrompt, systemPrompt) aiResponse, err = client.GenerateText(userPrompt, systemPrompt)
} }
} else { } else {
prompt, err = s.aiService.GenerateText(userPrompt, systemPrompt) aiResponse, err = s.aiService.GenerateText(userPrompt, systemPrompt)
} }
if err != nil { if err != nil {
s.log.Warnw("AI generation failed, using fallback", "error", err) s.log.Warnw("AI generation failed, using fallback", "error", err)
prompt = s.buildFallbackPrompt(sb, scene, "last frame, final state") fallbackPrompt := s.buildFallbackPrompt(sb, scene, "last frame, final state")
}
// 如果AI返回空字符串使用降级方案
prompt = strings.TrimSpace(prompt)
if prompt == "" {
s.log.Warnw("AI returned empty prompt, using fallback", "storyboard_id", sb.ID)
prompt = s.buildFallbackPrompt(sb, scene, "last frame, final state")
}
return &SingleFramePrompt{ return &SingleFramePrompt{
Prompt: prompt, Prompt: fallbackPrompt,
Description: "镜头结束画面,展示最终状态和结果", Description: "镜头结束画面,展示最终状态和结果",
} }
} }
// 解析AI返回的JSON
result := s.parseFramePromptJSON(aiResponse)
if result == nil {
// JSON解析失败使用降级方案
s.log.Warnw("Failed to parse AI JSON response, using fallback", "storyboard_id", sb.ID, "response", aiResponse)
fallbackPrompt := s.buildFallbackPrompt(sb, scene, "last frame, final state")
return &SingleFramePrompt{
Prompt: fallbackPrompt,
Description: "镜头结束画面,展示最终状态和结果",
}
}
return result
}
// generatePanelFrames 生成分镜板(多格组合) // generatePanelFrames 生成分镜板(多格组合)
func (s *FramePromptService) generatePanelFrames(sb models.Storyboard, scene *models.Scene, count int, model string) *MultiFramePrompt { func (s *FramePromptService) generatePanelFrames(sb models.Storyboard, scene *models.Scene, count int, model string) *MultiFramePrompt {
layout := fmt.Sprintf("horizontal_%d", count) layout := fmt.Sprintf("horizontal_%d", count)