MisterAI commited on
Commit
4e2a7f1
·
verified ·
1 Parent(s): d6e7124

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +307 -0
app.py ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #https://huggingface.co/spaces/MisterAI/GenDoc_05
2
+ #app.py_144
3
+ #Uniquement Granite 3b instruct
4
+
5
+
6
+ import os
7
+ import gradio as gr
8
+ from transformers import AutoModelForCausalLM, AutoTokenizer
9
+ from pptx import Presentation
10
+ from pptx.util import Inches, Pt
11
+ import torch
12
+ import time
13
+
14
+ #TEXT_MODELS = {
15
+ # "Utter-Project_EuroLLM-1.7B": "utter-project/EuroLLM-1.7B",
16
+ # "Mistral Nemo 2407 (GGUF)": "MisterAI/Bartowski_MistralAI_Mistral-Nemo-Instruct-2407-IQ4_XS.gguf",
17
+ ## "Mixtral 8x7B": "mistralai/Mixtral-8x7B-v0.1",
18
+ # "Lucie 7B": "OpenLLM-France/Lucie-7B"
19
+ #}
20
+
21
+
22
+ # Configuration du modèle unique
23
+ MODEL_PATH = "ibm-granite/granite-3.1-3b-a800m-Instruct"
24
+
25
+ PREPROMPT = """Vous êtes un assistant IA expert en création de présentations PowerPoint professionnelles.
26
+ Générez une présentation structurée et détaillée au format Markdown en suivant ce format EXACT:
27
+
28
+ TITRE: [Titre principal de la présentation]
29
+
30
+ DIAPO 1:
31
+ Titre: [Titre de la diapo]
32
+ Points:
33
+ - Point 1
34
+ - Point 2
35
+ - Point 3
36
+
37
+ DIAPO 2:
38
+ Titre: [Titre de la diapo]
39
+ Points:
40
+ - Point 1
41
+ - Point 2
42
+ - Point 3
43
+
44
+ [Continuez avec ce format pour chaque diapositive]
45
+
46
+ Analysez le texte suivant et créez une présentation professionnelle :"""
47
+
48
+ class ExecutionTimer:
49
+ def __init__(self):
50
+ self.start_time = None
51
+ self.last_duration = None
52
+
53
+ def start(self):
54
+ self.start_time = time.time()
55
+
56
+ def get_elapsed(self):
57
+ if self.start_time is None:
58
+ return 0
59
+ return time.time() - self.start_time
60
+
61
+ def stop(self):
62
+ if self.start_time is not None:
63
+ self.last_duration = self.get_elapsed()
64
+ self.start_time = None
65
+ return self.last_duration
66
+
67
+ def get_status(self):
68
+ if self.start_time is not None:
69
+ current = self.get_elapsed()
70
+ last = f" (précédent: {self.last_duration:.2f}s)" if self.last_duration else ""
71
+ return f"En cours... {current:.2f}s{last}"
72
+ elif self.last_duration:
73
+ return f"Terminé en {self.last_duration:.2f}s"
74
+ return "En attente..."
75
+
76
+ class PresentationGenerator:
77
+ def __init__(self):
78
+ print("Initialisation du modèle Granite...")
79
+ self.tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)
80
+ self.model = AutoModelForCausalLM.from_pretrained(
81
+ MODEL_PATH,
82
+ torch_dtype=torch.float32, # Utilisation de float32 pour plus de stabilité
83
+ device_map="auto" # Laisse le modèle choisir le meilleur device
84
+ )
85
+ self.model.eval() # Mode évaluation
86
+ print("Modèle initialisé avec succès!")
87
+
88
+ def generate_text(self, prompt, temperature=0.7, max_tokens=2048):
89
+ """Génère le texte de la présentation selon le format Granite"""
90
+ try:
91
+ # Formatage du chat selon les instructions Granite
92
+ chat = [{"role": "user", "content": prompt}]
93
+ formatted_prompt = self.tokenizer.apply_chat_template(
94
+ chat,
95
+ tokenize=False,
96
+ add_generation_prompt=True
97
+ )
98
+
99
+ # Tokenisation et génération
100
+ inputs = self.tokenizer(
101
+ formatted_prompt,
102
+ return_tensors="pt",
103
+ truncation=True,
104
+ max_length=4096
105
+ ).to(self.model.device)
106
+
107
+ with torch.no_grad():
108
+ outputs = self.model.generate(
109
+ **inputs,
110
+ max_new_tokens=max_tokens,
111
+ temperature=temperature,
112
+ do_sample=True,
113
+ pad_token_id=self.tokenizer.eos_token_id
114
+ )
115
+
116
+ return self.tokenizer.decode(outputs[0], skip_special_tokens=True)
117
+
118
+ except Exception as e:
119
+ print(f"Erreur lors de la génération: {str(e)}")
120
+ raise
121
+
122
+ def parse_presentation_content(self, content):
123
+ """Parse le contenu généré en sections pour les diapositives"""
124
+ slides = []
125
+ current_slide = None
126
+
127
+ for line in content.split('\n'):
128
+ line = line.strip()
129
+ if line.startswith('TITRE:'):
130
+ slides.append({'type': 'title', 'title': line[6:].strip()})
131
+ elif line.startswith('DIAPO'):
132
+ if current_slide:
133
+ slides.append(current_slide)
134
+ current_slide = {'type': 'content', 'title': '', 'points': []}
135
+ elif line.startswith('Titre:') and current_slide:
136
+ current_slide['title'] = line[6:].strip()
137
+ elif line.startswith('- ') and current_slide:
138
+ current_slide['points'].append(line[2:].strip())
139
+
140
+ if current_slide:
141
+ slides.append(current_slide)
142
+
143
+ return slides
144
+
145
+ def create_presentation(self, slides):
146
+ """Crée la présentation PowerPoint"""
147
+ prs = Presentation()
148
+
149
+ # Première diapo (titre)
150
+ title_slide = prs.slides.add_slide(prs.slide_layouts[0])
151
+ title_slide.shapes.title.text = slides[0]['title']
152
+
153
+ # Autres diapos
154
+ for slide in slides[1:]:
155
+ content_slide = prs.slides.add_slide(prs.slide_layouts[1])
156
+ content_slide.shapes.title.text = slide['title']
157
+
158
+ if slide['points']:
159
+ body = content_slide.shapes.placeholders[1].text_frame
160
+ body.clear()
161
+ for point in slide['points']:
162
+ p = body.add_paragraph()
163
+ p.text = point
164
+ p.level = 0
165
+
166
+ return prs
167
+
168
+ # Timer global pour le suivi du temps
169
+ timer = ExecutionTimer()
170
+
171
+ def update_status():
172
+ return timer.get_status()
173
+
174
+ def generate_skeleton(text, temperature, max_tokens, status_output):
175
+ """Génère le squelette de la présentation"""
176
+ try:
177
+ timer.start()
178
+ generator = PresentationGenerator()
179
+
180
+ # Génération du contenu
181
+ full_prompt = PREPROMPT + "\n\n" + text
182
+ generated_content = generator.generate_text(full_prompt, temperature, max_tokens)
183
+
184
+ timer.stop()
185
+ return timer.get_status(), generated_content, gr.update(visible=True)
186
+
187
+ except Exception as e:
188
+ timer.stop()
189
+ error_msg = f"Erreur: {str(e)}"
190
+ print(error_msg)
191
+ return error_msg, None, gr.update(visible=False)
192
+
193
+ def create_presentation_file(generated_content):
194
+ """Crée le fichier PowerPoint à partir du contenu généré"""
195
+ try:
196
+ timer.start()
197
+ generator = PresentationGenerator()
198
+
199
+ # Création et sauvegarde de la présentation
200
+ slides = generator.parse_presentation_content(generated_content)
201
+ prs = generator.create_presentation(slides)
202
+
203
+ output_path = os.path.join(os.getcwd(), "presentation.pptx")
204
+ prs.save(output_path)
205
+
206
+ timer.stop()
207
+ return output_path
208
+
209
+ except Exception as e:
210
+ timer.stop()
211
+ print(f"Erreur lors de la création du fichier: {str(e)}")
212
+ return None
213
+
214
+ # Interface Gradio
215
+ with gr.Blocks(theme=gr.themes.Glass()) as demo:
216
+ gr.Markdown(
217
+ """
218
+ # Générateur de Présentations PowerPoint IA
219
+
220
+ Créez des présentations professionnelles automatiquement avec l'aide de l'IA.
221
+ """
222
+ )
223
+
224
+ with gr.Row():
225
+ with gr.Column(scale=1):
226
+ temperature = gr.Slider(
227
+ minimum=0.1,
228
+ maximum=1.0,
229
+ value=0.7,
230
+ step=0.1,
231
+ label="Température"
232
+ )
233
+ max_tokens = gr.Slider(
234
+ minimum=1000,
235
+ maximum=4096,
236
+ value=2048,
237
+ step=256,
238
+ label="Tokens maximum"
239
+ )
240
+
241
+ with gr.Row():
242
+ with gr.Column(scale=2):
243
+ input_text = gr.Textbox(
244
+ lines=10,
245
+ label="Votre texte",
246
+ placeholder="Décrivez le contenu que vous souhaitez pour votre présentation..."
247
+ )
248
+
249
+ with gr.Row():
250
+ generate_skeleton_btn = gr.Button("Générer le Squelette de la Présentation", variant="primary")
251
+
252
+ with gr.Row():
253
+ with gr.Column():
254
+ status_output = gr.Textbox(
255
+ label="Statut",
256
+ lines=2,
257
+ every=1 # Met à jour toutes les secondes
258
+ )
259
+ generated_content = gr.Textbox(
260
+ label="Contenu généré",
261
+ lines=10,
262
+ show_copy_button=True
263
+ )
264
+ create_presentation_btn = gr.Button("Créer La Présentation", visible=False)
265
+ output_file = gr.File(
266
+ label="Présentation PowerPoint",
267
+ type="filepath" # Utilise filepath au lieu de binary
268
+ )
269
+
270
+ # Mise à jour du statut en temps réel
271
+ status_output.change(
272
+ fn=update_status,
273
+ inputs=[],
274
+ outputs=[status_output],
275
+ every=1
276
+ )
277
+
278
+ generate_skeleton_btn.click(
279
+ fn=generate_skeleton,
280
+ inputs=[
281
+ input_text,
282
+ temperature,
283
+ max_tokens,
284
+ status_output
285
+ ],
286
+ outputs=[
287
+ status_output,
288
+ generated_content,
289
+ create_presentation_btn
290
+ ]
291
+ )
292
+
293
+ create_presentation_btn.click(
294
+ fn=create_presentation_file,
295
+ inputs=[generated_content],
296
+ outputs=[output_file]
297
+ )
298
+
299
+ if __name__ == "__main__":
300
+ demo.launch()
301
+
302
+
303
+
304
+
305
+
306
+
307
+