Fixed Income Expert System

RAG chatbot for financial bond documents

FactEntry Data Solutions (A SIX Company)
  • LLaMA 3 8B via Groq
  • FAISS semantic search
  • FastAPI + Streamlit
  • systemd deployment

An AI-powered Q&A system that lets internal teams upload bond documentation PDFs and query them in natural language. Built with FastAPI backend, Streamlit frontend, SBERT embeddings, FAISS vector search, and LLaMA 3 8B via Groq API — deployed as persistent Linux systemd services for internal organisational use.

What it does

The Fixed Income Expert System allows finance teams to upload internal bond PDFs — deal sheets, policy documents, callable bond schedules — and ask natural-language questions like "What is the maturity date for bond XYZ?" or "List all callable bonds issued after 2020." The system retrieves relevant context from FAISS and sends it to LLaMA 3 8B via Groq for a grounded, concise answer.

Groq LLaMA 3 8B FAISS vector DB SBERT MiniLM embeddings systemd services Internal org deployment
Python FastAPI Streamlit FAISS Sentence Transformers LangChain PyMuPDF Groq API

Features

  • Knowledge Ingestion: Upload PDFs and extract structured, chunked content using heading-based and RecursiveCharacterTextSplitter strategies.
  • Semantic Search with FAISS: Find top-K relevant chunks using vector similarity with sentence-transformers/all-MiniLM-L6-v2 embeddings.
  • LLM Answering: LLaMA 3 8B via Groq API answers questions based only on retrieved context — no hallucination fallback.
  • File Metadata Management: View all uploaded files with chunk statistics and upload timestamps.
  • Clean Prompt Engineering: Optimised system prompts for precise, context-only responses.
  • Modular Architecture: Clean separation of backend (FastAPI) and frontend (Streamlit) with REST integration.

API Endpoints

MethodEndpointDescription
POST/uploadUpload and process a PDF file — extract, chunk, embed, index
POST/queryAsk a natural-language question — returns grounded LLM answer
GET/list-filesRetrieve metadata of all uploaded PDFs (chunks, timestamp)

Prompt template

You are a Financial Expert Bot. Your task is to provide accurate and concise answers to the user's questions based on the provided context. Instructions: - No disclaimers or unnecessary information. - No "I don't know" or "I'm an AI" type responses. - If the answer is not in context, say: "The answer is not in the context."

Project structure

fixed-income-expert/ ├── backend/ │ └── backend.py # FastAPI — /upload, /query, /list-files ├── frontend/ │ └── frontend.py # Streamlit UI ├── embeddings/ # Saved SBERT .npy embedding files (per PDF) ├── text_chunks/ # Pickled text chunks per document ├── metadata/ # JSON metadata per uploaded PDF ├── version-1-linux-service/ │ └── FactEntry_FEexpert/ # systemd service configs + startup scripts ├── .env # GROQ_API_KEY ├── requirements.txt └── docker-compose.yml

Architecture overview

Fixed Income Expert System architecture diagram

Full system architecture — PDF ingestion → FAISS indexing → SBERT embeddings → Groq LLaMA 3 → Streamlit UI

Component breakdown

  • Streamlit Frontend (port 8501): Three views — upload PDF, ask question, view file metadata. Communicates with backend via REST.
  • FastAPI Backend (port 8002): Handles PDF parsing (PyMuPDF), text splitting (LangChain), embedding (SBERT), FAISS indexing, and Groq LLM calls.
  • SBERT MiniLM: sentence-transformers/all-MiniLM-L6-v2 — fast, lightweight semantic embeddings stored as .npy files.
  • FAISS: In-process vector index for top-K similarity search at query time.
  • Groq API (LLaMA 3 8B): Ultra-fast inference — context chunks injected into prompt, model returns grounded answer only.
  • Metadata store: JSON files track each PDF's chunk count, upload timestamp, and file name for the metadata view.

1. Upload PDF

  • Text is extracted from the uploaded PDF using PyMuPDF (fitz).
  • Split into logical chunks based on headings and subchunks via LangChain RecursiveCharacterTextSplitter.
  • Each chunk is embedded using SBERT MiniLM — embeddings saved as .npy files, chunks pickled.
  • Metadata (chunk count, upload time) stored as JSON.

2. Ask a Question

  • The query is embedded with the same SBERT model.
  • FAISS performs top-K similarity search across all indexed chunks.
  • Top-K relevant chunks are injected into the LLM prompt as context.
  • Prompt sent to Groq-hosted LLaMA 3 8B — returns a precise, context-grounded answer.

3. View uploaded files

  • Lists all uploaded PDFs with metadata: number of chunks and upload timestamp.

Example queries

  • "What is the maturity date for bond XYZ?"
  • "Who is the issuer of the 2023 floating bond?"
  • "List all callable bonds issued after 2020."
  • "What is the coupon rate for the 5-year fixed bond?"

Tech stack

LayerTechnology
FrontendStreamlit
BackendFastAPI + uvicorn
Embedding modelsentence-transformers/all-MiniLM-L6-v2
Vector searchFAISS (in-process)
LLM providerGroq API — LLaMA 3 8B
PDF parsingPyMuPDF (fitz)
Text splittingLangChain RecursiveCharacterTextSplitter
Deploymentsystemd services on Linux server

Streamlit UI

Streamlit — Upload and embed PDF section

Upload & embed — PDF ingestion view

Streamlit — metadata index and embed view

Metadata index — uploaded files with chunk stats

Streamlit — LLM AI response to financial query

AI response — LLaMA 3 answering a bond query grounded in PDF context

systemd service logs

Streamlit systemd service running on server

Frontend service — Streamlit running on server via systemd

FastAPI systemd service running on server

Backend service — FastAPI uvicorn running on server via systemd

Local setup

git clone https://github.com/Harish-nika/FExpert.git cd FExpert python -m venv venv && source venv/bin/activate pip install -r requirements.txt # Add Groq API key echo "GROQ_API_KEY=your_key_here" > .env # Start backend uvicorn backend:app --host 0.0.0.0 --port 8002 --reload # Start frontend (separate terminal) streamlit run frontend/frontend.py

Hosted as systemd services (internal server)

For persistent internal deployment, both services run as Linux systemd units that start automatically on boot and restart on failure.

FastAPI service

# /etc/systemd/system/fastapi.service [Unit] Description=FastAPI backend for FactEntry FEexpert After=network.target [Service] User=harish WorkingDirectory=/home/harish/Project_works/FactEntry_FEexpert/backend ExecStart=/home/harish/Project_works/FactEntry_FEexpert/FExpENV/bin/python \ /home/harish/Project_works/FactEntry_FEexpert/backend/backend.py Restart=always [Install] WantedBy=multi-user.target

Streamlit service

# /etc/systemd/system/streamlit.service [Unit] Description=Streamlit frontend for FactEntry FEexpert After=network.target [Service] User=harish WorkingDirectory=/home/harish/Project_works/FactEntry_FEexpert/frontend ExecStart=/home/harish/Project_works/FactEntry_FEexpert/FExpENV/bin/streamlit \ run frontend.py --server.port 8501 Restart=always Environment="PATH=/home/harish/Project_works/FactEntry_FEexpert/FExpENV/bin" [Install] WantedBy=multi-user.target

Manage & monitor

# Enable and start sudo systemctl daemon-reload sudo systemctl enable fastapi.service streamlit.service sudo systemctl start fastapi.service streamlit.service # Status / restart sudo systemctl status fastapi.service streamlit.service sudo systemctl restart fastapi.service streamlit.service # Logs journalctl -u streamlit.service --no-pager | tail -n 20 journalctl -u fastapi.service --no-pager | tail -n 20

Access

  • FastAPI backend: http://<server-ip>:8002
  • Streamlit UI: http://<server-ip>:8501

Links

Back to Portfolio