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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -79
app.py CHANGED
@@ -1,144 +1,157 @@
1
- # Importujemy potrzebne biblioteki
2
  import gradio as gr
3
  from transformers import pipeline as text_pipeline
4
  from diffusers import DiffusionPipeline
5
  import torch
6
  import re
 
 
 
 
 
7
 
8
  # --- Konfiguracja Modeli ---
9
-
10
- # Model językowy do generowania tekstu
11
  LLM_MODEL = "mistralai/Mistral-7B-Instruct-v0.2"
12
- # Model do generowania obrazów - v1.5 jest sprawdzony i działa dobrze na darmowym sprzęcie
13
  IMAGE_MODEL = "runwayml/stable-diffusion-v1-5"
14
 
15
- # --- Ładowanie Modeli ---
16
- # Ładujemy modele na starcie aplikacji, aby uniknąć wielokrotnego ładowania.
17
- # To może zająć kilka minut przy pierwszym uruchomieniu.
18
-
19
- # Ładowanie modelu LLM
20
  try:
21
- text_generator = text_pipeline(
22
- "text-generation",
23
- model=LLM_MODEL,
24
- torch_dtype=torch.bfloat16,
25
- device_map="auto"
26
- )
27
  LLM_LOADED = True
28
  except Exception as e:
29
  print(f"Błąd ładowania LLM: {e}")
30
- text_generator = None
31
- LLM_LOADED = False
32
-
33
- # Ładowanie modelu Text-to-Image
34
  try:
35
- image_generator = DiffusionPipeline.from_pretrained(
36
- IMAGE_MODEL,
37
- torch_dtype=torch.float16,
38
- revision="fp16"
39
- )
40
  image_generator.to("cuda")
41
  IMAGE_MODEL_LOADED = True
42
  except Exception as e:
43
  print(f"Błąd ładowania Image Model: {e}")
44
- image_generator = None
45
- IMAGE_MODEL_LOADED = False
46
-
47
 
 
48
  def parse_steps_from_markdown(markdown_text):
49
- """
50
- Funkcja do wyciągania tytułów poszczególnych kroków z wygenerowanego tekstu.
51
- Używa wyrażeń regularnych do znalezienia linii zaczynających się od "X. **".
52
- """
53
- # Wzorzec do znalezienia linii typu "1. **Tytuł kroku**"
54
  pattern = re.compile(r"^\d+\.\s*\*\*(.*?)\*\*", re.MULTILINE)
55
  steps = pattern.findall(markdown_text)
56
  return steps
57
 
58
-
59
  def generate_course_and_images(topic, progress=gr.Progress(track_tqdm=True)):
60
- """
61
- Główna funkcja aplikacji: generuje tekst kursu, a następnie obrazy do każdego kroku.
62
- """
63
  if not LLM_LOADED or not IMAGE_MODEL_LOADED:
64
  error_msg = "Błąd krytyczny: Jeden z modeli AI nie został załadowany."
65
- return error_msg, None
66
 
67
  if not topic:
68
- return "Proszę wpisać temat kursu.", None
69
 
70
- # --- Krok 1: Generowanie struktury tekstowej kursu ---
71
  progress(0, desc="Generowanie tekstu kursu...")
72
- prompt = f"""
73
- [INST] Jesteś ekspertem w tworzeniu kursów online. Twoim zadaniem jest stworzenie zwięzłego, 5-etapowego planu kursu DIY na podany temat.
74
-
75
- Temat kursu: "{topic}"
76
-
77
- Wygeneruj odpowiedź w formacie Markdown, która zawiera:
78
- 1. Chwytliwy tytuł kursu (jako nagłówek H1).
79
- 2. Pięć ponumerowanych kroków kursu. Każdy krok powinien mieć tytuł (pogrubiony) i krótki, 2-3 zdaniowy opis.
80
-
81
- Nie dodawaj żadnych wstępów, podsumowań ani dodatkowych komentarzy. Trzymaj się ściśle podanej struktury. [/INST]
82
- """
83
  response = text_generator(prompt, max_new_tokens=1024, do_sample=True, temperature=0.7, top_p=0.95)
84
  course_text = response[0]['generated_text'].split('[/INST]')[-1].strip()
85
 
86
- # --- Krok 2: Parsowanie tekstu i generowanie obrazów ---
87
  steps = parse_steps_from_markdown(course_text)
88
  if not steps:
89
- return course_text, None # Zwróć sam tekst, jeśli nie udało się znaleźć kroków
90
 
91
  generated_images = []
92
  for i, step_title in enumerate(steps):
93
- progress((i + 1) / len(steps), desc=f"Generowanie obrazka dla kroku {i+1}/{len(steps)}: {step_title}")
94
-
95
- # Tworzymy prosty, ale skuteczny prompt dla modelu obrazkowego
96
  image_prompt = f"cinematic photo of '{step_title}', professional photography, high detail, 8k"
97
-
98
- # Generujemy obraz. `num_inference_steps` jest obniżone do 25 dla szybkości.
99
  image = image_generator(image_prompt, num_inference_steps=25).images[0]
100
  generated_images.append(image)
101
 
102
- return course_text, generated_images
 
 
 
 
 
 
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
  # --- Budowa Interfejsu Gradio ---
106
  with gr.Blocks(theme=gr.themes.Soft(), title="Kreator Kursów DIY") as demo:
107
- gr.Markdown(
108
- """
109
- # 🎨 Kreator Kursów DIY
110
- Wpisz temat, a AI wygeneruje dla Ciebie kompletny, ilustrowany kurs!
111
- """
112
- )
113
 
114
  with gr.Row():
115
- topic_input = gr.Textbox(
116
- label="Temat kursu",
117
- placeholder="np. Jak uprawiać zioła na balkonie?",
118
- lines=2,
119
- scale=4,
120
- )
121
 
122
  generate_button = gr.Button("Wygeneruj Kurs z Obrazkami!", variant="primary")
123
-
124
  gr.Markdown("---")
125
 
126
  gr.Markdown("### 📖 Twój Kurs")
127
  output_display = gr.Markdown("Tutaj pojawi się tekst Twojego kursu...")
128
 
129
  gr.Markdown("### 🖼️ Ilustracje do Kursu")
130
- image_gallery = gr.Gallery(
131
- label="Wygenerowane obrazy",
132
- show_label=False,
133
- elem_id="gallery",
134
- columns=5,
135
- height="auto"
136
- )
137
 
 
138
  generate_button.click(
139
  fn=generate_course_and_images,
140
  inputs=topic_input,
141
- outputs=[output_display, image_gallery] # Teraz mamy dwa wyjścia!
 
 
 
 
 
 
142
  )
143
 
144
  demo.launch()
 
1
+ # Importujemy wszystkie potrzebne biblioteki
2
  import gradio as gr
3
  from transformers import pipeline as text_pipeline
4
  from diffusers import DiffusionPipeline
5
  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
 
13
  # --- Konfiguracja Modeli ---
 
 
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")
138
+
139
+ with gr.Row():
140
+ pdf_button = gr.Button("Pobierz jako PDF", interactive=False)
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
 
157
  demo.launch()