Files changed (4) hide show
  1. agents.py +4 -37
  2. app.py +11 -51
  3. files_extraction.py +0 -60
  4. requirements.txt +1 -3
agents.py CHANGED
@@ -1,7 +1,6 @@
1
  # agents.py
2
  from langgraph.prebuilt import create_react_agent
3
  import os
4
- import json
5
  import logging
6
 
7
  # Set up logging
@@ -23,23 +22,6 @@ def set_api_key(api_key: str) -> bool:
23
  logger.error("Invalid API key provided")
24
  return False
25
 
26
- def load_document_data() -> str:
27
- """Load document data from JSON file if it exists"""
28
- try:
29
- if os.path.exists("document_data.json"):
30
- with open("document_data.json", "r", encoding="utf-8") as f:
31
- doc_data = json.load(f)
32
- if doc_data.get("documents"):
33
- # Format the documents for agent consumption
34
- formatted_docs = []
35
- for doc_id, doc_info in doc_data["documents"].items():
36
- formatted_docs.append(f"Document: {doc_info['title']}\nContent: {doc_info['content']}\n---")
37
- return "\n".join(formatted_docs)
38
- return ""
39
- except Exception as e:
40
- logger.error(f"Error loading document data: {e}")
41
- return ""
42
-
43
  def create_agent_response(prompt: str, user_input: str, model: str = "anthropic:claude-3-haiku-20240307") -> str:
44
  """Generic function to create and invoke any agent"""
45
  global _api_key
@@ -91,13 +73,9 @@ def create_agent_response(prompt: str, user_input: str, model: str = "anthropic:
91
 
92
  # ==================== CORE AGENT FUNCTIONS ====================
93
 
94
- def judge_agent(student_arg: str, opponent_arg: str = "") -> str:
95
  """Judge agent for evaluating legal arguments"""
96
  logger.info("Judge agent called")
97
-
98
- # Load document data
99
- doc_data = load_document_data()
100
-
101
  prompt = """You are an experienced federal judge presiding over a courtroom.
102
 
103
  Your role is to:
@@ -106,22 +84,17 @@ Your role is to:
106
  - Point out strengths and weaknesses in arguments
107
  - Ensure proper legal procedure is followed
108
  - Give guidance on how to strengthen legal positions
109
- - Reference case documents when relevant to support your analysis
110
 
111
  Be fair, professional, and educational in your feedback.
112
  ALWAYS respond in this exact format: Judge: [your response]
113
  Keep responses 2-4 sentences, focusing on legal analysis."""
114
 
115
- user_input = f"Student Argument: {student_arg}\nOpponent Argument: {opponent_arg}\nCase Documents: {doc_data}"
116
  return create_agent_response(prompt, user_input)
117
 
118
  def opponent_agent(student_arg: str, case_context: str = "") -> str:
119
  """Opponent agent for counter-arguments"""
120
  logger.info("Opponent agent called")
121
-
122
- # Load document data
123
- doc_data = load_document_data()
124
-
125
  prompt = """You are a skilled attorney arguing the opposing side in this case.
126
 
127
  Your role is to:
@@ -130,22 +103,17 @@ Your role is to:
130
  - Question the student's reasoning and evidence
131
  - Provide compelling opposition that helps the student improve
132
  - Stay focused on the legal issues at hand
133
- - Reference case documents when they support your opposing arguments
134
 
135
  Be persuasive, professional, and challenging but fair.
136
  ALWAYS respond in this exact format: Opponent: [your response]
137
  Keep responses 2-4 sentences, focused on strong legal counter-arguments."""
138
 
139
- user_input = f"Student's Argument: {student_arg}\nCase Context: {case_context}\n\nCase Documents:\n{doc_data}"
140
  return create_agent_response(prompt, user_input)
141
 
142
  def narrator_agent(context: str, student_arg: str = "", opponent_arg: str = "") -> str:
143
  """Enhanced narrator agent that handles courtroom atmosphere AND side character arguments"""
144
  logger.info("Narrator agent called")
145
-
146
- # Load document data
147
- doc_data = load_document_data()
148
-
149
  prompt = """You are a courtroom narrator who describes the scene and occasionally voices side characters.
150
 
151
  Your roles include:
@@ -154,7 +122,6 @@ Your roles include:
154
  - Occasionally speaking as side characters (bailiff, court clerk, witnesses, gallery reactions)
155
  - Setting the dramatic tone and maintaining engagement
156
  - Providing procedural context when needed
157
- - Referencing case documents when they add to the narrative
158
 
159
  You can voice side characters like:
160
  - Bailiff: "Order in the court!" or procedural announcements
@@ -167,7 +134,7 @@ When voicing side characters, format as: "Narrator: [description] - Character: '
167
  Otherwise format as: "Narrator: [your narration]"
168
  Keep responses 2-4 sentences, atmospheric and engaging."""
169
 
170
- user_input = f"Context: {context}\nStudent Argument: {student_arg}\nOpponent Argument: {opponent_arg}\n\nCase Documents:\n{doc_data}"
171
  return create_agent_response(prompt, user_input)
172
 
173
  # ==================== AGENT REGISTRY ====================
 
1
  # agents.py
2
  from langgraph.prebuilt import create_react_agent
3
  import os
 
4
  import logging
5
 
6
  # Set up logging
 
22
  logger.error("Invalid API key provided")
23
  return False
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  def create_agent_response(prompt: str, user_input: str, model: str = "anthropic:claude-3-haiku-20240307") -> str:
26
  """Generic function to create and invoke any agent"""
27
  global _api_key
 
73
 
74
  # ==================== CORE AGENT FUNCTIONS ====================
75
 
76
+ def judge_agent(student_arg: str, opponent_arg: str = "", documents: str = "") -> str:
77
  """Judge agent for evaluating legal arguments"""
78
  logger.info("Judge agent called")
 
 
 
 
79
  prompt = """You are an experienced federal judge presiding over a courtroom.
80
 
81
  Your role is to:
 
84
  - Point out strengths and weaknesses in arguments
85
  - Ensure proper legal procedure is followed
86
  - Give guidance on how to strengthen legal positions
 
87
 
88
  Be fair, professional, and educational in your feedback.
89
  ALWAYS respond in this exact format: Judge: [your response]
90
  Keep responses 2-4 sentences, focusing on legal analysis."""
91
 
92
+ user_input = f"Student Argument: {student_arg}\nOpponent Argument: {opponent_arg}\nCase Documents: {documents}"
93
  return create_agent_response(prompt, user_input)
94
 
95
  def opponent_agent(student_arg: str, case_context: str = "") -> str:
96
  """Opponent agent for counter-arguments"""
97
  logger.info("Opponent agent called")
 
 
 
 
98
  prompt = """You are a skilled attorney arguing the opposing side in this case.
99
 
100
  Your role is to:
 
103
  - Question the student's reasoning and evidence
104
  - Provide compelling opposition that helps the student improve
105
  - Stay focused on the legal issues at hand
 
106
 
107
  Be persuasive, professional, and challenging but fair.
108
  ALWAYS respond in this exact format: Opponent: [your response]
109
  Keep responses 2-4 sentences, focused on strong legal counter-arguments."""
110
 
111
+ user_input = f"Student's Argument: {student_arg}\nCase Context: {case_context}"
112
  return create_agent_response(prompt, user_input)
113
 
114
  def narrator_agent(context: str, student_arg: str = "", opponent_arg: str = "") -> str:
115
  """Enhanced narrator agent that handles courtroom atmosphere AND side character arguments"""
116
  logger.info("Narrator agent called")
 
 
 
 
117
  prompt = """You are a courtroom narrator who describes the scene and occasionally voices side characters.
118
 
119
  Your roles include:
 
122
  - Occasionally speaking as side characters (bailiff, court clerk, witnesses, gallery reactions)
123
  - Setting the dramatic tone and maintaining engagement
124
  - Providing procedural context when needed
 
125
 
126
  You can voice side characters like:
127
  - Bailiff: "Order in the court!" or procedural announcements
 
134
  Otherwise format as: "Narrator: [your narration]"
135
  Keep responses 2-4 sentences, atmospheric and engaging."""
136
 
137
+ user_input = f"Context: {context}\nStudent Argument: {student_arg}\nOpponent Argument: {opponent_arg}"
138
  return create_agent_response(prompt, user_input)
139
 
140
  # ==================== AGENT REGISTRY ====================
app.py CHANGED
@@ -1,4 +1,3 @@
1
- import json
2
  import gradio as gr
3
  import time
4
  import logging
@@ -6,8 +5,7 @@ from typing import Dict, List, Tuple, Optional
6
  from agents import judge_agent, opponent_agent, narrator_agent, set_api_key
7
  from dotenv import load_dotenv
8
  import os
9
- from files_extraction import (
10
- extract_text_from_pdf_bytes,extract_text_from_docx_bytes, extract_text_from_txt_bytes)
11
  # Set up logging
12
  logging.basicConfig(level=logging.INFO)
13
  logger = logging.getLogger(__name__)
@@ -72,11 +70,11 @@ class LawTrainingSystem:
72
  system = LawTrainingSystem()
73
 
74
  # ==================== AGENT RESPONSE HANDLERS ====================
75
- def generate_judge_response(student_message: str, opponent_message: str = "") -> str:
76
  """Generate Judge AI response"""
77
  try:
78
  logger.info("Generating judge response")
79
- return judge_agent(student_message, opponent_message)
80
  except Exception as e:
81
  logger.error(f"Error in judge response: {e}", exc_info=True)
82
  return f"Judge: I'm having trouble processing your argument. Error: {str(e)}"
@@ -205,52 +203,15 @@ def upload_case_documents(files) -> str:
205
  try:
206
  if not files:
207
  return "No documents uploaded"
208
-
209
- all_extracted_text = []
210
- document_data_for_agent = {"documents": {}}
211
-
212
- for idx, file_path in enumerate(files):
213
- # Read bytes from the file path
214
- with open(file_path, "rb") as f:
215
- file_bytes = f.read()
216
-
217
- # Determine extension
218
- file_extension = os.path.splitext(file_path)[1].lstrip(".").lower()
219
-
220
- # Extract text based on file type
221
- if file_extension == "pdf":
222
- text = extract_text_from_pdf_bytes(file_bytes)
223
- elif file_extension == "docx":
224
- text = extract_text_from_docx_bytes(file_bytes)
225
- elif file_extension == "pptx":
226
- text = extract_text_from_pptx_bytes(file_bytes)
227
- elif file_extension == "txt":
228
- text = extract_text_from_txt_bytes(file_bytes)
229
- else:
230
- text = ""
231
-
232
- # Collect results
233
- if text:
234
- all_extracted_text.append(text)
235
- document_data_for_agent["documents"][f"doc_{idx+1}"] = {
236
- "title": os.path.basename(file_path),
237
- "content": text
238
- }
239
-
240
- # Save JSON only once, after processing
241
- if document_data_for_agent["documents"]:
242
- json_filename = "document_data.json"
243
- with open(json_filename, "w", encoding="utf-8") as json_file:
244
- json.dump(document_data_for_agent, json_file, indent=4, ensure_ascii=False)
245
-
246
- # Log and return summary
247
- uploaded_names = [os.path.basename(p) for p in files]
248
- logger.info(f"Uploaded {len(files)} documents: {', '.join(uploaded_names)}")
249
- return f"Uploaded {len(files)} documents: {', '.join(uploaded_names)}"
250
-
251
  except Exception as e:
252
- logger.error("Error uploading documents", exc_info=True)
253
- return f"Error uploading documents: {e}"
254
 
255
  # ==================== GRADIO INTERFACE ====================
256
  def create_law_training_interface():
@@ -314,7 +275,6 @@ def create_law_training_interface():
314
  label="Upload Case Documents",
315
  file_count="multiple",
316
  file_types=[".pdf", ".txt", ".docx"],
317
- type="filepath",
318
  elem_classes="upload-section"
319
  )
320
  upload_status = gr.Textbox(
 
 
1
  import gradio as gr
2
  import time
3
  import logging
 
5
  from agents import judge_agent, opponent_agent, narrator_agent, set_api_key
6
  from dotenv import load_dotenv
7
  import os
8
+
 
9
  # Set up logging
10
  logging.basicConfig(level=logging.INFO)
11
  logger = logging.getLogger(__name__)
 
70
  system = LawTrainingSystem()
71
 
72
  # ==================== AGENT RESPONSE HANDLERS ====================
73
+ def generate_judge_response(student_message: str, opponent_message: str = "", documents: str = "") -> str:
74
  """Generate Judge AI response"""
75
  try:
76
  logger.info("Generating judge response")
77
+ return judge_agent(student_message, opponent_message, documents)
78
  except Exception as e:
79
  logger.error(f"Error in judge response: {e}", exc_info=True)
80
  return f"Judge: I'm having trouble processing your argument. Error: {str(e)}"
 
203
  try:
204
  if not files:
205
  return "No documents uploaded"
206
+
207
+ # TODO: Process uploaded documents with document parsing
208
+ file_names = [f.name for f in files]
209
+ logger.info(f"Uploaded {len(files)} documents: {file_names}")
210
+ return f"Uploaded {len(files)} documents: {', '.join(file_names)}"
211
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  except Exception as e:
213
+ logger.error(f"Error uploading documents: {e}", exc_info=True)
214
+ return f"Error uploading documents: {str(e)}"
215
 
216
  # ==================== GRADIO INTERFACE ====================
217
  def create_law_training_interface():
 
275
  label="Upload Case Documents",
276
  file_count="multiple",
277
  file_types=[".pdf", ".txt", ".docx"],
 
278
  elem_classes="upload-section"
279
  )
280
  upload_status = gr.Textbox(
files_extraction.py DELETED
@@ -1,60 +0,0 @@
1
-
2
- from PyPDF2 import PdfReader
3
- from docx import Document
4
- import zipfile
5
- import xml.etree.ElementTree as ET
6
- import io
7
-
8
- def clean_extracted_text(text: str) -> str:
9
- """
10
- Normalize and collapse whitespace in extracted text.
11
- """
12
- lines = [line.strip() for line in text.split("\n") if line.strip()]
13
- return ' '.join(lines)
14
-
15
- def extract_text_from_pdf_bytes(pdf_bytes: bytes) -> str:
16
- """
17
- Extract text from PDF bytes using PyPDF2.
18
- """
19
- try:
20
- pdf_file = io.BytesIO(pdf_bytes)
21
- reader = PdfReader(pdf_file)
22
- text = ""
23
- for page in reader.pages:
24
- page_text = page.extract_text() or ""
25
- text += clean_extracted_text(page_text) + "\n\n"
26
- return text.strip()
27
- except Exception as e:
28
- print(f"Error extracting text from PDF: {e}")
29
- return ""
30
-
31
- def extract_text_from_docx_bytes(docx_bytes: bytes) -> str:
32
- """
33
- Extract text (paragraphs and tables) from DOCX bytes.
34
- """
35
- try:
36
- docx_file = io.BytesIO(docx_bytes)
37
- doc = Document(docx_file)
38
- text = ""
39
- # paragraphs
40
- for para in doc.paragraphs:
41
- text += para.text + "\n"
42
- # tables
43
- for table in doc.tables:
44
- for row in table.rows:
45
- text += " | ".join(cell.text for cell in row.cells) + "\n"
46
- return clean_extracted_text(text).strip()
47
- except Exception as e:
48
- print(f"Error extracting text from DOCX: {e}")
49
- return ""
50
-
51
-
52
- def extract_text_from_txt_bytes(txt_bytes: bytes, encoding: str = 'utf-8') -> str:
53
- """
54
- Extract and clean text from raw TXT bytes using the given encoding.
55
- """
56
- try:
57
- raw_text = txt_bytes.decode(encoding, errors='ignore')
58
- except Exception:
59
- raw_text = txt_bytes.decode('latin-1', errors='ignore')
60
- return clean_extracted_text(raw_text).strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,6 +1,4 @@
1
  langgraph
2
  langchain
3
  dotenv
4
- langchain-anthropic
5
- python-docx
6
- PyPDF2
 
1
  langgraph
2
  langchain
3
  dotenv
4
+ langchain-anthropic