feat: add violence and eroticism level parameters to synopsis and script generation requests
This commit is contained in:
@@ -208,6 +208,16 @@ def parse_ai_script(script_text: str, char_map: dict) -> list[dict]:
|
||||
elif content.startswith('"') and content.endswith('"'):
|
||||
content = content[1:-1].strip()
|
||||
|
||||
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()
|
||||
|
||||
character = speaker
|
||||
|
||||
results.append({
|
||||
@@ -252,6 +262,8 @@ async def generate_ai_script(project_id: int, user: User, db: Session) -> None:
|
||||
style = cfg.get("style", "")
|
||||
num_characters = cfg.get("num_characters", 5)
|
||||
num_chapters = cfg.get("num_chapters", 8)
|
||||
violence_level = cfg.get("violence_level", 0)
|
||||
eroticism_level = cfg.get("eroticism_level", 0)
|
||||
|
||||
ps.append_line(key, f"\n[Step 1] 生成 {num_characters} 个角色...\n")
|
||||
ps.append_line(key, "")
|
||||
@@ -262,6 +274,7 @@ async def generate_ai_script(project_id: int, user: User, db: Session) -> None:
|
||||
characters_data = await llm.generate_story_characters(
|
||||
genre=genre, subgenre=subgenre, premise=premise, style=style,
|
||||
num_characters=num_characters, usage_callback=_log_usage,
|
||||
violence_level=violence_level, eroticism_level=eroticism_level,
|
||||
)
|
||||
|
||||
has_narrator = any(c.get("name") in ("narrator", "旁白") for c in characters_data)
|
||||
@@ -370,9 +383,16 @@ async def generate_ai_script_chapters(project_id: int, user: User, db: Session)
|
||||
premise = cfg.get("premise", "")
|
||||
style = cfg.get("style", "")
|
||||
num_chapters = cfg.get("num_chapters", 8)
|
||||
violence_level = cfg.get("violence_level", 0)
|
||||
eroticism_level = cfg.get("eroticism_level", 0)
|
||||
|
||||
llm = _get_llm_service(db)
|
||||
_llm_model = crud.get_system_setting(db, "llm_model")
|
||||
is_nsfw = cfg.get("nsfw_mode", False)
|
||||
if is_nsfw:
|
||||
llm = _get_grok_service(db)
|
||||
_llm_model = crud.get_system_setting(db, "grok_model") or "grok-4"
|
||||
else:
|
||||
llm = _get_llm_service(db)
|
||||
_llm_model = crud.get_system_setting(db, "llm_model")
|
||||
_user_id = user.id
|
||||
|
||||
def _log_usage(prompt_tokens: int, completion_tokens: int) -> None:
|
||||
@@ -400,6 +420,7 @@ async def generate_ai_script_chapters(project_id: int, user: User, db: Session)
|
||||
chapters_data = await llm.generate_chapter_outline(
|
||||
genre=genre, subgenre=subgenre, premise=premise, style=style,
|
||||
num_chapters=num_chapters, characters=characters_data, usage_callback=_log_usage,
|
||||
violence_level=violence_level, eroticism_level=eroticism_level,
|
||||
)
|
||||
|
||||
ps.append_line(key, f"\n\n[完成] 大纲:{len(chapters_data)} 章")
|
||||
@@ -440,6 +461,7 @@ async def generate_ai_script_chapters(project_id: int, user: User, db: Session)
|
||||
genre=genre, premise=premise,
|
||||
chapter_index=idx, chapter_title=title, chapter_summary=summary,
|
||||
characters=characters_data, on_token=on_token, usage_callback=_log_usage,
|
||||
violence_level=violence_level, eroticism_level=eroticism_level,
|
||||
)
|
||||
|
||||
chapter_obj.source_text = script_text
|
||||
@@ -530,9 +552,16 @@ async def continue_ai_script_chapters(project_id: int, additional_chapters: int,
|
||||
subgenre = cfg.get("subgenre", "")
|
||||
premise = cfg.get("premise", "")
|
||||
style = cfg.get("style", "")
|
||||
violence_level = cfg.get("violence_level", 0)
|
||||
eroticism_level = cfg.get("eroticism_level", 0)
|
||||
|
||||
llm = _get_llm_service(db)
|
||||
_llm_model = crud.get_system_setting(db, "llm_model")
|
||||
is_nsfw = cfg.get("nsfw_mode", False)
|
||||
if is_nsfw:
|
||||
llm = _get_grok_service(db)
|
||||
_llm_model = crud.get_system_setting(db, "grok_model") or "grok-4"
|
||||
else:
|
||||
llm = _get_llm_service(db)
|
||||
_llm_model = crud.get_system_setting(db, "llm_model")
|
||||
_user_id = user.id
|
||||
|
||||
def _log_usage(prompt_tokens: int, completion_tokens: int) -> None:
|
||||
@@ -568,6 +597,7 @@ async def continue_ai_script_chapters(project_id: int, additional_chapters: int,
|
||||
genre=genre, subgenre=subgenre, premise=premise, style=style,
|
||||
existing_chapters=existing_chapters_data, additional_chapters=additional_chapters,
|
||||
characters=characters_data, usage_callback=_log_usage,
|
||||
violence_level=violence_level, eroticism_level=eroticism_level,
|
||||
)
|
||||
|
||||
ps.append_line(key, f"\n\n[完成] 续写大纲:{len(new_chapters_data)} 章")
|
||||
@@ -596,6 +626,7 @@ async def continue_ai_script_chapters(project_id: int, additional_chapters: int,
|
||||
genre=genre, premise=premise,
|
||||
chapter_index=idx, chapter_title=title, chapter_summary=summary,
|
||||
characters=characters_data, on_token=on_token, usage_callback=_log_usage,
|
||||
violence_level=violence_level, eroticism_level=eroticism_level,
|
||||
)
|
||||
|
||||
chapter_obj.source_text = script_text
|
||||
@@ -1521,6 +1552,8 @@ async def generate_ai_script_nsfw(project_id: int, user: User, db: Session) -> N
|
||||
style = cfg.get("style", "")
|
||||
num_characters = cfg.get("num_characters", 5)
|
||||
num_chapters = cfg.get("num_chapters", 8)
|
||||
violence_level = cfg.get("violence_level", 0)
|
||||
eroticism_level = cfg.get("eroticism_level", 0)
|
||||
|
||||
ps.append_line(key, f"\n[Step 1] 生成 {num_characters} 个角色...\n")
|
||||
ps.append_line(key, "")
|
||||
@@ -1531,6 +1564,7 @@ async def generate_ai_script_nsfw(project_id: int, user: User, db: Session) -> N
|
||||
characters_data = await llm.generate_story_characters(
|
||||
genre=genre, subgenre=subgenre, premise=premise, style=style,
|
||||
num_characters=num_characters, usage_callback=_log_usage,
|
||||
violence_level=violence_level, eroticism_level=eroticism_level,
|
||||
)
|
||||
|
||||
has_narrator = any(c.get("name") in ("narrator", "旁白") for c in characters_data)
|
||||
|
||||
@@ -96,6 +96,9 @@ class LLMService:
|
||||
raw = "\n".join(inner).strip()
|
||||
if not raw:
|
||||
raise ValueError("LLM returned empty JSON after stripping markdown")
|
||||
if not raw.startswith(("{", "[")):
|
||||
logger.error(f"LLM refused or returned non-JSON. Raw (first 500): {raw[:500]}")
|
||||
raise ValueError(f"LLM拒绝响应:{raw[:200]}")
|
||||
try:
|
||||
return json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
@@ -245,6 +248,8 @@ class LLMService:
|
||||
style: str,
|
||||
num_characters: int,
|
||||
usage_callback: Optional[Callable[[int, int], None]] = None,
|
||||
violence_level: int = 0,
|
||||
eroticism_level: int = 0,
|
||||
) -> list[Dict]:
|
||||
genre_label = f"{genre}{'/' + subgenre if subgenre else ''}"
|
||||
system_prompt = (
|
||||
@@ -272,6 +277,10 @@ class LLMService:
|
||||
if style:
|
||||
parts.append(f"风格:{style}")
|
||||
parts.append(f"故事简介:{premise}")
|
||||
if violence_level > 0:
|
||||
parts.append(f"暴力程度:{violence_level}/10")
|
||||
if eroticism_level > 0:
|
||||
parts.append(f"色情程度:{eroticism_level}/10")
|
||||
parts.append(f"请为这个故事创作 {num_characters} 个主要角色,再加上旁白narrator,共 {num_characters + 1} 个角色。")
|
||||
user_message = "\n".join(parts)
|
||||
result = await self.stream_chat_json(system_prompt, user_message, max_tokens=4096, usage_callback=usage_callback)
|
||||
@@ -286,6 +295,8 @@ class LLMService:
|
||||
num_chapters: int,
|
||||
characters: list[Dict],
|
||||
usage_callback: Optional[Callable[[int, int], None]] = None,
|
||||
violence_level: int = 0,
|
||||
eroticism_level: int = 0,
|
||||
) -> list[Dict]:
|
||||
system_prompt = (
|
||||
"你是一个专业的故事创作助手。请根据给定的故事信息和角色列表,创作章节大纲。\n"
|
||||
@@ -295,12 +306,15 @@ class LLMService:
|
||||
)
|
||||
genre_label = f"{genre}{'/' + subgenre if subgenre else ''}"
|
||||
char_names = [c.get("name", "") for c in characters if c.get("name") not in ("narrator", "旁白")]
|
||||
violence_note = f"暴力程度:{violence_level}/10\n" if violence_level > 0 else ""
|
||||
eroticism_note = f"色情程度:{eroticism_level}/10\n" if eroticism_level > 0 else ""
|
||||
user_message = (
|
||||
f"故事类型:{genre_label}\n"
|
||||
+ (f"风格:{style}\n" if style else "")
|
||||
+ f"故事简介:{premise}\n"
|
||||
f"主要角色:{', '.join(char_names)}\n"
|
||||
f"请创作 {num_chapters} 章的大纲。"
|
||||
+ violence_note + eroticism_note
|
||||
+ f"请创作 {num_chapters} 章的大纲。"
|
||||
)
|
||||
result = await self.stream_chat_json(system_prompt, user_message, max_tokens=4096, usage_callback=usage_callback)
|
||||
return result.get("chapters", [])
|
||||
@@ -315,6 +329,8 @@ class LLMService:
|
||||
characters: list[Dict],
|
||||
on_token=None,
|
||||
usage_callback: Optional[Callable[[int, int], None]] = None,
|
||||
violence_level: int = 0,
|
||||
eroticism_level: int = 0,
|
||||
) -> str:
|
||||
char_names = [c.get("name", "") for c in characters if c.get("name") not in ("narrator", "旁白")]
|
||||
names_str = "、".join(char_names)
|
||||
@@ -337,10 +353,13 @@ class LLMService:
|
||||
"- 每行为一个独立片段,不要有空行\n"
|
||||
"- 直接输出脚本内容,不要有其他说明文字"
|
||||
)
|
||||
violence_note = f"暴力程度:{violence_level}/10\n" if violence_level > 0 else ""
|
||||
eroticism_note = f"色情程度:{eroticism_level}/10\n" if eroticism_level > 0 else ""
|
||||
user_message = (
|
||||
f"故事类型:{genre}\n"
|
||||
f"故事简介:{premise}\n\n"
|
||||
f"第 {chapter_index + 1} 章:{chapter_title}\n"
|
||||
f"故事简介:{premise}\n"
|
||||
+ violence_note + eroticism_note
|
||||
+ f"\n第 {chapter_index + 1} 章:{chapter_title}\n"
|
||||
f"章节内容:{chapter_summary}\n\n"
|
||||
"请创作这一章的完整对话脚本,包含旁白叙述和角色对话,内容充实,段落自然流畅。"
|
||||
)
|
||||
@@ -358,6 +377,8 @@ class LLMService:
|
||||
additional_chapters: int,
|
||||
characters: list[Dict],
|
||||
usage_callback: Optional[Callable[[int, int], None]] = None,
|
||||
violence_level: int = 0,
|
||||
eroticism_level: int = 0,
|
||||
) -> list[Dict]:
|
||||
system_prompt = (
|
||||
"你是一个专业的故事创作助手。请根据已有章节大纲,续写新的章节大纲。\n"
|
||||
@@ -373,12 +394,15 @@ class LLMService:
|
||||
f"第{ch.get('index', i) + 1}章「{ch.get('title', '')}」:{ch.get('summary', '')}"
|
||||
for i, ch in enumerate(existing_chapters)
|
||||
)
|
||||
violence_note = f"暴力程度:{violence_level}/10\n" if violence_level > 0 else ""
|
||||
eroticism_note = f"色情程度:{eroticism_level}/10\n" if eroticism_level > 0 else ""
|
||||
user_message = (
|
||||
f"故事类型:{genre_label}\n"
|
||||
+ (f"风格:{style}\n" if style else "")
|
||||
+ f"故事简介:{premise}\n"
|
||||
f"主要角色:{', '.join(char_names)}\n\n"
|
||||
f"已有章节大纲(共{len(existing_chapters)}章):\n{existing_summary}\n\n"
|
||||
f"主要角色:{', '.join(char_names)}\n"
|
||||
+ violence_note + eroticism_note
|
||||
+ f"\n已有章节大纲(共{len(existing_chapters)}章):\n{existing_summary}\n\n"
|
||||
f"请从第{start_index}章(索引{start_index})开始,续写{additional_chapters}章大纲,剧情要承接上文。"
|
||||
)
|
||||
result = await self.stream_chat_json(system_prompt, user_message, max_tokens=4096, usage_callback=usage_callback)
|
||||
|
||||
Reference in New Issue
Block a user