修复帧提取BUG
This commit is contained in:
38
application/services/frame_prompt_helper.go
Normal file
38
application/services/frame_prompt_helper.go
Normal 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
|
||||||
|
}
|
||||||
@@ -171,36 +171,42 @@ 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")
|
||||||
|
return &SingleFramePrompt{
|
||||||
|
Prompt: fallbackPrompt,
|
||||||
|
Description: "镜头开始的静态画面,展示初始状态",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果AI返回空字符串,使用降级方案
|
// 解析AI返回的JSON
|
||||||
prompt = strings.TrimSpace(prompt)
|
result := s.parseFramePromptJSON(aiResponse)
|
||||||
if prompt == "" {
|
if result == nil {
|
||||||
s.log.Warnw("AI returned empty prompt, using fallback", "storyboard_id", sb.ID)
|
// JSON解析失败,使用降级方案
|
||||||
prompt = s.buildFallbackPrompt(sb, scene, "first frame, static shot")
|
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 &SingleFramePrompt{
|
return result
|
||||||
Prompt: prompt,
|
|
||||||
Description: "镜头开始的静态画面,展示初始状态",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateKeyFrame 生成关键帧提示词
|
// generateKeyFrame 生成关键帧提示词
|
||||||
@@ -213,35 +219,41 @@ 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")
|
||||||
|
return &SingleFramePrompt{
|
||||||
|
Prompt: fallbackPrompt,
|
||||||
|
Description: "动作高潮瞬间,展示关键动作",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果AI返回空字符串,使用降级方案
|
// 解析AI返回的JSON
|
||||||
prompt = strings.TrimSpace(prompt)
|
result := s.parseFramePromptJSON(aiResponse)
|
||||||
if prompt == "" {
|
if result == nil {
|
||||||
s.log.Warnw("AI returned empty prompt, using fallback", "storyboard_id", sb.ID)
|
// JSON解析失败,使用降级方案
|
||||||
prompt = s.buildFallbackPrompt(sb, scene, "key frame, dynamic action")
|
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 &SingleFramePrompt{
|
return result
|
||||||
Prompt: prompt,
|
|
||||||
Description: "动作高潮瞬间,展示关键动作",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateLastFrame 生成尾帧提示词
|
// generateLastFrame 生成尾帧提示词
|
||||||
@@ -254,35 +266,41 @@ 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")
|
||||||
|
return &SingleFramePrompt{
|
||||||
|
Prompt: fallbackPrompt,
|
||||||
|
Description: "镜头结束画面,展示最终状态和结果",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果AI返回空字符串,使用降级方案
|
// 解析AI返回的JSON
|
||||||
prompt = strings.TrimSpace(prompt)
|
result := s.parseFramePromptJSON(aiResponse)
|
||||||
if prompt == "" {
|
if result == nil {
|
||||||
s.log.Warnw("AI returned empty prompt, using fallback", "storyboard_id", sb.ID)
|
// JSON解析失败,使用降级方案
|
||||||
prompt = s.buildFallbackPrompt(sb, scene, "last frame, final state")
|
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 &SingleFramePrompt{
|
return result
|
||||||
Prompt: prompt,
|
|
||||||
Description: "镜头结束画面,展示最终状态和结果",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generatePanelFrames 生成分镜板(多格组合)
|
// generatePanelFrames 生成分镜板(多格组合)
|
||||||
|
|||||||
Reference in New Issue
Block a user