fix: tự động chạy ai

This commit is contained in:
2026-07-10 07:24:34 +07:00
parent c3a69d145b
commit f4322ff815
16 changed files with 529 additions and 164 deletions
+139 -68
View File
@@ -3,6 +3,7 @@ from datetime import datetime
import json
import re
import traceback
import os
from locales.i18n import t
from services.novel_generator import OutlineParser
@@ -15,7 +16,48 @@ import logging
logger = logging.getLogger(__name__)
def build_create_tab():
# ==================== DRAFT PERSISTENCE ====================
DRAFT_PATH = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "data", "create_draft.json"
)
DRAFT_FIELDS = [
"genre", "sub_genres", "style", "title", "suggest_title_prompt",
"num_main", "num_sub", "character", "suggest_char_prompt",
"world", "suggest_world_prompt", "plot", "suggest_plot_prompt",
"custom_outline", "total_chapters", "memory_type", "memory_chapters",
"use_reflection", "outline",
]
def _save_create_draft(d: dict):
try:
os.makedirs(os.path.dirname(DRAFT_PATH), exist_ok=True)
with open(DRAFT_PATH, "w", encoding="utf-8") as f:
json.dump(d, f, ensure_ascii=False)
except Exception as e:
logger.error(f"Save create draft failed: {e}")
def _load_create_draft() -> dict:
try:
if os.path.exists(DRAFT_PATH):
with open(DRAFT_PATH, "r", encoding="utf-8") as f:
return json.load(f)
except Exception as e:
logger.error(f"Load create draft failed: {e}")
return {}
def _clear_create_draft():
try:
if os.path.exists(DRAFT_PATH):
os.remove(DRAFT_PATH)
except Exception as e:
logger.error(f"Clear create draft failed: {e}")
def build_create_tab(demo=None):
"""Xây dựng giao diện Tab Sáng tác từ đầu"""
with gr.Tab(t("tabs.create")):
gr.Markdown(f"### 🪄 {t('create.header')}")
@@ -74,51 +116,51 @@ def build_create_tab():
character_input = gr.Textbox(
label=t("create.char_setting"),
placeholder=t("create.char_setting_placeholder"),
lines=5, interactive=False
lines=5, interactive=True
)
with gr.Group():
with gr.Row():
num_main_chars = gr.Number(label=t("create.num_main_chars"), value=2, minimum=1, maximum=10, step=1, scale=1)
num_sub_chars = gr.Number(label=t("create.num_sub_chars"), value=3, minimum=0, maximum=20, step=1, scale=1)
with gr.Row():
suggest_char_prompt = gr.Textbox(show_label=False, placeholder=t("create.custom_prompt_placeholder"), lines=1, interactive=False, scale=4)
suggest_char_btn = gr.Button(t("create.suggest_btn"), variant="secondary", size="sm", scale=1, interactive=False)
suggest_char_prompt = gr.Textbox(show_label=False, placeholder=t("create.custom_prompt_placeholder"), lines=1, interactive=True, scale=4)
suggest_char_btn = gr.Button(t("create.suggest_btn"), variant="secondary", size="sm", scale=1, interactive=True)
suggest_char_status = gr.Textbox(show_label=False, interactive=False, visible=False)
with gr.Column():
world_input = gr.Textbox(
label=t("create.world_setting"),
placeholder=t("create.world_setting_placeholder"),
lines=5, interactive=False
lines=5, interactive=True
)
with gr.Group():
with gr.Row():
suggest_world_prompt = gr.Textbox(show_label=False, placeholder=t("create.custom_prompt_placeholder"), lines=1, interactive=False, scale=4)
suggest_world_btn = gr.Button(t("create.suggest_btn"), variant="secondary", size="sm", scale=1, interactive=False)
suggest_world_prompt = gr.Textbox(show_label=False, placeholder=t("create.custom_prompt_placeholder"), lines=1, interactive=True, scale=4)
suggest_world_btn = gr.Button(t("create.suggest_btn"), variant="secondary", size="sm", scale=1, interactive=True)
suggest_world_status = gr.Textbox(show_label=False, interactive=False, visible=False)
plot_input = gr.Textbox(
label=t("create.plot_idea"),
placeholder=t("create.plot_idea_placeholder"),
lines=3, interactive=False
lines=3, interactive=True
)
with gr.Group():
with gr.Row():
suggest_plot_prompt = gr.Textbox(show_label=False, placeholder=t("create.custom_prompt_placeholder"), lines=1, interactive=False, scale=4)
suggest_plot_btn = gr.Button(t("create.suggest_plot_btn"), variant="secondary", size="sm", scale=1, interactive=False)
suggest_plot_prompt = gr.Textbox(show_label=False, placeholder=t("create.custom_prompt_placeholder"), lines=1, interactive=True, scale=4)
suggest_plot_btn = gr.Button(t("create.suggest_plot_btn"), variant="secondary", size="sm", scale=1, interactive=True)
suggest_plot_status = gr.Textbox(show_label=False, interactive=False, visible=False)
with gr.Accordion("📝 3. Dàn ý truyện", open=False):
custom_outline_prompt = gr.Textbox(
label="Yêu cầu riêng/Chỉ dẫn bổ sung cho Dàn ý (Tùy chọn)",
placeholder="VD: Không có nữ chính, kết cục mở, nvc là người tu ma nhưng tính cách hài hước...",
lines=2, interactive=False
lines=2, interactive=True
)
with gr.Row():
total_chapters = gr.Number(
label=t("create.chapter_count"), value=20, minimum=1, maximum=200, step=1, scale=1, interactive=False
label=t("create.chapter_count"), value=20, minimum=1, maximum=200, step=1, scale=1, interactive=True
)
generate_outline_btn = gr.Button(t("create.gen_outline_btn"), variant="primary", size="lg", scale=3, interactive=False)
generate_outline_btn = gr.Button(t("create.gen_outline_btn"), variant="primary", size="lg", scale=3, interactive=True)
outline_output = gr.Textbox(label=t("create.outline_display"), lines=15, interactive=True)
outline_status = gr.Textbox(label=t("create.gen_status"), interactive=False)
@@ -132,8 +174,8 @@ def build_create_tab():
with gr.Column(scale=1):
use_reflection_checkbox = gr.Checkbox(label="Bật chế độ Tự kiểm duyệt (Self-Reflection)", value=False, info="AI tự đọc lại và sửa lỗi nháp. Tốn gấp đôi thời gian & Token.")
with gr.Row():
auto_generate_btn = gr.Button(t("create.start_gen_btn"), variant="primary", size="lg", interactive=False)
stop_btn = gr.Button(t("create.pause_gen_btn"), variant="stop", size="lg", interactive=False)
auto_generate_btn = gr.Button(t("create.start_gen_btn"), variant="primary", size="lg", interactive=True)
stop_btn = gr.Button(t("create.pause_gen_btn"), variant="stop", size="lg", interactive=True)
with gr.Row():
with gr.Column(scale=1):
@@ -182,7 +224,10 @@ def build_create_tab():
nm = int(num_main) if num_main else 2
ns = int(num_sub) if num_sub else 3
content, msg = gen.suggest_content("char", title, genre, sub_genres, "", "", custom_prompt, nm, ns)
yield gr.update(value=content if content else msg), gr.update(visible=False), gr.update(interactive=True)
if content:
yield gr.update(value=content), gr.update(visible=False), gr.update(interactive=True)
else:
yield gr.update(), gr.update(value=f"{msg}", visible=True), gr.update(interactive=True)
except Exception as e:
traceback.print_exc()
yield gr.update(), gr.update(value=f"❌ Lỗi: {str(e)}", visible=True), gr.update(interactive=True)
@@ -192,7 +237,10 @@ def build_create_tab():
try:
gen = app_state.get_generator()
content, msg = gen.suggest_content("world", title, genre, sub_genres, "", "", custom_prompt)
yield gr.update(value=content if content else msg), gr.update(visible=False), gr.update(interactive=True)
if content:
yield gr.update(value=content), gr.update(visible=False), gr.update(interactive=True)
else:
yield gr.update(), gr.update(value=f"{msg}", visible=True), gr.update(interactive=True)
except Exception as e:
traceback.print_exc()
yield gr.update(), gr.update(value=f"❌ Lỗi: {str(e)}", visible=True), gr.update(interactive=True)
@@ -202,7 +250,10 @@ def build_create_tab():
try:
gen = app_state.get_generator()
content, msg = gen.suggest_content("plot", title, genre, sub_genres, char_setting, world_setting, custom_prompt)
yield gr.update(value=content if content else msg), gr.update(visible=False), gr.update(interactive=True)
if content:
yield gr.update(value=content), gr.update(visible=False), gr.update(interactive=True)
else:
yield gr.update(), gr.update(value=f"{msg}", visible=True), gr.update(interactive=True)
except Exception as e:
traceback.print_exc()
yield gr.update(), gr.update(value=f"❌ Lỗi: {str(e)}", visible=True), gr.update(interactive=True)
@@ -218,6 +269,7 @@ def build_create_tab():
def on_auto_generate(title, genre, sub_genres, char_setting, world_setting, plot_idea, outline_text, mem_type, mem_chaps, use_reflection, selected_style, progress=gr.Progress()):
"""Tự động tạo toàn bộ tiểu thuyết"""
_clear_create_draft()
gen = app_state.get_generator()
# Cập nhật style vào config hiện tại
@@ -327,6 +379,75 @@ def build_create_tab():
app_state.stop_requested = True
return "⏸️ Đang dừng..."
# ==================== DRAFT PERSISTENCE ====================
draft_inputs = [
genre_dropdown, sub_genre_dropdown, create_style_dropdown,
title_input, suggest_title_prompt, num_main_chars, num_sub_chars,
character_input, suggest_char_prompt, world_input,
suggest_world_prompt, plot_input, suggest_plot_prompt,
custom_outline_prompt, total_chapters, memory_type,
memory_chapters, use_reflection_checkbox, outline_output,
]
def on_draft_change(*values):
d = dict(zip(DRAFT_FIELDS, values))
_save_create_draft(d)
return
for _comp in draft_inputs:
_comp.change(fn=on_draft_change, inputs=draft_inputs, outputs=[])
def on_load_draft():
d = _load_create_draft()
title = d.get("title", "")
character = d.get("character", "")
world = d.get("world", "")
plot = d.get("plot", "")
outline = d.get("outline", "")
return (
d.get("genre"),
d.get("sub_genres"),
d.get("style"),
title,
d.get("suggest_title_prompt"),
d.get("num_main", 2),
d.get("num_sub", 3),
d.get("character", ""),
gr.update(interactive=True),
gr.update(interactive=True),
d.get("world", ""),
gr.update(interactive=True),
gr.update(interactive=True),
d.get("plot", ""),
gr.update(interactive=True),
gr.update(interactive=True),
d.get("custom_outline", ""),
d.get("total_chapters", 20),
gr.update(interactive=True),
d.get("outline", ""),
gr.update(interactive=True),
gr.update(interactive=True),
d.get("memory_type", "Toàn văn"),
d.get("memory_chapters", 3),
bool(d.get("use_reflection", False)),
)
if demo is not None:
demo.load(
fn=on_load_draft,
inputs=None,
outputs=[
genre_dropdown, sub_genre_dropdown, create_style_dropdown,
title_input, suggest_title_prompt, num_main_chars, num_sub_chars,
character_input, suggest_char_prompt, suggest_char_btn,
world_input, suggest_world_prompt, suggest_world_btn,
plot_input, suggest_plot_prompt, suggest_plot_btn,
custom_outline_prompt, total_chapters, generate_outline_btn,
outline_output, auto_generate_btn, stop_btn,
memory_type, memory_chapters, use_reflection_checkbox,
],
)
# Bind events
suggest_title_btn.click(
fn=on_suggest_title,
@@ -370,53 +491,3 @@ def build_create_tab():
outputs=[chapter_content_display]
)
stop_btn.click(fn=on_stop, outputs=[generation_progress])
# Flow Enforcement Events
title_input.change(
fn=lambda t: [
gr.update(interactive=bool(t)),
gr.update(interactive=bool(t)),
gr.update(interactive=bool(t))
],
inputs=[title_input],
outputs=[character_input, suggest_char_prompt, suggest_char_btn]
)
character_input.change(
fn=lambda c: [
gr.update(interactive=bool(c)),
gr.update(interactive=bool(c)),
gr.update(interactive=bool(c))
],
inputs=[character_input],
outputs=[world_input, suggest_world_prompt, suggest_world_btn]
)
world_input.change(
fn=lambda w: [
gr.update(interactive=bool(w)),
gr.update(interactive=bool(w)),
gr.update(interactive=bool(w))
],
inputs=[world_input],
outputs=[plot_input, suggest_plot_prompt, suggest_plot_btn]
)
plot_input.change(
fn=lambda p: [
gr.update(interactive=bool(p)),
gr.update(interactive=bool(p)),
gr.update(interactive=bool(p))
],
inputs=[plot_input],
outputs=[total_chapters, custom_outline_prompt, generate_outline_btn]
)
outline_output.change(
fn=lambda o: [
gr.update(interactive=bool(o)),
gr.update(interactive=bool(o))
],
inputs=[outline_output],
outputs=[auto_generate_btn, stop_btn]
)