## 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)