Docfile commited on
Commit
3aff6bf
·
verified ·
1 Parent(s): 1b2f27f

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -459
app.py DELETED
@@ -1,459 +0,0 @@
1
- from flask import Flask, render_template, request, send_file
2
- import os
3
- import convertapi
4
- from docx import Document
5
- from docx.shared import Pt, Cm, RGBColor
6
- from docx.enum.text import WD_ALIGN_PARAGRAPH
7
- from docx.enum.table import WD_TABLE_ALIGNMENT
8
- from docx.oxml.ns import nsdecls, qn
9
- from docx.oxml import parse_xml, OxmlElement
10
- from docx.enum.style import WD_STYLE_TYPE
11
-
12
- # Configuration des identifiants ConvertAPI
13
- convertapi.api_credentials = 'secret_8wCI6pgOP9AxLVJG'
14
-
15
- def set_cell_border(cell, border_color="92D050", border_sz="8"):
16
- """
17
- Ajoute ou met à jour les bordures d'une cellule avec la couleur et taille spécifiées.
18
- """
19
- tc = cell._tc
20
- tcPr = tc.get_or_add_tcPr()
21
- borders = tcPr.find(qn("w:tcBorders"))
22
- if borders is None:
23
- borders = OxmlElement("w:tcBorders")
24
- tcPr.append(borders)
25
- for border in ['top', 'left', 'bottom', 'right']:
26
- element = borders.find(qn("w:" + border))
27
- if element is None:
28
- element = OxmlElement("w:" + border)
29
- borders.append(element)
30
- element.set(qn("w:val"), "single")
31
- element.set(qn("w:sz"), border_sz)
32
- element.set(qn("w:space"), "0")
33
- element.set(qn("w:color"), border_color)
34
-
35
- class EvaluationGymnique:
36
- def __init__(self):
37
- self.document = Document()
38
- self.document.sections[0].page_height = Cm(29.7)
39
- self.document.sections[0].page_width = Cm(21)
40
- self.document.sections[0].left_margin = Cm(1.5)
41
- self.document.sections[0].right_margin = Cm(1.5)
42
- self.document.sections[0].top_margin = Cm(1)
43
- self.document.sections[0].bottom_margin = Cm(1)
44
-
45
- # Appliquer des styles généraux (personnalisation des polices et couleurs)
46
- self.appliquer_styles_generaux()
47
-
48
- # Informations d'en-tête par défaut
49
- self.centre_examen = "Centre d'examen"
50
- self.type_examen = "Bac Général"
51
- self.serie = "Série"
52
- self.etablissement = "Établissement"
53
- self.session = "2025"
54
- self.nom_candidat = "Candidat"
55
-
56
- # Liste vide pour les éléments techniques
57
- self.elements_techniques = []
58
- self.appreciations = ["M", "PM", "NM", "NR"]
59
-
60
- def appliquer_styles_generaux(self):
61
- # Modifier le style Normal pour un rendu moderne
62
- style = self.document.styles['Normal']
63
- style.font.name = 'Calibri'
64
- style.font.size = Pt(11)
65
-
66
- # Créer (ou réutiliser) un style personnalisé pour les titres
67
- try:
68
- custom_heading = self.document.styles.add_style('CustomHeading', WD_STYLE_TYPE.PARAGRAPH)
69
- except Exception:
70
- custom_heading = self.document.styles['Heading 1']
71
- custom_heading.font.name = 'Arial'
72
- custom_heading.font.size = Pt(16)
73
- custom_heading.font.bold = True
74
- custom_heading.font.color.rgb = RGBColor(0, 32, 96)
75
-
76
- def ajouter_entete_colore(self):
77
- header_paragraph = self.document.add_paragraph()
78
- header_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
79
- header_paragraph.space_after = Pt(6)
80
- header_run = header_paragraph.add_run("ÉVALUATION GYMNASTIQUE")
81
- header_run.bold = True
82
- header_run.font.size = Pt(14)
83
- header_run.font.color.rgb = RGBColor(0, 32, 96)
84
-
85
- header_table = self.document.add_table(rows=3, cols=2)
86
- header_table.style = 'Table Grid'
87
- header_table.autofit = False
88
-
89
- # Configuration de la hauteur des lignes et ajout de shading sur chaque cellule
90
- for row in header_table.rows:
91
- row.height = Cm(0.8)
92
- for cell in row.cells:
93
- shading_elm = parse_xml(f'<w:shd {nsdecls("w")} w:fill="D9E2F3"/>')
94
- cell._tc.get_or_add_tcPr().append(shading_elm)
95
-
96
- # Première ligne
97
- cell = header_table.cell(0, 0)
98
- paragraph = cell.paragraphs[0]
99
- run = paragraph.add_run("Centre d'examen: ")
100
- run.bold = True
101
- run.font.size = Pt(10)
102
- run.font.color.rgb = RGBColor(0, 32, 96)
103
- paragraph.add_run(self.centre_examen).font.size = Pt(10)
104
-
105
- cell = header_table.cell(0, 1)
106
- paragraph = cell.paragraphs[0]
107
- run = paragraph.add_run("Examen: ")
108
- run.bold = True
109
- run.font.size = Pt(10)
110
- run.font.color.rgb = RGBColor(0, 32, 96)
111
- paragraph.add_run(self.type_examen).font.size = Pt(10)
112
-
113
- # Deuxième ligne
114
- cell = header_table.cell(1, 0)
115
- paragraph = cell.paragraphs[0]
116
- run = paragraph.add_run("Série: ")
117
- run.bold = True
118
- run.font.size = Pt(10)
119
- run.font.color.rgb = RGBColor(0, 32, 96)
120
- paragraph.add_run(self.serie).font.size = Pt(10)
121
-
122
- cell = header_table.cell(1, 1)
123
- paragraph = cell.paragraphs[0]
124
- run = paragraph.add_run("Établissement: ")
125
- run.bold = True
126
- run.font.size = Pt(10)
127
- run.font.color.rgb = RGBColor(0, 32, 96)
128
- paragraph.add_run(self.etablissement).font.size = Pt(10)
129
-
130
- # Troisième ligne
131
- cell = header_table.cell(2, 0)
132
- paragraph = cell.paragraphs[0]
133
- run = paragraph.add_run("Session: ")
134
- run.bold = True
135
- run.font.size = Pt(10)
136
- run.font.color.rgb = RGBColor(0, 32, 96)
137
- paragraph.add_run(self.session).font.size = Pt(10)
138
-
139
- cell = header_table.cell(2, 1)
140
- paragraph = cell.paragraphs[0]
141
- run = paragraph.add_run("Candidat: ")
142
- run.bold = True
143
- run.font.size = Pt(10)
144
- run.font.color.rgb = RGBColor(0, 32, 96)
145
- paragraph.add_run(self.nom_candidat).font.size = Pt(10)
146
-
147
- self.document.add_paragraph().space_after = Pt(4)
148
-
149
- def creer_tableau_elements(self):
150
- # Création d'un tableau pour les éléments techniques avec une mise en forme améliorée
151
- table = self.document.add_table(rows=len(self.elements_techniques) + 1, cols=5)
152
- table.style = 'Table Grid'
153
- table.alignment = WD_TABLE_ALIGNMENT.CENTER
154
-
155
- # Définir les largeurs de colonnes pour une meilleure lisibilité
156
- col_widths = [Cm(8), Cm(3), Cm(2), Cm(2.5), Cm(2.5)]
157
- for col_idx, width in enumerate(col_widths):
158
- for cell in table.columns[col_idx].cells:
159
- cell.width = width
160
-
161
- # Ajustement de la hauteur des lignes et espacement interne
162
- for row in table.rows:
163
- row.height = Cm(1)
164
- for cell in row.cells:
165
- for paragraph in cell.paragraphs:
166
- paragraph.paragraph_format.space_before = Pt(2)
167
- paragraph.paragraph_format.space_after = Pt(2)
168
-
169
- # En-tête du tableau avec arrière-plan personnalisé
170
- header_row = table.rows[0]
171
- for cell in header_row.cells:
172
- shading_elm = parse_xml(f'<w:shd {nsdecls("w")} w:fill="BDD7EE"/>')
173
- cell._tc.get_or_add_tcPr().append(shading_elm)
174
-
175
- headers = ["ELEMENTS TECHNIQUES", "CATEGORIES D'ELEMENTS TECHNIQUES ET PONDERATION", "", "APPRECIATIONS", "POINTS Accordés"]
176
- for i, header in enumerate(headers):
177
- cell = table.cell(0, i)
178
- cell.text = header
179
- cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
180
- run = cell.paragraphs[0].runs[0]
181
- run.bold = True
182
- run.font.size = Pt(9)
183
- run.font.color.rgb = RGBColor(0, 32, 96)
184
- # Fusionner les deux cellules centrales de l'en-tête
185
- table.cell(0, 1).merge(table.cell(0, 2))
186
-
187
- # Remplissage du tableau avec les éléments techniques
188
- for i, element in enumerate(self.elements_techniques, 1):
189
- # Colonne nom de l'élément
190
- element_cell = table.cell(i, 0)
191
- element_cell.text = element["nom"]
192
- element_cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.LEFT
193
- run = element_cell.paragraphs[0].runs[0]
194
- run.bold = True
195
- run.font.size = Pt(9)
196
-
197
- # Colonne catégorie
198
- categorie_cell = table.cell(i, 1)
199
- categorie_cell.text = element["categorie"]
200
- categorie_cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
201
- run = categorie_cell.paragraphs[0].runs[0]
202
- run.bold = True
203
- run.font.size = Pt(9)
204
- run.italic = True
205
-
206
- # Colonne points
207
- points_cell = table.cell(i, 2)
208
- points_cell.text = str(element["points"])
209
- points_cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
210
- run = points_cell.paragraphs[0].runs[0]
211
- run.bold = True
212
- run.font.size = Pt(9)
213
- run.italic = True
214
-
215
- def ajouter_note_jury(self):
216
- para = self.document.add_paragraph()
217
- para.space_before = Pt(4)
218
- para.space_after = Pt(4)
219
- run = para.add_run("NB1 : Zone réservée aux membres du jury ! Le jury cochera le point correspondant au niveau de réalisation de l'élément gymnique par le candidat.")
220
- run.bold = True
221
- run.font.color.rgb = RGBColor(255, 0, 0)
222
- run.font.size = Pt(9)
223
-
224
- def creer_tableau_recapitulatif(self):
225
- note_table = self.document.add_table(rows=3, cols=13)
226
- note_table.style = 'Table Grid'
227
- note_table.alignment = WD_TABLE_ALIGNMENT.CENTER
228
-
229
- for row in note_table.rows:
230
- row.height = Cm(0.6)
231
- for cell in note_table.rows[0].cells:
232
- shading_elm = parse_xml(f'<w:shd {nsdecls("w")} w:fill="BDD7EE"/>')
233
- cell._tc.get_or_add_tcPr().append(shading_elm)
234
-
235
- for col, (type_lettre, points) in enumerate([("A", "1pt"), ("B", "1,5pt"), ("C", "2pts"), ("D", "2,5pts"), ("E", "3pts")]):
236
- idx = col * 2
237
- if idx + 1 < len(note_table.columns):
238
- cell = note_table.cell(0, idx)
239
- cell.merge(note_table.cell(0, idx + 1))
240
- cell.text = f"Type {type_lettre}\n{points}"
241
- cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
242
- for run in cell.paragraphs[0].runs:
243
- run.bold = True
244
- run.font.size = Pt(9)
245
- run.font.color.rgb = RGBColor(0, 32, 96)
246
-
247
- for col, (titre, points) in enumerate([("ROV", "2pts"), ("Projet", "2pts"), ("Réalisation", "16pts")], 10):
248
- if col < len(note_table.columns):
249
- cell = note_table.cell(0, col)
250
- cell.text = f"{titre}\n{points}"
251
- cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
252
- for run in cell.paragraphs[0].runs:
253
- run.bold = True
254
- run.font.size = Pt(9)
255
- run.font.color.rgb = RGBColor(0, 32, 96)
256
-
257
- for col in range(5):
258
- idx = col * 2
259
- if idx + 1 < len(note_table.columns):
260
- neg_cell = note_table.cell(1, idx)
261
- neg_cell.text = "NEG"
262
- neg_cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
263
- for run in neg_cell.paragraphs[0].runs:
264
- run.italic = True
265
- run.font.size = Pt(9)
266
-
267
- note_cell = note_table.cell(1, idx + 1)
268
- note_cell.text = "Note"
269
- note_cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
270
- for run in note_cell.paragraphs[0].runs:
271
- run.italic = True
272
- run.font.size = Pt(9)
273
-
274
- for col in range(10, 13):
275
- if col < len(note_table.columns):
276
- cell = note_table.cell(1, col)
277
- cell.text = "Note"
278
- cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
279
- for run in cell.paragraphs[0].runs:
280
- run.italic = True
281
- run.font.size = Pt(9)
282
-
283
- for col, type_lettre in enumerate(["A", "B", "C", "D", "E"]):
284
- idx = col * 2
285
- if idx < len(note_table.columns):
286
- neg_cell = note_table.cell(2, idx)
287
- neg_cell.text = ""
288
- neg_cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
289
-
290
- def ajouter_accolade(self):
291
- # Créer un tableau pour simuler l'accolade
292
- accolade_table = self.document.add_table(rows=1, cols=3)
293
- accolade_table.alignment = WD_TABLE_ALIGNMENT.CENTER
294
-
295
- # Supprimer les bordures (simulation)
296
- for cell in accolade_table.rows[0].cells:
297
- cell.border_width = 0
298
-
299
- # Définir les largeurs des cellules
300
- accolade_table.columns[0].width = Cm(8)
301
- accolade_table.columns[1].width = Cm(2)
302
- accolade_table.columns[2].width = Cm(8)
303
-
304
- cell = accolade_table.cell(0, 1)
305
- paragraph = cell.paragraphs[0]
306
- paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
307
- run = paragraph.add_run("}")
308
- run.font.size = Pt(48)
309
- run.font.bold = True
310
-
311
- # Rotation du symbole grâce à une modification XML
312
- rPr = run._element.get_or_add_rPr()
313
- rotation = OxmlElement('w:eastAsianLayout')
314
- rotation.set(qn('w:vert'), 'eaVert270')
315
- rPr.append(rotation)
316
-
317
- accolade_table.rows[0].height = Cm(3)
318
-
319
- def ajouter_zone_note(self):
320
- # Tableau pour la note finale avec bordure verte
321
- zone_note = self.document.add_table(rows=1, cols=1)
322
- zone_note.style = 'Table Grid'
323
- zone_note.alignment = WD_TABLE_ALIGNMENT.CENTER
324
-
325
- cell = zone_note.cell(0, 0)
326
- cell.width = Cm(5)
327
- zone_note.rows[0].height = Cm(2)
328
-
329
- # Appliquer la bordure verte à la cellule via la fonction utilitaire
330
- set_cell_border(cell, border_color="92D050", border_sz="8")
331
-
332
- p = cell.paragraphs[0]
333
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
334
- run = p.add_run("Note finale/20")
335
- run.bold = True
336
- run.font.size = Pt(14)
337
- run.font.color.rgb = RGBColor(0, 0, 0)
338
-
339
- self.document.add_paragraph().space_after = Pt(12)
340
-
341
- def ajouter_note_candidat_avec_cadre(self):
342
- note_table = self.document.add_table(rows=1, cols=1)
343
- note_table.style = 'Table Grid'
344
- note_table.alignment = WD_TABLE_ALIGNMENT.CENTER
345
-
346
- cell = note_table.cell(0, 0)
347
- shading_elm = parse_xml(f'<w:shd {nsdecls("w")} w:fill="E2EFDA"/>')
348
- cell._tc.get_or_add_tcPr().append(shading_elm)
349
-
350
- p = cell.paragraphs[0]
351
- run = p.add_run("NB2: Après le choix des catégories d'éléments gymniques par le candidat, ce dernier remplira la colonne de pointage selon l'orientation suivante: A (0.25; 0.5; 0.75; 1) B (0.25; 0.5; 0.75; 1; 1.25; 1.5) C (0.5; 0.75; 1; 1.25; 1.5; 2) D (0.75; 1; 1.25; 1.5; 2; 2.5) et E (0.75; 1; 1.5; 2; 2.5; 3) également, le candidat devra fournir 2 copies de son projet sur une page! (appréciations: NR, NM, PM, M).")
352
- run.italic = True
353
- run.font.size = Pt(8)
354
-
355
- def ajouter_lignes_correcteurs(self):
356
- para_intro = self.document.add_paragraph()
357
- para_intro.space_before = Pt(6)
358
-
359
- for role in ["Projet", "principal", "ROV"]:
360
- para = self.document.add_paragraph()
361
- para.space_before = Pt(4)
362
- para.space_after = Pt(4)
363
- run = para.add_run(f"Correcteur {role} : ")
364
- run.bold = True
365
- para.add_run(".................................................................")
366
-
367
- # Méthodes de modification des données
368
- def modifier_centre_examen(self, nom):
369
- self.centre_examen = nom
370
-
371
- def modifier_type_examen(self, type_examen):
372
- self.type_examen = type_examen
373
-
374
- def modifier_serie(self, serie):
375
- self.serie = serie
376
-
377
- def modifier_etablissement(self, nom):
378
- self.etablissement = nom
379
-
380
- def modifier_session(self, annee):
381
- self.session = annee
382
-
383
- def modifier_candidat(self, nom):
384
- self.nom_candidat = nom
385
-
386
- def ajouter_element(self, nom, categorie, points):
387
- self.elements_techniques.append({
388
- "nom": nom,
389
- "categorie": categorie,
390
- "points": float(points)
391
- })
392
-
393
- def generer_document(self, nom_fichier="evaluation_gymnastique.docx"):
394
- self.ajouter_entete_colore()
395
- self.creer_tableau_elements()
396
- self.ajouter_note_jury()
397
- self.creer_tableau_recapitulatif()
398
- self.ajouter_accolade()
399
- self.ajouter_zone_note()
400
- self.ajouter_note_candidat_avec_cadre()
401
- self.ajouter_lignes_correcteurs()
402
- self.document.save(nom_fichier)
403
- return nom_fichier
404
-
405
- # --- Application Flask ---
406
- app = Flask(__name__)
407
-
408
- @app.route("/", methods=["GET", "POST"])
409
- def index():
410
- if request.method == "POST":
411
- # Récupération des informations depuis le formulaire
412
- centre_examen = request.form.get("centre_examen", "Centre d'examen")
413
- type_examen = request.form.get("type_examen", "Bac Général")
414
- serie = request.form.get("serie", "Série")
415
- etablissement = request.form.get("etablissement", "Établissement")
416
- session_value = request.form.get("session", "2025")
417
- nom_candidat = request.form.get("nom_candidat", "Candidat")
418
-
419
- # Création et configuration du document
420
- evaluation = EvaluationGymnique()
421
- evaluation.modifier_centre_examen(centre_examen)
422
- evaluation.modifier_type_examen(type_examen)
423
- evaluation.modifier_serie(serie)
424
- evaluation.modifier_etablissement(etablissement)
425
- evaluation.modifier_session(session_value)
426
- evaluation.modifier_candidat(nom_candidat)
427
-
428
- # Récupération des éléments techniques ajoutés dynamiquement
429
- element_names = request.form.getlist("new_element_name")
430
- element_categories = request.form.getlist("new_element_categorie")
431
- element_points = request.form.getlist("new_element_points")
432
- for name, cat, pts in zip(element_names, element_categories, element_points):
433
- if name and cat and pts:
434
- evaluation.ajouter_element(name, cat, pts)
435
-
436
- # Génération du document DOCX
437
- filename = "evaluation_gymnastique.docx"
438
- evaluation.generer_document(filename)
439
-
440
- # Vérification du format de sortie demandé
441
- output_format = request.form.get("format", "docx")
442
- if output_format == "pdf":
443
- # Conversion en PDF via ConvertAPI
444
- result = convertapi.convert('pdf', {
445
- 'File': filename,
446
- 'FileName': 'evaluation_gymnastique',
447
- 'ConvertMetadata': 'false',
448
- 'ConvertHeadings': 'false'
449
- }, from_format='doc')
450
- pdf_filename = "evaluation_gymnastique.pdf"
451
- result.save_files(pdf_filename)
452
- return send_file(pdf_filename, as_attachment=True)
453
- else:
454
- return send_file(filename, as_attachment=True)
455
-
456
- return render_template("index.html")
457
-
458
- if __name__ == "__main__":
459
- app.run(debug=True)