2024-10-03 22:30:39 -04:00
|
|
|
import streamlit as st
|
|
|
|
from datetime import datetime, time
|
|
|
|
import pandas as pd
|
|
|
|
import plotly.express as px
|
|
|
|
from dotenv import load_dotenv
|
2025-01-02 23:04:35 -05:00
|
|
|
|
|
|
|
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
|
2024-10-03 22:30:39 -04:00
|
|
|
|
2024-11-30 19:10:01 -05:00
|
|
|
# Configurer la page en mode large
|
2024-10-03 22:36:29 -04:00
|
|
|
st.set_page_config(layout="wide")
|
|
|
|
|
2025-01-02 23:04:35 -05:00
|
|
|
# Load and apply the CSS
|
|
|
|
def load_css(file_name):
|
|
|
|
with open(file_name) as f:
|
|
|
|
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
|
|
|
|
|
|
|
|
# Load the CSS file
|
|
|
|
load_css('style.css') # If the CSS file is in a subdirectory, adjust the path accordingly
|
2024-10-03 22:30:39 -04:00
|
|
|
|
|
|
|
# Charger les variables d'environnement
|
|
|
|
load_dotenv()
|
|
|
|
|
|
|
|
# Interface utilisateur Streamlit
|
2024-10-03 22:38:59 -04:00
|
|
|
st.title('Recherche dans tes contenus publiés sur le web')
|
2024-10-03 22:30:39 -04:00
|
|
|
|
2024-11-30 22:03:49 -05:00
|
|
|
# Indiquer le nombre total de documents indexés dans Typesense
|
|
|
|
collections = client.collections.retrieve()
|
|
|
|
total_documents = sum(collection['num_documents'] for collection in collections)
|
|
|
|
|
2024-10-03 22:30:39 -04:00
|
|
|
# Champ de recherche
|
|
|
|
requete = st.text_input('Entrez votre requête de recherche')
|
|
|
|
|
|
|
|
# Filtre de plage de dates
|
|
|
|
col1, col2 = st.columns(2)
|
2024-11-30 22:03:49 -05:00
|
|
|
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())
|
2024-10-03 22:30:39 -04:00
|
|
|
|
2024-11-30 22:25:47 -05:00
|
|
|
# Filtre de réseau social et de langue
|
2024-11-30 22:03:49 -05:00
|
|
|
|
2024-11-30 22:25:47 -05:00
|
|
|
col3, col4 = st.columns(2)
|
2025-01-02 23:04:35 -05:00
|
|
|
reseaux = recuperer_reseaux()
|
2024-11-30 22:25:47 -05:00
|
|
|
reseaux_selectionnes = col3.multiselect('Sélectionnez les réseaux sociaux', reseaux,
|
2024-11-30 22:03:49 -05:00
|
|
|
default=reseaux[0] if reseaux else None)
|
|
|
|
langues = [('fr', 'Français'), ('en', 'English')]
|
2024-11-30 22:25:47 -05:00
|
|
|
langue_selectionnees = col4.multiselect('Sélectionnez la langue',
|
2024-11-30 22:03:49 -05:00
|
|
|
options=[label for code, label in langues],
|
|
|
|
format_func=lambda x: x,
|
|
|
|
default='Français')
|
|
|
|
|
2025-01-02 23:04:35 -05:00
|
|
|
# Filtre sur le nombre de mots
|
|
|
|
nombre_mots = st.slider('Nombre de mots minimum', min_value=0, max_value=1000, value=100, step=10)
|
|
|
|
|
2024-11-30 22:03:49 -05:00
|
|
|
# Convertir les étiquettes en codes de langage
|
|
|
|
selected_lang_codes = [code for code, label in langues if label in langue_selectionnees]
|
2024-10-03 22:30:39 -04:00
|
|
|
|
2025-01-02 23:04:35 -05:00
|
|
|
# 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
|
2024-11-30 22:25:47 -05:00
|
|
|
|
2024-10-03 22:30:39 -04:00
|
|
|
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())}]"
|
2025-01-02 23:04:35 -05:00
|
|
|
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
|
2024-11-30 22:25:47 -05:00
|
|
|
filtre_mots = f"nombre_de_mots:[{nombre_mots}..10000]" if nombre_mots > 0 else None
|
2024-10-03 22:30:39 -04:00
|
|
|
|
2025-01-02 23:04:35 -05:00
|
|
|
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
|
2024-10-03 22:30:39 -04:00
|
|
|
# Effectuer la recherche pour tous les résultats
|
2025-01-02 23:04:35 -05:00
|
|
|
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é")
|
|
|
|
|
|
|
|
|
2024-10-03 22:30:39 -04:00
|
|
|
if nombre_total_resultats > 0:
|
2025-01-02 23:04:35 -05:00
|
|
|
# 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"""
|
|
|
|
<span style="background-color: #007bff; color: white; padding: 2px 6px; border-radius: 10px;">
|
|
|
|
{hit['document']['langue']}
|
|
|
|
</span>
|
|
|
|
""", 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)
|