import streamlit as st from datetime import datetime, time import pandas as pd import plotly.express as px from dotenv import load_dotenv from import_data.utils.typesense_client import client from search_app_ui.rechercher_documents import rechercher_documents from search_app_ui.recuperer_reseaux import recuperer_reseaux # Configurer la page en mode large st.set_page_config(layout="wide") # Load and apply the CSS def load_css(file_name): with open(file_name) as f: st.markdown(f'', unsafe_allow_html=True) # Load the CSS file load_css('style.css') # If the CSS file is in a subdirectory, adjust the path accordingly # Charger les variables d'environnement load_dotenv() # Interface utilisateur Streamlit st.title('Recherche dans tes contenus publiés sur le web') # Indiquer le nombre total de documents indexés dans Typesense collections = client.collections.retrieve() total_documents = sum(collection['num_documents'] for collection in collections) # Champ de recherche requete = st.text_input('Entrez votre requête de recherche') # Filtre de plage de dates col1, col2 = st.columns(2) date_debut = col1.date_input('Date de début', value=datetime.now() - pd.DateOffset(years=1)) date_fin = col2.date_input('Date de fin', value=datetime.now()) # Filtre de réseau social et de langue col3, col4 = st.columns(2) reseaux = recuperer_reseaux() reseaux_selectionnes = col3.multiselect('Sélectionnez les réseaux sociaux', reseaux, default=reseaux[0] if reseaux else None) langues = [('fr', 'Français'), ('en', 'English')] langue_selectionnees = col4.multiselect('Sélectionnez la langue', options=[label for code, label in langues], format_func=lambda x: x, default='Français') # Filtre sur le nombre de mots nombre_mots = st.slider('Nombre de mots minimum', min_value=0, max_value=1000, value=100, step=10) # Convertir les étiquettes en codes de langage selected_lang_codes = [code for code, label in langues if label in langue_selectionnees] # Nouvelle section pour les options de recherche avancées st.sidebar.header("Options de recherche avancées") # Option pour activer/désactiver les options avancées show_advanced_options = st.sidebar.checkbox("Activer les options avancées") if show_advanced_options: # Champs de recherche query_by = st.sidebar.multiselect( "Champs de recherche", ["texte", "embedding"], default=["texte", "embedding"] ) # Tri sort_options = [ "_text_match:desc", "creation_timestamp:desc", "_text_match:asc", "creation_timestamp:asc", ] nb_buckets = st.sidebar.number_input("Nombre de buckets pour le tri", min_value=1, value=10) sort_by = st.sidebar.multiselect( "Trier par", sort_options, default=["_text_match:desc", "creation_timestamp:desc"] ) # Préfixe prefix = st.sidebar.checkbox("Activer la recherche par préfixe", value=False) # Pagination per_page = st.sidebar.slider("Résultats par page", min_value=1, max_value=100, value=10) page = st.sidebar.number_input("Page", min_value=1, value=1) else: # Valeurs par défaut si les options avancées ne sont pas affichées query_by = ["texte", "embedding"] sort_by = ["_text_match:desc", "creation_timestamp:desc"] prefix = False nb_buckets = 10 per_page = 10 page = 1 if st.button('Rechercher'): # Préparer les filtres debut_datetime = datetime.combine(date_debut, time.min) fin_datetime = datetime.combine(date_fin, time.max) filtre_date = f"creation_timestamp:[{int(debut_datetime.timestamp())}..{int(fin_datetime.timestamp())}]" filtre_reseau = f"network:=[{', '.join(reseaux_selectionnes)}]" if reseaux_selectionnes else None filtre_langue = f"langue:=[{', '.join(selected_lang_codes)}]" if selected_lang_codes else None filtre_mots = f"nombre_de_mots:[{nombre_mots}..10000]" if nombre_mots > 0 else None liste_filtres = [] if filtre_date: liste_filtres.append(filtre_date) if filtre_reseau: liste_filtres.append(filtre_reseau) if filtre_langue: liste_filtres.append(filtre_langue) if filtre_mots: liste_filtres.append(filtre_mots) filtres = ' && '.join(liste_filtres) if liste_filtres else None # Effectuer la recherche pour tous les résultats tous_resultats = rechercher_documents( requete, ces_filtres=filtres, facette_par='network', query_by=','.join(query_by), sort_by=','.join(sort_by), nb_buckets=nb_buckets, prefix=prefix, per_page=per_page, page=page ) if tous_resultats: nombre_total_resultats = tous_resultats['found'] # Afficher le nombre total de résultats st.subheader(f"Trouvé {nombre_total_resultats} résultats parmi {total_documents } documents indexés") else: nombre_total_resultats = 0 st.subheader("Aucun résultat trouvé") if nombre_total_resultats > 0: # Affichage des résultats (100 maximum) st.subheader("Résultats de la recherche") for hit in tous_resultats['hits'][:100]: # Limite à 100 résultats col1, col2 = st.columns([1, 4]) with col1: st.markdown(f"**{hit['document']['network']}**") st.markdown( f"**{datetime.fromtimestamp(hit['document']['creation_timestamp']).strftime('%Y-%m-%d %H:%M:%S')}**") st.markdown(f"**{hit['document']['nombre_de_mots']} mots**") # Score if "texte" in query_by and "embedding" in query_by: score = hit["hybrid_search_info"]['rank_fusion_score'] score_type = "Hybrid" elif "texte" in query_by: score = hit["text_match_info"]['score'] score_type = "Text" elif "embedding" in query_by: score = hit["vector_distance"] score_type = "Vector" else: score = "N/A" score_type = "Unknown" st.markdown(f"**{score_type} Score: {score}**") # Étiquettes de couleur pour les facettes st.markdown(f""" {hit['document']['langue']} """, unsafe_allow_html=True) with col2: # Boîte de texte pour le contenu st.text_area("Contenu", hit['document']['texte'], height=150) # URI en dessous if 'uri' in hit['document']: st.markdown(f"[Lien vers le post original]({hit['document']['uri']})") # Affichage du hit brut st.subheader("Données brutes") st.json(hit, expanded=False) st.markdown("---") # Afficher les facettes if 'facet_counts' in tous_resultats: facettes_reseau = {facette['value']: facette['count'] for facette in tous_resultats['facet_counts'][0]['counts']} st.subheader("Résultats par Réseau") # Graphique en camembert pour montrer la distribution des résultats par réseau social fig = px.pie(values=list(facettes_reseau.values()), names=list(facettes_reseau.keys()), title="Distribution par Réseau") # Ce graphique montre la proportion de résultats pour chaque réseau social st.plotly_chart(fig) # Distribution temporelle par réseau et par mois if nombre_total_resultats > 0: st.subheader("Résultats au fil du temps par réseau (agrégation mensuelle)") df_temporel = pd.DataFrame({ 'date': [datetime.fromtimestamp(hit['document']['creation_timestamp']) for hit in tous_resultats['hits']], 'network': [hit['document']['network'] for hit in tous_resultats['hits']] }) df_temporel['mois'] = df_temporel['date'].dt.to_period('M') df_temporel = df_temporel.groupby(['mois', 'network']).size().reset_index(name='count') df_temporel['mois'] = df_temporel['mois'].dt.to_timestamp() # Graphique linéaire pour montrer l'évolution du nombre de posts par réseau au fil du temps fig = px.line(df_temporel, x='mois', y='count', color='network', title="Distribution temporelle par réseau (agrégation mensuelle)") fig.update_layout(xaxis_title="Mois", yaxis_title="Nombre de posts") fig.update_xaxes(tickformat="%B %Y") # Ce graphique permet de visualiser les tendances de publication pour chaque réseau social au fil des mois st.plotly_chart(fig) # Graphique à barres empilées pour montrer la répartition des posts par réseau pour chaque mois fig_bar = px.bar(df_temporel, x='mois', y='count', color='network', title="Distribution temporelle par réseau (barres empilées, agrégation mensuelle)") fig_bar.update_layout(xaxis_title="Mois", yaxis_title="Nombre de posts") fig_bar.update_xaxes(tickformat="%B %Y") # Ce graphique permet de comparer facilement le volume de posts entre les différents réseaux sociaux pour chaque mois st.plotly_chart(fig_bar) st.subheader("Tableau récapitulatif mensuel") df_pivot = df_temporel.pivot(index='mois', columns='network', values='count').fillna(0) df_pivot['Total'] = df_pivot.sum(axis=1) df_pivot = df_pivot.reset_index() df_pivot['mois'] = df_pivot['mois'].dt.strftime('%B %Y') # Ce tableau fournit un résumé détaillé du nombre de posts par réseau social pour chaque mois st.dataframe(df_pivot)