SurfSense/surfsense_backend/app/agents/alison/nodes.py

130 lines
5 KiB
Python
Raw Normal View History

import json
from typing import Any, List
from langchain_core.runnables import RunnableConfig
from langgraph.types import StreamWriter
from .state import AlisonState
from .prompts import (
get_alison_system_prompt,
get_problem_identification_prompt,
get_escalation_prompt,
)
from langchain_core.messages import SystemMessage, HumanMessage
from app.services.llm_service import get_user_fast_llm
async def identify_problem(state: AlisonState, config: RunnableConfig, writer: StreamWriter) -> dict[str, Any]:
"""
Identifies the user's problem based on their query.
"""
user_id = config["configurable"]["user_id"]
user_query = state["user_query"]
llm = await get_user_fast_llm(state["db_session"], user_id)
if not llm:
# Handle case where LLM is not configured
# For now, we'll just return a default problem
return {"identified_problem": "Could not identify problem: LLM not configured."}
prompt = get_problem_identification_prompt().format(user_query=user_query)
messages = [
SystemMessage(content=get_alison_system_prompt()),
HumanMessage(content=prompt),
]
response = await llm.ainvoke(messages)
identified_problem = response.content.strip()
return {"identified_problem": identified_problem}
from app.retriever.alison_knowledge_retriever import AlisonKnowledgeRetriever
async def search_knowledge_base(state: AlisonState, config: RunnableConfig, writer: StreamWriter) -> dict[str, Any]:
"""
Searches the knowledge base for troubleshooting guides related to the identified problem.
"""
identified_problem = state["identified_problem"]
if not identified_problem:
return {"troubleshooting_steps": [], "visual_aids": []}
retriever = AlisonKnowledgeRetriever(state["db_session"])
documents = await retriever.hybrid_search(identified_problem, top_k=3)
if not documents:
return {"troubleshooting_steps": [], "visual_aids": []}
# For now, we'll just return the content of the first document.
# We can improve this later to synthesize an answer from multiple documents.
first_document_content = documents[0]["content"]
return {"troubleshooting_steps": [first_document_content], "visual_aids": []}
async def generate_troubleshooting_response(state: AlisonState, config: RunnableConfig, writer: StreamWriter) -> dict[str, Any]:
"""
Generates a response with troubleshooting steps and visual aids.
"""
troubleshooting_steps = state.get("troubleshooting_steps")
if not troubleshooting_steps:
return {"escalation_required": True}
user_role = config["configurable"].get("user_role", "professor")
content = troubleshooting_steps[0] # Assuming only one document is returned for now
# Simple markdown parsing
sections = {}
current_section = None
for line in content.split('\\n'):
if line.startswith("## "):
current_section = line[3:].strip()
sections[current_section] = []
elif current_section:
sections[current_section].append(line)
response_parts = []
if "Issue" in sections:
response_parts.append(f"I understand you're having an issue with: **{''.join(sections['Issue'])}**")
response_parts.append("Here are some steps you can try:")
if "Troubleshooting Steps" in sections:
response_parts.extend(sections["Troubleshooting Steps"])
if "Role-Specific Advice" in sections:
advice_text = '\\n'.join(sections['Role-Specific Advice'])
if f"- **{user_role.capitalize()}:**" in advice_text:
role_advice = [line for line in advice_text.split('\\n') if line.startswith(f"- **{user_role.capitalize()}:**")]
if role_advice:
response_parts.append("\\n**Advice for you as a {user_role}:**")
response_parts.append(role_advice[0].replace(f"- **{user_role.capitalize()}:**", "").strip())
if "Visual Aid" in sections:
for line in sections["Visual Aid"]:
if "[Image:" in line:
response_parts.append(f"You can also refer to this visual guide: {line}")
final_response = "\\n".join(response_parts)
return {"final_response": final_response}
async def handle_escalation(state: AlisonState, config: RunnableConfig, writer: StreamWriter) -> dict[str, Any]:
"""
Generates a response for escalating the issue to IT support.
"""
user_id = config["configurable"]["user_id"]
identified_problem = state["identified_problem"]
llm = await get_user_fast_llm(state["db_session"], user_id)
if not llm:
return {"final_response": "I am unable to resolve this issue. Please contact IT support."}
prompt = get_escalation_prompt().format(identified_problem=identified_problem)
messages = [
SystemMessage(content=get_alison_system_prompt()),
HumanMessage(content=prompt),
]
response = await llm.ainvoke(messages)
escalation_message = response.content.strip()
return {"final_response": escalation_message}