Spaces:
Runtime error
Runtime error
Charles Grandjean commited on
Commit ·
6d35100
1
Parent(s): 2f4c4da
Update the retrieve doc
Browse files- agent_api.py +4 -4
- agent_states/agent_state.py +1 -1
- agent_states/lawyer_messenger_state.py +1 -1
- langgraph_agent.py +11 -5
- prompts/main.py +2 -10
- structured_outputs/api_models.py +2 -2
- subagents/lawyer_messenger.py +3 -3
- utils/tools.py +116 -7
agent_api.py
CHANGED
|
@@ -129,7 +129,7 @@ class CyberLegalAPI:
|
|
| 129 |
# Initialize Resend
|
| 130 |
resend.api_key = os.getenv("RESEND_API_KEY")
|
| 131 |
logger.info("✅ Resend client initialized")
|
| 132 |
-
|
| 133 |
self.agent_client = CyberLegalAgent(llm=llm, tools=tools.tools_for_client,tools_facade=tools.tools_for_client_facade)
|
| 134 |
self.agent_lawyer = CyberLegalAgent(llm=llm, tools=tools.tools_for_lawyer,tools_facade=tools.tools_for_lawyer_facade)
|
| 135 |
self.pdf_analyzer = PDFAnalyzerAgent(llm=llm, mistral_client=mistral_client)
|
|
@@ -283,7 +283,7 @@ class CyberLegalAPI:
|
|
| 283 |
logger.info(f"🤖 Calling agent.process_query with jurisdiction: {request.jurisdiction}")
|
| 284 |
result = await agent.process_query(
|
| 285 |
user_query=request.message,
|
| 286 |
-
|
| 287 |
conversation_history=conversation_history,
|
| 288 |
jurisdiction=request.jurisdiction,
|
| 289 |
system_prompt=system_prompt
|
|
@@ -415,7 +415,7 @@ class CyberLegalAPI:
|
|
| 415 |
logger.info("=" * 80)
|
| 416 |
logger.info("📥 DOC_CREATOR REQUEST RECEIVED")
|
| 417 |
logger.info("=" * 80)
|
| 418 |
-
logger.info(f"👤
|
| 419 |
logger.info(f"📋 Instruction: {request.instruction}")
|
| 420 |
logger.info(f"📏 Document size: {len(request.documentContent)} bytes")
|
| 421 |
|
|
@@ -564,7 +564,7 @@ async def doc_creator_endpoint(request: DocCreatorRequest):
|
|
| 564 |
- contentFormat: Always "html"
|
| 565 |
- documentSummaries: Optional context from analyzed documents
|
| 566 |
- conversationHistory: Optional previous conversation messages
|
| 567 |
-
-
|
| 568 |
|
| 569 |
Returns:
|
| 570 |
DocCreatorResponse with assistant's response and modified document
|
|
|
|
| 129 |
# Initialize Resend
|
| 130 |
resend.api_key = os.getenv("RESEND_API_KEY")
|
| 131 |
logger.info("✅ Resend client initialized")
|
| 132 |
+
|
| 133 |
self.agent_client = CyberLegalAgent(llm=llm, tools=tools.tools_for_client,tools_facade=tools.tools_for_client_facade)
|
| 134 |
self.agent_lawyer = CyberLegalAgent(llm=llm, tools=tools.tools_for_lawyer,tools_facade=tools.tools_for_lawyer_facade)
|
| 135 |
self.pdf_analyzer = PDFAnalyzerAgent(llm=llm, mistral_client=mistral_client)
|
|
|
|
| 283 |
logger.info(f"🤖 Calling agent.process_query with jurisdiction: {request.jurisdiction}")
|
| 284 |
result = await agent.process_query(
|
| 285 |
user_query=request.message,
|
| 286 |
+
user_id=request.userId,
|
| 287 |
conversation_history=conversation_history,
|
| 288 |
jurisdiction=request.jurisdiction,
|
| 289 |
system_prompt=system_prompt
|
|
|
|
| 415 |
logger.info("=" * 80)
|
| 416 |
logger.info("📥 DOC_CREATOR REQUEST RECEIVED")
|
| 417 |
logger.info("=" * 80)
|
| 418 |
+
logger.info(f"👤 User ID: {request.userId}")
|
| 419 |
logger.info(f"📋 Instruction: {request.instruction}")
|
| 420 |
logger.info(f"📏 Document size: {len(request.documentContent)} bytes")
|
| 421 |
|
|
|
|
| 564 |
- contentFormat: Always "html"
|
| 565 |
- documentSummaries: Optional context from analyzed documents
|
| 566 |
- conversationHistory: Optional previous conversation messages
|
| 567 |
+
- userId: Unique user identifier (UUID)
|
| 568 |
|
| 569 |
Returns:
|
| 570 |
DocCreatorResponse with assistant's response and modified document
|
agent_states/agent_state.py
CHANGED
|
@@ -13,7 +13,7 @@ class AgentState(TypedDict):
|
|
| 13 |
"""
|
| 14 |
# User interaction
|
| 15 |
user_query: str
|
| 16 |
-
|
| 17 |
conversation_history: List[Dict[str, str]]
|
| 18 |
intermediate_steps: List[Dict[str, Any]]
|
| 19 |
system_prompt: Optional[str]
|
|
|
|
| 13 |
"""
|
| 14 |
# User interaction
|
| 15 |
user_query: str
|
| 16 |
+
user_id: Optional[str]
|
| 17 |
conversation_history: List[Dict[str, str]]
|
| 18 |
intermediate_steps: List[Dict[str, Any]]
|
| 19 |
system_prompt: Optional[str]
|
agent_states/lawyer_messenger_state.py
CHANGED
|
@@ -12,7 +12,7 @@ class LawyerMessengerState(TypedDict):
|
|
| 12 |
|
| 13 |
# Input
|
| 14 |
conversation_history: List[dict]
|
| 15 |
-
|
| 16 |
|
| 17 |
# Intermediate
|
| 18 |
lawyers: Optional[List[dict]] # Fetched from frontend API
|
|
|
|
| 12 |
|
| 13 |
# Input
|
| 14 |
conversation_history: List[dict]
|
| 15 |
+
user_id: str
|
| 16 |
|
| 17 |
# Intermediate
|
| 18 |
lawyers: Optional[List[dict]] # Fetched from frontend API
|
langgraph_agent.py
CHANGED
|
@@ -113,10 +113,16 @@ class CyberLegalAgent:
|
|
| 113 |
args["jurisdiction"] = state.get("jurisdiction")
|
| 114 |
logger.info(f"🌍 Injecting jurisdiction: {args['jurisdiction']}")
|
| 115 |
|
| 116 |
-
# Inject
|
| 117 |
if tool_call['name'] == "message_lawyer":
|
| 118 |
-
args["
|
| 119 |
-
logger.info(f"👤 Injecting
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
tool_call['name']="_" + tool_call['name']
|
| 121 |
|
| 122 |
result = await tool_func.ainvoke(args)
|
|
@@ -126,10 +132,10 @@ class CyberLegalAgent:
|
|
| 126 |
state["intermediate_steps"] = intermediate_steps
|
| 127 |
return state
|
| 128 |
|
| 129 |
-
async def process_query(self, user_query: str,
|
| 130 |
initial_state = {
|
| 131 |
"user_query": user_query,
|
| 132 |
-
"
|
| 133 |
"conversation_history": conversation_history or [],
|
| 134 |
"intermediate_steps": [],
|
| 135 |
"relevant_documents": [],
|
|
|
|
| 113 |
args["jurisdiction"] = state.get("jurisdiction")
|
| 114 |
logger.info(f"🌍 Injecting jurisdiction: {args['jurisdiction']}")
|
| 115 |
|
| 116 |
+
# Inject user_id for message_lawyer tool
|
| 117 |
if tool_call['name'] == "message_lawyer":
|
| 118 |
+
args["user_id"] = state.get("user_id")
|
| 119 |
+
logger.info(f"👤 Injecting user_id: {args['user_id']}")
|
| 120 |
+
|
| 121 |
+
# Inject user_id for retrieve_lawyer_document tool
|
| 122 |
+
if tool_call['name'] == "retrieve_lawyer_document":
|
| 123 |
+
args["user_id"] = state.get("user_id")
|
| 124 |
+
logger.info(f"📄 Injecting user_id for retrieve_lawyer_document: {args['user_id']}")
|
| 125 |
+
|
| 126 |
tool_call['name']="_" + tool_call['name']
|
| 127 |
|
| 128 |
result = await tool_func.ainvoke(args)
|
|
|
|
| 132 |
state["intermediate_steps"] = intermediate_steps
|
| 133 |
return state
|
| 134 |
|
| 135 |
+
async def process_query(self, user_query: str, user_id: Optional[str] = None, jurisdiction: str = "Romania", conversation_history: Optional[List[Dict[str, str]]] = None, system_prompt: Optional[str] = None) -> Dict[str, Any]:
|
| 136 |
initial_state = {
|
| 137 |
"user_query": user_query,
|
| 138 |
+
"user_id": user_id,
|
| 139 |
"conversation_history": conversation_history or [],
|
| 140 |
"intermediate_steps": [],
|
| 141 |
"relevant_documents": [],
|
prompts/main.py
CHANGED
|
@@ -71,6 +71,7 @@ Lawyer Jurisdiction: {jurisdiction}
|
|
| 71 |
### Available Tools
|
| 72 |
1. **query_knowledge_graph**: Search legal documents to answer questions about law, regulations and directives.
|
| 73 |
2. **search_web**: Search the web for current information, court decisions, or news that may not be in the knowledge graph.
|
|
|
|
| 74 |
|
| 75 |
### Tool-Calling Process
|
| 76 |
You operate in an iterative loop:
|
|
@@ -84,6 +85,7 @@ You operate in an iterative loop:
|
|
| 84 |
2. Reference specific articles, paragraphs, recitals, and provisions from regulations and directives. Include precise legal citations.
|
| 85 |
3. Analyze legal implications, potential interpretations, and relevant jurisprudence where applicable.
|
| 86 |
4. Create a section at the end of your response called "References" that lists the source documents used to answer the user's question with full legal citations.
|
|
|
|
| 87 |
|
| 88 |
### Tone
|
| 89 |
- Professional and authoritative
|
|
@@ -94,13 +96,3 @@ You operate in an iterative loop:
|
|
| 94 |
|
| 95 |
# Default system prompt (client-friendly for backward compatibility)
|
| 96 |
SYSTEM_PROMPT = SYSTEM_PROMPT_CLIENT
|
| 97 |
-
|
| 98 |
-
RESPONSE_FORMATTING_PROMPT = """### Task
|
| 99 |
-
We aim at answering the user's question based on your common knowledge as well as the knowledge graph context.
|
| 100 |
-
|
| 101 |
-
### Inputs
|
| 102 |
-
**Knowledge Graph Context:**{context}
|
| 103 |
-
**User Query:** {user_query}
|
| 104 |
-
|
| 105 |
-
### Response format
|
| 106 |
-
Answer in clear language and provide a direct answer to the user's question."""
|
|
|
|
| 71 |
### Available Tools
|
| 72 |
1. **query_knowledge_graph**: Search legal documents to answer questions about law, regulations and directives.
|
| 73 |
2. **search_web**: Search the web for current information, court decisions, or news that may not be in the knowledge graph.
|
| 74 |
+
3. **retrieve_lawyer_document**: Retrieve the full content of a specific document from your document database. Use this tool when you need to inspect the detailed text, clauses, or specific provisions of a document mentioned in your documents_tree. But avoid it if the summary key details and actors are sufficient as it can introduce long document in the chat.
|
| 75 |
|
| 76 |
### Tool-Calling Process
|
| 77 |
You operate in an iterative loop:
|
|
|
|
| 85 |
2. Reference specific articles, paragraphs, recitals, and provisions from regulations and directives. Include precise legal citations.
|
| 86 |
3. Analyze legal implications, potential interpretations, and relevant jurisprudence where applicable.
|
| 87 |
4. Create a section at the end of your response called "References" that lists the source documents used to answer the user's question with full legal citations.
|
| 88 |
+
5. If the user asks a specific detail about a document from your documents_tree, use the retrieve_lawyer_document tool, but avoid it if the summary key details and actors are sufficient as it can introduce long document in the chat.
|
| 89 |
|
| 90 |
### Tone
|
| 91 |
- Professional and authoritative
|
|
|
|
| 96 |
|
| 97 |
# Default system prompt (client-friendly for backward compatibility)
|
| 98 |
SYSTEM_PROMPT = SYSTEM_PROMPT_CLIENT
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
structured_outputs/api_models.py
CHANGED
|
@@ -52,7 +52,7 @@ class DocumentsTree(BaseModel):
|
|
| 52 |
|
| 53 |
class ChatRequest(BaseModel):
|
| 54 |
"""Chat request model"""
|
| 55 |
-
|
| 56 |
message: str = Field(..., description="User's question")
|
| 57 |
conversationHistory: Optional[List[Message]] = Field(default=[], description="Previous conversation messages")
|
| 58 |
userType: Optional[str] = Field(default="client", description="User type: 'client' for general users or 'lawyer' for legal professionals")
|
|
@@ -102,7 +102,7 @@ class DocCreatorRequest(BaseModel):
|
|
| 102 |
contentFormat: str = Field(default="html", description="Format of document content (always 'html')")
|
| 103 |
documents_tree: Optional[DocumentsTree] = Field(default=None, description="Hierarchical tree of documents for context")
|
| 104 |
conversationHistory: Optional[List[Message]] = Field(default=[], description="Previous conversation messages")
|
| 105 |
-
|
| 106 |
|
| 107 |
|
| 108 |
class DocCreatorResponse(BaseModel):
|
|
|
|
| 52 |
|
| 53 |
class ChatRequest(BaseModel):
|
| 54 |
"""Chat request model"""
|
| 55 |
+
userId: str = Field(..., description="Unique user identifier (UUID)")
|
| 56 |
message: str = Field(..., description="User's question")
|
| 57 |
conversationHistory: Optional[List[Message]] = Field(default=[], description="Previous conversation messages")
|
| 58 |
userType: Optional[str] = Field(default="client", description="User type: 'client' for general users or 'lawyer' for legal professionals")
|
|
|
|
| 102 |
contentFormat: str = Field(default="html", description="Format of document content (always 'html')")
|
| 103 |
documents_tree: Optional[DocumentsTree] = Field(default=None, description="Hierarchical tree of documents for context")
|
| 104 |
conversationHistory: Optional[List[Message]] = Field(default=[], description="Previous conversation messages")
|
| 105 |
+
userId: str = Field(..., description="Unique user identifier (UUID)")
|
| 106 |
|
| 107 |
|
| 108 |
class DocCreatorResponse(BaseModel):
|
subagents/lawyer_messenger.py
CHANGED
|
@@ -171,7 +171,7 @@ class LawyerMessengerAgent:
|
|
| 171 |
API_KEY = os.getenv("CYBERLGL_API_KEY")
|
| 172 |
|
| 173 |
payload = {
|
| 174 |
-
"
|
| 175 |
"lawyerId": lawyer_selection["lawyer_id"],
|
| 176 |
"subject": lawyer_selection["subject"],
|
| 177 |
"message": lawyer_selection["message"]
|
|
@@ -221,11 +221,11 @@ class LawyerMessengerAgent:
|
|
| 221 |
state["message_sent"] = False
|
| 222 |
return state
|
| 223 |
|
| 224 |
-
async def send_lawyer_message(self, conversation_history: List[dict],
|
| 225 |
"""Main entry point: identify lawyer and send message"""
|
| 226 |
result = await self.workflow.ainvoke({
|
| 227 |
"conversation_history": conversation_history,
|
| 228 |
-
"
|
| 229 |
"lawyers": None,
|
| 230 |
"lawyer_selection": None,
|
| 231 |
"message_sent": False,
|
|
|
|
| 171 |
API_KEY = os.getenv("CYBERLGL_API_KEY")
|
| 172 |
|
| 173 |
payload = {
|
| 174 |
+
"userId": state["user_id"],
|
| 175 |
"lawyerId": lawyer_selection["lawyer_id"],
|
| 176 |
"subject": lawyer_selection["subject"],
|
| 177 |
"message": lawyer_selection["message"]
|
|
|
|
| 221 |
state["message_sent"] = False
|
| 222 |
return state
|
| 223 |
|
| 224 |
+
async def send_lawyer_message(self, conversation_history: List[dict], user_id: str) -> str:
|
| 225 |
"""Main entry point: identify lawyer and send message"""
|
| 226 |
result = await self.workflow.ainvoke({
|
| 227 |
"conversation_history": conversation_history,
|
| 228 |
+
"user_id": user_id,
|
| 229 |
"lawyers": None,
|
| 230 |
"lawyer_selection": None,
|
| 231 |
"message_sent": False,
|
utils/tools.py
CHANGED
|
@@ -219,14 +219,14 @@ async def message_lawyer() -> str:
|
|
| 219 |
if lawyer_messenger_agent is None:
|
| 220 |
raise ValueError("LawyerMessengerAgent not initialized. Please initialize it in agent_api.py")
|
| 221 |
|
| 222 |
-
# conversation_history and
|
| 223 |
-
raise ValueError("conversation_history and
|
| 224 |
|
| 225 |
except Exception as e:
|
| 226 |
return f"Error sending message to lawyer: {str(e)}"
|
| 227 |
|
| 228 |
@tool
|
| 229 |
-
async def _message_lawyer(conversation_history,
|
| 230 |
"""
|
| 231 |
Send a message to a lawyer identified from the conversation.
|
| 232 |
|
|
@@ -245,7 +245,7 @@ async def _message_lawyer(conversation_history, client_id) -> str:
|
|
| 245 |
raise ValueError("LawyerMessengerAgent not initialized. Please initialize it in agent_api.py")
|
| 246 |
|
| 247 |
|
| 248 |
-
return await lawyer_messenger_agent.send_lawyer_message(conversation_history,
|
| 249 |
except Exception as e:
|
| 250 |
return f"Error sending message to lawyer: {str(e)}"
|
| 251 |
|
|
@@ -339,9 +339,118 @@ async def _edit_document(doc_text: str, instruction: str, doc_summaries: List[st
|
|
| 339 |
return f"Error editing document: {str(e)}"
|
| 340 |
|
| 341 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
# Export tool sets for different user types
|
| 343 |
tools_for_client_facade = [query_knowledge_graph, find_lawyers, message_lawyer, search_web, edit_document]
|
| 344 |
tools_for_client = [_query_knowledge_graph, _find_lawyers, _message_lawyer, search_web, _edit_document]
|
| 345 |
-
tools_for_lawyer_facade = [query_knowledge_graph, search_web, edit_document]
|
| 346 |
-
tools_for_lawyer = [_query_knowledge_graph, search_web, _edit_document]
|
| 347 |
-
tools = tools_for_client
|
|
|
|
| 219 |
if lawyer_messenger_agent is None:
|
| 220 |
raise ValueError("LawyerMessengerAgent not initialized. Please initialize it in agent_api.py")
|
| 221 |
|
| 222 |
+
# conversation_history and user_id will be injected by the agent from state
|
| 223 |
+
raise ValueError("conversation_history and user_id not provided - these should be injected by the agent")
|
| 224 |
|
| 225 |
except Exception as e:
|
| 226 |
return f"Error sending message to lawyer: {str(e)}"
|
| 227 |
|
| 228 |
@tool
|
| 229 |
+
async def _message_lawyer(conversation_history, user_id) -> str:
|
| 230 |
"""
|
| 231 |
Send a message to a lawyer identified from the conversation.
|
| 232 |
|
|
|
|
| 245 |
raise ValueError("LawyerMessengerAgent not initialized. Please initialize it in agent_api.py")
|
| 246 |
|
| 247 |
|
| 248 |
+
return await lawyer_messenger_agent.send_lawyer_message(conversation_history, user_id)
|
| 249 |
except Exception as e:
|
| 250 |
return f"Error sending message to lawyer: {str(e)}"
|
| 251 |
|
|
|
|
| 339 |
return f"Error editing document: {str(e)}"
|
| 340 |
|
| 341 |
|
| 342 |
+
@tool
|
| 343 |
+
async def retrieve_lawyer_document(file_path: str) -> str:
|
| 344 |
+
"""
|
| 345 |
+
Retrieve a specific document from the lawyer's document database.
|
| 346 |
+
|
| 347 |
+
This tool fetches a document by its file path from the lawyer's personal
|
| 348 |
+
document storage. It returns the extracted text, summary, actors, and key
|
| 349 |
+
details for the document.
|
| 350 |
+
|
| 351 |
+
Use this tool when you need to inspect the full content of a document
|
| 352 |
+
mentioned in the documents_tree, such as when:
|
| 353 |
+
- User asks about specific clauses or details in a contract
|
| 354 |
+
- You need to verify information in a legal document
|
| 355 |
+
- User requests analysis of a specific document's content
|
| 356 |
+
|
| 357 |
+
Args:
|
| 358 |
+
file_path: Path to the document from the documents_tree
|
| 359 |
+
(e.g., "Contracts/bail-commercial.pdf" or "note-juridique.pdf")
|
| 360 |
+
|
| 361 |
+
Returns:
|
| 362 |
+
Document content including extracted_text, summary, actors, and key_details
|
| 363 |
+
"""
|
| 364 |
+
try:
|
| 365 |
+
raise ValueError("user_id not provided - this should be injected by the agent")
|
| 366 |
+
except Exception as e:
|
| 367 |
+
return f"Error retrieving document: {str(e)}"
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
@tool
|
| 371 |
+
async def _retrieve_lawyer_document(
|
| 372 |
+
user_id: str,
|
| 373 |
+
file_path: str
|
| 374 |
+
) -> str:
|
| 375 |
+
"""
|
| 376 |
+
Retrieve a specific document from the lawyer's document database.
|
| 377 |
+
|
| 378 |
+
Args:
|
| 379 |
+
user_id: UUID of the lawyer (injected from userId)
|
| 380 |
+
file_path: Path to the document (e.g., "Contracts/bail-commercial.pdf")
|
| 381 |
+
format: "text" (default) returns JSON with extracted_text,
|
| 382 |
+
"raw" returns raw file bytes
|
| 383 |
+
|
| 384 |
+
Returns:
|
| 385 |
+
Document content including extracted_text, summary, actors, and key_details
|
| 386 |
+
"""
|
| 387 |
+
try:
|
| 388 |
+
import httpx
|
| 389 |
+
|
| 390 |
+
# Check configuration from environment
|
| 391 |
+
lawyer_db_url = os.getenv("LAWYER_DB_URL")
|
| 392 |
+
cyberlgl_api_key = os.getenv("CYBERLGL_API_KEY")
|
| 393 |
+
|
| 394 |
+
if not lawyer_db_url:
|
| 395 |
+
return "Error: LAWYER_DB_URL not configured in environment"
|
| 396 |
+
|
| 397 |
+
if not cyberlgl_api_key:
|
| 398 |
+
return "Error: CYBERLGL_API_KEY not configured in environment"
|
| 399 |
+
|
| 400 |
+
# Build URL - remove any trailing slash
|
| 401 |
+
base_url = lawyer_db_url.rstrip('/')
|
| 402 |
+
url = f"{base_url}/retrieve-lawyer-document"
|
| 403 |
+
|
| 404 |
+
# Make request
|
| 405 |
+
async with httpx.AsyncClient() as client:
|
| 406 |
+
response = await client.get(
|
| 407 |
+
url,
|
| 408 |
+
params={
|
| 409 |
+
"lawyer_id": user_id,
|
| 410 |
+
"file_path": file_path,
|
| 411 |
+
"format": 'text'
|
| 412 |
+
},
|
| 413 |
+
headers={
|
| 414 |
+
"x-api-key": cyberlgl_api_key
|
| 415 |
+
},
|
| 416 |
+
timeout=30.0
|
| 417 |
+
)
|
| 418 |
+
|
| 419 |
+
# Handle different status codes
|
| 420 |
+
if response.status_code == 404:
|
| 421 |
+
return f"Document not found: {file_path}"
|
| 422 |
+
elif response.status_code == 403:
|
| 423 |
+
return "Access denied: You do not have permission to access this document"
|
| 424 |
+
elif response.status_code != 200:
|
| 425 |
+
return f"Error retrieving document: HTTP {response.status_code}"
|
| 426 |
+
|
| 427 |
+
# Parse JSON response
|
| 428 |
+
data = response.json()
|
| 429 |
+
|
| 430 |
+
# Format the response for the LLM
|
| 431 |
+
output = [
|
| 432 |
+
f"📄 Document: {data.get('file_name', file_path)}",
|
| 433 |
+
"-" * 30,
|
| 434 |
+
"\nExtracted Text:",
|
| 435 |
+
data.get('extracted_text', 'No text available'),
|
| 436 |
+
"-" * 80
|
| 437 |
+
]
|
| 438 |
+
|
| 439 |
+
return "\n".join(output)
|
| 440 |
+
|
| 441 |
+
except httpx.TimeoutError:
|
| 442 |
+
return "Error: Timeout while retrieving document"
|
| 443 |
+
except httpx.RequestError as e:
|
| 444 |
+
return f"Error: Failed to connect to document server: {str(e)}"
|
| 445 |
+
except json.JSONDecodeError:
|
| 446 |
+
return "Error: Invalid response from document server"
|
| 447 |
+
except Exception as e:
|
| 448 |
+
return f"Error retrieving document: {str(e)}"
|
| 449 |
+
|
| 450 |
+
|
| 451 |
# Export tool sets for different user types
|
| 452 |
tools_for_client_facade = [query_knowledge_graph, find_lawyers, message_lawyer, search_web, edit_document]
|
| 453 |
tools_for_client = [_query_knowledge_graph, _find_lawyers, _message_lawyer, search_web, _edit_document]
|
| 454 |
+
tools_for_lawyer_facade = [query_knowledge_graph, search_web, edit_document, retrieve_lawyer_document]
|
| 455 |
+
tools_for_lawyer = [_query_knowledge_graph, search_web, _edit_document, _retrieve_lawyer_document]
|
| 456 |
+
tools = tools_for_client
|