fix: tự động chạy ai
This commit is contained in:
+139
-68
@@ -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]
|
||||
)
|
||||
|
||||
+6
-6
@@ -150,12 +150,12 @@ def build_settings_tab():
|
||||
# Handle updating the existing backend with new details
|
||||
# If name was changed, it requires updating that as well but the update_backend method modifies existing object's properties in place based on its previous name
|
||||
result = ConfigAPIManager.update_backend(
|
||||
old_name,
|
||||
name=new_name.strip(),
|
||||
type=btype,
|
||||
base_url=url,
|
||||
api_key=key,
|
||||
model=model,
|
||||
old_name,
|
||||
new_name=new_name.strip(),
|
||||
type=btype,
|
||||
base_url=url,
|
||||
api_key=key,
|
||||
model=model,
|
||||
timeout=int(timeout)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user