feat: update emotion handling in audiobook segments and UI for multi-emotion selection

This commit is contained in:
2026-03-13 15:14:49 +08:00
parent 161e7fa76d
commit bf1532200a
4 changed files with 131 additions and 60 deletions

View File

@@ -16,7 +16,31 @@ from db.models import AudiobookProject, AudiobookCharacter, User
logger = logging.getLogger(__name__)
_LINE_RE = re.compile(r'^【(.+?)】(.*)$')
_EMO_RE = re.compile(r'([^:]+):([0-9.]+)\s*$')
_EMO_RE = re.compile(r'([^]+)\s*$')
def _parse_emo(raw: str) -> tuple[Optional[str], Optional[float]]:
tokens = [t.strip() for t in raw.split('+') if t.strip()]
if not tokens:
return None, None
weighted = [(':' in t) for t in tokens]
if all(weighted) and len(tokens) > 1:
return raw, 1.0
elif len(tokens) == 1 and weighted[0]:
name, _, a = tokens[0].partition(':')
try:
return name.strip(), float(a)
except ValueError:
return None, None
elif weighted[-1]:
last_name, _, a = tokens[-1].rpartition(':')
names = tokens[:-1] + [last_name]
try:
return '+'.join(n.strip() for n in names), float(a)
except ValueError:
return None, None
else:
return None, None
# Cancellation events for batch operations, keyed by project_id
_cancel_events: dict[int, asyncio.Event] = {}
@@ -196,12 +220,10 @@ def parse_ai_script(script_text: str, char_map: dict) -> list[dict]:
emo_alpha = None
emo_m = _EMO_RE.search(content)
if emo_m:
emo_text = emo_m.group(1)
try:
emo_alpha = float(emo_m.group(2))
except ValueError:
emo_alpha = None
content = content[:emo_m.start()].strip()
et, ea = _parse_emo(emo_m.group(1))
if et is not None:
emo_text, emo_alpha = et, ea
content = content[:emo_m.start()].strip()
if content.startswith('"') and content.endswith('"'):
content = content[1:-1].strip()
@@ -211,12 +233,10 @@ def parse_ai_script(script_text: str, char_map: dict) -> list[dict]:
if emo_text is None:
emo_m = _EMO_RE.search(content)
if emo_m:
emo_text = emo_m.group(1)
try:
emo_alpha = float(emo_m.group(2))
except ValueError:
emo_alpha = None
content = content[:emo_m.start()].strip()
et, ea = _parse_emo(emo_m.group(1))
if et is not None:
emo_text, emo_alpha = et, ea
content = content[:emo_m.start()].strip()
character = speaker