import pandas as pd import gradio as gr import os from datetime import datetime from pathlib import Path BASE_PATH = "." class FeedbackState: def __init__(self, username): self.current_idx = 0 self.feedback_data = [] self.username = username self.responses = [] # Read TSV file with tab separator df = pd.read_csv(os.path.join(BASE_PATH, 'parameters.tsv'), sep='\t') with gr.Blocks(title="Évaluation des descriptions auto-générées") as demo: # Login page with welcome message with gr.Row(visible=True) as login_row: with gr.Column(): gr.Markdown("""### Bienvenue à l'évaluation des descriptions auto-générées! Ton retour est essentiel pour améliorer notre feature de descriptions automatiques d'annonces. En évaluant ces descriptions, tu nous aides à garantir qu'elles capturent précisément les caractéristiques des produits et adoptent le ton et style approprié pour chaque catégorie. ⏱️ Temps estimé: environ 2 minutes par annonce""") username_input = gr.Textbox(label="Ton nom") login_button = gr.Button("Commencer l'évaluation") with gr.Column(visible=False) as thank_you_container: completion_msg = gr.Markdown("", visible=False) download_link = gr.File(label="Télécharge le fichier CSV des retours") with gr.Column(visible=False) as main_interface: state = gr.State(lambda: None) # Instructions at the top of evaluation interface gr.Markdown("""### Instructions: 1. Tu trouveras pour chaque annonce: - L'image et caractéristiques du produit (à droite) - Deux versions à évaluer: description générée par l'IA avec titre (gauche) et description générée par l'IA sans titre (droite) 2. Pour chaque version: - Choisis "Accepter" ou "Refuser" - Si "Refuser": sélectionne la raison principale - Si "Autre": précise brièvement pourquoi 3. Navigation et fin: - Utilise "Précédent"/"Suivant" pour parcourir les annonces - Le compteur en bas à gauche indique ta progression - À la fin: télécharge le fichier CSV et partage-le dans #cognition-users sur Slack""") with gr.Row(): image_display = gr.Image(label="Image du Produit", height=400) param_view = gr.JSON(label="Paramètres de l'Annonce") with gr.Row(): # Left column - With Title with gr.Column(): gr.Markdown("### Description générée par l'IA en tenant compte du titre") title_display = gr.Textbox(label="Titre", interactive=False) desc_with_title = gr.Textbox(label="Description", interactive=False) feedback_with_title = gr.Radio( ["Accepter", "Refuser"], label="Évalue cette version" ) with gr.Column(visible=False) as improvement_with_title_container: improvement_with_title = gr.Radio( ["Attributs manquants/imprécis", "Style trop robotique/impersonnel", "Style trop familier", "Description trop longue/verbeuse", "Description trop courte", "Autre"], label="Si tu as choisi 'Refuser', indique la raison principale :" ) other_comment_with_title = gr.Textbox( label="Si 'Autre', précise en quelques mots :", max_lines=1, visible=False ) # Right column - Without Title with gr.Column(): gr.Markdown("### Description générée par l'IA sans tenir compte du titre") desc_without_title = gr.Textbox(label="Description", interactive=False) feedback_without_title = gr.Radio( ["Accepter", "Refuser"], label="Évalue cette version" ) with gr.Column(visible=False) as improvement_without_title_container: improvement_without_title = gr.Radio( ["Attributs manquants/imprécis", "Style trop robotique/impersonnel", "Style trop familier", "Description trop longue/verbeuse", "Description trop courte", "Autre"], label="Si tu as choisi 'Refuser', indique la raison principale :" ) other_comment_without_title = gr.Textbox( label="Si 'Autre', précise en quelques mots :", max_lines=1, visible=False ) with gr.Row(): prev_btn = gr.Button("Précédent", visible=False) next_btn = gr.Button("Suivant") export_btn = gr.Button("Terminer et Exporter en CSV", visible=False) status = gr.Markdown() def show_improvement_options(feedback_choice, is_with_title=True): return { improvement_with_title_container if is_with_title else improvement_without_title_container: gr.update(visible=feedback_choice == "Refuser") } def show_other_comment(improvement_choice, is_with_title=True): return { other_comment_with_title if is_with_title else other_comment_without_title: gr.update(visible=improvement_choice == "Autre") } def login(username): if not username.strip(): return { login_row: gr.update(visible=True), main_interface: gr.update(visible=False), username_input: gr.update(value="", error="Entre un nom s'il te plaît") } return { login_row: gr.update(visible=False), main_interface: gr.update(visible=True), state: FeedbackState(username) } def load_listing(idx, state): if state is None: return None record = df.iloc[idx] is_last = idx == len(df) - 1 is_first = idx == 0 return { image_display: os.path.join(BASE_PATH, str(record['image_filename']).strip()), param_view: eval(str(record['listing_params']).strip()), title_display: str(record['listing_title']).strip(), desc_with_title: str(record['generated_description_with_title']).strip(), desc_without_title: str(record['generated_description_without_title']).strip(), status: f"Annonce {idx+1} sur {len(df)}", prev_btn: gr.update(visible=not is_first), next_btn: gr.update(visible=not is_last), export_btn: gr.update(visible=is_last), feedback_with_title: None, feedback_without_title: None, improvement_with_title: None, improvement_without_title: None, other_comment_with_title: "", other_comment_without_title: "", improvement_with_title_container: gr.update(visible=False), improvement_without_title_container: gr.update(visible=False) } def navigate(direction, state, feedback_with_title, improvement_with_title, other_comment_with_title, feedback_without_title, improvement_without_title, other_comment_without_title): if state is None: return None if feedback_with_title or feedback_without_title: current_feedback = { 'username': state.username, 'listing_id': df.iloc[state.current_idx]['listing_id'], 'feedback_with_title': feedback_with_title, 'improvement_with_title': improvement_with_title if feedback_with_title == "Refuser" else "", 'other_comment_with_title': other_comment_with_title if improvement_with_title == "Autre" else "", 'feedback_without_title': feedback_without_title, 'improvement_without_title': improvement_without_title if feedback_without_title == "Refuser" else "", 'other_comment_without_title': other_comment_without_title if improvement_without_title == "Autre" else "", 'timestamp': datetime.now().isoformat() } state.responses.append(current_feedback) new_idx = max(0, min(len(df)-1, state.current_idx + direction)) state.current_idx = new_idx return load_listing(new_idx, state) def save_and_export(state, feedback_with_title, improvement_with_title, other_comment_with_title, feedback_without_title, improvement_without_title, other_comment_without_title): if not (feedback_with_title and feedback_without_title): return ( gr.update(value="Merci de sélectionner Accepter ou Refuser pour les deux versions.", visible=True), gr.update(visible=True), gr.update(visible=False), None ) final_feedback = { 'username': state.username, 'listing_id': df.iloc[state.current_idx]['listing_id'], 'feedback_with_title': feedback_with_title, 'improvement_with_title': improvement_with_title if feedback_with_title == "Refuser" else "", 'other_comment_with_title': other_comment_with_title if improvement_with_title == "Autre" else "", 'feedback_without_title': feedback_without_title, 'improvement_without_title': improvement_without_title if feedback_without_title == "Refuser" else "", 'other_comment_without_title': other_comment_without_title if improvement_without_title == "Autre" else "", 'timestamp': datetime.now().isoformat() } state.responses.append(final_feedback) feedback_df = pd.DataFrame(state.responses) timestamp = datetime.now().strftime('%Y%m%d') username_safe = state.username.replace(' ', '_') csv_filename = f'resultats_feedback_{timestamp}_{username_safe}.csv' feedback_df.to_csv(csv_filename, index=False) thank_you_message = "## Merci d'avoir complété l'évaluation ! 🎉\n\nClique ci-dessous pour télécharger ton fichier CSV de retours." return ( gr.update(value=thank_you_message, visible=True), gr.update(visible=False), gr.update(visible=True), csv_filename ) # Event handlers login_button.click( fn=login, inputs=[username_input], outputs=[login_row, main_interface, state] ).then( fn=lambda s: load_listing(0, s), inputs=[state], outputs=[image_display, param_view, title_display, desc_with_title, desc_without_title, status, prev_btn, next_btn, export_btn, feedback_with_title, feedback_without_title, improvement_with_title, improvement_without_title, other_comment_with_title, other_comment_without_title, improvement_with_title_container, improvement_without_title_container] ) feedback_with_title.change( fn=show_improvement_options, inputs=[feedback_with_title], outputs=[improvement_with_title_container] ) feedback_without_title.change( fn=lambda x: show_improvement_options(x, False), inputs=[feedback_without_title], outputs=[improvement_without_title_container] ) improvement_with_title.change( fn=show_other_comment, inputs=[improvement_with_title], outputs=[other_comment_with_title] ) improvement_without_title.change( fn=lambda x: show_other_comment(x, False), inputs=[improvement_without_title], outputs=[other_comment_without_title] ) prev_btn.click( fn=navigate, inputs=[gr.State(-1), state, feedback_with_title, improvement_with_title, other_comment_with_title, feedback_without_title, improvement_without_title, other_comment_without_title], outputs=[image_display, param_view, title_display, desc_with_title, desc_without_title, status, prev_btn, next_btn, export_btn, feedback_with_title, feedback_without_title, improvement_with_title, improvement_without_title, other_comment_with_title, other_comment_without_title, improvement_with_title_container, improvement_without_title_container] ) next_btn.click( fn=navigate, inputs=[gr.State(1), state, feedback_with_title, improvement_with_title, other_comment_with_title, feedback_without_title, improvement_without_title, other_comment_without_title], outputs=[image_display, param_view, title_display, desc_with_title, desc_without_title, status, prev_btn, next_btn, export_btn, feedback_with_title, feedback_without_title, improvement_with_title, improvement_without_title, other_comment_with_title, other_comment_without_title, improvement_with_title_container, improvement_without_title_container] ) export_btn.click( fn=save_and_export, inputs=[state, feedback_with_title, improvement_with_title, other_comment_with_title, feedback_without_title, improvement_without_title, other_comment_without_title], outputs=[completion_msg, main_interface, thank_you_container, download_link] ) if __name__ == "__main__": demo.launch()