HardbanRecordsLab commited on
Commit
e9ffb4e
·
verified ·
1 Parent(s): 436e716

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +126 -74
app.py CHANGED
@@ -1,4 +1,37 @@
1
- # Importujemy wszystkie potrzebne biblioteki
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import gradio as gr
3
  from transformers import pipeline as text_pipeline
4
  from diffusers import DiffusionPipeline
@@ -6,7 +39,6 @@ import torch
6
  import re
7
  from fpdf import FPDF
8
  from PIL import Image
9
- import os
10
  import io
11
  import time
12
 
@@ -14,124 +46,143 @@ import time
14
  LLM_MODEL = "mistralai/Mistral-7B-Instruct-v0.2"
15
  IMAGE_MODEL = "runwayml/stable-diffusion-v1-5"
16
 
17
- # --- Ładowanie Modeli (z obsługą błędów) ---
18
- # Ta sekcja pozostaje bez zmian, ładuje modele AI na starcie.
19
  try:
20
  text_generator = text_pipeline("text-generation", model=LLM_MODEL, torch_dtype=torch.bfloat16, device_map="auto")
21
  LLM_LOADED = True
22
  except Exception as e:
23
- print(f"Błąd ładowania LLM: {e}")
24
- text_generator = None; LLM_LOADED = False
25
  try:
26
  image_generator = DiffusionPipeline.from_pretrained(IMAGE_MODEL, torch_dtype=torch.float16, revision="fp16")
27
  image_generator.to("cuda")
28
  IMAGE_MODEL_LOADED = True
29
  except Exception as e:
30
- print(f"Błąd ładowania Image Model: {e}")
31
- image_generator = None; IMAGE_MODEL_LOADED = False
32
-
33
- # --- Funkcje pomocnicze ---
34
- def parse_steps_from_markdown(markdown_text):
35
- pattern = re.compile(r"^\d+\.\s*\*\*(.*?)\*\*", re.MULTILINE)
36
- steps = pattern.findall(markdown_text)
37
- return steps
38
-
39
- def generate_course_and_images(topic, progress=gr.Progress(track_tqdm=True)):
40
- """Generuje tekst kursu i obrazy, zwraca je do wyświetlenia i zapisania w stanie."""
 
 
 
 
 
 
 
 
41
  if not LLM_LOADED or not IMAGE_MODEL_LOADED:
42
- error_msg = "Błąd krytyczny: Jeden z modeli AI nie został załadowany."
43
- return error_msg, None, gr.State([]), gr.Button(interactive=False)
44
-
45
- if not topic:
46
- return "Proszę wpisać temat kursu.", None, gr.State([]), gr.Button(interactive=False)
47
 
48
  progress(0, desc="Generowanie tekstu kursu...")
49
  prompt = f"[INST] Jesteś ekspertem w tworzeniu kursów online. Twoim zadaniem jest stworzenie zwięzłego, 5-etapowego planu kursu DIY na podany temat. Temat kursu: \"{topic}\". Wygeneruj odpowiedź w formacie Markdown, która zawiera: 1. Chwytliwy tytuł kursu (jako nagłówek H1). 2. Pięć ponumerowanych kroków kursu. Każdy krok powinien mieć tytuł (pogrubiony) i krótki, 2-3 zdaniowy opis. Nie dodawaj żadnych wstępów, podsumowań ani dodatkowych komentarzy. Trzymaj się ściśle podanej struktury. [/INST]"
50
  response = text_generator(prompt, max_new_tokens=1024, do_sample=True, temperature=0.7, top_p=0.95)
51
  course_text = response[0]['generated_text'].split('[/INST]')[-1].strip()
52
 
53
- steps = parse_steps_from_markdown(course_text)
54
- if not steps:
55
- return course_text, None, gr.State([]), gr.Button(interactive=False)
56
-
57
  generated_images = []
58
- for i, step_title in enumerate(steps):
59
- progress((i + 1) / len(steps), desc=f"Generowanie obrazka dla kroku {i+1}/{len(steps)}...")
60
- image_prompt = f"cinematic photo of '{step_title}', professional photography, high detail, 8k"
61
- image = image_generator(image_prompt, num_inference_steps=25).images[0]
62
- generated_images.append(image)
63
-
64
- # Zwracamy wyniki i aktywujemy przycisk PDF
65
- return course_text, generated_images, gr.State(generated_images), gr.Button(interactive=True)
66
-
67
- def generate_pdf_file(course_text, images_state, progress=gr.Progress(track_tqdm=True)):
68
- """Tworzy plik PDF z tekstu i obrazów i zwraca ścieżkę do niego."""
69
- if not course_text or not images_state:
 
 
 
 
 
 
 
 
70
  return None
71
 
72
- progress(0, desc="Inicjalizacja PDF...")
73
  pdf = FPDF()
74
  pdf.add_page()
 
 
 
 
 
 
 
 
75
 
76
- # Dodajemy czcionkę obsługującą polskie znaki
77
- pdf.add_font('DejaVu', '', 'DejaVuSans.ttf', uni=True)
78
- pdf.set_font('DejaVu', '', 12)
79
 
80
- # Zapisujemy obrazy tymczasowo, aby dodać je do PDF
81
  temp_image_paths = []
82
  for i, img in enumerate(images_state):
83
  path = f"/tmp/temp_image_{i}.png"
84
  img.save(path)
85
  temp_image_paths.append(path)
86
 
87
- # Przetwarzanie tekstu i dodawanie do PDF
88
- lines = course_text.split('\n')
89
  image_counter = 0
90
- for i, line in enumerate(lines):
91
- progress((i + 1) / len(lines), desc=f"Dodawanie treści do PDF...")
92
- if line.startswith('# '):
93
- pdf.set_font('DejaVu', 'B', 24)
94
- pdf.multi_cell(0, 10, line[2:].strip())
95
- pdf.ln(10)
96
- elif re.match(r"^\d+\.\s*\*\*(.*?)\*\*", line):
97
- pdf.set_font('DejaVu', 'B', 16)
98
- pdf.multi_cell(0, 8, line.strip())
99
  pdf.ln(4)
100
- # Dodaj obrazek po tytule kroku
101
  if image_counter < len(temp_image_paths):
102
  pdf.image(temp_image_paths[image_counter], x=None, y=None, w=180)
103
  pdf.ln(5)
104
  image_counter += 1
105
- else:
106
- pdf.set_font('DejaVu', '', 12)
107
- pdf.multi_cell(0, 6, line.strip())
108
- pdf.ln(2)
109
 
110
- # Zapisujemy PDF i sprzątamy
 
 
 
111
  pdf_output_path = f"/tmp/kurs_{int(time.time())}.pdf"
112
  pdf.output(pdf_output_path)
113
  for path in temp_image_paths:
114
  os.remove(path)
115
-
116
  return pdf_output_path
117
 
118
  # --- Budowa Interfejsu Gradio ---
119
  with gr.Blocks(theme=gr.themes.Soft(), title="Kreator Kursów DIY") as demo:
120
  gr.Markdown("# 🎨 Kreator Kursów DIY")
121
- gr.Markdown("Wpisz temat, a AI wygeneruje dla Ciebie kompletny, ilustrowany kurs, gotowy do pobrania jako PDF!")
122
 
123
- # Komponent State do przechowywania obrazów między krokami
124
  images_state = gr.State([])
125
 
126
  with gr.Row():
127
- topic_input = gr.Textbox(label="Temat kursu", placeholder="np. Jak zrobić świecę sojową w domu?", lines=2, scale=4)
128
-
129
- generate_button = gr.Button("Wygeneruj Kurs z Obrazkami!", variant="primary")
130
 
131
  gr.Markdown("---")
132
 
133
- gr.Markdown("### 📖 Twój Kurs")
134
- output_display = gr.Markdown("Tutaj pojawi się tekst Twojego kursu...")
 
 
 
 
 
 
 
 
 
 
135
 
136
  gr.Markdown("### 🖼️ Ilustracje do Kursu")
137
  image_gallery = gr.Gallery(label="Wygenerowane obrazy", show_label=False, elem_id="gallery", columns=5, height="auto")
@@ -141,16 +192,17 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Kreator Kursów DIY") as demo:
141
 
142
  file_output = gr.File(label="Pobierz gotowy plik PDF")
143
 
144
- # Definicje akcji dla przycisków
 
145
  generate_button.click(
146
- fn=generate_course_and_images,
147
- inputs=topic_input,
148
- outputs=[output_display, image_gallery, images_state, pdf_button]
149
  )
150
 
151
  pdf_button.click(
152
- fn=generate_pdf_file,
153
- inputs=[output_display, images_state],
154
  outputs=file_output
155
  )
156
 
 
1
+ # ==============================================================================
2
+ # KROK NAPRAWCZY: Wymuszona instalacja brakujących bibliotek
3
+ # Ten blok kodu rozwiązuje problem z ignorowaniem pliku requirements.txt
4
+ # ==============================================================================
5
+ import os
6
+ import subprocess
7
+ import sys
8
+
9
+ def install_packages():
10
+ packages = [
11
+ "transformers>=4.38.1",
12
+ "torch>=2.2.0",
13
+ "accelerate>=0.27.2",
14
+ "diffusers>=0.26.3",
15
+ "fpdf2",
16
+ "Pillow"
17
+ ]
18
+ for package in packages:
19
+ try:
20
+ # Sprawdź, czy pakiet jest już zainstalowany
21
+ __import__(package.split('>')[0].split('=')[0].split('<')[0])
22
+ print(f"{package} jest już zainstalowany.")
23
+ except ImportError:
24
+ print(f"Instalowanie {package}...")
25
+ subprocess.check_call([sys.executable, "-m", "pip", "install", package])
26
+
27
+ # Uruchom instalację tylko raz
28
+ if 'PACKAGES_INSTALLED' not in os.environ:
29
+ install_packages()
30
+ os.environ['PACKAGES_INSTALLED'] = 'TRUE'
31
+
32
+ # ==============================================================================
33
+ # Reszta kodu aplikacji (bez zmian w stosunku do poprzedniej wersji)
34
+ # ==============================================================================
35
  import gradio as gr
36
  from transformers import pipeline as text_pipeline
37
  from diffusers import DiffusionPipeline
 
39
  import re
40
  from fpdf import FPDF
41
  from PIL import Image
 
42
  import io
43
  import time
44
 
 
46
  LLM_MODEL = "mistralai/Mistral-7B-Instruct-v0.2"
47
  IMAGE_MODEL = "runwayml/stable-diffusion-v1-5"
48
 
49
+ # --- Ładowanie Modeli ---
 
50
  try:
51
  text_generator = text_pipeline("text-generation", model=LLM_MODEL, torch_dtype=torch.bfloat16, device_map="auto")
52
  LLM_LOADED = True
53
  except Exception as e:
54
+ print(f"Błąd ładowania LLM: {e}"); text_generator = None; LLM_LOADED = False
 
55
  try:
56
  image_generator = DiffusionPipeline.from_pretrained(IMAGE_MODEL, torch_dtype=torch.float16, revision="fp16")
57
  image_generator.to("cuda")
58
  IMAGE_MODEL_LOADED = True
59
  except Exception as e:
60
+ print(f"Błąd ładowania Image Model: {e}"); image_generator = None; IMAGE_MODEL_LOADED = False
61
+
62
+ # --- Funkcje Aplikacji (bez zmian) ---
63
+
64
+ def parse_course_to_structure(markdown_text):
65
+ course_data = {'title': "Nowy Kurs", 'steps': []}
66
+ title_match = re.search(r"^#\s*(.*)", markdown_text, re.MULTILINE)
67
+ if title_match:
68
+ course_data['title'] = title_match.group(1).strip()
69
+ step_pattern = re.compile(r"(\d+\.\s*\*\*(.*?)\*\*)\s*([\s\S]*?)(?=\n\d+\.|\Z)", re.MULTILINE)
70
+ steps_found = step_pattern.findall(markdown_text)
71
+ for _, step_title, step_description in steps_found:
72
+ course_data['steps'].append({
73
+ 'title': step_title.strip(),
74
+ 'description': step_description.strip()
75
+ })
76
+ return course_data
77
+
78
+ def generate_course_structure_and_images(topic, progress=gr.Progress(track_tqdm=True)):
79
  if not LLM_LOADED or not IMAGE_MODEL_LOADED:
80
+ return None, gr.State([]), gr.State({}), gr.update(visible=False), gr.update(interactive=False)
 
 
 
 
81
 
82
  progress(0, desc="Generowanie tekstu kursu...")
83
  prompt = f"[INST] Jesteś ekspertem w tworzeniu kursów online. Twoim zadaniem jest stworzenie zwięzłego, 5-etapowego planu kursu DIY na podany temat. Temat kursu: \"{topic}\". Wygeneruj odpowiedź w formacie Markdown, która zawiera: 1. Chwytliwy tytuł kursu (jako nagłówek H1). 2. Pięć ponumerowanych kroków kursu. Każdy krok powinien mieć tytuł (pogrubiony) i krótki, 2-3 zdaniowy opis. Nie dodawaj żadnych wstępów, podsumowań ani dodatkowych komentarzy. Trzymaj się ściśle podanej struktury. [/INST]"
84
  response = text_generator(prompt, max_new_tokens=1024, do_sample=True, temperature=0.7, top_p=0.95)
85
  course_text = response[0]['generated_text'].split('[/INST]')[-1].strip()
86
 
87
+ course_data = parse_course_to_structure(course_text)
88
+
89
+ progress(0.2, desc="Generowanie obrazków...")
 
90
  generated_images = []
91
+ if course_data['steps']:
92
+ for i, step in enumerate(course_data['steps']):
93
+ progress(0.2 + (i + 1) / len(course_data['steps']) * 0.8, desc=f"Generowanie obrazka dla: {step['title']}")
94
+ image_prompt = f"cinematic photo of '{step['title']}', professional photography, high detail, 8k"
95
+ image = image_generator(image_prompt, num_inference_steps=25).images[0]
96
+ generated_images.append(image)
97
+
98
+ updates = [gr.update(value=course_data['title'])]
99
+ for i in range(5):
100
+ if i < len(course_data['steps']):
101
+ updates.append(gr.update(value=course_data['steps'][i]['title']))
102
+ updates.append(gr.update(value=course_data['steps'][i]['description']))
103
+ else:
104
+ updates.append(gr.update(value=""))
105
+ updates.append(gr.update(value=""))
106
+
107
+ return generated_images, gr.State(generated_images), gr.update(visible=True), gr.update(interactive=True), *updates
108
+
109
+ def generate_pdf_from_ui(images_state, course_title, *args):
110
+ if not course_title or not images_state:
111
  return None
112
 
 
113
  pdf = FPDF()
114
  pdf.add_page()
115
+ # Ważne: W środowisku HF Spaces może nie być czcionki 'DejaVu'.
116
+ # Użyjemy standardowej, ale polskie znaki mogą nie działać poprawnie w PDF.
117
+ try:
118
+ pdf.add_font('DejaVu', '', 'DejaVuSans.ttf', uni=True)
119
+ pdf.set_font('DejaVu', '', 12)
120
+ except RuntimeError:
121
+ print("Czcionka DejaVu nie znaleziona, używam 'Arial'. Polskie znaki mogą nie być widoczne w PDF.")
122
+ pdf.set_font('Arial', '', 12)
123
 
124
+ pdf.set_font_size(24)
125
+ pdf.multi_cell(0, 10, course_title.encode('latin-1', 'replace').decode('latin-1'))
126
+ pdf.ln(10)
127
 
 
128
  temp_image_paths = []
129
  for i, img in enumerate(images_state):
130
  path = f"/tmp/temp_image_{i}.png"
131
  img.save(path)
132
  temp_image_paths.append(path)
133
 
134
+ step_data = list(args)
 
135
  image_counter = 0
136
+ for i in range(0, len(step_data), 2):
137
+ step_title = step_data[i]
138
+ step_description = step_data[i+1]
139
+
140
+ if step_title:
141
+ pdf.set_font_size(16)
142
+ pdf.multi_cell(0, 8, f"Krok {i//2 + 1}: {step_title}".encode('latin-1', 'replace').decode('latin-1'))
 
 
143
  pdf.ln(4)
144
+
145
  if image_counter < len(temp_image_paths):
146
  pdf.image(temp_image_paths[image_counter], x=None, y=None, w=180)
147
  pdf.ln(5)
148
  image_counter += 1
 
 
 
 
149
 
150
+ pdf.set_font_size(12)
151
+ pdf.multi_cell(0, 6, step_description.encode('latin-1', 'replace').decode('latin-1'))
152
+ pdf.ln(10)
153
+
154
  pdf_output_path = f"/tmp/kurs_{int(time.time())}.pdf"
155
  pdf.output(pdf_output_path)
156
  for path in temp_image_paths:
157
  os.remove(path)
 
158
  return pdf_output_path
159
 
160
  # --- Budowa Interfejsu Gradio ---
161
  with gr.Blocks(theme=gr.themes.Soft(), title="Kreator Kursów DIY") as demo:
162
  gr.Markdown("# 🎨 Kreator Kursów DIY")
163
+ gr.Markdown("Wpisz temat, a AI wygeneruje dla Ciebie w pełni edytowalny, ilustrowany kurs!")
164
 
 
165
  images_state = gr.State([])
166
 
167
  with gr.Row():
168
+ topic_input = gr.Textbox(label="Temat kursu", placeholder="np. Jak zrobić las w słoiku?", lines=2, scale=4)
169
+
170
+ generate_button = gr.Button("Wygeneruj Kurs!", variant="primary")
171
 
172
  gr.Markdown("---")
173
 
174
+ with gr.Box(visible=False) as editor_box:
175
+ gr.Markdown("### ✍️ Edytor Kursu")
176
+ gr.Markdown("Możesz teraz dowolnie modyfikować wygenerowaną treść.")
177
+
178
+ course_title_editor = gr.Textbox(label="Tytuł Główny Kursu")
179
+
180
+ step_editors = []
181
+ for i in range(5):
182
+ with gr.Accordion(f"Krok {i+1}", open=True):
183
+ step_title = gr.Textbox(label="Tytuł kroku")
184
+ step_description = gr.Textbox(label="Opis kroku", lines=4)
185
+ step_editors.extend([step_title, step_description])
186
 
187
  gr.Markdown("### 🖼️ Ilustracje do Kursu")
188
  image_gallery = gr.Gallery(label="Wygenerowane obrazy", show_label=False, elem_id="gallery", columns=5, height="auto")
 
192
 
193
  file_output = gr.File(label="Pobierz gotowy plik PDF")
194
 
195
+ all_editor_fields = [course_title_editor] + step_editors
196
+
197
  generate_button.click(
198
+ fn=generate_course_structure_and_images,
199
+ inputs=[topic_input],
200
+ outputs=[image_gallery, images_state, editor_box, pdf_button] + all_editor_fields
201
  )
202
 
203
  pdf_button.click(
204
+ fn=generate_pdf_from_ui,
205
+ inputs=[images_state] + all_editor_fields,
206
  outputs=file_output
207
  )
208