Akhmad123 commited on
Commit
6e6bdf8
·
verified ·
1 Parent(s): 53680c7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -87
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 # batas maksimal bab
18
 
19
  # ============================
20
- # USER DATABASE (SIMPLE)
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 IMAGE HELPERS (MODEL GRATIS + FALLBACK)
44
  # ============================
45
- def generate_image_flux(prompt: str) -> str:
46
- """Flux Schnell FREE (cover)"""
47
  try:
48
- output = replicate.run(
49
  "black-forest-labs/flux-schnell-free",
50
  input={"prompt": prompt}
51
  )
52
- if isinstance(output, list) and len(output) > 0:
53
- return output[0]
54
- except Exception:
55
  return ""
56
  return ""
57
 
58
- def generate_image_sdxl(prompt: str) -> str:
59
- """SDXL Lite FREE (chapter illustrations)"""
60
  try:
61
- output = replicate.run(
62
  "stability-ai/sdxl-lite",
63
  input={"prompt": prompt}
64
  )
65
- if isinstance(output, list) and len(output) > 0:
66
- return output[0]
67
- except Exception:
68
  return ""
69
  return ""
70
 
71
- def download_image(url: str, filename: str) -> str:
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
- chapters = 5
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 E-BOOK GENERATOR (A4) + IMAGES
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
- # ===== COVER IMAGE VIA FLUX (FREE) =====
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) # aman
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
- # ===== TABLE OF CONTENTS =====
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
- # ===== BODY TEMPLATE =====
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, dan mengajak pembaca untuk merenungkan makna di balik setiap peristiwa."
189
  )
190
 
191
- # ===== CHAPTERS =====
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
- # ===== ILLUSTRATION =====
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, kid-friendly, Islamic."
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
- # LOGIN HANDLER
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- # LOGIN LOGIC
 
 
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
- # E-BOOK GENERATE JSON
 
 
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(login_user, login_tier, goal, genre, tone, style, platform, length, chapters)
 
 
 
 
362
 
363
  ebook_generate_btn.click(
364
  handle_ebook_generate,
365
- [login_status, login_user, login_tier,
366
- ebook_goal, ebook_genre, ebook_tone, ebook_style, ebook_platform, ebook_length, ebook_chapters],
 
 
 
 
367
  ebook_output
368
  )
369
 
370
- # E-BOOK GENERATE PDF
 
 
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
- pdf_path = build_ebook_pdf_with_images(login_user, goal_, genre_, tone_, style_, length_, cover_, chapters)
 
 
 
382
  return pdf_path
383
 
384
  ebook_pdf_btn.click(
385
  handle_ebook_pdf,
386
- [login_status, login_user,
387
- ebook_goal, ebook_genre, ebook_tone, ebook_style, ebook_length, ebook_cover_brief, ebook_chapters],
 
 
 
 
388
  ebook_pdf_file
389
  )
390
 
391
- # LAUNCH
 
 
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,