Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
# app.py
|
| 2 |
import gradio as gr
|
| 3 |
import json
|
| 4 |
from datetime import datetime
|
|
@@ -14,10 +13,10 @@ import replicate
|
|
| 14 |
REPLICATE_API_TOKEN = "r8_OHfjZvEbVoU9fuioi4qfQ50OHdpAmqV4OAa5b"
|
| 15 |
os.environ["REPLICATE_API_TOKEN"] = REPLICATE_API_TOKEN
|
| 16 |
|
| 17 |
-
MAX_CHAPTERS = 10
|
| 18 |
|
| 19 |
# ============================
|
| 20 |
-
# USER
|
| 21 |
# ============================
|
| 22 |
USER_DB = {
|
| 23 |
"akhmad": {"password": "12345", "tier": "super"},
|
|
@@ -33,6 +32,10 @@ def normalize(v, default=""):
|
|
| 33 |
return default
|
| 34 |
return str(v).strip()
|
| 35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
def now_iso():
|
| 37 |
return datetime.utcnow().isoformat() + "Z"
|
| 38 |
|
|
@@ -40,36 +43,33 @@ def ensure_outputs_dir():
|
|
| 40 |
os.makedirs("outputs", exist_ok=True)
|
| 41 |
|
| 42 |
# ============================
|
| 43 |
-
# REPLICATE
|
| 44 |
# ============================
|
| 45 |
-
def generate_image_flux(prompt
|
| 46 |
-
"""Flux Schnell FREE (cover)"""
|
| 47 |
try:
|
| 48 |
-
|
| 49 |
"black-forest-labs/flux-schnell-free",
|
| 50 |
input={"prompt": prompt}
|
| 51 |
)
|
| 52 |
-
if isinstance(
|
| 53 |
-
return
|
| 54 |
-
except
|
| 55 |
return ""
|
| 56 |
return ""
|
| 57 |
|
| 58 |
-
def generate_image_sdxl(prompt
|
| 59 |
-
"""SDXL Lite FREE (chapter illustrations)"""
|
| 60 |
try:
|
| 61 |
-
|
| 62 |
"stability-ai/sdxl-lite",
|
| 63 |
input={"prompt": prompt}
|
| 64 |
)
|
| 65 |
-
if isinstance(
|
| 66 |
-
return
|
| 67 |
-
except
|
| 68 |
return ""
|
| 69 |
return ""
|
| 70 |
|
| 71 |
-
def download_image(url
|
| 72 |
-
"""Download image safely"""
|
| 73 |
if not url:
|
| 74 |
return ""
|
| 75 |
ensure_outputs_dir()
|
|
@@ -80,50 +80,11 @@ def download_image(url: str, filename: str) -> str:
|
|
| 80 |
with open(path, "wb") as f:
|
| 81 |
f.write(r.content)
|
| 82 |
return path
|
| 83 |
-
except Exception:
|
| 84 |
-
return ""
|
| 85 |
-
|
| 86 |
-
# ============================
|
| 87 |
-
# E-BOOK JSON GENERATOR
|
| 88 |
-
# ============================
|
| 89 |
-
def generate_ebook_json(username, tier,
|
| 90 |
-
goal, genre, tone, style,
|
| 91 |
-
platform, length, chapters):
|
| 92 |
-
|
| 93 |
-
goal = normalize(goal, "Islamic children's story about good manners.")
|
| 94 |
-
genre = normalize(genre, "Islamic Children Story")
|
| 95 |
-
tone = normalize(tone, "Friendly")
|
| 96 |
-
style = normalize(style, "Storybook style")
|
| 97 |
-
platform = normalize(platform, "KDP")
|
| 98 |
-
length = normalize(length, "Medium (30–50 pages)")
|
| 99 |
-
|
| 100 |
-
try:
|
| 101 |
-
chapters = int(chapters)
|
| 102 |
except:
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
chapters = max(1, min(MAX_CHAPTERS, chapters))
|
| 106 |
-
|
| 107 |
-
chapter_titles = [f"Bab {i}: Judul Bab {i}" for i in range(1, chapters + 1)]
|
| 108 |
-
|
| 109 |
-
data = {
|
| 110 |
-
"type": "ebook",
|
| 111 |
-
"generated_at": now_iso(),
|
| 112 |
-
"user": username,
|
| 113 |
-
"tier": tier,
|
| 114 |
-
"platform": platform,
|
| 115 |
-
"genre": genre,
|
| 116 |
-
"tone": tone,
|
| 117 |
-
"writing_style": style,
|
| 118 |
-
"length": length,
|
| 119 |
-
"goal": goal,
|
| 120 |
-
"chapters": chapter_titles,
|
| 121 |
-
}
|
| 122 |
-
|
| 123 |
-
return json.dumps(data, ensure_ascii=False, indent=2)
|
| 124 |
|
| 125 |
# ============================
|
| 126 |
-
# PDF
|
| 127 |
# ============================
|
| 128 |
class EbookPDF(FPDF):
|
| 129 |
def header(self):
|
|
@@ -143,32 +104,40 @@ def build_ebook_pdf_with_images(username, goal, genre, tone, style, length,
|
|
| 143 |
|
| 144 |
ensure_outputs_dir()
|
| 145 |
pdf = EbookPDF(format="A4")
|
| 146 |
-
pdf.set_auto_page_break(auto=True, margin=15)
|
| 147 |
|
| 148 |
-
#
|
| 149 |
cover_prompt = f"{cover_brief} | {goal} | {genre} | {style} | pastel, kid-friendly, Islamic"
|
| 150 |
cover_url = generate_image_flux(cover_prompt)
|
| 151 |
cover_path = download_image(cover_url, f"cover_{uuid.uuid4().hex}.png")
|
| 152 |
|
| 153 |
-
# ===== COVER PAGE =====
|
| 154 |
pdf.add_page()
|
| 155 |
|
|
|
|
|
|
|
|
|
|
| 156 |
if cover_path:
|
| 157 |
pdf.image(cover_path, x=0, y=0, w=210)
|
| 158 |
-
pdf.set_y(210)
|
| 159 |
else:
|
| 160 |
pdf.set_fill_color(230, 240, 255)
|
| 161 |
pdf.rect(0, 0, 210, 297, "F")
|
| 162 |
pdf.set_y(50)
|
| 163 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
pdf.set_font("Helvetica", "B", 20)
|
| 165 |
-
pdf.multi_cell(0, 10, goal, 0, "L")
|
| 166 |
|
| 167 |
pdf.set_font("Helvetica", "", 12)
|
| 168 |
-
pdf.multi_cell(0, 7, f"Genre: {genre}", 0, "L")
|
| 169 |
-
pdf.multi_cell(0, 7, f"Tone: {tone} | Style: {style}", 0, "L")
|
| 170 |
|
| 171 |
-
#
|
| 172 |
pdf.add_page()
|
| 173 |
pdf.set_font("Helvetica", "B", 18)
|
| 174 |
pdf.cell(0, 10, "Daftar Isi", 0, 1)
|
|
@@ -179,28 +148,27 @@ def build_ebook_pdf_with_images(username, goal, genre, tone, style, length,
|
|
| 179 |
chapters = [f"Bab {i}: Peristiwa Penting {i}" for i in range(1, chapters_count + 1)]
|
| 180 |
|
| 181 |
for i, ch in enumerate(chapters, start=1):
|
| 182 |
-
pdf.cell(0, 8, f"{i}. {ch}", 0, 1)
|
| 183 |
|
| 184 |
-
#
|
| 185 |
body_paragraph = (
|
| 186 |
f"Cerita ini mengisahkan tentang {goal.lower()}, disampaikan dengan gaya {style.lower()} "
|
| 187 |
f"dan nuansa {tone.lower()}. Cerita dirancang agar mudah dipahami anak-anak, "
|
| 188 |
-
"mengandung nilai-nilai kebaikan
|
| 189 |
)
|
| 190 |
|
| 191 |
-
#
|
| 192 |
for idx, ch in enumerate(chapters, start=1):
|
| 193 |
pdf.add_page()
|
| 194 |
pdf.set_font("Helvetica", "B", 16)
|
| 195 |
-
pdf.cell(0, 10, ch, 0, 1)
|
| 196 |
pdf.ln(4)
|
| 197 |
|
| 198 |
-
#
|
| 199 |
illus_prompt = (
|
| 200 |
f"Illustration for chapter {idx} of an Islamic children's story about {goal}. "
|
| 201 |
-
f"Scene: {ch}. Style: {style}, tone {tone}, pastel colors
|
| 202 |
)
|
| 203 |
-
|
| 204 |
illus_url = generate_image_sdxl(illus_prompt)
|
| 205 |
illus_path = download_image(illus_url, f"chapter_{idx}_{uuid.uuid4().hex}.png")
|
| 206 |
|
|
@@ -211,7 +179,7 @@ def build_ebook_pdf_with_images(username, goal, genre, tone, style, length,
|
|
| 211 |
|
| 212 |
pdf.set_font("Helvetica", "", 12)
|
| 213 |
for _ in range(5):
|
| 214 |
-
pdf.multi_cell(0, 7, body_paragraph, 0, "L")
|
| 215 |
pdf.ln(2)
|
| 216 |
|
| 217 |
filename = os.path.join("outputs", f"ebook_{uuid.uuid4().hex}.pdf")
|
|
@@ -219,7 +187,46 @@ def build_ebook_pdf_with_images(username, goal, genre, tone, style, length,
|
|
| 219 |
return filename
|
| 220 |
|
| 221 |
# ============================
|
| 222 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
# ============================
|
| 224 |
def login(username, password):
|
| 225 |
if username in USER_DB and USER_DB[username]["password"] == password:
|
|
@@ -335,7 +342,9 @@ with gr.Blocks() as demo:
|
|
| 335 |
ebook_pdf_btn = gr.Button("Generate PDF E-book")
|
| 336 |
ebook_pdf_file = gr.File(label="Download E-book PDF")
|
| 337 |
|
| 338 |
-
#
|
|
|
|
|
|
|
| 339 |
def handle_login(username, password):
|
| 340 |
ok, tier, msg = login(username, password)
|
| 341 |
return (
|
|
@@ -353,42 +362,64 @@ with gr.Blocks() as demo:
|
|
| 353 |
[login_msg, login_ui, main_ui, login_status, login_user, login_tier]
|
| 354 |
)
|
| 355 |
|
| 356 |
-
#
|
|
|
|
|
|
|
| 357 |
def handle_ebook_generate(login_status, login_user, login_tier,
|
| 358 |
goal, genre, tone, style, platform, length, chapters):
|
| 359 |
if not login_status:
|
| 360 |
return "❌ Anda belum login."
|
| 361 |
-
return generate_ebook_json(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 362 |
|
| 363 |
ebook_generate_btn.click(
|
| 364 |
handle_ebook_generate,
|
| 365 |
-
[
|
| 366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
ebook_output
|
| 368 |
)
|
| 369 |
|
| 370 |
-
#
|
|
|
|
|
|
|
| 371 |
def handle_ebook_pdf(login_status, login_user,
|
| 372 |
goal, genre, tone, style, length, cover_brief, chapters):
|
| 373 |
if not login_status:
|
| 374 |
return None
|
|
|
|
| 375 |
goal_ = normalize(goal, "Islamic children's story about good manners.")
|
| 376 |
genre_ = normalize(genre, "Islamic Children Story")
|
| 377 |
tone_ = normalize(tone, "Friendly")
|
| 378 |
style_ = normalize(style, "Storybook style")
|
| 379 |
length_ = normalize(length, "Medium (30–50 pages)")
|
| 380 |
cover_ = normalize(cover_brief, "Pastel Islamic illustration of children reading together.")
|
| 381 |
-
|
|
|
|
|
|
|
|
|
|
| 382 |
return pdf_path
|
| 383 |
|
| 384 |
ebook_pdf_btn.click(
|
| 385 |
handle_ebook_pdf,
|
| 386 |
-
[
|
| 387 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
ebook_pdf_file
|
| 389 |
)
|
| 390 |
|
| 391 |
-
#
|
|
|
|
|
|
|
| 392 |
demo.launch(
|
| 393 |
server_name="0.0.0.0",
|
| 394 |
server_port=7860,
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import json
|
| 3 |
from datetime import datetime
|
|
|
|
| 13 |
REPLICATE_API_TOKEN = "r8_OHfjZvEbVoU9fuioi4qfQ50OHdpAmqV4OAa5b"
|
| 14 |
os.environ["REPLICATE_API_TOKEN"] = REPLICATE_API_TOKEN
|
| 15 |
|
| 16 |
+
MAX_CHAPTERS = 10
|
| 17 |
|
| 18 |
# ============================
|
| 19 |
+
# USER DB
|
| 20 |
# ============================
|
| 21 |
USER_DB = {
|
| 22 |
"akhmad": {"password": "12345", "tier": "super"},
|
|
|
|
| 32 |
return default
|
| 33 |
return str(v).strip()
|
| 34 |
|
| 35 |
+
def safe_text(text):
|
| 36 |
+
# Hanya izinkan ASCII 32–126 (FPDF tidak support Unicode)
|
| 37 |
+
return ''.join(c if 32 <= ord(c) <= 126 else ' ' for c in text)
|
| 38 |
+
|
| 39 |
def now_iso():
|
| 40 |
return datetime.utcnow().isoformat() + "Z"
|
| 41 |
|
|
|
|
| 43 |
os.makedirs("outputs", exist_ok=True)
|
| 44 |
|
| 45 |
# ============================
|
| 46 |
+
# REPLICATE (FREE MODELS)
|
| 47 |
# ============================
|
| 48 |
+
def generate_image_flux(prompt):
|
|
|
|
| 49 |
try:
|
| 50 |
+
out = replicate.run(
|
| 51 |
"black-forest-labs/flux-schnell-free",
|
| 52 |
input={"prompt": prompt}
|
| 53 |
)
|
| 54 |
+
if isinstance(out, list) and out:
|
| 55 |
+
return out[0]
|
| 56 |
+
except:
|
| 57 |
return ""
|
| 58 |
return ""
|
| 59 |
|
| 60 |
+
def generate_image_sdxl(prompt):
|
|
|
|
| 61 |
try:
|
| 62 |
+
out = replicate.run(
|
| 63 |
"stability-ai/sdxl-lite",
|
| 64 |
input={"prompt": prompt}
|
| 65 |
)
|
| 66 |
+
if isinstance(out, list) and out:
|
| 67 |
+
return out[0]
|
| 68 |
+
except:
|
| 69 |
return ""
|
| 70 |
return ""
|
| 71 |
|
| 72 |
+
def download_image(url, filename):
|
|
|
|
| 73 |
if not url:
|
| 74 |
return ""
|
| 75 |
ensure_outputs_dir()
|
|
|
|
| 80 |
with open(path, "wb") as f:
|
| 81 |
f.write(r.content)
|
| 82 |
return path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
except:
|
| 84 |
+
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
|
| 86 |
# ============================
|
| 87 |
+
# PDF BUILDER
|
| 88 |
# ============================
|
| 89 |
class EbookPDF(FPDF):
|
| 90 |
def header(self):
|
|
|
|
| 104 |
|
| 105 |
ensure_outputs_dir()
|
| 106 |
pdf = EbookPDF(format="A4")
|
|
|
|
| 107 |
|
| 108 |
+
# COVER IMAGE
|
| 109 |
cover_prompt = f"{cover_brief} | {goal} | {genre} | {style} | pastel, kid-friendly, Islamic"
|
| 110 |
cover_url = generate_image_flux(cover_prompt)
|
| 111 |
cover_path = download_image(cover_url, f"cover_{uuid.uuid4().hex}.png")
|
| 112 |
|
|
|
|
| 113 |
pdf.add_page()
|
| 114 |
|
| 115 |
+
# MATIKAN AUTO PAGE BREAK SAAT COVER
|
| 116 |
+
pdf.set_auto_page_break(False)
|
| 117 |
+
|
| 118 |
if cover_path:
|
| 119 |
pdf.image(cover_path, x=0, y=0, w=210)
|
| 120 |
+
pdf.set_y(210)
|
| 121 |
else:
|
| 122 |
pdf.set_fill_color(230, 240, 255)
|
| 123 |
pdf.rect(0, 0, 210, 297, "F")
|
| 124 |
pdf.set_y(50)
|
| 125 |
|
| 126 |
+
# AKTIFKAN KEMBALI AUTO PAGE BREAK
|
| 127 |
+
pdf.set_auto_page_break(True, margin=15)
|
| 128 |
+
|
| 129 |
+
# PAKSA Y AMAN
|
| 130 |
+
pdf.set_y(max(pdf.get_y(), 50))
|
| 131 |
+
|
| 132 |
+
# COVER TEXT
|
| 133 |
pdf.set_font("Helvetica", "B", 20)
|
| 134 |
+
pdf.multi_cell(0, 10, safe_text(goal), 0, "L")
|
| 135 |
|
| 136 |
pdf.set_font("Helvetica", "", 12)
|
| 137 |
+
pdf.multi_cell(0, 7, safe_text(f"Genre: {genre}"), 0, "L")
|
| 138 |
+
pdf.multi_cell(0, 7, safe_text(f"Tone: {tone} | Style: {style}"), 0, "L")
|
| 139 |
|
| 140 |
+
# TABLE OF CONTENTS
|
| 141 |
pdf.add_page()
|
| 142 |
pdf.set_font("Helvetica", "B", 18)
|
| 143 |
pdf.cell(0, 10, "Daftar Isi", 0, 1)
|
|
|
|
| 148 |
chapters = [f"Bab {i}: Peristiwa Penting {i}" for i in range(1, chapters_count + 1)]
|
| 149 |
|
| 150 |
for i, ch in enumerate(chapters, start=1):
|
| 151 |
+
pdf.cell(0, 8, safe_text(f"{i}. {ch}"), 0, 1)
|
| 152 |
|
| 153 |
+
# BODY TEMPLATE
|
| 154 |
body_paragraph = (
|
| 155 |
f"Cerita ini mengisahkan tentang {goal.lower()}, disampaikan dengan gaya {style.lower()} "
|
| 156 |
f"dan nuansa {tone.lower()}. Cerita dirancang agar mudah dipahami anak-anak, "
|
| 157 |
+
"mengandung nilai-nilai kebaikan."
|
| 158 |
)
|
| 159 |
|
| 160 |
+
# CHAPTERS
|
| 161 |
for idx, ch in enumerate(chapters, start=1):
|
| 162 |
pdf.add_page()
|
| 163 |
pdf.set_font("Helvetica", "B", 16)
|
| 164 |
+
pdf.cell(0, 10, safe_text(ch), 0, 1)
|
| 165 |
pdf.ln(4)
|
| 166 |
|
| 167 |
+
# ILLUSTRATION
|
| 168 |
illus_prompt = (
|
| 169 |
f"Illustration for chapter {idx} of an Islamic children's story about {goal}. "
|
| 170 |
+
f"Scene: {ch}. Style: {style}, tone {tone}, pastel colors."
|
| 171 |
)
|
|
|
|
| 172 |
illus_url = generate_image_sdxl(illus_prompt)
|
| 173 |
illus_path = download_image(illus_url, f"chapter_{idx}_{uuid.uuid4().hex}.png")
|
| 174 |
|
|
|
|
| 179 |
|
| 180 |
pdf.set_font("Helvetica", "", 12)
|
| 181 |
for _ in range(5):
|
| 182 |
+
pdf.multi_cell(0, 7, safe_text(body_paragraph), 0, "L")
|
| 183 |
pdf.ln(2)
|
| 184 |
|
| 185 |
filename = os.path.join("outputs", f"ebook_{uuid.uuid4().hex}.pdf")
|
|
|
|
| 187 |
return filename
|
| 188 |
|
| 189 |
# ============================
|
| 190 |
+
# E-BOOK JSON GENERATOR
|
| 191 |
+
# ============================
|
| 192 |
+
def generate_ebook_json(username, tier,
|
| 193 |
+
goal, genre, tone, style,
|
| 194 |
+
platform, length, chapters):
|
| 195 |
+
|
| 196 |
+
goal = normalize(goal, "Islamic children's story about good manners.")
|
| 197 |
+
genre = normalize(genre, "Islamic Children Story")
|
| 198 |
+
tone = normalize(tone, "Friendly")
|
| 199 |
+
style = normalize(style, "Storybook style")
|
| 200 |
+
platform = normalize(platform, "KDP")
|
| 201 |
+
length = normalize(length, "Medium (30–50 pages)")
|
| 202 |
+
|
| 203 |
+
try:
|
| 204 |
+
chapters = int(chapters)
|
| 205 |
+
except:
|
| 206 |
+
chapters = 5
|
| 207 |
+
|
| 208 |
+
chapters = max(1, min(MAX_CHAPTERS, chapters))
|
| 209 |
+
|
| 210 |
+
chapter_titles = [f"Bab {i}: Judul Bab {i}" for i in range(1, chapters + 1)]
|
| 211 |
+
|
| 212 |
+
data = {
|
| 213 |
+
"type": "ebook",
|
| 214 |
+
"generated_at": now_iso(),
|
| 215 |
+
"user": username,
|
| 216 |
+
"tier": tier,
|
| 217 |
+
"platform": platform,
|
| 218 |
+
"genre": genre,
|
| 219 |
+
"tone": tone,
|
| 220 |
+
"writing_style": style,
|
| 221 |
+
"length": length,
|
| 222 |
+
"goal": goal,
|
| 223 |
+
"chapters": chapter_titles,
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
return json.dumps(data, ensure_ascii=False, indent=2)
|
| 227 |
+
|
| 228 |
+
# ============================
|
| 229 |
+
# LOGIN
|
| 230 |
# ============================
|
| 231 |
def login(username, password):
|
| 232 |
if username in USER_DB and USER_DB[username]["password"] == password:
|
|
|
|
| 342 |
ebook_pdf_btn = gr.Button("Generate PDF E-book")
|
| 343 |
ebook_pdf_file = gr.File(label="Download E-book PDF")
|
| 344 |
|
| 345 |
+
# ============================
|
| 346 |
+
# LOGIN HANDLER
|
| 347 |
+
# ============================
|
| 348 |
def handle_login(username, password):
|
| 349 |
ok, tier, msg = login(username, password)
|
| 350 |
return (
|
|
|
|
| 362 |
[login_msg, login_ui, main_ui, login_status, login_user, login_tier]
|
| 363 |
)
|
| 364 |
|
| 365 |
+
# ============================
|
| 366 |
+
# E-BOOK GENERATE JSON
|
| 367 |
+
# ============================
|
| 368 |
def handle_ebook_generate(login_status, login_user, login_tier,
|
| 369 |
goal, genre, tone, style, platform, length, chapters):
|
| 370 |
if not login_status:
|
| 371 |
return "❌ Anda belum login."
|
| 372 |
+
return generate_ebook_json(
|
| 373 |
+
login_user, login_tier,
|
| 374 |
+
goal, genre, tone, style,
|
| 375 |
+
platform, length, chapters
|
| 376 |
+
)
|
| 377 |
|
| 378 |
ebook_generate_btn.click(
|
| 379 |
handle_ebook_generate,
|
| 380 |
+
[
|
| 381 |
+
login_status, login_user, login_tier,
|
| 382 |
+
ebook_goal, ebook_genre, ebook_tone,
|
| 383 |
+
ebook_style, ebook_platform, ebook_length,
|
| 384 |
+
ebook_chapters
|
| 385 |
+
],
|
| 386 |
ebook_output
|
| 387 |
)
|
| 388 |
|
| 389 |
+
# ============================
|
| 390 |
+
# E-BOOK GENERATE PDF
|
| 391 |
+
# ============================
|
| 392 |
def handle_ebook_pdf(login_status, login_user,
|
| 393 |
goal, genre, tone, style, length, cover_brief, chapters):
|
| 394 |
if not login_status:
|
| 395 |
return None
|
| 396 |
+
|
| 397 |
goal_ = normalize(goal, "Islamic children's story about good manners.")
|
| 398 |
genre_ = normalize(genre, "Islamic Children Story")
|
| 399 |
tone_ = normalize(tone, "Friendly")
|
| 400 |
style_ = normalize(style, "Storybook style")
|
| 401 |
length_ = normalize(length, "Medium (30–50 pages)")
|
| 402 |
cover_ = normalize(cover_brief, "Pastel Islamic illustration of children reading together.")
|
| 403 |
+
|
| 404 |
+
pdf_path = build_ebook_pdf_with_images(
|
| 405 |
+
login_user, goal_, genre_, tone_, style_, length_, cover_, chapters
|
| 406 |
+
)
|
| 407 |
return pdf_path
|
| 408 |
|
| 409 |
ebook_pdf_btn.click(
|
| 410 |
handle_ebook_pdf,
|
| 411 |
+
[
|
| 412 |
+
login_status, login_user,
|
| 413 |
+
ebook_goal, ebook_genre, ebook_tone,
|
| 414 |
+
ebook_style, ebook_length, ebook_cover_brief,
|
| 415 |
+
ebook_chapters
|
| 416 |
+
],
|
| 417 |
ebook_pdf_file
|
| 418 |
)
|
| 419 |
|
| 420 |
+
# ============================
|
| 421 |
+
# LAUNCH APP
|
| 422 |
+
# ============================
|
| 423 |
demo.launch(
|
| 424 |
server_name="0.0.0.0",
|
| 425 |
server_port=7860,
|