Cyril Dupland
Enhance PDF generation and update configurations: Add PDF_LOGO_PATH to .env.example, include markdown-pdf in requirements.txt, and refactor PDF generation logic to support logo integration. Introduce tests for PDF generation from Markdown input and update summarizer agent to streamline export functionality.
3cd0aad | """Orchestrated workflow with classification routing.""" | |
| from langgraph.graph import StateGraph, END | |
| from langchain_core.language_models.chat_models import BaseChatModel | |
| from graphs.state import AgentState | |
| from graphs.agents.classifier_agent import classifier_node | |
| from graphs.nodes.retrieval import retrieve_catalogue, retrieve_projects | |
| from graphs.agents.chat_agent import chat_node | |
| from graphs.agents.summarizer_agent import summarizer_llm_node, summarizer_export_node | |
| from tools.pdf import markdown_to_pdf | |
| from tools.storage import upload_pdf_to_supabase | |
| def create_orchestrated_graph(llm: BaseChatModel, checkpointer=None): | |
| workflow = StateGraph(AgentState) | |
| # Nodes | |
| workflow.add_node("classify", classifier_node(llm)) | |
| workflow.add_node("retrieve", retrieve_catalogue) | |
| # Route to classic vs project retrieval | |
| def _router_passthrough(state: AgentState) -> AgentState: | |
| # Must write at least one allowed key; pass through the current query | |
| q = state.get("query") or "" | |
| return {"query": q} | |
| workflow.add_node("retrieve_router", _router_passthrough) | |
| workflow.add_node("retrieve_project", retrieve_projects) | |
| workflow.add_node("agent", chat_node(llm)) | |
| workflow.add_node("summarizer_llm", summarizer_llm_node(llm)) | |
| workflow.add_node( | |
| "summarizer_export", | |
| summarizer_export_node( | |
| markdown_to_pdf=markdown_to_pdf, | |
| upload_pdf=upload_pdf_to_supabase, | |
| ), | |
| ) | |
| # Entry | |
| workflow.set_entry_point("classify") | |
| # Conditional routing | |
| workflow.add_conditional_edges( | |
| "classify", | |
| lambda s: getattr(s.get("classification"), "classification", "CLASSIC"), | |
| { | |
| # Route through a retrieval router to optionally branch to project retrieval | |
| "CLASSIC": "retrieve_router", | |
| "SUMMARIZE": "summarizer_llm", | |
| "UNKNOWN": "retrieve_router", | |
| }, | |
| ) | |
| # Conditional choice between project vs classic retrieval | |
| workflow.add_conditional_edges( | |
| "retrieve_router", | |
| lambda s: "PROJECT" if s.get("project_id") else "CLASSIC", | |
| { | |
| "PROJECT": "retrieve_project", | |
| "CLASSIC": "retrieve", | |
| }, | |
| ) | |
| # Linear branches | |
| # If project path is taken, run project retrieval then classic retrieval | |
| workflow.add_edge("retrieve_project", "retrieve") | |
| workflow.add_edge("retrieve", "agent") | |
| workflow.add_edge("agent", END) | |
| workflow.add_edge("summarizer_llm", "summarizer_export") | |
| workflow.add_edge("summarizer_export", END) | |
| return workflow.compile(checkpointer=checkpointer) | |