Spaces:
Sleeping
Sleeping
| """ | |
| graph/workflow.py — LangGraph StateGraph Tanımı | |
| AGENTIC PATTERN: State Machine (LangGraph) | |
| ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | |
| LangGraph'ta bir "graph" şunlardan oluşur: | |
| - StateGraph: state type + node'lar + edge'ler | |
| - Node: state alan, state parçası döndüren fonksiyon | |
| - Edge: iki node arasındaki bağlantı | |
| - Conditional Edge: state'e göre dinamik yönlendirme | |
| compile() çağrısı graph'ı çalıştırılabilir hale getirir. | |
| MemorySaver ile her thread (oturum) kendi checkpoint'ını korur. | |
| Görsel üretmek için: | |
| from graph.workflow import create_graph | |
| g = create_graph() | |
| print(g.get_graph().draw_mermaid()) | |
| """ | |
| from langgraph.graph import StateGraph, END | |
| from langgraph.checkpoint.memory import MemorySaver | |
| from graph.state import ConversationState | |
| from graph.nodes import ( | |
| input_guard_node, | |
| supervisor_node, | |
| intake_new_node, | |
| intake_used_node, | |
| faq_agent_node, | |
| validation_new_node, | |
| validation_used_node, | |
| reflection_node, | |
| recap_node, | |
| submission_node, | |
| crosssell_node, | |
| wait_node, | |
| ) | |
| from graph.edges import ( | |
| route_after_supervisor, | |
| route_after_intake_new, | |
| route_after_intake_used, | |
| route_after_validation, | |
| route_after_reflection, | |
| route_after_recap, | |
| route_after_submission, | |
| route_after_crosssell, | |
| route_after_faq, | |
| ) | |
| # Singleton compiled graph | |
| _compiled_graph = None | |
| def create_graph(): | |
| """ | |
| LangGraph StateGraph'ı oluşturur ve compile eder. | |
| Graf Yapısı: | |
| input_guard → supervisor → [intake_new | intake_used | faq_agent] | |
| ↓ ↓ | |
| validation_new validation_used | |
| ↓ ↓ | |
| reflection | |
| ↓ | |
| recap | |
| ↓ | |
| submission | |
| ↓ | |
| crosssell | |
| ↓ | |
| END | |
| """ | |
| graph = StateGraph(ConversationState) | |
| # ── Node'ları Ekle ───────────────────────────────────────────────────────── | |
| graph.add_node("input_guard", input_guard_node) | |
| graph.add_node("supervisor", supervisor_node) | |
| graph.add_node("intake_new", intake_new_node) | |
| graph.add_node("intake_used", intake_used_node) | |
| graph.add_node("faq_agent", faq_agent_node) | |
| graph.add_node("validation_new", validation_new_node) | |
| graph.add_node("validation_used", validation_used_node) | |
| graph.add_node("reflection", reflection_node) | |
| graph.add_node("recap", recap_node) | |
| graph.add_node("submission", submission_node) | |
| graph.add_node("crosssell", crosssell_node) | |
| graph.add_node("wait_for_input", wait_node) | |
| # ── Başlangıç Node'u ─────────────────────────────────────────────────────── | |
| # Her kullanıcı mesajı input_guard'dan girer | |
| graph.set_entry_point("input_guard") | |
| # ── Sabit Edge'ler (her zaman aynı yönlendirme) ─────────────────────────── | |
| graph.add_edge("input_guard", "supervisor") | |
| # ── Koşullu Edge'ler (state'e göre dinamik yönlendirme) ────────────────── | |
| # Supervisor kararı | |
| # route_after_supervisor(state) fonksiyonu state'e bakar ve bir string döner. | |
| # LangGraph bu string'i aşağıdaki dictionary'den lookup'tan geçirip ilgili node'a atlar. | |
| graph.add_conditional_edges( | |
| "supervisor", | |
| route_after_supervisor, | |
| { | |
| "intake_new": "intake_new", | |
| "intake_used": "intake_used", | |
| "faq_agent": "faq_agent", | |
| "reflection": "reflection", | |
| "crosssell": "crosssell", | |
| "wait_for_input": "wait_for_input", | |
| "END": END, | |
| }, | |
| ) | |
| # Yeni araç intake | |
| graph.add_conditional_edges( | |
| "intake_new", | |
| route_after_intake_new, | |
| { | |
| "validation_new": "validation_new", | |
| "wait_for_input": "wait_for_input", | |
| "END": END, | |
| }, | |
| ) | |
| # 2. El intake | |
| graph.add_conditional_edges( | |
| "intake_used", | |
| route_after_intake_used, | |
| { | |
| "validation_used": "validation_used", | |
| "wait_for_input": "wait_for_input", | |
| "END": END, | |
| }, | |
| ) | |
| # Validation | |
| graph.add_conditional_edges( | |
| "validation_new", | |
| route_after_validation, | |
| {"reflection": "reflection", "intake_new": "intake_new", "END": END}, | |
| ) | |
| graph.add_conditional_edges( | |
| "validation_used", | |
| route_after_validation, | |
| {"reflection": "reflection", "intake_used": "intake_used", "END": END}, | |
| ) | |
| # Reflection | |
| graph.add_conditional_edges( | |
| "reflection", | |
| route_after_reflection, | |
| {"recap": "recap", "intake_new": "intake_new", "intake_used": "intake_used", "END": END}, | |
| ) | |
| # Recap → Submission | |
| graph.add_conditional_edges( | |
| "recap", | |
| route_after_recap, | |
| { | |
| "submission": "submission", | |
| "intake_new": "intake_new", | |
| "intake_used": "intake_used", | |
| "wait_for_input": "wait_for_input", | |
| "END": END, | |
| }, | |
| ) | |
| # Submission → CrossSell | |
| graph.add_conditional_edges( | |
| "submission", | |
| route_after_submission, | |
| {"crosssell": "crosssell", "END": END}, | |
| ) | |
| # CrossSell → END | |
| graph.add_conditional_edges( | |
| "crosssell", | |
| route_after_crosssell, | |
| {"wait_for_input": "wait_for_input", "END": END}, | |
| ) | |
| # FAQ cevabından kaldığı yere dön | |
| graph.add_conditional_edges( | |
| "faq_agent", | |
| route_after_faq, | |
| { | |
| "supervisor": "supervisor", | |
| "intake_new": "intake_new", | |
| "intake_used": "intake_used", | |
| "recap": "recap", | |
| "wait_for_input": "wait_for_input", | |
| }, | |
| ) | |
| # Bekleme node'u her zaman durur (kullanıcı girdisi bekliyor) | |
| graph.add_edge("wait_for_input", END) | |
| return graph | |
| def get_compiled_graph(): | |
| """ | |
| MemorySaver ile compile edilmiş graph'ı döndürür (singleton). | |
| MemorySaver: Her thread_id için ayrı checkpoint tutar. | |
| thread_id = session_id → her kullanıcı oturumu bağımsız. | |
| """ | |
| global _compiled_graph | |
| if _compiled_graph is None: | |
| checkpointer = MemorySaver() | |
| graph = create_graph() | |
| _compiled_graph = graph.compile(checkpointer=checkpointer) | |
| return _compiled_graph | |
| def get_workflow_mermaid() -> str: | |
| """Graf yapısını Mermaid diyagramı olarak döndürür (görsel için).""" | |
| graph = create_graph() | |
| compiled = graph.compile() | |
| return compiled.get_graph().draw_mermaid() | |