Upload 3 files
Browse files- interface_wizard.py +693 -0
- text_analyzer.py +187 -0
- wizard_style.css +222 -0
interface_wizard.py
ADDED
@@ -0,0 +1,693 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Module définissant l'interface utilisateur Gradio sous forme d'assistant progressif (wizard).
|
3 |
+
Cette version permet une navigation par étapes avec aperçu en temps réel.
|
4 |
+
"""
|
5 |
+
import gradio as gr
|
6 |
+
from utils import collect_author_info, ensure_default_supports
|
7 |
+
from text_analyzer import analyze_work_description, get_explanation
|
8 |
+
from config import (CONTRACT_TYPES, CESSION_MODES, ADDITIONAL_RIGHTS,
|
9 |
+
AUTHOR_TYPES, CIVILITY_OPTIONS, SUPPORTS_OPTIONS)
|
10 |
+
import time
|
11 |
+
|
12 |
+
|
13 |
+
def create_wizard_interface(generate_pdf_fn, preview_contract_fn):
|
14 |
+
"""
|
15 |
+
Crée l'interface utilisateur Gradio avec navigation progressive par étapes.
|
16 |
+
|
17 |
+
Args:
|
18 |
+
generate_pdf_fn: Fonction pour générer le PDF
|
19 |
+
preview_contract_fn: Fonction pour prévisualiser le contrat
|
20 |
+
|
21 |
+
Returns:
|
22 |
+
gr.Blocks: L'interface Gradio configurée
|
23 |
+
"""
|
24 |
+
# Définir le nombre total d'étapes
|
25 |
+
TOTAL_STEPS = 6
|
26 |
+
|
27 |
+
with gr.Blocks(title="Assistant de Contrats de Cession", css="style.css") as demo:
|
28 |
+
# Variables d'état pour stocker les données entre les étapes
|
29 |
+
current_step = gr.State(value=1)
|
30 |
+
contract_data = gr.State(value={
|
31 |
+
"type_contrat": [],
|
32 |
+
"type_cession": "Gratuite",
|
33 |
+
"droits_cedes": [],
|
34 |
+
"exclusivite": False,
|
35 |
+
"auteur_type": "Personne physique",
|
36 |
+
"auteur_info": {},
|
37 |
+
"description_oeuvre": "",
|
38 |
+
"description_image": "",
|
39 |
+
"supports": [],
|
40 |
+
"remuneration": ""
|
41 |
+
})
|
42 |
+
|
43 |
+
gr.Markdown("# Assistant de Création de Contrat de Cession")
|
44 |
+
gr.Markdown("Cet assistant vous guide pas à pas dans la création d'un contrat adapté à vos besoins spécifiques.")
|
45 |
+
|
46 |
+
# Layout principal en deux colonnes
|
47 |
+
with gr.Row():
|
48 |
+
# COLONNE GAUCHE - FORMULAIRE PROGRESSIF
|
49 |
+
with gr.Column(scale=3):
|
50 |
+
# Indicateur de progression
|
51 |
+
progress_bar = gr.Slider(
|
52 |
+
minimum=1,
|
53 |
+
maximum=TOTAL_STEPS,
|
54 |
+
value=1,
|
55 |
+
step=1,
|
56 |
+
interactive=False,
|
57 |
+
label="Progression"
|
58 |
+
)
|
59 |
+
progress_text = gr.Markdown("**Étape 1 sur 6**: Type d'œuvre")
|
60 |
+
|
61 |
+
# ===== ÉTAPE 1: DESCRIPTION ET TYPE DE CONTRAT =====
|
62 |
+
with gr.Group(visible=True) as step1_group:
|
63 |
+
gr.Markdown("## Décrivez votre projet")
|
64 |
+
gr.Markdown("""
|
65 |
+
Décrivez en quelques mots l'œuvre ou le contenu pour lequel vous souhaitez établir un contrat.
|
66 |
+
Exemples: "Une chanson que j'ai composée", "Des photos de mannequins", "Un logo pour une entreprise", etc.
|
67 |
+
""")
|
68 |
+
|
69 |
+
project_description = gr.Textbox(
|
70 |
+
label="Description de votre projet",
|
71 |
+
placeholder="Ex: Une vidéo où je me filme en train de jouer ma composition au piano",
|
72 |
+
lines=3
|
73 |
+
)
|
74 |
+
|
75 |
+
analyze_btn = gr.Button("Analyser mon projet", variant="secondary")
|
76 |
+
|
77 |
+
contract_type_suggestion = gr.Markdown(
|
78 |
+
value="Complétez la description et cliquez sur 'Analyser mon projet' pour obtenir une suggestion.",
|
79 |
+
elem_id="contract-suggestion"
|
80 |
+
)
|
81 |
+
|
82 |
+
gr.Markdown("### Type de contrat nécessaire")
|
83 |
+
contract_type = gr.CheckboxGroup(
|
84 |
+
CONTRACT_TYPES,
|
85 |
+
label="Sélectionnez le(s) type(s) de contrat",
|
86 |
+
value=[]
|
87 |
+
)
|
88 |
+
|
89 |
+
# ===== ÉTAPE 2: MODE DE CESSION ET DROITS =====
|
90 |
+
with gr.Group(visible=False) as step2_group:
|
91 |
+
gr.Markdown("## Mode de cession et droits")
|
92 |
+
|
93 |
+
gr.Markdown("### Mode de cession")
|
94 |
+
gr.Markdown("""
|
95 |
+
La cession peut se faire à titre gratuit ou onéreux (moyennant rémunération).
|
96 |
+
Une cession gratuite limite les droits cédés aux droits de base (reproduction et représentation).
|
97 |
+
""")
|
98 |
+
|
99 |
+
cession_mode = gr.Radio(
|
100 |
+
CESSION_MODES,
|
101 |
+
label="La cession se fait-elle à titre gratuit ou onéreux?",
|
102 |
+
value="Gratuite"
|
103 |
+
)
|
104 |
+
|
105 |
+
# Droits cédés (visible uniquement si onéreux)
|
106 |
+
with gr.Group(visible=False) as group_rights:
|
107 |
+
gr.Markdown("### Droits supplémentaires (cession onéreuse)")
|
108 |
+
gr.Markdown("""
|
109 |
+
Pour une cession onéreuse, vous pouvez céder des droits supplémentaires.
|
110 |
+
Les droits de reproduction et de représentation sont toujours inclus.
|
111 |
+
""")
|
112 |
+
|
113 |
+
additional_rights = gr.CheckboxGroup(
|
114 |
+
ADDITIONAL_RIGHTS,
|
115 |
+
label="Sélectionnez les droits supplémentaires à céder",
|
116 |
+
value=[]
|
117 |
+
)
|
118 |
+
|
119 |
+
gr.Markdown("### Exclusivité")
|
120 |
+
gr.Markdown("""
|
121 |
+
L'exclusivité signifie que le cédant ne pourra pas exploiter lui-même l'œuvre
|
122 |
+
ni céder les mêmes droits à d'autres personnes pendant la durée du contrat.
|
123 |
+
""")
|
124 |
+
|
125 |
+
exclusivity = gr.Checkbox(
|
126 |
+
label="Cession exclusive",
|
127 |
+
value=False,
|
128 |
+
info="Cochez cette case pour une cession exclusive"
|
129 |
+
)
|
130 |
+
|
131 |
+
# ===== ÉTAPE 3: INFORMATIONS SUR L'AUTEUR/MODÈLE =====
|
132 |
+
with gr.Group(visible=False) as step3_group:
|
133 |
+
gr.Markdown("## Informations sur l'auteur/modèle")
|
134 |
+
|
135 |
+
author_type = gr.Radio(
|
136 |
+
AUTHOR_TYPES,
|
137 |
+
label="L'auteur/modèle est:",
|
138 |
+
value="Personne physique"
|
139 |
+
)
|
140 |
+
|
141 |
+
# Personne physique
|
142 |
+
with gr.Group() as group_physical_person:
|
143 |
+
civility = gr.Radio(
|
144 |
+
CIVILITY_OPTIONS,
|
145 |
+
label="Civilité",
|
146 |
+
value="M."
|
147 |
+
)
|
148 |
+
|
149 |
+
with gr.Row():
|
150 |
+
last_name = gr.Textbox(
|
151 |
+
label="Nom",
|
152 |
+
placeholder="Nom de famille"
|
153 |
+
)
|
154 |
+
first_name = gr.Textbox(
|
155 |
+
label="Prénom",
|
156 |
+
placeholder="Prénom"
|
157 |
+
)
|
158 |
+
|
159 |
+
with gr.Row():
|
160 |
+
birth_date = gr.Textbox(
|
161 |
+
label="Date de naissance (facultatif)",
|
162 |
+
placeholder="JJ/MM/AAAA"
|
163 |
+
)
|
164 |
+
nationality = gr.Textbox(
|
165 |
+
label="Nationalité",
|
166 |
+
placeholder="Ex: française"
|
167 |
+
)
|
168 |
+
|
169 |
+
address = gr.Textbox(
|
170 |
+
label="Adresse complète",
|
171 |
+
placeholder="Numéro, rue, code postal, ville"
|
172 |
+
)
|
173 |
+
|
174 |
+
contact_physical = gr.Textbox(
|
175 |
+
label="Moyen de contact (email, téléphone)",
|
176 |
+
placeholder="Email et/ou téléphone"
|
177 |
+
)
|
178 |
+
|
179 |
+
# Personne morale
|
180 |
+
with gr.Group(visible=False) as group_legal_entity:
|
181 |
+
company_name = gr.Textbox(
|
182 |
+
label="Nom de la société",
|
183 |
+
placeholder="Dénomination sociale"
|
184 |
+
)
|
185 |
+
|
186 |
+
with gr.Row():
|
187 |
+
legal_status = gr.Textbox(
|
188 |
+
label="Statut juridique",
|
189 |
+
placeholder="Ex: SARL, SAS, EURL, etc."
|
190 |
+
)
|
191 |
+
rcs_number = gr.Textbox(
|
192 |
+
label="Numéro RCS",
|
193 |
+
placeholder="Ex: 123 456 789 R.C.S. Paris"
|
194 |
+
)
|
195 |
+
|
196 |
+
company_address = gr.Textbox(
|
197 |
+
label="Adresse du siège social",
|
198 |
+
placeholder="Adresse complète du siège"
|
199 |
+
)
|
200 |
+
|
201 |
+
contact_company = gr.Textbox(
|
202 |
+
label="Moyen de contact (email, téléphone)",
|
203 |
+
placeholder="Email et/ou téléphone"
|
204 |
+
)
|
205 |
+
|
206 |
+
# ===== ÉTAPE 4: DESCRIPTION DE L'ŒUVRE/IMAGE =====
|
207 |
+
with gr.Group(visible=False) as step4_group:
|
208 |
+
description_title = gr.Markdown("## Description détaillée")
|
209 |
+
|
210 |
+
# Description de l'œuvre (visible si contrat de droits d'auteur)
|
211 |
+
with gr.Group(visible=True) as group_work_description:
|
212 |
+
gr.Markdown("### Description de l'œuvre")
|
213 |
+
gr.Markdown("""
|
214 |
+
Décrivez précisément l'œuvre concernée par la cession de droits.
|
215 |
+
Cette description sera intégrée dans le contrat pour identifier sans ambiguïté l'objet de la cession.
|
216 |
+
""")
|
217 |
+
|
218 |
+
work_description = gr.Textbox(
|
219 |
+
label="Description de l'œuvre",
|
220 |
+
placeholder="Titre, format, dimensions, support, technique utilisée, date de création, etc.",
|
221 |
+
lines=5
|
222 |
+
)
|
223 |
+
|
224 |
+
# Description de l'image (visible si contrat de droits à l'image)
|
225 |
+
with gr.Group(visible=False) as group_image_description:
|
226 |
+
gr.Markdown("### Description des images")
|
227 |
+
gr.Markdown("""
|
228 |
+
Décrivez précisément les images ou vidéos concernées par la cession du droit à l'image.
|
229 |
+
Précisez le contexte, la date et le lieu de prise de vue, le nombre d'images concernées, etc.
|
230 |
+
""")
|
231 |
+
|
232 |
+
image_description = gr.Textbox(
|
233 |
+
label="Description des images/vidéos",
|
234 |
+
placeholder="Ex: Séance photo réalisée le [date] à [lieu], comprenant X photographies où apparaît [nom du modèle]",
|
235 |
+
lines=5
|
236 |
+
)
|
237 |
+
|
238 |
+
# ===== ÉTAPE 5: SUPPORTS D'EXPLOITATION =====
|
239 |
+
with gr.Group(visible=False) as step5_group:
|
240 |
+
gr.Markdown("## Supports d'exploitation")
|
241 |
+
gr.Markdown("""
|
242 |
+
Sélectionnez les supports sur lesquels l'œuvre et/ou l'image pourra être exploitée.
|
243 |
+
Le site web et Discord de Tellers sont automatiquement inclus.
|
244 |
+
""")
|
245 |
+
|
246 |
+
exploitation_supports = gr.CheckboxGroup(
|
247 |
+
SUPPORTS_OPTIONS,
|
248 |
+
label="Sur quels supports les droits seront-ils exploités?",
|
249 |
+
value=["Réseaux sociaux (Facebook, Instagram, Twitter, etc.)"]
|
250 |
+
)
|
251 |
+
|
252 |
+
# Rémunération (visible uniquement si onéreux)
|
253 |
+
with gr.Group(visible=False) as group_remuneration:
|
254 |
+
gr.Markdown("### Rémunération")
|
255 |
+
gr.Markdown("""
|
256 |
+
Précisez les modalités de rémunération pour cette cession onéreuse.
|
257 |
+
Cela peut être un montant forfaitaire ou proportionnel aux recettes.
|
258 |
+
""")
|
259 |
+
|
260 |
+
remuneration_details = gr.Textbox(
|
261 |
+
label="Modalités de rémunération",
|
262 |
+
placeholder="Ex: 500€ versés à la signature, 5% des recettes versés trimestriellement",
|
263 |
+
lines=3
|
264 |
+
)
|
265 |
+
|
266 |
+
# ===== ÉTAPE 6: VALIDATION ET GÉNÉRATION =====
|
267 |
+
with gr.Group(visible=False) as step6_group:
|
268 |
+
gr.Markdown("## Validation et génération du contrat")
|
269 |
+
gr.Markdown("""
|
270 |
+
Vous avez complété toutes les étapes nécessaires.
|
271 |
+
Vérifiez le contrat dans l'aperçu à droite, puis générez le PDF final.
|
272 |
+
""")
|
273 |
+
|
274 |
+
gr.Markdown("### Options de génération")
|
275 |
+
contract_name = gr.Textbox(
|
276 |
+
label="Nom du fichier PDF (optionnel)",
|
277 |
+
placeholder="Ex: Contrat_Cession_Dupont_2025",
|
278 |
+
value=""
|
279 |
+
)
|
280 |
+
|
281 |
+
# Indicateur de génération
|
282 |
+
with gr.Group(visible=False) as generation_status_group:
|
283 |
+
generation_status = gr.Markdown("Préparation du contrat en cours...")
|
284 |
+
generation_progress = gr.Slider(
|
285 |
+
minimum=0,
|
286 |
+
maximum=100,
|
287 |
+
value=0,
|
288 |
+
step=1,
|
289 |
+
interactive=False,
|
290 |
+
label="Progression"
|
291 |
+
)
|
292 |
+
|
293 |
+
# Boutons de navigation entre les étapes
|
294 |
+
with gr.Row():
|
295 |
+
back_button = gr.Button("Précédent", variant="secondary")
|
296 |
+
next_button = gr.Button("Suivant", variant="primary")
|
297 |
+
|
298 |
+
# Bouton de génération (visible uniquement à la dernière étape)
|
299 |
+
with gr.Row(visible=False) as generate_button_row:
|
300 |
+
generate_button = gr.Button("Générer le PDF", variant="primary", elem_id="generate-btn")
|
301 |
+
|
302 |
+
# COLONNE DROITE - PRÉVISUALISATION EN TEMPS RÉEL
|
303 |
+
with gr.Column(scale=2):
|
304 |
+
# En-tête de prévisualisation
|
305 |
+
preview_header = gr.Markdown("## Aperçu du contrat en temps réel")
|
306 |
+
preview_info = gr.Markdown(
|
307 |
+
"Au fur et à mesure que vous remplissez le formulaire, votre contrat se construit ici."
|
308 |
+
)
|
309 |
+
|
310 |
+
# Prévisualisation du contrat
|
311 |
+
contract_preview = gr.Markdown(
|
312 |
+
value="*Commencez à remplir le formulaire pour voir l'aperçu du contrat*",
|
313 |
+
elem_id="contract-preview"
|
314 |
+
)
|
315 |
+
|
316 |
+
# Zone de téléchargement (visible uniquement après génération)
|
317 |
+
with gr.Group(visible=False) as download_group:
|
318 |
+
gr.Markdown("### Téléchargement")
|
319 |
+
pdf_output = gr.File(label="Votre contrat est prêt!")
|
320 |
+
|
321 |
+
# ===== FONCTIONS DE NAVIGATION ET MISE À JOUR =====
|
322 |
+
|
323 |
+
# Fonction pour mettre à jour l'indicateur de progression
|
324 |
+
def update_progress(step):
|
325 |
+
progress_text_value = f"**Étape {step} sur {TOTAL_STEPS}**: "
|
326 |
+
|
327 |
+
if step == 1:
|
328 |
+
progress_text_value += "Type d'œuvre"
|
329 |
+
elif step == 2:
|
330 |
+
progress_text_value += "Mode de cession et droits"
|
331 |
+
elif step == 3:
|
332 |
+
progress_text_value += "Informations sur l'auteur/modèle"
|
333 |
+
elif step == 4:
|
334 |
+
progress_text_value += "Description détaillée"
|
335 |
+
elif step == 5:
|
336 |
+
progress_text_value += "Supports d'exploitation"
|
337 |
+
elif step == 6:
|
338 |
+
progress_text_value += "Validation et génération"
|
339 |
+
|
340 |
+
return step, progress_text_value
|
341 |
+
|
342 |
+
# Fonction pour analyser la description et suggérer le type de contrat
|
343 |
+
def analyze_project(description):
|
344 |
+
"""Analyse la description et suggère le type de contrat approprié."""
|
345 |
+
if not description.strip():
|
346 |
+
return "Veuillez fournir une description pour obtenir une suggestion.", []
|
347 |
+
|
348 |
+
detected_types = analyze_work_description(description)
|
349 |
+
explanation = get_explanation(detected_types)
|
350 |
+
|
351 |
+
return explanation, detected_types
|
352 |
+
|
353 |
+
# Associer le bouton d'analyse à la fonction
|
354 |
+
analyze_btn.click(
|
355 |
+
fn=analyze_project,
|
356 |
+
inputs=[project_description],
|
357 |
+
outputs=[contract_type_suggestion, contract_type]
|
358 |
+
)
|
359 |
+
|
360 |
+
# Fonction pour naviguer à l'étape suivante
|
361 |
+
def next_step(current, data,
|
362 |
+
# Étape 1
|
363 |
+
project_desc, contract_types,
|
364 |
+
# Étape 2
|
365 |
+
cession_type, rights, is_exclusive,
|
366 |
+
# Étape 3
|
367 |
+
author_type_val, civility_val, last_name_val, first_name_val, birth_date_val,
|
368 |
+
nationality_val, address_val, contact_physical_val, company_name_val,
|
369 |
+
legal_status_val, rcs_val, company_address_val, contact_company_val,
|
370 |
+
# Étape 4
|
371 |
+
work_desc, image_desc,
|
372 |
+
# Étape 5
|
373 |
+
supports_val, remuneration_val):
|
374 |
+
"""Passe à l'étape suivante et met à jour les données du contrat."""
|
375 |
+
|
376 |
+
# Mettre à jour les données en fonction de l'étape actuelle
|
377 |
+
if current == 1:
|
378 |
+
data["project_description"] = project_desc
|
379 |
+
data["type_contrat"] = contract_types
|
380 |
+
elif current == 2:
|
381 |
+
data["type_cession"] = cession_type
|
382 |
+
data["droits_cedes"] = rights if rights else []
|
383 |
+
data["exclusivite"] = is_exclusive
|
384 |
+
elif current == 3:
|
385 |
+
data["auteur_type"] = author_type_val
|
386 |
+
|
387 |
+
# Recueillir les informations sur l'auteur en fonction du type
|
388 |
+
if author_type_val == "Personne physique":
|
389 |
+
author_info = {
|
390 |
+
"gentille": civility_val,
|
391 |
+
"nom": last_name_val,
|
392 |
+
"prenom": first_name_val,
|
393 |
+
"date_naissance": birth_date_val,
|
394 |
+
"nationalite": nationality_val,
|
395 |
+
"adresse": address_val,
|
396 |
+
"contact": contact_physical_val
|
397 |
+
}
|
398 |
+
else:
|
399 |
+
author_info = {
|
400 |
+
"nom_societe": company_name_val,
|
401 |
+
"statut": legal_status_val,
|
402 |
+
"rcs": rcs_val,
|
403 |
+
"siege": company_address_val,
|
404 |
+
"contact": contact_company_val
|
405 |
+
}
|
406 |
+
|
407 |
+
data["auteur_info"] = author_info
|
408 |
+
elif current == 4:
|
409 |
+
data["description_oeuvre"] = work_desc
|
410 |
+
data["description_image"] = image_desc
|
411 |
+
elif current == 5:
|
412 |
+
data["supports"] = supports_val
|
413 |
+
data["remuneration"] = remuneration_val
|
414 |
+
|
415 |
+
# Si c'est la dernière étape, ne pas avancer
|
416 |
+
if current >= TOTAL_STEPS:
|
417 |
+
current = TOTAL_STEPS
|
418 |
+
else:
|
419 |
+
current += 1
|
420 |
+
|
421 |
+
# Visibilité des groupes en fonction de la nouvelle étape
|
422 |
+
step1_visibility = (current == 1)
|
423 |
+
step2_visibility = (current == 2)
|
424 |
+
step3_visibility = (current == 3)
|
425 |
+
step4_visibility = (current == 4)
|
426 |
+
step5_visibility = (current == 5)
|
427 |
+
step6_visibility = (current == 6)
|
428 |
+
|
429 |
+
# Visibilité conditionnelle des droits supplémentaires et rémunération
|
430 |
+
rights_visibility = (current == 2 and cession_type == "Onéreuse")
|
431 |
+
remuneration_visibility = (current == 5 and data["type_cession"] == "Onéreuse")
|
432 |
+
|
433 |
+
# Visibilité des champs de description en fonction du type de contrat
|
434 |
+
show_work_desc = True
|
435 |
+
show_image_desc = False
|
436 |
+
|
437 |
+
if current == 4:
|
438 |
+
show_work_desc = "Auteur (droits d'auteur)" in data["type_contrat"]
|
439 |
+
show_image_desc = "Image (droit à l'image)" in data["type_contrat"]
|
440 |
+
|
441 |
+
# Visibilité du type de personne
|
442 |
+
show_physical_person = (current == 3 and author_type_val == "Personne physique")
|
443 |
+
show_legal_entity = (current == 3 and author_type_val == "Personne morale")
|
444 |
+
|
445 |
+
# Visibilité du bouton de génération (uniquement à la dernière étape)
|
446 |
+
show_generate_button = (current == TOTAL_STEPS)
|
447 |
+
|
448 |
+
# Mettre à jour l'aperçu du contrat
|
449 |
+
preview = preview_contract(data)
|
450 |
+
|
451 |
+
# Mettre à jour la progression
|
452 |
+
new_progress, progress_text_val = update_progress(current)
|
453 |
+
|
454 |
+
return (
|
455 |
+
# État mis à jour
|
456 |
+
current, data,
|
457 |
+
# Progression
|
458 |
+
new_progress, progress_text_val,
|
459 |
+
# Visibilité des étapes
|
460 |
+
gr.update(visible=step1_visibility), gr.update(visible=step2_visibility),
|
461 |
+
gr.update(visible=step3_visibility), gr.update(visible=step4_visibility),
|
462 |
+
gr.update(visible=step5_visibility), gr.update(visible=step6_visibility),
|
463 |
+
# Visibilité conditionnelle
|
464 |
+
gr.update(visible=rights_visibility), gr.update(visible=remuneration_visibility),
|
465 |
+
gr.update(visible=show_work_desc), gr.update(visible=show_image_desc),
|
466 |
+
gr.update(visible=show_physical_person), gr.update(visible=show_legal_entity),
|
467 |
+
gr.update(visible=show_generate_button),
|
468 |
+
# Aperçu du contrat
|
469 |
+
preview
|
470 |
+
)
|
471 |
+
|
472 |
+
# Fonction pour naviguer à l'étape précédente
|
473 |
+
def previous_step(current, data):
|
474 |
+
"""Revient à l'étape précédente."""
|
475 |
+
|
476 |
+
if current <= 1:
|
477 |
+
current = 1
|
478 |
+
else:
|
479 |
+
current -= 1
|
480 |
+
|
481 |
+
# Visibilité des groupes en fonction de la nouvelle étape
|
482 |
+
step1_visibility = (current == 1)
|
483 |
+
step2_visibility = (current == 2)
|
484 |
+
step3_visibility = (current == 3)
|
485 |
+
step4_visibility = (current == 4)
|
486 |
+
step5_visibility = (current == 5)
|
487 |
+
step6_visibility = (current == 6)
|
488 |
+
|
489 |
+
# Visibilité conditionnelle des droits supplémentaires et rémunération
|
490 |
+
rights_visibility = (current == 2 and data["type_cession"] == "Onéreuse")
|
491 |
+
remuneration_visibility = (current == 5 and data["type_cession"] == "Onéreuse")
|
492 |
+
|
493 |
+
# Visibilité des champs de description en fonction du type de contrat
|
494 |
+
show_work_desc = True
|
495 |
+
show_image_desc = False
|
496 |
+
|
497 |
+
if current == 4:
|
498 |
+
show_work_desc = "Auteur (droits d'auteur)" in data["type_contrat"]
|
499 |
+
show_image_desc = "Image (droit à l'image)" in data["type_contrat"]
|
500 |
+
|
501 |
+
# Visibilité du type de personne
|
502 |
+
show_physical_person = (current == 3 and data["auteur_type"] == "Personne physique")
|
503 |
+
show_legal_entity = (current == 3 and data["auteur_type"] == "Personne morale")
|
504 |
+
|
505 |
+
# Visibilité du bouton de génération (uniquement à la dernière étape)
|
506 |
+
show_generate_button = (current == TOTAL_STEPS)
|
507 |
+
|
508 |
+
# Mettre à jour l'aperçu du contrat
|
509 |
+
preview = preview_contract(data)
|
510 |
+
|
511 |
+
# Mettre à jour la progression
|
512 |
+
new_progress, progress_text_val = update_progress(current)
|
513 |
+
|
514 |
+
return (
|
515 |
+
# État mis à jour
|
516 |
+
current, data,
|
517 |
+
# Progression
|
518 |
+
new_progress, progress_text_val,
|
519 |
+
# Visibilité des étapes
|
520 |
+
gr.update(visible=step1_visibility), gr.update(visible=step2_visibility),
|
521 |
+
gr.update(visible=step3_visibility), gr.update(visible=step4_visibility),
|
522 |
+
gr.update(visible=step5_visibility), gr.update(visible=step6_visibility),
|
523 |
+
# Visibilité conditionnelle
|
524 |
+
gr.update(visible=rights_visibility), gr.update(visible=remuneration_visibility),
|
525 |
+
gr.update(visible=show_work_desc), gr.update(visible=show_image_desc),
|
526 |
+
gr.update(visible=show_physical_person), gr.update(visible=show_legal_entity),
|
527 |
+
gr.update(visible=show_generate_button),
|
528 |
+
# Aperçu du contrat
|
529 |
+
preview
|
530 |
+
)
|
531 |
+
|
532 |
+
# Fonction pour mettre à jour l'affichage en fonction du mode de cession
|
533 |
+
def update_cession_mode_display(mode):
|
534 |
+
"""Met à jour l'affichage des champs liés au mode de cession."""
|
535 |
+
is_onereux = (mode == "Onéreuse")
|
536 |
+
return gr.update(visible=is_onereux)
|
537 |
+
|
538 |
+
# Fonction pour mettre à jour l'affichage en fonction du type d'auteur
|
539 |
+
def update_author_type_display(type_val):
|
540 |
+
"""Met à jour l'affichage des champs liés au type d'auteur."""
|
541 |
+
is_physical = (type_val == "Personne physique")
|
542 |
+
return gr.update(visible=is_physical), gr.update(visible=not is_physical)
|
543 |
+
|
544 |
+
# Fonction pour générer le PDF
|
545 |
+
def generate_pdf(contract_data, filename):
|
546 |
+
"""Génère le PDF du contrat avec indication de progression."""
|
547 |
+
|
548 |
+
# Mise à jour de l'interface pour indiquer le début de la génération
|
549 |
+
yield gr.update(visible=True), gr.update(value="Préparation des données..."), 0, gr.update(visible=False), None
|
550 |
+
time.sleep(0.5)
|
551 |
+
|
552 |
+
# Étape 1: Préparation du contrat (25%)
|
553 |
+
yield gr.update(visible=True), gr.update(value="Construction du contrat..."), 25, gr.update(visible=False), None
|
554 |
+
time.sleep(0.5)
|
555 |
+
|
556 |
+
# Étape 2: Mise en forme (50%)
|
557 |
+
yield gr.update(visible=True), gr.update(value="Mise en forme du document..."), 50, gr.update(visible=False), None
|
558 |
+
time.sleep(0.5)
|
559 |
+
|
560 |
+
# Étape 3: Génération du PDF (75%)
|
561 |
+
yield gr.update(visible=True), gr.update(value="Génération du PDF..."), 75, gr.update(visible=False), None
|
562 |
+
|
563 |
+
# Appel à la fonction de génération réelle
|
564 |
+
pdf_path = generate_pdf_fn(
|
565 |
+
contract_data["type_contrat"],
|
566 |
+
contract_data["type_cession"],
|
567 |
+
contract_data["auteur_type"],
|
568 |
+
contract_data["auteur_info"],
|
569 |
+
contract_data["description_oeuvre"],
|
570 |
+
contract_data["description_image"],
|
571 |
+
contract_data["supports"],
|
572 |
+
contract_data["droits_cedes"],
|
573 |
+
contract_data["remuneration"],
|
574 |
+
contract_data["exclusivite"]
|
575 |
+
)
|
576 |
+
|
577 |
+
# Finalisation (100%)
|
578 |
+
yield gr.update(visible=True), gr.update(value="Contrat PDF généré avec succès!"), 100, gr.update(visible=True), pdf_path
|
579 |
+
|
580 |
+
# Fonction simplifiée pour prévisualiser le contrat
|
581 |
+
def preview_contract(data):
|
582 |
+
"""Génère un aperçu HTML formaté du contrat."""
|
583 |
+
|
584 |
+
# Vérifier qu'il y a suffisamment de données pour prévisualiser
|
585 |
+
if not data.get("type_contrat"):
|
586 |
+
return "*Complétez au moins le type de contrat pour voir l'aperçu*"
|
587 |
+
|
588 |
+
# Appeler la fonction de prévisualisation
|
589 |
+
try:
|
590 |
+
preview_text = preview_contract_fn(
|
591 |
+
data.get("type_contrat", []),
|
592 |
+
data.get("type_cession", "Gratuite"),
|
593 |
+
data.get("auteur_type", "Personne physique"),
|
594 |
+
data.get("auteur_info", {}),
|
595 |
+
data.get("description_oeuvre", ""),
|
596 |
+
data.get("description_image", ""),
|
597 |
+
data.get("supports", []),
|
598 |
+
data.get("droits_cedes", []),
|
599 |
+
data.get("remuneration", ""),
|
600 |
+
data.get("exclusivite", False)
|
601 |
+
)
|
602 |
+
|
603 |
+
# Conversion en HTML avec mise en évidence des données utilisateur
|
604 |
+
preview_html = preview_text.replace("\n", "<br>")
|
605 |
+
|
606 |
+
# Mettre en évidence les titres
|
607 |
+
for ligne in preview_text.split("\n"):
|
608 |
+
if ligne.strip().startswith("ARTICLE") or ligne.strip().isupper():
|
609 |
+
preview_html = preview_html.replace(ligne, f"<h3>{ligne}</h3>")
|
610 |
+
|
611 |
+
return preview_html
|
612 |
+
except Exception as e:
|
613 |
+
return f"*Erreur de prévisualisation: {str(e)}*"
|
614 |
+
|
615 |
+
# ===== ÉVÉNEMENTS =====
|
616 |
+
|
617 |
+
# Navigation entre les étapes
|
618 |
+
next_button.click(
|
619 |
+
fn=next_step,
|
620 |
+
inputs=[
|
621 |
+
current_step, contract_data,
|
622 |
+
# Étape 1
|
623 |
+
project_description, contract_type,
|
624 |
+
# Étape 2
|
625 |
+
cession_mode, additional_rights, exclusivity,
|
626 |
+
# Étape 3
|
627 |
+
author_type, civility, last_name, first_name, birth_date,
|
628 |
+
nationality, address, contact_physical, company_name,
|
629 |
+
legal_status, rcs_number, company_address, contact_company,
|
630 |
+
# Étape 4
|
631 |
+
work_description, image_description,
|
632 |
+
# Étape 5
|
633 |
+
exploitation_supports, remuneration_details
|
634 |
+
],
|
635 |
+
outputs=[
|
636 |
+
current_step, contract_data,
|
637 |
+
# Progression
|
638 |
+
progress_bar, progress_text,
|
639 |
+
# Visibilité des étapes
|
640 |
+
step1_group, step2_group, step3_group, step4_group, step5_group, step6_group,
|
641 |
+
# Visibilité conditionnelle
|
642 |
+
group_rights, group_remuneration,
|
643 |
+
group_work_description, group_image_description,
|
644 |
+
group_physical_person, group_legal_entity,
|
645 |
+
generate_button_row,
|
646 |
+
# Aperçu du contrat
|
647 |
+
contract_preview
|
648 |
+
]
|
649 |
+
)
|
650 |
+
|
651 |
+
back_button.click(
|
652 |
+
fn=previous_step,
|
653 |
+
inputs=[current_step, contract_data],
|
654 |
+
outputs=[
|
655 |
+
current_step, contract_data,
|
656 |
+
# Progression
|
657 |
+
progress_bar, progress_text,
|
658 |
+
# Visibilité des étapes
|
659 |
+
step1_group, step2_group, step3_group, step4_group, step5_group, step6_group,
|
660 |
+
# Visibilité conditionnelle
|
661 |
+
group_rights, group_remuneration,
|
662 |
+
group_work_description, group_image_description,
|
663 |
+
group_physical_person, group_legal_entity,
|
664 |
+
generate_button_row,
|
665 |
+
# Aperçu du contrat
|
666 |
+
contract_preview
|
667 |
+
]
|
668 |
+
)
|
669 |
+
|
670 |
+
# Mise à jour des affichages conditionnels
|
671 |
+
cession_mode.change(
|
672 |
+
fn=update_cession_mode_display,
|
673 |
+
inputs=[cession_mode],
|
674 |
+
outputs=[group_rights]
|
675 |
+
)
|
676 |
+
|
677 |
+
author_type.change(
|
678 |
+
fn=update_author_type_display,
|
679 |
+
inputs=[author_type],
|
680 |
+
outputs=[group_physical_person, group_legal_entity]
|
681 |
+
)
|
682 |
+
|
683 |
+
# Génération du PDF
|
684 |
+
generate_button.click(
|
685 |
+
fn=generate_pdf,
|
686 |
+
inputs=[contract_data, contract_name],
|
687 |
+
outputs=[
|
688 |
+
generation_status_group, generation_status,
|
689 |
+
generation_progress, download_group, pdf_output
|
690 |
+
]
|
691 |
+
)
|
692 |
+
|
693 |
+
return demo
|
text_analyzer.py
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Module d'analyse de texte pour détecter automatiquement le type de contrat nécessaire.
|
3 |
+
"""
|
4 |
+
|
5 |
+
def analyze_work_description(description):
|
6 |
+
"""
|
7 |
+
Analyse la description fournie par l'utilisateur pour déterminer le type de contrat approprié.
|
8 |
+
|
9 |
+
Args:
|
10 |
+
description (str): Description fournie par l'utilisateur
|
11 |
+
|
12 |
+
Returns:
|
13 |
+
list: Liste des types de contrats nécessaires ["Auteur (droits d'auteur)", "Image (droit à l'image)"]
|
14 |
+
"""
|
15 |
+
# Normaliser le texte pour l'analyse
|
16 |
+
texte = description.lower()
|
17 |
+
|
18 |
+
# Initialiser les scores
|
19 |
+
score_auteur = 0
|
20 |
+
score_image = 0
|
21 |
+
|
22 |
+
# DROITS D'AUTEUR - Mots-clés par catégorie
|
23 |
+
mots_textuels = ["livre", "roman", "nouvelle", "poème", "article", "essai", "mémoire", "thèse", "scénario",
|
24 |
+
"manuscrit", "rédaction", "texte", "écriture", "publication", "écrit", "éditorial", "blog",
|
25 |
+
"ouvrage", "brochure", "journal", "magazine", "recueil", "rédactionnel"]
|
26 |
+
|
27 |
+
mots_musicaux = ["musique", "composition", "partition", "chanson", "mélodie", "arrangement", "œuvre musicale",
|
28 |
+
"symphonie", "album", "single", "son", "enregistrement", "morceau", "opus", "instrumental",
|
29 |
+
"concert", "orchestration", "chant", "lyrics", "paroles", "refrain", "harmonie", "acoustique",
|
30 |
+
"piano", "guitare", "violon", "batterie", "chanter", "interprétation musicale"]
|
31 |
+
|
32 |
+
mots_graphiques = ["peinture", "dessin", "illustration", "graphisme", "logo", "infographie", "design",
|
33 |
+
"tableau", "esquisse", "croquis", "fresque", "œuvre plastique", "affiche", "aquarelle",
|
34 |
+
"sculpture", "gravure", "sérigraphie", "street art", "graffiti", "photographie artistique",
|
35 |
+
"collage", "estampe", "lithographie", "pochette", "couverture"]
|
36 |
+
|
37 |
+
mots_numeriques = ["logiciel", "site web", "application", "code", "programme", "script", "algorithme",
|
38 |
+
"jeu vidéo", "développement", "appli", "interface", "plateforme", "solution digitale",
|
39 |
+
"nft", "token", "crypto", "blockchain", "web3", "intelligence artificielle", "ia",
|
40 |
+
"données", "base de données", "système", "api", "plugin", "extension", "widget"]
|
41 |
+
|
42 |
+
mots_architecturaux = ["plan", "maquette", "conception architecturale", "design d'espace", "modélisation 3D",
|
43 |
+
"architecture", "structure", "bâtiment", "édifice", "monument", "urbanisme",
|
44 |
+
"aménagement", "paysagisme", "intérieur", "déco", "décoration"]
|
45 |
+
|
46 |
+
mots_autres_auteur = ["concept", "idée", "invention", "savoir-faire", "méthode", "formule", "base de données",
|
47 |
+
"compilation", "collection", "œuvre", "création", "synthèse", "travail", "production",
|
48 |
+
"droit d'auteur", "propriété intellectuelle", "copyright", "brevet"]
|
49 |
+
|
50 |
+
# DROITS À L'IMAGE - Mots-clés par catégorie
|
51 |
+
mots_image_personne = ["photographie", "portrait", "silhouette", "apparence", "visage", "corps", "identité visuelle",
|
52 |
+
"selfie", "avatar", "photo d'identité", "figure", "physionomie", "traits", "mannequin",
|
53 |
+
"modèle photo", "acteur", "actrice", "comédien", "comédienne", "figurant", "témoignage vidéo"]
|
54 |
+
|
55 |
+
mots_image_contexte = ["pose", "séance photo", "shooting", "mannequin", "modèle", "figurant", "mise en scène",
|
56 |
+
"studio photo", "apparition", "photoshoot", "objectif", "capturer", "appareil photo",
|
57 |
+
"caméra", "filmer", "enregistrer", "photographier", "filmer", "enregistrer"]
|
58 |
+
|
59 |
+
mots_image_visibilité = ["identifiable", "reconnaissable", "apparaître", "figurer", "posant", "visible",
|
60 |
+
"présent", "participation", "exposé", "exhibé", "montré", "droit à l'image",
|
61 |
+
"consentement", "image", "vidéo"]
|
62 |
+
|
63 |
+
mots_image_supports = ["photo", "image", "pellicule", "cliché", "instantané", "polaroid", "négatif",
|
64 |
+
"diapositive", "tirage", "impression photographique", "portrait", "photomaton"]
|
65 |
+
|
66 |
+
# COMBINAISON DROITS D'AUTEUR + DROITS À L'IMAGE
|
67 |
+
mots_videos = ["vidéo", "film", "court-métrage", "clip", "documentaire", "reportage", "captation", "tournage",
|
68 |
+
"filmé", "filmage", "enregistrement vidéo", "séquence", "rushes", "montage vidéo", "movie",
|
69 |
+
"cinéma", "réalisation", "vidéaste", "youtubeur", "youtubeuse", "influenceur", "influenceuse",
|
70 |
+
"vlog", "tiktok", "instagram", "content creator", "créateur de contenu"]
|
71 |
+
|
72 |
+
mots_performances = ["performance", "spectacle", "concert", "prestation", "apparition", "interprétation",
|
73 |
+
"récital", "show", "émission", "interview", "représentation", "apparition publique",
|
74 |
+
"scène", "plateaux", "théâtre", "danse", "chorégraphie", "ballet", "opéra", "music-hall",
|
75 |
+
"one man show", "stand-up", "humoriste", "conférence", "conférencier"]
|
76 |
+
|
77 |
+
mots_digital_personnel = ["stream", "livestream", "webinaire", "podcast vidéo", "tutoriel vidéo", "cours filmé",
|
78 |
+
"formation vidéo", "diffusion en direct", "chaîne youtube", "vlog", "direct",
|
79 |
+
"twitch", "live", "enregistrement zoom", "vidéoconférence", "stories", "reels"]
|
80 |
+
|
81 |
+
mots_œuvres_mixtes = ["œuvre audiovisuelle", "multimédia", "installation artistique interactive",
|
82 |
+
"réalité virtuelle", "réalité augmentée", "performance audiovisuelle", "mapping vidéo",
|
83 |
+
"projection", "hologramme", "expo interactive", "jeu immersif"]
|
84 |
+
|
85 |
+
# Vérifier les correspondances pour les droits d'auteur
|
86 |
+
for mot in mots_textuels + mots_musicaux + mots_graphiques + mots_numeriques + mots_architecturaux + mots_autres_auteur:
|
87 |
+
if mot in texte or any(m in texte for m in mot.split()):
|
88 |
+
score_auteur += 1
|
89 |
+
|
90 |
+
# Vérifier les correspondances pour les droits à l'image
|
91 |
+
for mot in mots_image_personne + mots_image_contexte + mots_image_visibilité + mots_image_supports:
|
92 |
+
if mot in texte or any(m in texte for m in mot.split()):
|
93 |
+
score_image += 1
|
94 |
+
|
95 |
+
# Vérifier les correspondances pour la combinaison (augmente les deux scores)
|
96 |
+
for mot in mots_videos + mots_performances + mots_digital_personnel + mots_œuvres_mixtes:
|
97 |
+
if mot in texte or any(m in texte for m in mot.split()):
|
98 |
+
score_auteur += 1
|
99 |
+
score_image += 1
|
100 |
+
|
101 |
+
# Cas spéciaux nécessitant une analyse plus contextuelle
|
102 |
+
if "chant" in texte or "chante" in texte or "chanson" in texte:
|
103 |
+
score_auteur += 1
|
104 |
+
if any(mot in texte for mot in ["vidéo", "film", "enregistrement vidéo", "youtube", "clip"]):
|
105 |
+
score_image += 1
|
106 |
+
|
107 |
+
if "exposit" in texte: # exposition/expositions
|
108 |
+
score_auteur += 1
|
109 |
+
if any(mot in texte for mot in ["photo", "portrait", "modèle", "personne"]):
|
110 |
+
score_image += 1
|
111 |
+
|
112 |
+
# Analyser les combinaisons courantes
|
113 |
+
if "voix" in texte:
|
114 |
+
score_auteur += 1
|
115 |
+
if "visage" in texte or "image" in texte or "vidéo" in texte:
|
116 |
+
score_image += 1
|
117 |
+
|
118 |
+
# Déterminer le type de contrat
|
119 |
+
types_contrat = []
|
120 |
+
if score_auteur > 0:
|
121 |
+
types_contrat.append("Auteur (droits d'auteur)")
|
122 |
+
if score_image > 0:
|
123 |
+
types_contrat.append("Image (droit à l'image)")
|
124 |
+
|
125 |
+
# Si aucun type détecté, suggérer les deux par sécurité
|
126 |
+
if not types_contrat:
|
127 |
+
return ["Auteur (droits d'auteur)", "Image (droit à l'image)"]
|
128 |
+
|
129 |
+
return types_contrat
|
130 |
+
|
131 |
+
|
132 |
+
def get_explanation(detected_types):
|
133 |
+
"""
|
134 |
+
Génère une explication claire des types de contrats détectés.
|
135 |
+
|
136 |
+
Args:
|
137 |
+
detected_types (list): Types de contrats détectés
|
138 |
+
|
139 |
+
Returns:
|
140 |
+
str: Explication pour l'utilisateur
|
141 |
+
"""
|
142 |
+
if len(detected_types) == 2:
|
143 |
+
return """
|
144 |
+
J'ai détecté que vous avez besoin d'un **contrat combiné de cession de droits d'auteur et de droits à l'image**.
|
145 |
+
|
146 |
+
Ce type de contrat est adapté lorsque:
|
147 |
+
- L'œuvre est protégée par le droit d'auteur (texte, musique, design, etc.)
|
148 |
+
- ET l'image d'une personne est visible et exploitée (vidéo, photo, etc.)
|
149 |
+
|
150 |
+
Vous pouvez modifier cette sélection si nécessaire.
|
151 |
+
"""
|
152 |
+
|
153 |
+
elif "Auteur (droits d'auteur)" in detected_types:
|
154 |
+
return """
|
155 |
+
J'ai détecté que vous avez besoin d'un **contrat de cession de droits d'auteur** uniquement.
|
156 |
+
|
157 |
+
Ce type de contrat est adapté pour les œuvres protégées comme:
|
158 |
+
- Textes, livres, articles
|
159 |
+
- Musiques, compositions
|
160 |
+
- Dessins, peintures, designs
|
161 |
+
- Logiciels, sites web
|
162 |
+
- Et autres créations originales
|
163 |
+
|
164 |
+
Si votre projet implique également l'image reconnaissable d'une personne, vous pourriez aussi avoir besoin d'un contrat de droits à l'image.
|
165 |
+
"""
|
166 |
+
|
167 |
+
elif "Image (droit à l'image)" in detected_types:
|
168 |
+
return """
|
169 |
+
J'ai détecté que vous avez besoin d'un **contrat de cession de droits à l'image** uniquement.
|
170 |
+
|
171 |
+
Ce type de contrat est adapté lorsque:
|
172 |
+
- L'image ou la vidéo d'une personne est utilisée
|
173 |
+
- La personne est identifiable ou reconnaissable
|
174 |
+
- Il n'y a pas d'œuvre originale protégée par le droit d'auteur
|
175 |
+
|
176 |
+
Si votre projet implique également une œuvre originale, vous pourriez aussi avoir besoin d'un contrat de cession de droits d'auteur.
|
177 |
+
"""
|
178 |
+
|
179 |
+
else:
|
180 |
+
return """
|
181 |
+
Je n'ai pas pu déterminer automatiquement le type de contrat nécessaire.
|
182 |
+
|
183 |
+
Veuillez sélectionner manuellement:
|
184 |
+
- Contrat de droits d'auteur: pour les œuvres originales (textes, musiques, designs, etc.)
|
185 |
+
- Contrat de droits à l'image: pour l'utilisation de l'image d'une personne
|
186 |
+
- Les deux: si les deux aspects sont présents
|
187 |
+
"""
|
wizard_style.css
ADDED
@@ -0,0 +1,222 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* Style personnalisé pour l'interface du générateur de contrats en mode wizard */
|
2 |
+
|
3 |
+
/* Style global */
|
4 |
+
body {
|
5 |
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
6 |
+
}
|
7 |
+
|
8 |
+
/* Style pour le conteneur principal */
|
9 |
+
.gradio-container {
|
10 |
+
max-width: 1400px;
|
11 |
+
margin: 0 auto;
|
12 |
+
}
|
13 |
+
|
14 |
+
/* Style pour la barre de progression */
|
15 |
+
.progress-container {
|
16 |
+
margin-bottom: 20px;
|
17 |
+
}
|
18 |
+
|
19 |
+
/* Style pour l'aperçu du contrat */
|
20 |
+
#contract-preview {
|
21 |
+
max-height: 700px;
|
22 |
+
overflow-y: auto;
|
23 |
+
padding: 25px;
|
24 |
+
border: 1px solid #ddd;
|
25 |
+
border-radius: 8px;
|
26 |
+
background-color: #f9f9f9;
|
27 |
+
font-family: 'Times New Roman', Times, serif;
|
28 |
+
line-height: 1.6;
|
29 |
+
font-size: 14px;
|
30 |
+
margin-top: 10px;
|
31 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
32 |
+
}
|
33 |
+
|
34 |
+
/* Style pour la suggestion de type de contrat */
|
35 |
+
#contract-suggestion {
|
36 |
+
padding: 15px;
|
37 |
+
border-left: 4px solid #3b82f6;
|
38 |
+
background-color: #f0f7ff;
|
39 |
+
margin: 15px 0;
|
40 |
+
border-radius: 0 4px 4px 0;
|
41 |
+
}
|
42 |
+
|
43 |
+
/* Style pour les titres dans la prévisualisation */
|
44 |
+
#contract-preview h3 {
|
45 |
+
color: #222;
|
46 |
+
font-weight: bold;
|
47 |
+
margin-top: 15px;
|
48 |
+
margin-bottom: 5px;
|
49 |
+
border-bottom: 1px solid #ccc;
|
50 |
+
padding-bottom: 5px;
|
51 |
+
}
|
52 |
+
|
53 |
+
/* Style pour mettre en évidence les saisies utilisateur */
|
54 |
+
#contract-preview strong {
|
55 |
+
color: #0056b3;
|
56 |
+
font-weight: bold;
|
57 |
+
}
|
58 |
+
|
59 |
+
/* Style pour le bouton de génération */
|
60 |
+
#generate-btn {
|
61 |
+
background-color: #2563eb;
|
62 |
+
color: white;
|
63 |
+
font-weight: bold;
|
64 |
+
padding: 12px 24px;
|
65 |
+
border-radius: 5px;
|
66 |
+
transition: all 0.3s;
|
67 |
+
font-size: 16px;
|
68 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
69 |
+
}
|
70 |
+
|
71 |
+
#generate-btn:hover {
|
72 |
+
background-color: #1d4ed8;
|
73 |
+
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
74 |
+
transform: translateY(-2px);
|
75 |
+
}
|
76 |
+
|
77 |
+
/* Style pour les boutons de navigation */
|
78 |
+
.navigation-buttons {
|
79 |
+
margin-top: 20px;
|
80 |
+
display: flex;
|
81 |
+
justify-content: space-between;
|
82 |
+
}
|
83 |
+
|
84 |
+
/* Style pour les titres de section */
|
85 |
+
.gradio-container h2 {
|
86 |
+
color: #1e40af;
|
87 |
+
border-bottom: 2px solid #e5e7eb;
|
88 |
+
padding-bottom: 10px;
|
89 |
+
margin-top: 30px;
|
90 |
+
margin-bottom: 20px;
|
91 |
+
font-size: 24px;
|
92 |
+
}
|
93 |
+
|
94 |
+
.gradio-container h3 {
|
95 |
+
color: #333;
|
96 |
+
margin-top: 20px;
|
97 |
+
font-size: 18px;
|
98 |
+
}
|
99 |
+
|
100 |
+
/* Style pour les groupes */
|
101 |
+
.gradio-container .gr-group {
|
102 |
+
border: 1px solid #e5e7eb;
|
103 |
+
border-radius: 8px;
|
104 |
+
padding: 15px;
|
105 |
+
margin-bottom: 20px;
|
106 |
+
background-color: #fff;
|
107 |
+
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
108 |
+
}
|
109 |
+
|
110 |
+
/* Style pour les labels des champs */
|
111 |
+
.gradio-container label {
|
112 |
+
font-weight: 600;
|
113 |
+
color: #4b5563;
|
114 |
+
margin-bottom: 5px;
|
115 |
+
}
|
116 |
+
|
117 |
+
/* Style pour les champs du formulaire */
|
118 |
+
.gradio-container input[type="text"],
|
119 |
+
.gradio-container textarea {
|
120 |
+
border: 1px solid #d1d5db;
|
121 |
+
border-radius: 6px;
|
122 |
+
padding: 10px 14px;
|
123 |
+
transition: all 0.3s;
|
124 |
+
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
125 |
+
}
|
126 |
+
|
127 |
+
.gradio-container input[type="text"]:focus,
|
128 |
+
.gradio-container textarea:focus {
|
129 |
+
border-color: #3b82f6;
|
130 |
+
outline: none;
|
131 |
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.25);
|
132 |
+
}
|
133 |
+
|
134 |
+
/* Style pour les informations/descriptions */
|
135 |
+
.gradio-container .info {
|
136 |
+
color: #6b7280;
|
137 |
+
font-size: 14px;
|
138 |
+
margin-top: 4px;
|
139 |
+
}
|
140 |
+
|
141 |
+
/* Style pour les étapes du wizard */
|
142 |
+
.step-number {
|
143 |
+
display: inline-block;
|
144 |
+
width: 30px;
|
145 |
+
height: 30px;
|
146 |
+
background-color: #3b82f6;
|
147 |
+
color: white;
|
148 |
+
border-radius: 50%;
|
149 |
+
text-align: center;
|
150 |
+
line-height: 30px;
|
151 |
+
margin-right: 10px;
|
152 |
+
font-weight: bold;
|
153 |
+
}
|
154 |
+
|
155 |
+
/* Style pour les informations d'aide */
|
156 |
+
.help-text {
|
157 |
+
background-color: #f3f4f6;
|
158 |
+
padding: 12px;
|
159 |
+
border-radius: 6px;
|
160 |
+
margin-bottom: 15px;
|
161 |
+
border-left: 4px solid #9ca3af;
|
162 |
+
}
|
163 |
+
|
164 |
+
/* Style pour l'indicateur de progression */
|
165 |
+
.progress-indicator {
|
166 |
+
display: flex;
|
167 |
+
justify-content: space-between;
|
168 |
+
align-items: center;
|
169 |
+
margin-bottom: 30px;
|
170 |
+
}
|
171 |
+
|
172 |
+
.progress-step {
|
173 |
+
flex: 1;
|
174 |
+
text-align: center;
|
175 |
+
position: relative;
|
176 |
+
}
|
177 |
+
|
178 |
+
.progress-step:not(:last-child):after {
|
179 |
+
content: '';
|
180 |
+
position: absolute;
|
181 |
+
top: 50%;
|
182 |
+
right: 0;
|
183 |
+
width: 100%;
|
184 |
+
height: 2px;
|
185 |
+
background-color: #e5e7eb;
|
186 |
+
z-index: 1;
|
187 |
+
}
|
188 |
+
|
189 |
+
.progress-step.active:not(:last-child):after,
|
190 |
+
.progress-step.completed:not(:last-child):after {
|
191 |
+
background-color: #3b82f6;
|
192 |
+
}
|
193 |
+
|
194 |
+
.progress-step-circle {
|
195 |
+
width: 24px;
|
196 |
+
height: 24px;
|
197 |
+
border-radius: 50%;
|
198 |
+
background-color: #e5e7eb;
|
199 |
+
display: inline-flex;
|
200 |
+
justify-content: center;
|
201 |
+
align-items: center;
|
202 |
+
position: relative;
|
203 |
+
z-index: 2;
|
204 |
+
}
|
205 |
+
|
206 |
+
.progress-step.active .progress-step-circle,
|
207 |
+
.progress-step.completed .progress-step-circle {
|
208 |
+
background-color: #3b82f6;
|
209 |
+
color: white;
|
210 |
+
}
|
211 |
+
|
212 |
+
.progress-step-text {
|
213 |
+
font-size: 12px;
|
214 |
+
margin-top: 8px;
|
215 |
+
color: #6b7280;
|
216 |
+
}
|
217 |
+
|
218 |
+
.progress-step.active .progress-step-text,
|
219 |
+
.progress-step.completed .progress-step-text {
|
220 |
+
color: #1e40af;
|
221 |
+
font-weight: 600;
|
222 |
+
}
|