Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dronabopche/100-ML-AI-Project/llms.txt

Use this file to discover all available pages before exploring further.

Conversational AI encompasses a wide range of architectures — from simple pattern-matching scripts to fine-tuned large language models. The four projects in this section represent each major paradigm: a deterministic rule-based FAQ bot, an empathetic response agent for mental health support, an LLM fine-tuned on a 28,000-row legal Q&A dataset, and a voice-to-text pipeline that adds speech recognition at the front of the conversation loop. Studying them together reveals the genuine trade-offs between interpretability, latency, data requirements, and conversational quality.
Chatbot architecture decision guide
ApproachWhen to useStrengthsWeaknesses
Rule-basedFixed, predictable FAQ domainsZero ML overhead, fully auditable, fastBreaks on out-of-vocabulary queries
ML-based (intent classification)Medium-complexity assistants with defined intent taxonomyGeneralizes to paraphrases, trainableNeeds labeled data, struggles with multi-turn context
LLM fine-tunedOpen-ended domain Q&A with nuanced answersHigh fluency, handles novel phrasingRequires compute, can hallucinate
LLM + RAGKnowledge-intensive domains (legal, medical, research)Grounded in real documents, updatableHigher latency, retrieval quality affects answer quality

Projects at a glance

ProjectApproachInput TypeUse Case
LegalEase ChatBot (60)GPT-2 fine-tuned on legal Q&AText promptIndian legal queries
Rule-Based FAQ System (61)Pattern matching + keyword lookupTextStructured FAQ domains
Mental Health Support Bot (62)Retrieval + empathy-aware responsesTextEmotional support conversation
Voice-to-Text Chatbot (65)ASR (Whisper/SpeechRecognition) + NLPAudio / microphoneHands-free chatbot interaction
Goal: Fine-tune GPT-2 on a 28,689-row dataset of Indian legal question-answer pairs and serve the model through a FastAPI endpoint for interactive legal queries.Dataset: legal_qa.csv with question and answer columns covering Indian civil law, writ petitions, PIL, and constitutional schedules.Training pipeline (from LegalEase_CharBot.ipynb):Each row is formatted as a prompt-completion pair:
def format_qa(q: str, a: str) -> str:
    return f"### Question:\n{q}\n\n### Answer:\n{a}\n"
The dataset is converted to a HuggingFace Dataset, tokenized to max_length=384, and trained for one epoch using the Trainer API:
from transformers import (
    AutoTokenizer, AutoModelForCausalLM,
    DataCollatorForLanguageModeling,
    Trainer, TrainingArguments,
)

MODEL_NAME = "gpt2"
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME)
tokenizer.pad_token = tokenizer.eos_token
model.config.pad_token_id = tokenizer.eos_token_id

training_args = TrainingArguments(
    output_dir="models",
    eval_strategy="steps",
    eval_steps=300,
    per_device_train_batch_size=1,
    gradient_accumulation_steps=8,
    num_train_epochs=1,
    learning_rate=5e-5,
    weight_decay=0.01,
    warmup_steps=100,
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_tok,
    eval_dataset=val_tok,
    data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False),
)
trainer.train()
Inference:
def ask_bot(question: str, max_new_tokens: int = 180, temperature: float = 0.7) -> str:
    prompt = f"### Question:\n{question}\n\n### Answer:\n"
    inputs = tokenizer(prompt, return_tensors="pt")
    output_ids = model.generate(
        **inputs,
        max_new_tokens=max_new_tokens,
        do_sample=True,
        temperature=temperature,
        top_p=0.9,
        pad_token_id=tokenizer.eos_token_id,
    )
    decoded = tokenizer.decode(output_ids[0], skip_special_tokens=True)
    return decoded.split("### Answer:")[-1].strip()
FastAPI service (src/app.py):The trained model is wrapped in a FastAPI service. Incoming prompts go through preprocess_prompt() (cleaning + whitespace normalization) before reaching the model:
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI(title="Prompt Inference API")

class PromptRequest(BaseModel):
    prompt: str

@app.post("/generate")
def generate(req: PromptRequest):
    tokens = preprocess_prompt(req.prompt.strip())
    output = generate_output(tokens)
    return {"prompt": req.prompt, "output": output}
Run the API locally:
pip install fastapi uvicorn transformers torch
uvicorn src.app:app --reload --port 8000
Then query it:
curl -X POST http://localhost:8000/generate \
  -H "Content-Type: application/json" \
  -d '{"prompt": "What is the punishment for cheque bounce in India?"}'
Goal: Answer frequently asked questions by matching the user’s input against a predefined set of patterns and returning the associated canned response.How it works:The bot maintains a list of (pattern, response) pairs. Each user message is normalized (lowercased, punctuation stripped) and matched against the patterns in order. The first match wins and its associated response is returned. For more flexible matching, patterns can be regular expressions rather than exact strings.
import re

FAQ = [
    (r"hours?|open|close|opening", "We are open Monday–Friday, 9 AM – 6 PM."),
    (r"return|refund|money back",   "You can return any item within 30 days for a full refund."),
    (r"ship|delivery|deliver",      "Standard delivery takes 3–5 business days."),
    (r"password|login|sign.?in",    "Visit /forgot-password to reset your credentials."),
    (r"contact|email|phone|reach",  "Email us at support@example.com or call 1-800-000-0000."),
]
FALLBACK = "I'm not sure about that. Please contact support@example.com for help."

def normalize(text: str) -> str:
    return re.sub(r"[^a-z0-9 ]", "", text.lower().strip())

def faq_bot(user_input: str) -> str:
    normalized = normalize(user_input)
    for pattern, response in FAQ:
        if re.search(pattern, normalized):
            return response
    return FALLBACK

# Example
print(faq_bot("How do I return an item?"))
# → "You can return any item within 30 days for a full refund."
Strengths: Zero training data, zero latency, fully auditable. Every response is traceable to a specific rule.Limitations: Brittle to spelling variations, synonyms not in the pattern set, and multi-turn context. Combining rule-based matching with a small intent classifier (e.g., a TF-IDF + logistic regression pipeline) handles paraphrases far better.
Goal: Provide empathetic, non-judgmental conversational responses to users expressing emotional distress, loneliness, anxiety, or depression.How it works:This project takes a retrieval-based approach: a corpus of empathetic dialogue pairs (e.g., the EmpatheticDialogues dataset from Facebook Research) is indexed by embedding. At inference time, the user’s message is embedded and the most semantically similar previous dialogue turn is retrieved. The bot replies with the response associated with that retrieved turn.
from sentence_transformers import SentenceTransformer, util
import torch

# Load pre-indexed empathetic dialogue corpus
embedder = SentenceTransformer("all-MiniLM-L6-v2")

# corpus_turns: list of user utterances from EmpatheticDialogues
# corpus_responses: corresponding bot responses
corpus_embeddings = embedder.encode(corpus_turns, convert_to_tensor=True)

def respond(user_message: str, top_k: int = 1) -> str:
    query_emb = embedder.encode(user_message, convert_to_tensor=True)
    scores = util.cos_sim(query_emb, corpus_embeddings)[0]
    best_idx = int(scores.argmax())
    return corpus_responses[best_idx]

# Example
print(respond("I've been feeling really lonely lately."))
Empathy-aware design considerations:
  • Always include a safety fallback: if the user mentions self-harm or crisis keywords, redirect to a professional helpline regardless of retrieval results.
  • Avoid generating unsolicited advice. The retrieved responses in EmpatheticDialogues are designed to validate feelings rather than prescribe solutions.
  • Log nothing that could re-identify the user; mental health conversations require strict privacy handling.
CRISIS_KEYWORDS = {"suicide", "self-harm", "kill myself", "end it all", "hurt myself"}
CRISIS_RESPONSE = (
    "I'm really concerned about what you shared. "
    "Please reach out to a crisis line — in the US, call or text 988 (Suicide & Crisis Lifeline). "
    "You don't have to go through this alone."
)

def safe_respond(user_message: str) -> str:
    if any(kw in user_message.lower() for kw in CRISIS_KEYWORDS):
        return CRISIS_RESPONSE
    return respond(user_message)
Goal: Accept spoken audio as input, transcribe it to text using automatic speech recognition (ASR), pass the transcript to an NLP chatbot, and optionally speak the response back to the user with text-to-speech (TTS).How it works:The pipeline chains three components:
  1. ASR — OpenAI Whisper (or the SpeechRecognition library for simpler use cases) converts recorded audio to a text transcript.
  2. NLP chatbot — any of the other chatbot projects in this section can serve as the text-processing core.
  3. TTS (optional)pyttsx3 or gTTS reads the bot’s response aloud.
import whisper
import sounddevice as sd
import numpy as np
import scipy.io.wavfile as wav
import pyttsx3

# --- Step 1: Record audio ---
def record_audio(duration: int = 5, sample_rate: int = 16000) -> np.ndarray:
    print(f"Recording for {duration} seconds...")
    audio = sd.rec(int(duration * sample_rate), samplerate=sample_rate,
                   channels=1, dtype="int16")
    sd.wait()
    wav.write("input.wav", sample_rate, audio)
    return audio

# --- Step 2: Transcribe with Whisper ---
asr_model = whisper.load_model("base")

def transcribe(audio_path: str = "input.wav") -> str:
    result = asr_model.transcribe(audio_path)
    return result["text"].strip()

# --- Step 3: Pass transcript to chatbot ---
def voice_chatbot_turn(chatbot_fn) -> str:
    record_audio(duration=5)
    user_text = transcribe()
    print(f"You said: {user_text}")
    response = chatbot_fn(user_text)
    print(f"Bot: {response}")
    return response

# --- Step 4 (optional): Speak the response ---
tts_engine = pyttsx3.init()

def speak(text: str) -> None:
    tts_engine.say(text)
    tts_engine.runAndWait()
Install dependencies:
pip install openai-whisper sounddevice scipy pyttsx3
# On Linux you may also need:
sudo apt-get install portaudio19-dev python3-pyaudio
Whisper model sizes: tiny and base run on CPU; small and medium benefit from a GPU. For low-latency applications, tiny transcribes a 5-second clip in under a second on a modern laptop CPU.Latency budget: ASR (0.5–2 s) + chatbot inference (0.1–5 s depending on model) + TTS (0.2 s) = 1–7 s end-to-end. For production voice assistants, streaming ASR (e.g., Whisper with faster-whisper) and streamed LLM generation reduce perceived latency significantly.

Build docs developers (and LLMs) love