feat: enhance parseAllChapters API to support force parsing and update Audiobook component for AI mode handling
This commit is contained in:
@@ -17,6 +17,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
_LINE_RE = re.compile(r'^【(.+?)】(.*)$')
|
||||
_EMO_RE = re.compile(r'(([^)]+))\s*$')
|
||||
_EMO_PREFIX_RE = re.compile(r'^(([^)]+))\s*')
|
||||
|
||||
|
||||
def _parse_emo(raw: str) -> tuple[Optional[str], Optional[float]]:
|
||||
@@ -225,6 +226,14 @@ def parse_ai_script(script_text: str, char_map: dict) -> list[dict]:
|
||||
emo_text, emo_alpha = et, ea
|
||||
content = content[:emo_m.start()].strip()
|
||||
|
||||
if emo_text is None:
|
||||
emo_m = _EMO_PREFIX_RE.match(content)
|
||||
if emo_m:
|
||||
et, ea = _parse_emo(emo_m.group(1))
|
||||
if et is not None:
|
||||
emo_text, emo_alpha = et, ea
|
||||
content = content[emo_m.end():].strip()
|
||||
|
||||
if content.startswith('"') and content.endswith('"'):
|
||||
content = content[1:-1].strip()
|
||||
elif content.startswith('"') and content.endswith('"'):
|
||||
@@ -238,6 +247,14 @@ def parse_ai_script(script_text: str, char_map: dict) -> list[dict]:
|
||||
emo_text, emo_alpha = et, ea
|
||||
content = content[:emo_m.start()].strip()
|
||||
|
||||
if emo_text is None:
|
||||
emo_m = _EMO_PREFIX_RE.match(content)
|
||||
if emo_m:
|
||||
et, ea = _parse_emo(emo_m.group(1))
|
||||
if et is not None:
|
||||
emo_text, emo_alpha = et, ea
|
||||
content = content[emo_m.end():].strip()
|
||||
|
||||
character = speaker
|
||||
|
||||
results.append({
|
||||
@@ -937,16 +954,66 @@ def identify_chapters(project_id: int, db, project) -> None:
|
||||
logger.info(f"Project {project_id} chapters identified: {real_idx} chapters")
|
||||
|
||||
|
||||
async def _parse_ai_chapter(project_id: int, chapter_id: int, chapter, user: User, db, key: str) -> None:
|
||||
try:
|
||||
characters = crud.list_audiobook_characters(db, project_id)
|
||||
char_map: dict[str, AudiobookCharacter] = {c.name: c for c in characters}
|
||||
|
||||
label = chapter.title or f"第 {chapter.chapter_index + 1} 章"
|
||||
ps.append_line(key, f"[{label}] 重新解析 AI 剧本 ({len(chapter.source_text or '')} 字)")
|
||||
|
||||
crud.delete_audiobook_segments_for_chapter(db, project_id, chapter.chapter_index)
|
||||
|
||||
segments_dir = Path(settings.OUTPUT_DIR) / "audiobook" / str(project_id) / "segments"
|
||||
if segments_dir.exists():
|
||||
chapter_prefix = f"ch{chapter.chapter_index:03d}_"
|
||||
for f in segments_dir.glob(f"{chapter_prefix}*.wav"):
|
||||
f.unlink(missing_ok=True)
|
||||
|
||||
segments_data = parse_ai_script(chapter.source_text or "", char_map)
|
||||
|
||||
seg_counter = 0
|
||||
for seg in segments_data:
|
||||
seg_text = seg.get("text", "").strip()
|
||||
if not seg_text:
|
||||
continue
|
||||
char = char_map.get(seg.get("character", "旁白")) or char_map.get("旁白") or char_map.get("narrator")
|
||||
if not char:
|
||||
continue
|
||||
crud.create_audiobook_segment(
|
||||
db, project_id, char.id, seg_text,
|
||||
chapter.chapter_index, seg_counter,
|
||||
emo_text=seg.get("emo_text"), emo_alpha=seg.get("emo_alpha"),
|
||||
)
|
||||
seg_counter += 1
|
||||
|
||||
crud.update_audiobook_chapter_status(db, chapter_id, "ready")
|
||||
ps.append_line(key, f"\n[完成] 共 {seg_counter} 段")
|
||||
ps.mark_done(key)
|
||||
logger.info(f"AI chapter {chapter_id} reparsed: {seg_counter} segments")
|
||||
except Exception as e:
|
||||
logger.error(f"_parse_ai_chapter {chapter_id} failed: {e}", exc_info=True)
|
||||
ps.append_line(key, f"\n[错误] {e}")
|
||||
ps.mark_done(key)
|
||||
crud.update_audiobook_chapter_status(db, chapter_id, "error", error_message=str(e))
|
||||
|
||||
|
||||
async def parse_one_chapter(project_id: int, chapter_id: int, user: User, db) -> None:
|
||||
chapter = crud.get_audiobook_chapter(db, chapter_id)
|
||||
if not chapter:
|
||||
return
|
||||
|
||||
project = db.query(AudiobookProject).filter(AudiobookProject.id == project_id).first()
|
||||
is_ai_mode = project and project.source_type == "ai_generated"
|
||||
|
||||
key = f"ch_{chapter_id}"
|
||||
ps.reset(key)
|
||||
try:
|
||||
crud.update_audiobook_chapter_status(db, chapter_id, "parsing")
|
||||
|
||||
if is_ai_mode:
|
||||
return await _parse_ai_chapter(project_id, chapter_id, chapter, user, db, key)
|
||||
|
||||
llm = _get_llm_service(db)
|
||||
_llm_model = crud.get_system_setting(db, "llm_model")
|
||||
_user_id = user.id
|
||||
|
||||
Reference in New Issue
Block a user