Spaces:
Runtime error
Runtime error
File size: 6,886 Bytes
f3997d4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | from sqlalchemy.orm import Session
from typing import List, Dict, Optional
import json
from app.database.models import Message, Session as ChatSession
from app.services.session_service import SessionService
from app.utils.helpers import generate_id
class ChatService:
"""Service for chat operations and agent orchestration."""
@staticmethod
def process_message(
db: Session,
message: str,
session_id: Optional[str] = None,
user_id: Optional[str] = None,
policy_ids: Optional[List[str]] = None
) -> Dict:
"""
Process a user message and generate response using LangGraph workflow.
Args:
db: Database session
message: User message content
session_id: Optional session ID
user_id: Optional user ID
policy_ids: Optional list of policy IDs to search within
Returns:
Dictionary with response message and metadata
"""
from app.llm.graph import multi_agent_graph
# Create or get session
if not session_id:
chat_session = SessionService.create_session(db, user_id)
session_id = chat_session.id
else:
chat_session = SessionService.get_session_by_id(db, session_id)
if not chat_session:
raise ValueError("Session not found")
# Save user message
user_message = Message(
id=generate_id(),
session_id=session_id,
role="user",
content=message
)
db.add(user_message)
db.commit()
# Get chat history for context
chat_history = ChatService.get_chat_history(db, session_id, limit=10)
# Format chat history for the graph
history_messages = [
{"role": msg["role"], "content": msg["content"]}
for msg in chat_history
]
# Process query through LangGraph workflow
response_data = multi_agent_graph.process_query(
query=message,
user_id=user_id,
chat_history=history_messages,
policy_ids=policy_ids
)
# Prepare metadata
meta = {
"agent": response_data.get("agent", "unknown"),
"routing_reasoning": response_data.get("routing_reasoning", ""),
"sources": response_data.get("sources", []),
"metadata": response_data.get("metadata", {}),
"policy_names": response_data.get("policy_names", []) # Policy document names
}
print(f"[Chat Service] Saving meta with policy_names: {meta.get('policy_names', [])}")
# Save assistant message
assistant_message = Message(
id=generate_id(),
session_id=session_id,
role="assistant",
content=response_data.get("answer", "I apologize, but I couldn't generate a response."),
meta=json.dumps(meta)
)
db.add(assistant_message)
# Update session timestamp
SessionService.update_session_timestamp(db, session_id)
db.commit()
db.refresh(assistant_message)
# Auto-generate session title if this is the first exchange
messages_count = db.query(Message).filter(Message.session_id == session_id).count()
if messages_count == 2 and chat_session.title == "New Conversation":
# Generate title from first user message
title = ChatService._generate_session_title(message)
SessionService.update_session_title(db, session_id, title)
return {
"message": assistant_message,
"session_id": session_id,
"agent": meta["agent"],
"sources": meta.get("sources", [])
}
@staticmethod
def get_chat_history(
db: Session,
session_id: str,
limit: Optional[int] = None
) -> List[Dict]:
"""
Get chat history for a session.
Args:
db: Database session
session_id: Session ID
limit: Optional limit on number of messages
Returns:
List of message dictionaries
"""
query = db.query(Message).filter(
Message.session_id == session_id
).order_by(Message.created_at.asc())
if limit:
# Get last N messages
total = query.count()
if total > limit:
query = query.offset(total - limit)
messages = query.all()
return [
{
"id": msg.id,
"role": msg.role,
"content": msg.content,
"meta": json.loads(msg.meta) if msg.meta else {},
"created_at": msg.created_at.isoformat()
}
for msg in messages
]
@staticmethod
def _generate_session_title(first_message: str) -> str:
"""
Generate a ChatGPT-style session title using LLM.
Args:
first_message: The first user message in the conversation
Returns:
A concise, descriptive title (max 50 characters)
"""
from app.llm.client import llm_client
try:
prompt = f"""Generate a very short, concise title for a chat conversation that starts with this message:
"{first_message}"
Requirements:
- Maximum 50 characters
- Be specific and descriptive
- Capture the main topic/question
- Professional tone
- No quotes around the title
- Examples: "Building Code Requirements", "Fire Safety Regulations", "Basement Definition"
Return ONLY the title, nothing else:"""
title = llm_client.get_completion(
messages=[{"role": "user", "content": prompt}],
temperature=0.7,
max_tokens=20
)
# Clean up the title
title = title.strip().strip('"').strip("'")
# Ensure it's not too long
if len(title) > 50:
title = title[:47] + "..."
# Fallback if empty or too short
if len(title) < 3:
title = first_message[:50].strip()
if len(first_message) > 50:
title += "..."
return title
except Exception as e:
print(f"[Chat Service] Error generating title: {e}")
# Fallback to simple truncation
title = first_message[:50].strip()
if len(first_message) > 50:
title += "..."
return title
# Global chat service instance
chat_service = ChatService()
|