Akhmad123 commited on
Commit
4ae11a0
Β·
verified Β·
1 Parent(s): 6f37e55

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -169
app.py CHANGED
@@ -14,12 +14,11 @@ from groq import Groq
14
  REPLICATE_API_TOKEN = "r8_OHfjZvEbVoU9fuioi4qfQ50OHdpAmqV4OAa5b"
15
  os.environ["REPLICATE_API_TOKEN"] = REPLICATE_API_TOKEN
16
 
17
- # === MASUKKAN API KEY GROQ DI SINI ===
18
  GROQ_API_KEY = "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"
19
  client = Groq(api_key=GROQ_API_KEY)
20
 
21
  MAX_CHAPTERS = 10
22
- PANELS_PER_CHAPTER = 4 # komik: 4 panel per bab
23
 
24
  # ============================
25
  # USER DB
@@ -48,7 +47,7 @@ def ensure_outputs_dir():
48
  os.makedirs("outputs", exist_ok=True)
49
 
50
  # ============================
51
- # AI TEXT GENERATOR (GROQ – KOMIK PANEL)
52
  # ============================
53
  def ai_generate(prompt):
54
  try:
@@ -61,6 +60,9 @@ def ai_generate(prompt):
61
  except Exception as e:
62
  return f"AI gagal menghasilkan teks. Error: {str(e)}"
63
 
 
 
 
64
  def generate_comic_panels(goal, style, tone, chapter_title, panels=PANELS_PER_CHAPTER):
65
  prompt = f"""
66
  Kamu adalah penulis komik anak Islami berbahasa Indonesia.
@@ -72,15 +74,15 @@ def generate_comic_panels(goal, style, tone, chapter_title, panels=PANELS_PER_CH
72
  Tone: {tone}
73
  Target: anak-anak SD, Islami, lembut, positif.
74
 
75
- Format output HARUS seperti ini (tanpa penjelasan tambahan):
76
 
77
- Panel 1: [deskripsi singkat adegan + dialog/narasi]
78
- Panel 2: [deskripsi singkat adegan + dialog/narasi]
79
  Panel 3: ...
 
80
  Panel {panels}: ...
81
 
82
- Jangan pakai bullet, jangan pakai tanda bintang, jangan pakai heading.
83
- Hanya baris-baris Panel X: ...
84
  """
85
  raw = ai_generate(prompt)
86
  lines = [l.strip() for l in raw.split("\n") if l.strip()]
@@ -93,7 +95,24 @@ def generate_comic_panels(goal, style, tone, chapter_title, panels=PANELS_PER_CH
93
  return panels_text[:panels]
94
 
95
  # ============================
96
- # REPLICATE IMAGE MODELS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  # ============================
98
  def generate_image_flux(prompt):
99
  try:
@@ -107,18 +126,6 @@ def generate_image_flux(prompt):
107
  return ""
108
  return ""
109
 
110
- def generate_image_sdxl(prompt):
111
- try:
112
- out = replicate.run(
113
- "stability-ai/sdxl-lite",
114
- input={"prompt": prompt}
115
- )
116
- if isinstance(out, list) and out:
117
- return out[0]
118
- except:
119
- return ""
120
- return ""
121
-
122
  def download_image(url, filename):
123
  if not url:
124
  return ""
@@ -134,9 +141,9 @@ def download_image(url, filename):
134
  return ""
135
 
136
  # ============================
137
- # PDF BUILDER (KOMIK)
138
  # ============================
139
- class EbookPDF(FPDF):
140
  def header(self):
141
  if self.page_no() == 1:
142
  return
@@ -149,17 +156,17 @@ class EbookPDF(FPDF):
149
  self.set_font("Helvetica", "I", 9)
150
  self.cell(0, 10, f"Page {self.page_no()}", 0, 0, "C")
151
 
152
- def build_ebook_pdf_with_images(username, goal, genre, tone, style, length,
153
- cover_brief, chapters_count):
154
 
155
  ensure_outputs_dir()
156
- pdf = EbookPDF(format="A4")
157
  pdf.set_margins(15, 15, 15)
158
 
159
- # COVER IMAGE (lebih realistik tapi tetap ramah anak)
160
  cover_prompt = (
161
- f"{cover_brief} | {goal} | {genre} | {style} | "
162
- "realistic comic cover, soft lighting, kid-friendly, Islamic, high detail"
163
  )
164
  cover_url = generate_image_flux(cover_prompt)
165
  cover_path = download_image(cover_url, f"cover_{uuid.uuid4().hex}.png")
@@ -171,15 +178,14 @@ def build_ebook_pdf_with_images(username, goal, genre, tone, style, length,
171
  pdf.image(cover_path, x=0, y=0, w=210)
172
  pdf.set_y(210)
173
  else:
174
- pdf.set_fill_color(230, 240, 255)
175
  pdf.rect(0, 0, 210, 297, "F")
176
  pdf.set_y(50)
177
 
178
  pdf.set_auto_page_break(True, margin=15)
179
  pdf.set_y(max(pdf.get_y(), 50))
180
 
181
- # COVER TEXT
182
- pdf.set_font("Helvetica", "B", 20)
183
  pdf.multi_cell(180, 10, safe_text(goal), 0)
184
 
185
  pdf.set_font("Helvetica", "", 12)
@@ -192,92 +198,64 @@ def build_ebook_pdf_with_images(username, goal, genre, tone, style, length,
192
  pdf.cell(0, 10, "Daftar Isi (Komik)", 0, 1)
193
  pdf.ln(5)
194
 
195
- pdf.set_font("Helvetica", "", 12)
196
  chapters_count = max(1, min(MAX_CHAPTERS, int(chapters_count)))
197
  chapters = [f"Bab {i}: Peristiwa Penting {i}" for i in range(1, chapters_count + 1)]
198
 
 
199
  for i, ch in enumerate(chapters, start=1):
200
  pdf.cell(0, 8, safe_text(f"{i}. {ch}"), 0, 1)
201
 
202
- # CHAPTERS β†’ KOMIK PANEL
203
  for idx, ch in enumerate(chapters, start=1):
204
  pdf.add_page()
205
  pdf.set_font("Helvetica", "B", 16)
206
  pdf.cell(0, 10, safe_text(ch), 0, 1)
207
  pdf.ln(4)
208
 
209
- # Generate panel texts (Groq)
210
  panels_text = generate_comic_panels(goal, style, tone, ch, PANELS_PER_CHAPTER)
211
 
212
- # Untuk tiap panel: gambar + teks
213
  for p_idx, panel in enumerate(panels_text, start=1):
214
- # ILLUSTRATION (lebih realistik, gaya komik)
215
- illus_prompt = (
216
- f"Realistic comic panel illustration of an Islamic children's story about {goal}. "
217
- f"Scene: {panel}. Style: semi-realistic, soft colors, expressive faces, "
218
- f"cinematic lighting, kid-friendly, high detail."
 
 
 
 
 
 
 
 
219
  )
220
- illus_url = generate_image_flux(illus_prompt)
221
- illus_path = download_image(illus_url, f"chapter_{idx}_panel_{p_idx}_{uuid.uuid4().hex}.png")
222
 
 
223
  pdf.set_font("Helvetica", "B", 12)
224
  pdf.cell(0, 8, safe_text(f"Panel {p_idx}"), 0, 1)
225
  pdf.ln(1)
226
 
 
227
  if illus_path:
228
  y_start = pdf.get_y()
229
- # Lebar panel komik
230
  pdf.image(illus_path, x=20, y=y_start, w=170)
231
  pdf.set_y(y_start + 80)
232
 
 
233
  pdf.set_font("Helvetica", "", 11)
234
  pdf.multi_cell(180, 6, safe_text(panel), 0)
235
  pdf.ln(3)
236
 
237
- filename = os.path.join("outputs", f"comic_{uuid.uuid4().hex}.pdf")
 
 
 
 
 
238
  pdf.output(filename)
239
  return filename
240
 
241
- # ============================
242
- # E-BOOK JSON GENERATOR (MASIH BISA DIPAKAI)
243
- # ============================
244
- def generate_ebook_json(username, tier,
245
- goal, genre, tone, style,
246
- platform, length, chapters):
247
-
248
- goal = normalize(goal, "Islamic children's story about good manners.")
249
- genre = normalize(genre, "Islamic Children Story (Comic)")
250
- tone = normalize(tone, "Friendly")
251
- style = normalize(style, "Comic style")
252
- platform = normalize(platform, "KDP")
253
- length = normalize(length, "Medium (30–50 pages)")
254
-
255
- try:
256
- chapters = int(chapters)
257
- except:
258
- chapters = 5
259
-
260
- chapters = max(1, min(MAX_CHAPTERS, chapters))
261
-
262
- chapter_titles = [f"Bab {i}: Judul Bab {i}" for i in range(1, chapters + 1)]
263
-
264
- data = {
265
- "type": "comic",
266
- "generated_at": now_iso(),
267
- "user": username,
268
- "tier": tier,
269
- "platform": platform,
270
- "genre": genre,
271
- "tone": tone,
272
- "writing_style": style,
273
- "length": length,
274
- "goal": goal,
275
- "chapters": chapter_titles,
276
- "panels_per_chapter": PANELS_PER_CHAPTER,
277
- }
278
-
279
- return json.dumps(data, ensure_ascii=False, indent=2)
280
-
281
  # ============================
282
  # LOGIN
283
  # ============================
@@ -295,6 +273,7 @@ with gr.Blocks() as demo:
295
  login_user = gr.State("")
296
  login_tier = gr.State("free")
297
 
 
298
  with gr.Group(visible=True) as login_ui:
299
  gr.Markdown("# πŸ” Login untuk Menggunakan AIPromptLab")
300
  username = gr.Textbox(label="Username")
@@ -302,72 +281,54 @@ with gr.Blocks() as demo:
302
  login_btn = gr.Button("Login")
303
  login_msg = gr.Markdown("")
304
 
 
305
  with gr.Group(visible=False) as main_ui:
306
 
307
- gr.Markdown("# 🌟 AIPromptLab β€” Comic JSON & PDF Generator (Groq + Replicate)")
308
 
309
  with gr.Tabs():
310
 
311
- with gr.Tab("Comic Prompt & PDF"):
 
 
 
 
312
 
313
- ebook_goal = gr.Textbox(label="Goal / Ide Komik")
314
- ebook_genre = gr.Dropdown(
315
  label="Genre",
316
  choices=[
317
  "Islamic Children Comic",
318
- "Islamic Adventure",
319
- "Islamic Moral Story",
320
- "Fantasy",
321
- "Education",
322
  "Adventure",
323
- "Mystery"
 
 
324
  ],
325
  value="Islamic Children Comic"
326
  )
327
- ebook_tone = gr.Dropdown(
 
328
  label="Tone",
329
  choices=[
330
  "Friendly",
331
  "Inspirational",
332
  "Educational",
333
- "Storytelling",
334
- "Humorous",
335
- "Calm"
336
  ],
337
  value="Friendly"
338
  )
339
- ebook_style = gr.Dropdown(
 
340
  label="Comic Style",
341
  choices=[
342
- "Semi-realistic comic",
343
- "Cartoon comic",
344
- "Pastel Islamic comic",
345
- "Manga-like",
346
- "Webtoon style"
347
  ],
348
- value="Semi-realistic comic"
349
- )
350
- ebook_platform = gr.Dropdown(
351
- label="Target Platform",
352
- choices=[
353
- "KDP",
354
- "Webtoon",
355
- "PDF / E-Learning",
356
- "Print"
357
- ],
358
- value="PDF / E-Learning"
359
- )
360
- ebook_length = gr.Dropdown(
361
- label="Length",
362
- choices=[
363
- "Short (1–2 chapters)",
364
- "Medium (3–5 chapters)",
365
- "Long (6–10 chapters)"
366
- ],
367
- value="Medium (3–5 chapters)"
368
  )
369
 
370
- ebook_chapters = gr.Slider(
371
  label="Jumlah Bab Komik",
372
  minimum=1,
373
  maximum=MAX_CHAPTERS,
@@ -375,18 +336,36 @@ with gr.Blocks() as demo:
375
  value=1
376
  )
377
 
378
- ebook_cover_brief = gr.Textbox(
379
  label="Cover Illustration Brief",
380
- value="Realistic comic cover of Islamic children in adventure, soft colors, warm light, friendly faces."
 
 
 
 
 
 
 
381
  )
382
 
383
- ebook_generate_btn = gr.Button("πŸš€ Generate Comic JSON")
384
- ebook_output = gr.Textbox(label="Comic JSON Output", lines=18)
 
 
 
 
 
 
 
 
 
 
 
385
 
386
- gr.Markdown("### πŸ“„ Generate PDF Komik (A4 + Cover + Panel Komik)")
387
- ebook_pdf_btn = gr.Button("Generate Comic PDF")
388
- ebook_pdf_file = gr.File(label="Download Comic PDF")
389
 
 
390
  def handle_login(username, password):
391
  ok, tier, msg = login(username, password)
392
  return (
@@ -404,53 +383,37 @@ with gr.Blocks() as demo:
404
  [login_msg, login_ui, main_ui, login_status, login_user, login_tier]
405
  )
406
 
407
- def handle_ebook_generate(login_status, login_user, login_tier,
408
- goal, genre, tone, style, platform, length, chapters):
409
- if not login_status:
410
- return "❌ Anda belum login."
411
- return generate_ebook_json(
412
- login_user, login_tier,
413
- goal, genre, tone, style,
414
- platform, length, chapters
415
- )
416
 
417
- ebook_generate_btn.click(
418
- handle_ebook_generate,
419
- [
420
- login_status, login_user, login_tier,
421
- ebook_goal, ebook_genre, ebook_tone,
422
- ebook_style, ebook_platform, ebook_length,
423
- ebook_chapters
424
- ],
425
- ebook_output
426
- )
427
-
428
- def handle_ebook_pdf(login_status, login_user,
429
- goal, genre, tone, style, length, cover_brief, chapters):
430
  if not login_status:
431
  return None
432
 
433
- goal_ = normalize(goal, "Islamic children's comic about good manners.")
434
- genre_ = normalize(genre, "Islamic Children Comic")
435
- tone_ = normalize(tone, "Friendly")
436
- style_ = normalize(style, "Semi-realistic comic")
437
- length_ = normalize(length, "Medium (3–5 chapters)")
438
- cover_ = normalize(cover_brief, "Realistic Islamic children comic cover.")
439
-
440
- pdf_path = build_ebook_pdf_with_images(
441
- login_user, goal_, genre_, tone_, style_, length_, cover_, chapters
 
 
442
  )
443
  return pdf_path
444
 
445
- ebook_pdf_btn.click(
446
- handle_ebook_pdf,
447
  [
448
  login_status, login_user,
449
- ebook_goal, ebook_genre, ebook_tone,
450
- ebook_style, ebook_length, ebook_cover_brief,
451
- ebook_chapters
452
  ],
453
- ebook_pdf_file
454
  )
455
 
456
  demo.launch(
 
14
  REPLICATE_API_TOKEN = "r8_OHfjZvEbVoU9fuioi4qfQ50OHdpAmqV4OAa5b"
15
  os.environ["REPLICATE_API_TOKEN"] = REPLICATE_API_TOKEN
16
 
 
17
  GROQ_API_KEY = "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"
18
  client = Groq(api_key=GROQ_API_KEY)
19
 
20
  MAX_CHAPTERS = 10
21
+ PANELS_PER_CHAPTER = 8 # sesuai permintaan
22
 
23
  # ============================
24
  # USER DB
 
47
  os.makedirs("outputs", exist_ok=True)
48
 
49
  # ============================
50
+ # AI TEXT GENERATOR (GROQ)
51
  # ============================
52
  def ai_generate(prompt):
53
  try:
 
60
  except Exception as e:
61
  return f"AI gagal menghasilkan teks. Error: {str(e)}"
62
 
63
+ # ============================
64
+ # PANEL GENERATOR
65
+ # ============================
66
  def generate_comic_panels(goal, style, tone, chapter_title, panels=PANELS_PER_CHAPTER):
67
  prompt = f"""
68
  Kamu adalah penulis komik anak Islami berbahasa Indonesia.
 
74
  Tone: {tone}
75
  Target: anak-anak SD, Islami, lembut, positif.
76
 
77
+ Format output HARUS seperti ini:
78
 
79
+ Panel 1: ...
80
+ Panel 2: ...
81
  Panel 3: ...
82
+ ...
83
  Panel {panels}: ...
84
 
85
+ Jangan pakai bullet, jangan pakai heading.
 
86
  """
87
  raw = ai_generate(prompt)
88
  lines = [l.strip() for l in raw.split("\n") if l.strip()]
 
95
  return panels_text[:panels]
96
 
97
  # ============================
98
+ # VISUAL PROMPT GENERATOR
99
+ # ============================
100
+ def convert_panel_to_visual_prompt(panel_text, character_mode, character_desc):
101
+ """
102
+ Mengubah teks panel menjadi prompt visual pastel cartoon.
103
+ """
104
+ base_style = (
105
+ "Cute pastel cartoon illustration, soft colors, round shapes, kid-friendly, "
106
+ "Islamic-friendly, simple background, environmental setting, high quality."
107
+ )
108
+
109
+ if character_mode == "Custom" and character_desc.strip():
110
+ return f"{base_style} Featuring: {character_desc}. Scene: {panel_text}."
111
+
112
+ return f"{base_style} Scene: {panel_text}."
113
+
114
+ # ============================
115
+ # IMAGE GENERATOR (FLUX)
116
  # ============================
117
  def generate_image_flux(prompt):
118
  try:
 
126
  return ""
127
  return ""
128
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  def download_image(url, filename):
130
  if not url:
131
  return ""
 
141
  return ""
142
 
143
  # ============================
144
+ # PDF BUILDER (COMIC)
145
  # ============================
146
+ class ComicPDF(FPDF):
147
  def header(self):
148
  if self.page_no() == 1:
149
  return
 
156
  self.set_font("Helvetica", "I", 9)
157
  self.cell(0, 10, f"Page {self.page_no()}", 0, 0, "C")
158
 
159
+ def build_comic_pdf(username, goal, genre, tone, style, cover_brief,
160
+ chapters_count, character_mode, character_desc, comic_name):
161
 
162
  ensure_outputs_dir()
163
+ pdf = ComicPDF(format="A4")
164
  pdf.set_margins(15, 15, 15)
165
 
166
+ # COVER
167
  cover_prompt = (
168
+ f"Cute pastel cartoon cover, soft colors, kid-friendly, Islamic-friendly, "
169
+ f"{cover_brief}, theme: {goal}"
170
  )
171
  cover_url = generate_image_flux(cover_prompt)
172
  cover_path = download_image(cover_url, f"cover_{uuid.uuid4().hex}.png")
 
178
  pdf.image(cover_path, x=0, y=0, w=210)
179
  pdf.set_y(210)
180
  else:
181
+ pdf.set_fill_color(240, 230, 255)
182
  pdf.rect(0, 0, 210, 297, "F")
183
  pdf.set_y(50)
184
 
185
  pdf.set_auto_page_break(True, margin=15)
186
  pdf.set_y(max(pdf.get_y(), 50))
187
 
188
+ pdf.set_font("Helvetica", "B", 22)
 
189
  pdf.multi_cell(180, 10, safe_text(goal), 0)
190
 
191
  pdf.set_font("Helvetica", "", 12)
 
198
  pdf.cell(0, 10, "Daftar Isi (Komik)", 0, 1)
199
  pdf.ln(5)
200
 
 
201
  chapters_count = max(1, min(MAX_CHAPTERS, int(chapters_count)))
202
  chapters = [f"Bab {i}: Peristiwa Penting {i}" for i in range(1, chapters_count + 1)]
203
 
204
+ pdf.set_font("Helvetica", "", 12)
205
  for i, ch in enumerate(chapters, start=1):
206
  pdf.cell(0, 8, safe_text(f"{i}. {ch}"), 0, 1)
207
 
208
+ # CHAPTERS
209
  for idx, ch in enumerate(chapters, start=1):
210
  pdf.add_page()
211
  pdf.set_font("Helvetica", "B", 16)
212
  pdf.cell(0, 10, safe_text(ch), 0, 1)
213
  pdf.ln(4)
214
 
215
+ # Generate panels
216
  panels_text = generate_comic_panels(goal, style, tone, ch, PANELS_PER_CHAPTER)
217
 
 
218
  for p_idx, panel in enumerate(panels_text, start=1):
219
+
220
+ # Visual prompt
221
+ visual_prompt = convert_panel_to_visual_prompt(
222
+ panel,
223
+ character_mode,
224
+ character_desc
225
+ )
226
+
227
+ # Generate image
228
+ illus_url = generate_image_flux(visual_prompt)
229
+ illus_path = download_image(
230
+ illus_url,
231
+ f"chapter_{idx}_panel_{p_idx}_{uuid.uuid4().hex}.png"
232
  )
 
 
233
 
234
+ # Panel title
235
  pdf.set_font("Helvetica", "B", 12)
236
  pdf.cell(0, 8, safe_text(f"Panel {p_idx}"), 0, 1)
237
  pdf.ln(1)
238
 
239
+ # Image
240
  if illus_path:
241
  y_start = pdf.get_y()
 
242
  pdf.image(illus_path, x=20, y=y_start, w=170)
243
  pdf.set_y(y_start + 80)
244
 
245
+ # Text
246
  pdf.set_font("Helvetica", "", 11)
247
  pdf.multi_cell(180, 6, safe_text(panel), 0)
248
  pdf.ln(3)
249
 
250
+ # OUTPUT FILE
251
+ if comic_name.strip():
252
+ filename = os.path.join("outputs", f"{comic_name}.pdf")
253
+ else:
254
+ filename = os.path.join("outputs", "comic_output.pdf")
255
+
256
  pdf.output(filename)
257
  return filename
258
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  # ============================
260
  # LOGIN
261
  # ============================
 
273
  login_user = gr.State("")
274
  login_tier = gr.State("free")
275
 
276
+ # LOGIN UI
277
  with gr.Group(visible=True) as login_ui:
278
  gr.Markdown("# πŸ” Login untuk Menggunakan AIPromptLab")
279
  username = gr.Textbox(label="Username")
 
281
  login_btn = gr.Button("Login")
282
  login_msg = gr.Markdown("")
283
 
284
+ # MAIN UI
285
  with gr.Group(visible=False) as main_ui:
286
 
287
+ gr.Markdown("# 🌟 AIPromptLab β€” Comic Generator 2.0 (Cartoon Pastel Edition)")
288
 
289
  with gr.Tabs():
290
 
291
+ with gr.Tab("Comic Generator"):
292
+
293
+ comic_name = gr.Textbox(label="Nama Komik (tanpa .pdf)")
294
+
295
+ comic_goal = gr.Textbox(label="Goal / Ide Cerita Komik")
296
 
297
+ comic_genre = gr.Dropdown(
 
298
  label="Genre",
299
  choices=[
300
  "Islamic Children Comic",
 
 
 
 
301
  "Adventure",
302
+ "Fantasy",
303
+ "Moral Story",
304
+ "Education"
305
  ],
306
  value="Islamic Children Comic"
307
  )
308
+
309
+ comic_tone = gr.Dropdown(
310
  label="Tone",
311
  choices=[
312
  "Friendly",
313
  "Inspirational",
314
  "Educational",
315
+ "Calm",
316
+ "Humorous"
 
317
  ],
318
  value="Friendly"
319
  )
320
+
321
+ comic_style = gr.Dropdown(
322
  label="Comic Style",
323
  choices=[
324
+ "Cartoon Pastel",
325
+ "Cute Cartoon",
326
+ "Soft Pastel"
 
 
327
  ],
328
+ value="Cartoon Pastel"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  )
330
 
331
+ chapters_slider = gr.Slider(
332
  label="Jumlah Bab Komik",
333
  minimum=1,
334
  maximum=MAX_CHAPTERS,
 
336
  value=1
337
  )
338
 
339
+ cover_brief = gr.Textbox(
340
  label="Cover Illustration Brief",
341
+ value="Cute pastel cartoon cover of Islamic children adventure."
342
+ )
343
+
344
+ # CHARACTER MODE
345
+ character_mode = gr.Dropdown(
346
+ label="Mode Karakter",
347
+ choices=["Otomatis", "Custom"],
348
+ value="Otomatis"
349
  )
350
 
351
+ character_desc = gr.Textbox(
352
+ label="Deskripsi Karakter (jika Custom)",
353
+ visible=False
354
+ )
355
+
356
+ def toggle_character_desc(mode):
357
+ return gr.update(visible=(mode == "Custom"))
358
+
359
+ character_mode.change(
360
+ toggle_character_desc,
361
+ [character_mode],
362
+ [character_desc]
363
+ )
364
 
365
+ generate_pdf_btn = gr.Button("πŸš€ Generate Comic PDF")
366
+ pdf_output = gr.File(label="Download Comic PDF")
 
367
 
368
+ # LOGIN HANDLER
369
  def handle_login(username, password):
370
  ok, tier, msg = login(username, password)
371
  return (
 
383
  [login_msg, login_ui, main_ui, login_status, login_user, login_tier]
384
  )
385
 
386
+ # PDF GENERATOR HANDLER
387
+ def handle_generate_pdf(login_status, login_user,
388
+ comic_name, goal, genre, tone, style,
389
+ chapters, cover_brief, character_mode, character_desc):
 
 
 
 
 
390
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  if not login_status:
392
  return None
393
 
394
+ pdf_path = build_comic_pdf(
395
+ login_user,
396
+ goal,
397
+ genre,
398
+ tone,
399
+ style,
400
+ cover_brief,
401
+ chapters,
402
+ character_mode,
403
+ character_desc,
404
+ comic_name
405
  )
406
  return pdf_path
407
 
408
+ generate_pdf_btn.click(
409
+ handle_generate_pdf,
410
  [
411
  login_status, login_user,
412
+ comic_name, comic_goal, comic_genre, comic_tone,
413
+ comic_style, chapters_slider, cover_brief,
414
+ character_mode, character_desc
415
  ],
416
+ pdf_output
417
  )
418
 
419
  demo.launch(