finsight_llmops / app.py
fuggingrace's picture
Update app.py
38468f8 verified
Raw
History Blame Contribute Delete
5.89 kB
## Setup
# Install the necessary libraries
import os
import httpx
import json
import tiktoken
from datasets import load_dataset
import pandas as pd
import gradio as gr
import uuid
from pathlib import Path
from huggingface_hub import CommitScheduler
from openai import OpenAI
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.documents import Document
from langchain_community.document_loaders import PyPDFDirectoryLoader
from langchain_community.embeddings.sentence_transformer import (
SentenceTransformerEmbeddings
)
from langchain_community.embeddings.sentence_transformer import (
SentenceTransformerEmbeddings
)
from langchain_community.vectorstores import Chroma
# Create Client
hf_token = os.getenv("HF_TOKEN")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_BASE_URL = os.getenv("OPENAI_BASE_URL")
import zipfile
# Define the correct paths
zip_path = "reports_db.zip"
unzip_path = "reports_db"
# Extract the zip file only if it hasn't been extracted
if not os.path.exists(unzip_path) or not os.path.exists(os.path.join(unzip_path, "chroma.sqlite3")):
print("Extracting ChromaDB files...")
with zipfile.ZipFile(zip_path, "r") as zip_ref:
zip_ref.extractall(unzip_path)
print("Extraction complete.")
# Set the correct persisted location
persisted_vectordb_location = unzip_path
client = OpenAI(http_client=httpx.Client())
# Define the embedding model and the vectorstore
embedding_model = SentenceTransformerEmbeddings(model_name='thenlper/gte-large')
collection_name = 'report_collections'
# Load the persisted vectorDB
try:
reports_db = Chroma(
collection_name=collection_name,
persist_directory=persisted_vectordb_location, # Make sure this points to the correct extracted folder
embedding_function=embedding_model
)
print("ChromaDB successfully loaded.")
except Exception as e:
print(f"Error loading ChromaDB: {e}")
# Prepare the logging functionality
log_file = Path("logs/") / f"data_{uuid.uuid4()}.json"
log_folder = log_file.parent
scheduler = CommitScheduler(
repo_id="fuggingrace/finsight_llmops",
repo_type="dataset",
token=hf_token,
folder_path=log_folder,
path_in_repo="data",
every=2
)
# Define the Q&A system message
qna_system_message = """
You are an expert financial analyst assistant specializing in extracting key insights from 10-K reports of major companies.
You must ONLY answer based on the provided context, ensuring accuracy, and citing the source document with page numbers.
- If the information is **partially available**, provide the best possible summary using ONLY the given context.
- If the **context does not contain an answer**, state: "I cannot answer this question based on the context provided."
- ALWAYS **cite the document page number** in the format: (Page [page number]).
"""
# Define the user message template
qna_user_message_template = """
### Context:
The following extracted text from 10-K reports is relevant to answering the question.
{context}
### Question:
{question}
### Instructions:
- Answer the question concisely using ONLY the provided context.
- If the answer is found, cite the page number (e.g., "According to the report, the company allocated $500M to AI R&D. (Page 12)")
- If the context is not sufficient, say: "I cannot answer this question based on the context provided."
"""
sample_metadata = reports_db.get()
print("Database metadata:", sample_metadata)
# Define the predict function that runs when 'Submit' is clicked or when a API request is made
def predict(user_input, company):
filter_criteria = "/content/dataset/" + company + "-10-k-2023.pdf"
relevant_document_chunks = reports_db.similarity_search(
user_input, k=100, filter={"source": filter_criteria}
)
# Create context_for_query
context_list = [
f"Page {d.metadata['page']}: {d.page_content}"
for d in relevant_document_chunks
]
context_for_query = "\n\n".join(context_list)
# Create messages
prompt = [
{'role': 'system', 'content': qna_system_message},
{
'role': 'user',
'content': qna_user_message_template.format(
context=context_for_query, question=user_input
),
},
]
# Get response from the LLM
try:
response = client.chat.completions.create(
model='gpt-4o-mini', messages=prompt, temperature=0
)
prediction = response.choices[0].message.content.strip()
except Exception as e:
prediction = f'Sorry, I encountered the following error: \n {e}'
# While the prediction is made, log both the inputs and outputs to a local log file
# While writing to the log file, ensure that the commit scheduler is locked to avoid parallel
# access
with scheduler.lock:
with log_file.open("a") as f:
f.write(json.dumps(
{
'user_input': user_input,
'retrieved_context': context_for_query,
'model_response': prediction,
'company': company
}
))
f.write("\n")
return prediction
# Set-up the Gradio UI
# Add text box and radio button to the interface
# The radio button is used to select the company 10k report in which the context needs to be retrieved.
# Set-up the Gradio UI
user_input = gr.Textbox(label="Enter your question here:")
company = gr.Radio(
choices=["aws", "google", "msft", "IBM", "Meta"],
label="Select the company:",
)
# # Create the interface
demo = gr.Interface(
fn=predict,
inputs=[user_input, company],
outputs="text",
title="Finsights Grey - RAG for Effective Information Retrieval",
description="Ask questions about financial reports.",
)
demo.queue()
demo.launch(share=True)