Update app.py
Browse files
app.py
CHANGED
|
@@ -10,16 +10,12 @@ Intégration complète avec:
|
|
| 10 |
- Chain of Thought visible
|
| 11 |
- Style personnalisé (dark theme)
|
| 12 |
"""
|
| 13 |
-
|
| 14 |
import os
|
| 15 |
import json
|
| 16 |
import asyncio
|
| 17 |
from typing import Dict, Any, List, Optional
|
| 18 |
-
|
| 19 |
import chainlit as cl
|
| 20 |
from chainlit.types import ThreadDict, Starter
|
| 21 |
-
#from langsmith import Client
|
| 22 |
-
#from langsmith.run_helpers import traceable
|
| 23 |
from langsmith import traceable
|
| 24 |
|
| 25 |
# Import du module agent (votre code existant)
|
|
@@ -33,36 +29,9 @@ from agent_collaboratif_avid import (
|
|
| 33 |
MAX_VALIDATION_LOOPS
|
| 34 |
)
|
| 35 |
import bcrypt
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
from
|
| 39 |
-
from supabase.lib.client_options import ClientOptions
|
| 40 |
-
|
| 41 |
-
#from langfuse.langchain import CallbackHandler
|
| 42 |
-
#import getpass
|
| 43 |
-
#os.environ['LANGFUSE_SECRET_KEY'] = getpass.getpass("Enter your Secret key: ")
|
| 44 |
-
#os.environ['LANGFUSE_PUBLIC_KEY'] = getpass.getpass("Enter your Public key: ")
|
| 45 |
-
#os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com"
|
| 46 |
-
#langfuse_handler = CallbackHandler()
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
SUPABASE_URL = os.environ.get("SUPABASE_URL")
|
| 50 |
-
SUPABASE_ANON_KEY = os.environ.get("SUPABASE_ANON_KEY")
|
| 51 |
-
CONNINFO = os.environ.get("CONNINFO")
|
| 52 |
-
|
| 53 |
-
url: str = SUPABASE_URL
|
| 54 |
-
key: str = SUPABASE_ANON_KEY
|
| 55 |
-
supabase: Client = create_client(url, key)
|
| 56 |
-
|
| 57 |
-
#url: str = "https://urtvfyesitnmwrouarze.supabase.co"
|
| 58 |
-
#key: str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVydHZmeWVzaXRubXdyb3VhcnplIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTk5NTgyNzIsImV4cCI6MjA3NTUzNDI3Mn0.HvZVdlyyck6iI6L5XiPupPZ8voLt-u4NCKAqgwHl6dE"
|
| 59 |
-
#supabase: Client = create_client(url, key, options=ClientOptions(auto_refresh_token=False,persist_session=True))
|
| 60 |
-
#@cl.data_layer
|
| 61 |
-
#def get_data_layer():
|
| 62 |
-
# return SQLAlchemyDataLayer(conninfo="postgresql+asyncpg://postgres.urtvfyesitnmwrouarze:2VlIHUmI3qVhJpcb@aws-1-eu-north-1.pooler.supabase.com:5432/postgres", storage_provider=supabase)
|
| 63 |
-
@cl.data_layer
|
| 64 |
-
def get_data_layer():
|
| 65 |
-
return SQLAlchemyDataLayer(conninfo=CONNINFO, storage_provider=supabase)
|
| 66 |
|
| 67 |
# =============================================================================
|
| 68 |
# CONFIGURATION DE L'AUTHENTIFICATION (Optionnel)
|
|
@@ -108,9 +77,23 @@ if LANGCHAIN_API_KEY:
|
|
| 108 |
print(f"✅ LangSmith activé - Projet: {LANGSMITH_PROJECT}")
|
| 109 |
else:
|
| 110 |
print("⚠️ LANGCHAIN_API_KEY non définie - Monitoring désactivé")
|
| 111 |
-
langsmith_client = None
|
| 112 |
-
|
| 113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
# =============================================================================
|
| 115 |
# FONCTIONS AUXILIAIRES POUR L'AFFICHAGE
|
| 116 |
# =============================================================================
|
|
@@ -211,11 +194,11 @@ async def display_similar_info(similar_info: List[Dict[str, Any]]):
|
|
| 211 |
)
|
| 212 |
elements.append(element)
|
| 213 |
|
| 214 |
-
if elements:
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
|
| 220 |
async def display_web_search_results(web_search_results: List[Dict[str, Any]]):
|
| 221 |
"""Affiche les résultats de recherche web."""
|
|
@@ -328,7 +311,26 @@ async def process_query_with_tracing(query: str, thread_id: str) -> Dict[str, An
|
|
| 328 |
# event est un dictionnaire avec les nœuds comme clés
|
| 329 |
for node_name, node_state in event.items():
|
| 330 |
# Ignorer le nœud spécial __start__
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
if node_name == "__start__":
|
|
|
|
| 332 |
continue
|
| 333 |
|
| 334 |
# Afficher un message de progression pour le nœud actuel
|
|
@@ -340,7 +342,35 @@ async def process_query_with_tracing(query: str, thread_id: str) -> Dict[str, An
|
|
| 340 |
"refine_response": "⚙️ Refinement de la réponse",
|
| 341 |
"collect_similar_information": "🔗 Collecte d'informations similaires"
|
| 342 |
}
|
| 343 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 344 |
display_name = node_display_names.get(node_name, f"⚙️ {node_name}")
|
| 345 |
|
| 346 |
# Message de progression
|
|
@@ -451,6 +481,11 @@ async def chat_profile(current_user: cl.User):
|
|
| 451 |
),cl.ChatProfile(
|
| 452 |
name="Avid Dataviz",
|
| 453 |
markdown_description="💡 Avid Dataviz permet d'avoir recours à des éléments statistiques et de corrélation entre les données laboratoires et les thématiques Ville Durable",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
)
|
| 455 |
]
|
| 456 |
|
|
@@ -458,13 +493,43 @@ async def chat_profile(current_user: cl.User):
|
|
| 458 |
@cl.on_chat_start
|
| 459 |
async def start():
|
| 460 |
"""Initialisation de la session chat."""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 461 |
user = cl.user_session.get("user")
|
| 462 |
chat_profile = cl.user_session.get("chat_profile")
|
| 463 |
if chat_profile == "Avid Dataviz":
|
| 464 |
await cl.Message(
|
| 465 |
content=f"Bienvenue {user.identifier}!\n\nL'environnement {chat_profile} vous restitue les données sous forme d'objets statistiques."
|
| 466 |
).send()
|
| 467 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 468 |
# Message de bienvenue avec style
|
| 469 |
# welcome_msg = f"""# 🎓 Agent Collaboratif - Université Gustave Eiffel
|
| 470 |
|
|
@@ -562,6 +627,9 @@ async def main(message: cl.Message):
|
|
| 562 |
# Supprimer le message de traitement initial vide
|
| 563 |
processing_msg.content = "✅ Traitement terminé"
|
| 564 |
await processing_msg.update()
|
|
|
|
|
|
|
|
|
|
| 565 |
|
| 566 |
# Sauvegarder dans l'historique de session
|
| 567 |
cl.user_session.set(f"query_{query_count}", {
|
|
|
|
| 10 |
- Chain of Thought visible
|
| 11 |
- Style personnalisé (dark theme)
|
| 12 |
"""
|
|
|
|
| 13 |
import os
|
| 14 |
import json
|
| 15 |
import asyncio
|
| 16 |
from typing import Dict, Any, List, Optional
|
|
|
|
| 17 |
import chainlit as cl
|
| 18 |
from chainlit.types import ThreadDict, Starter
|
|
|
|
|
|
|
| 19 |
from langsmith import traceable
|
| 20 |
|
| 21 |
# Import du module agent (votre code existant)
|
|
|
|
| 29 |
MAX_VALIDATION_LOOPS
|
| 30 |
)
|
| 31 |
import bcrypt
|
| 32 |
+
|
| 33 |
+
from trace_agent_collaboratif import get_trace
|
| 34 |
+
from dataviz_avid import display_barplotcorrelation, display_barplotpublication, display_barplotformation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
# =============================================================================
|
| 37 |
# CONFIGURATION DE L'AUTHENTIFICATION (Optionnel)
|
|
|
|
| 77 |
print(f"✅ LangSmith activé - Projet: {LANGSMITH_PROJECT}")
|
| 78 |
else:
|
| 79 |
print("⚠️ LANGCHAIN_API_KEY non définie - Monitoring désactivé")
|
| 80 |
+
#langsmith_client = None
|
| 81 |
+
|
| 82 |
+
@cl.action_callback("display_trace")
|
| 83 |
+
async def on_action(action: cl.Action):
|
| 84 |
+
# Create the TaskList
|
| 85 |
+
task_list = cl.TaskList()
|
| 86 |
+
task_list.status = "Running..."
|
| 87 |
+
task1 = cl.Task(title="Connexion au serveur d'historique des données d'actions des utilisateurs de l'agent collabroatif AVID.", status=cl.TaskStatus.RUNNING)
|
| 88 |
+
await task_list.add_task(task1)
|
| 89 |
+
await task_list.send()
|
| 90 |
+
trace = await get_trace(LANGCHAIN_API_KEY, task_list)
|
| 91 |
+
task1.status = cl.TaskStatus.DONE
|
| 92 |
+
await task_list.send()
|
| 93 |
+
await cl.ElementSidebar.set_elements([cl.Text(content=trace, name="trace")])
|
| 94 |
+
await cl.ElementSidebar.set_title(" ⌛ Historique de conversation :")
|
| 95 |
+
#await cl.Message(content="Afficher l'historique des actions",elements=[cl.Text(content=trace, name="trace", display="side")]).send()
|
| 96 |
+
|
| 97 |
# =============================================================================
|
| 98 |
# FONCTIONS AUXILIAIRES POUR L'AFFICHAGE
|
| 99 |
# =============================================================================
|
|
|
|
| 194 |
)
|
| 195 |
elements.append(element)
|
| 196 |
|
| 197 |
+
#if elements:
|
| 198 |
+
# await cl.Message(
|
| 199 |
+
# content="💡 **Informations similaires trouvées dans d'autres bases**",
|
| 200 |
+
# elements=elements
|
| 201 |
+
# ).send()
|
| 202 |
|
| 203 |
async def display_web_search_results(web_search_results: List[Dict[str, Any]]):
|
| 204 |
"""Affiche les résultats de recherche web."""
|
|
|
|
| 311 |
# event est un dictionnaire avec les nœuds comme clés
|
| 312 |
for node_name, node_state in event.items():
|
| 313 |
# Ignorer le nœud spécial __start__
|
| 314 |
+
task_list = cl.TaskList()
|
| 315 |
+
task_list.status = "Running..."
|
| 316 |
+
task1 = cl.Task(title="Traitement de la requête utilisateur de l'agent collaboratif AVID par une action conditionnelle.")
|
| 317 |
+
task1.status = cl.TaskStatus.RUNNING
|
| 318 |
+
await task_list.add_task(task1)
|
| 319 |
+
task2 = cl.Task(title="Collecte d'informations dans les bases de données et caractérisation des informations par un score de pertinence par rapport à la requête utilisateur.")
|
| 320 |
+
await task_list.add_task(task2)
|
| 321 |
+
task3 = cl.Task(title="Génération d'une première réponse par l'agent collaboratif AVID et vérification de sa validité en corrélant les informations collectées.")
|
| 322 |
+
await task_list.add_task(task3)
|
| 323 |
+
task4 = cl.Task(title="Vérification de la validité de la réponse par l'agent collaboratif AVID et correction si nécessaire pour éviter les réponses erronées.")
|
| 324 |
+
await task_list.add_task(task4)
|
| 325 |
+
task5 = cl.Task(title="Génération d'une réponse finale par l'agent collaboratif AVID et vérification de sa validité grâce à un dernier traitement de vérification anti-hallucination.")
|
| 326 |
+
await task_list.add_task(task5)
|
| 327 |
+
task6 = cl.Task(title="Affichage de la réponse finale et collecte d'informations similaires dans les bases de données non prises en compte dans la réponse finale.")
|
| 328 |
+
await task_list.add_task(task6)
|
| 329 |
+
task7 = cl.Task(title="Recherche sur le web des informations complémentaires par rapport à la requête utilisateur.")
|
| 330 |
+
await task_list.add_task(task7)
|
| 331 |
+
await task_list.send()
|
| 332 |
if node_name == "__start__":
|
| 333 |
+
# Create the TaskList
|
| 334 |
continue
|
| 335 |
|
| 336 |
# Afficher un message de progression pour le nœud actuel
|
|
|
|
| 342 |
"refine_response": "⚙️ Refinement de la réponse",
|
| 343 |
"collect_similar_information": "🔗 Collecte d'informations similaires"
|
| 344 |
}
|
| 345 |
+
if node_name == "analyze_query":
|
| 346 |
+
task1.status = cl.TaskStatus.DONE
|
| 347 |
+
task2.status = cl.TaskStatus.RUNNING
|
| 348 |
+
await task_list.send()
|
| 349 |
+
if node_name == "collect_information":
|
| 350 |
+
task2.status = cl.TaskStatus.DONE
|
| 351 |
+
task3.status = cl.TaskStatus.RUNNING
|
| 352 |
+
await task_list.send()
|
| 353 |
+
if node_name == "generate_response":
|
| 354 |
+
task3.status = cl.TaskStatus.DONE
|
| 355 |
+
task4.status = cl.TaskStatus.RUNNING
|
| 356 |
+
await task_list.send()
|
| 357 |
+
if node_name == "validate_response":
|
| 358 |
+
task4.status = cl.TaskStatus.DONE
|
| 359 |
+
task5.status = cl.TaskStatus.RUNNING
|
| 360 |
+
await task_list.send()
|
| 361 |
+
if node_name == "refine_response":
|
| 362 |
+
task5.status = cl.TaskStatus.DONE
|
| 363 |
+
task6.status = cl.TaskStatus.RUNNING
|
| 364 |
+
await task_list.send()
|
| 365 |
+
if node_name == "collect_similar_information":
|
| 366 |
+
task6.status = cl.TaskStatus.DONE
|
| 367 |
+
task7.status = cl.TaskStatus.RUNNING
|
| 368 |
+
await task_list.send()
|
| 369 |
+
if node_name == "web_search":
|
| 370 |
+
task7.status = cl.TaskStatus.DONE
|
| 371 |
+
task7.status = cl.TaskStatus.READY
|
| 372 |
+
await task_list.send()
|
| 373 |
+
|
| 374 |
display_name = node_display_names.get(node_name, f"⚙️ {node_name}")
|
| 375 |
|
| 376 |
# Message de progression
|
|
|
|
| 481 |
),cl.ChatProfile(
|
| 482 |
name="Avid Dataviz",
|
| 483 |
markdown_description="💡 Avid Dataviz permet d'avoir recours à des éléments statistiques et de corrélation entre les données laboratoires et les thématiques Ville Durable",
|
| 484 |
+
icon="/public/charts.png",
|
| 485 |
+
),cl.ChatProfile(
|
| 486 |
+
name="Avid Historique",
|
| 487 |
+
markdown_description="💡 RUNNING...\nAvid Historique permet d'avoir recours aux actions des utilisateurs sur l'agent collaboratif AVID",
|
| 488 |
+
icon="/public/threads.png",
|
| 489 |
)
|
| 490 |
]
|
| 491 |
|
|
|
|
| 493 |
@cl.on_chat_start
|
| 494 |
async def start():
|
| 495 |
"""Initialisation de la session chat."""
|
| 496 |
+
commands = [
|
| 497 |
+
{"id": "Search", "icon": "globe", "description": "Rechercher sur le web"},
|
| 498 |
+
]
|
| 499 |
+
await cl.context.emitter.set_commands(commands)
|
| 500 |
user = cl.user_session.get("user")
|
| 501 |
chat_profile = cl.user_session.get("chat_profile")
|
| 502 |
if chat_profile == "Avid Dataviz":
|
| 503 |
await cl.Message(
|
| 504 |
content=f"Bienvenue {user.identifier}!\n\nL'environnement {chat_profile} vous restitue les données sous forme d'objets statistiques."
|
| 505 |
).send()
|
| 506 |
+
|
| 507 |
+
actions = [cl.Action(name="display_trace",icon="mouse-pointer-click",payload={"value": "trace"},label="Afficher l'historique des actions")]
|
| 508 |
+
await cl.Message(content="Fil des conversations", actions=actions).send()
|
| 509 |
+
|
| 510 |
+
elements = []
|
| 511 |
+
figure_correlation = await display_barplotcorrelation()
|
| 512 |
+
figure_publication = await display_barplotpublication()
|
| 513 |
+
figure_formation = await display_barplotformation()
|
| 514 |
+
elements.append(cl.Plotly(name="chart_correlation", figure=figure_correlation, size="large", display="inline"))
|
| 515 |
+
elements.append(cl.Plotly(name="chart_publication", figure=figure_publication, size="large", display="inline"))
|
| 516 |
+
elements.append(cl.Plotly(name="chart_formation", figure=figure_formation, size="large", display="inline"))
|
| 517 |
+
|
| 518 |
+
await cl.Message(content="Datavisualisation des thématiques Ville Durable en fonction des laboratoires, en fonction des publications de recherche et en fonction des formations", elements=elements).send()
|
| 519 |
+
|
| 520 |
+
|
| 521 |
+
elif chat_profile == "Avid Historique":
|
| 522 |
+
# Create the TaskList
|
| 523 |
+
task_list = cl.TaskList()
|
| 524 |
+
task_list.status = "Running..."
|
| 525 |
+
task1 = cl.Task(title="Connexion au serveur d'historique des données d'actions des utilisateurs de l'agent collabroatif AVID.", status=cl.TaskStatus.RUNNING)
|
| 526 |
+
await task_list.add_task(task1)
|
| 527 |
+
await task_list.send()
|
| 528 |
+
trace = await get_trace(LANGCHAIN_API_KEY,task_list)
|
| 529 |
+
task1.status = cl.TaskStatus.DONE
|
| 530 |
+
await task_list.send()
|
| 531 |
+
elements = [cl.Text(content=trace, display="inline")]
|
| 532 |
+
await cl.Message(content="Fil des conversations", elements=elements).send()
|
| 533 |
# Message de bienvenue avec style
|
| 534 |
# welcome_msg = f"""# 🎓 Agent Collaboratif - Université Gustave Eiffel
|
| 535 |
|
|
|
|
| 627 |
# Supprimer le message de traitement initial vide
|
| 628 |
processing_msg.content = "✅ Traitement terminé"
|
| 629 |
await processing_msg.update()
|
| 630 |
+
|
| 631 |
+
actions = [cl.Action(name="display_trace",icon="mouse-pointer-click",payload={"value": "trace"},label="Afficher l'historique des actions")]
|
| 632 |
+
await cl.Message(content="Fil des conversations", actions=actions).send()
|
| 633 |
|
| 634 |
# Sauvegarder dans l'historique de session
|
| 635 |
cl.user_session.set(f"query_{query_count}", {
|