Illia56 commited on
Commit
017057d
·
verified ·
1 Parent(s): 6f2ad1d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -49
app.py CHANGED
@@ -17,6 +17,8 @@ from langchain_core.output_parsers import StrOutputParser
17
  from langchain import hub
18
  from langgraph.graph import END, StateGraph, START
19
  from typing_extensions import TypedDict
 
 
20
 
21
  # Load environment variables
22
  dotenv.load_dotenv()
@@ -48,15 +50,28 @@ def initialize_retriever():
48
  try:
49
  loader = PyPDFLoader(file_path)
50
  docs = loader.load() # Each doc is a page
 
 
 
 
 
 
 
51
  for doc in docs:
52
- doc.metadata["source_file"] = os.path.basename(file_path)
53
- doc.metadata["file_path"] = file_path
54
- doc.metadata["chunk_size"] = len(doc.page_content)
55
- doc.metadata["chunk_id"] = f"{os.path.basename(file_path)}-page-{doc.metadata.get('page', '0')}"
56
- if "page" in doc.metadata:
57
- doc.metadata["page_num"] = doc.metadata["page"]
58
- logger.info(f"Processed {file_path}: extracted {len(docs)} page-chunks")
59
- return docs
 
 
 
 
 
 
60
  except Exception as e:
61
  logger.error(f"Error processing {file_path}: {str(e)}")
62
  return []
@@ -99,7 +114,7 @@ def initialize_retriever():
99
  return retriever
100
 
101
  # Define graders and components
102
- def setup_components(retriever):
103
  # Data models for grading
104
  class GradeDocuments(BaseModel):
105
  """Binary score for relevance check on retrieved documents."""
@@ -120,7 +135,7 @@ def setup_components(retriever):
120
  )
121
 
122
  # LLM models
123
- llm = ChatOpenAI(model="gpt-4.1", temperature=0)
124
  doc_grader = llm.with_structured_output(GradeDocuments)
125
  hallucination_grader_llm = llm.with_structured_output(GradeHallucinations)
126
  answer_grader_llm = llm.with_structured_output(GradeAnswer)
@@ -304,62 +319,76 @@ def build_rag_graph(components):
304
  # Compile the graph
305
  return workflow.compile()
306
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  # Processing function for Gradio
308
- def process_query(question, display_logs=False):
309
  logs = []
310
  answer = ""
311
-
312
  try:
313
- # Initialize retriever if not done yet
314
- global retriever, rag_app
315
- if 'retriever' not in globals() or retriever is None:
316
- logs.append("Initializing retriever...")
317
- retriever = initialize_retriever()
318
- if retriever is None:
319
- return "Error: No PDF files found. Please add PDF files to the Data directory.", "\n".join(logs)
320
-
321
- logs.append("Setting up RAG components...")
322
- components = setup_components(retriever)
323
-
324
- logs.append("Building RAG graph...")
325
- rag_app = build_rag_graph(components)
326
 
 
 
 
 
 
 
 
327
  logs.append("Processing query: " + question)
328
-
329
- # Run the query through the RAG graph
330
  logs.append("Starting RAG pipeline...")
331
  final_output = None
332
- for i, output in enumerate(rag_app.stream({"question": question})):
333
- step_info = f"Step {i+1}: "
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
- if 'retrieve' in output:
336
- step_info += f"Retrieved {len(output['retrieve']['documents'])} documents"
337
- elif 'grade_documents' in output:
338
- step_info += f"Graded documents, {len(output['grade_documents']['documents'])} deemed relevant"
339
- elif 'transform_query' in output:
340
- step_info += f"Transformed query to: {output['transform_query']['question']}"
341
- elif 'generate' in output:
342
- step_info += "Generated answer"
343
- final_output = output
344
 
345
- logs.append(step_info)
346
-
347
  if final_output and 'generate' in final_output:
348
  answer = final_output['generate']['generation']
349
  logs.append("Final answer generated successfully")
350
  else:
351
  answer = "No answer could be generated. Please try rephrasing your question."
352
  logs.append("Failed to generate answer")
353
-
354
  except Exception as e:
355
  logs.append(f"Error: {str(e)}")
356
  answer = f"An error occurred: {str(e)}"
357
-
358
- return answer, "\n".join(logs) if display_logs else ""
359
-
360
- # Initialize global variables
361
- retriever = None
362
- rag_app = None
363
 
364
  # Create Gradio interface
365
  with gr.Blocks(title="Self-RAG Document Assistant", theme=gr.themes.Base()) as demo:
@@ -383,6 +412,11 @@ with gr.Blocks(title="Self-RAG Document Assistant", theme=gr.themes.Base()) as d
383
  )
384
 
385
  with gr.Column(scale=1):
 
 
 
 
 
386
  show_logs = gr.Checkbox(label="Show Debugging Logs", value=False)
387
  submit_btn = gr.Button("Submit", variant="primary")
388
 
@@ -400,12 +434,18 @@ with gr.Blocks(title="Self-RAG Document Assistant", theme=gr.themes.Base()) as d
400
  lines=15,
401
  visible=False
402
  )
 
 
 
 
 
 
403
 
404
  # Event handlers
405
  submit_btn.click(
406
  fn=process_query,
407
- inputs=[query_input, show_logs],
408
- outputs=[answer_output, logs_output]
409
  )
410
 
411
  show_logs.change(
 
17
  from langchain import hub
18
  from langgraph.graph import END, StateGraph, START
19
  from typing_extensions import TypedDict
20
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
21
+ from langchain_community.callbacks import get_openai_callback
22
 
23
  # Load environment variables
24
  dotenv.load_dotenv()
 
50
  try:
51
  loader = PyPDFLoader(file_path)
52
  docs = loader.load() # Each doc is a page
53
+
54
+ # Split each page into smaller chunks
55
+ text_splitter = RecursiveCharacterTextSplitter(
56
+ chunk_size=1024, # or 512, adjust as needed
57
+ chunk_overlap=100
58
+ )
59
+ split_docs = []
60
  for doc in docs:
61
+ for chunk in text_splitter.split_text(doc.page_content):
62
+ new_doc = doc.__class__(
63
+ page_content=chunk,
64
+ metadata=doc.metadata.copy()
65
+ )
66
+ new_doc.metadata["source_file"] = os.path.basename(file_path)
67
+ new_doc.metadata["file_path"] = file_path
68
+ new_doc.metadata["chunk_size"] = len(chunk)
69
+ new_doc.metadata["chunk_id"] = f"{os.path.basename(file_path)}-page-{doc.metadata.get('page', '0')}-chunk"
70
+ if "page" in doc.metadata:
71
+ new_doc.metadata["page_num"] = doc.metadata["page"]
72
+ split_docs.append(new_doc)
73
+ logger.info(f"Processed {file_path}: extracted {len(split_docs)} chunks")
74
+ return split_docs
75
  except Exception as e:
76
  logger.error(f"Error processing {file_path}: {str(e)}")
77
  return []
 
114
  return retriever
115
 
116
  # Define graders and components
117
+ def setup_components(retriever, model_choice):
118
  # Data models for grading
119
  class GradeDocuments(BaseModel):
120
  """Binary score for relevance check on retrieved documents."""
 
135
  )
136
 
137
  # LLM models
138
+ llm = ChatOpenAI(model=model_choice, temperature=0)
139
  doc_grader = llm.with_structured_output(GradeDocuments)
140
  hallucination_grader_llm = llm.with_structured_output(GradeHallucinations)
141
  answer_grader_llm = llm.with_structured_output(GradeAnswer)
 
319
  # Compile the graph
320
  return workflow.compile()
321
 
322
+ # Initialize global variables
323
+ retriever = None
324
+ rag_app = None
325
+ components = None
326
+ current_model_choice = "gpt-4.1" # Default
327
+
328
+ # Run PDF processing and RAG setup ONCE at startup, with default model
329
+ retriever = initialize_retriever()
330
+ if retriever is not None:
331
+ components = setup_components(retriever, current_model_choice)
332
+ rag_app = build_rag_graph(components)
333
+ else:
334
+ logger.error("No retriever could be initialized. Please add PDF files to the Data directory.")
335
+
336
  # Processing function for Gradio
337
+ def process_query(question, display_logs=False, model_choice="gpt-4.1"):
338
  logs = []
339
  answer = ""
340
+ token_usage = {}
341
  try:
342
+ global retriever, rag_app, components, current_model_choice
343
+ if retriever is None:
344
+ logs.append("Error: No PDF files found. Please add PDF files to the Data directory and restart the app.")
345
+ return "Error: No PDF files found. Please add PDF files to the Data directory.", "\n".join(logs), token_usage
 
 
 
 
 
 
 
 
 
346
 
347
+ # If model_choice changed, re-initialize components and rag_app
348
+ if model_choice != current_model_choice:
349
+ logs.append(f"Switching model to {model_choice} ...")
350
+ components = setup_components(retriever, model_choice)
351
+ rag_app = build_rag_graph(components)
352
+ current_model_choice = model_choice
353
+
354
  logs.append("Processing query: " + question)
355
+ logs.append(f"Using model: {model_choice}")
 
356
  logs.append("Starting RAG pipeline...")
357
  final_output = None
358
+
359
+ with get_openai_callback() as cb:
360
+ for i, output in enumerate(rag_app.stream({"question": question})):
361
+ step_info = f"Step {i+1}: "
362
+ if 'retrieve' in output:
363
+ step_info += f"Retrieved {len(output['retrieve']['documents'])} documents"
364
+ elif 'grade_documents' in output:
365
+ step_info += f"Graded documents, {len(output['grade_documents']['documents'])} deemed relevant"
366
+ elif 'transform_query' in output:
367
+ step_info += f"Transformed query to: {output['transform_query']['question']}"
368
+ elif 'generate' in output:
369
+ step_info += "Generated answer"
370
+ final_output = output
371
+ logs.append(step_info)
372
 
373
+ # Store token usage information
374
+ token_usage = {
375
+ "total_tokens": cb.total_tokens,
376
+ "prompt_tokens": cb.prompt_tokens,
377
+ "completion_tokens": cb.completion_tokens,
378
+ "total_cost": cb.total_cost
379
+ }
380
+ logs.append(f"Token usage: {token_usage}")
 
381
 
 
 
382
  if final_output and 'generate' in final_output:
383
  answer = final_output['generate']['generation']
384
  logs.append("Final answer generated successfully")
385
  else:
386
  answer = "No answer could be generated. Please try rephrasing your question."
387
  logs.append("Failed to generate answer")
 
388
  except Exception as e:
389
  logs.append(f"Error: {str(e)}")
390
  answer = f"An error occurred: {str(e)}"
391
+ return answer, "\n".join(logs) if display_logs else "", token_usage
 
 
 
 
 
392
 
393
  # Create Gradio interface
394
  with gr.Blocks(title="Self-RAG Document Assistant", theme=gr.themes.Base()) as demo:
 
412
  )
413
 
414
  with gr.Column(scale=1):
415
+ model_choice_input = gr.Dropdown(
416
+ label="Model",
417
+ choices=["gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano"],
418
+ value="gpt-4.1"
419
+ )
420
  show_logs = gr.Checkbox(label="Show Debugging Logs", value=False)
421
  submit_btn = gr.Button("Submit", variant="primary")
422
 
 
434
  lines=15,
435
  visible=False
436
  )
437
+
438
+ with gr.Row():
439
+ token_usage_output = gr.JSON(
440
+ label="Token Usage Statistics",
441
+ visible=True
442
+ )
443
 
444
  # Event handlers
445
  submit_btn.click(
446
  fn=process_query,
447
+ inputs=[query_input, show_logs, model_choice_input],
448
+ outputs=[answer_output, logs_output, token_usage_output]
449
  )
450
 
451
  show_logs.change(