aniketsirsikar's picture
Update app.py
abcb7a7 verified
Raw
History Blame Contribute Delete
14.3 kB
import os
import gradio as gr
import numpy as np
import faiss
from sentence_transformers import SentenceTransformer
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import pandas as pd
import plotly.express as px
from datetime import datetime
# =========================================================
# CONFIG
# =========================================================
EMBEDDING_MODEL = "all-MiniLM-L6-v2"
GENERATION_MODEL = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
TOP_K = 3
MAX_NEW_TOKENS = 200
# =========================================================
# LOAD DOCUMENTS WITH METADATA
# =========================================================
def load_documents():
documents = []
folders = {
"knowledge_base": "core_profile",
"synthetic_data": "extended_profile"
}
for folder, category in folders.items():
if not os.path.exists(folder):
continue
for file in os.listdir(folder):
if file.endswith(".txt"):
with open(os.path.join(folder, file), "r", encoding="utf-8") as f:
content = f.read().strip()
if content:
documents.append({
"content": content,
"source": file,
"category": category
})
if not documents:
documents.append({
"content": "Name: Aniket Sirsikar. Education: PGDM SPJIMR. Skills: Product Management, Data Analytics, AI Systems.",
"source": "fallback.txt",
"category": "core_profile"
})
return documents
# =========================================================
# CHUNKING
# =========================================================
def chunk_documents(documents, max_words=100):
chunks = []
overlap = 20
for doc in documents:
words = doc["content"].split()
for i in range(0, len(words), max_words - overlap):
chunk_text = " ".join(words[i:i + max_words])
if chunk_text.strip():
chunks.append({
"text": chunk_text,
"source": doc["source"],
"category": doc["category"]
})
return chunks
# =========================================================
# VECTOR STORE
# =========================================================
def build_vector_store(chunks):
embedder = SentenceTransformer(EMBEDDING_MODEL)
texts = [c["text"] for c in chunks]
embeddings = embedder.encode(texts, convert_to_numpy=True).astype("float32")
index = faiss.IndexFlatL2(embeddings.shape[1])
index.add(embeddings)
return index, chunks, embedder
# =========================================================
# RETRIEVAL
# =========================================================
def retrieve(query, index, chunks, embedder):
q_emb = embedder.encode([query], convert_to_numpy=True).astype("float32")
_, idxs = index.search(q_emb, min(TOP_K, len(chunks)))
return [chunks[i] for i in idxs[0]]
# =========================================================
# GENERATION ENGINE (LLAMA – CAUSAL)
# =========================================================
class AnswerGenerator:
def __init__(self):
self.tokenizer = AutoTokenizer.from_pretrained(GENERATION_MODEL)
self.model = AutoModelForCausalLM.from_pretrained(GENERATION_MODEL)
self.device = "cuda" if torch.cuda.is_available() else "cpu"
self.model.to(self.device)
def generate(self, query, context_chunks):
context = "\n".join([c["text"] for c in context_chunks[:3]])
prompt = (
"<|system|>\n"
"You are an AI professional profile assistant.\n"
"Answer using ONLY the information provided.\n"
"Be concise and recruiter-facing.\n"
"<|user|>\n"
f"Information:\n{context}\n\n"
f"Question: {query}\n"
"<|assistant|>\n"
)
inputs = self.tokenizer(prompt, return_tensors="pt", truncation=True, max_length=1024)
inputs = {k: v.to(self.device) for k, v in inputs.items()}
with torch.no_grad():
outputs = self.model.generate(
**inputs,
max_new_tokens=MAX_NEW_TOKENS,
do_sample=False,
temperature=0.2,
repetition_penalty=1.1,
eos_token_id=self.tokenizer.eos_token_id
)
decoded = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
answer = decoded.split("<|assistant|>")[-1].strip()
return answer
# =========================================================
# QUERY ENHANCEMENT
# =========================================================
def enhance_query(query):
mapping = {
"skills": "What are my professional and technical skills?",
"roles": "What roles suit me based on my profile?",
"projects": "What projects have I worked on?",
"experience": "What is my professional experience?",
"education": "What is my educational background?",
"goals": "What are my career goals?"
}
for k, v in mapping.items():
if k in query.lower():
return v
return query
# =========================================================
# INITIALIZE SYSTEM
# =========================================================
documents = load_documents()
chunks = chunk_documents(documents)
index, chunks, embedder = build_vector_store(chunks)
generator = AnswerGenerator()
def answer_question(user_query):
enhanced = enhance_query(user_query)
retrieved = retrieve(enhanced, index, chunks, embedder)
return generator.generate(enhanced, retrieved)
# =========================================================
# PREMIUM UI / UX (FULL VERSION – NO CORE CHANGES)
# =========================================================
# -----------------------------
# CV PATH
# -----------------------------
def get_cv_path():
path = "cv/aniket_sirsikar.pdf"
return path if os.path.exists(path) else None
# -----------------------------
# CONTACT FORM
# -----------------------------
def submit_contact(name, email, company, message):
if not name or not email or not message:
return "❌ Please fill in Name, Email and Message."
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
entry = f"""
========================================
{timestamp}
Name: {name}
Email: {email}
Company: {company}
Message: {message}
========================================
"""
try:
with open("recruiter_contacts.txt", "a") as f:
f.write(entry)
except:
pass
return f"✅ Thank you {name}. I will reach out shortly."
# -----------------------------
# ANALYTICS CHARTS
# -----------------------------
def create_skills_chart():
df = pd.DataFrame({
"Skill": ["Python", "SQL", "Machine Learning", "Product Mgmt", "Analytics", "AI Systems"],
"Level": [95, 90, 85, 85, 90, 80],
"Category": ["Programming", "Programming", "AI/ML", "Product", "Analytics", "AI/ML"]
})
fig = px.bar(
df,
x="Skill",
y="Level",
color="Category",
title="Core Skill Areas",
color_discrete_map={
"Programming": "#3498db",
"AI/ML": "#e74c3c",
"Analytics": "#f39c12",
"Product": "#9b59b6"
}
)
fig.update_layout(
plot_bgcolor="white",
paper_bgcolor="white",
height=350
)
return fig
def create_experience_pie():
df = pd.DataFrame({
"Area": ["Product", "Analytics", "AI/ML", "Leadership"],
"Share": [30, 30, 25, 15]
})
fig = px.pie(
df,
values="Share",
names="Area",
title="Experience Distribution"
)
fig.update_layout(
plot_bgcolor="white",
paper_bgcolor="white",
height=400
)
return fig
def create_projects_timeline():
df = pd.DataFrame({
"Project": ["AI Twin", "Fraud Detection", "Analytics Dashboard", "AI Workflow Agents"],
"Start": pd.to_datetime(["2024-01", "2023-01", "2023-06", "2025-01"]),
"End": pd.to_datetime(["2024-04", "2023-09", "2023-12", "2025-04"]),
"Impact": ["High", "High", "Medium", "Very High"]
})
fig = px.timeline(
df,
x_start="Start",
x_end="End",
y="Project",
color="Impact"
)
fig.update_layout(
plot_bgcolor="white",
paper_bgcolor="white",
height=350
)
return fig
# -----------------------------
# CUSTOM CSS
# -----------------------------
custom_css = """
.profile-summary {
background: #2c3e50 !important;
border: 2px solid #34495e;
border-radius: 12px;
padding: 1.5rem;
}
.profile-summary h3,
.profile-summary p,
.profile-summary strong {
color: #ecf0f1 !important;
}
.section-header {
background: #34495e;
padding: 1rem 1.5rem;
border-left: 5px solid #3498db;
border-radius: 6px;
margin-top: 1.5rem;
}
.section-header h3 {
color: #ecf0f1 !important;
margin: 0;
}
"""
# =========================================================
# UI LAYOUT
# =========================================================
# =========================================================
# CHAT RESPONSE HANDLER
# =========================================================
def respond(message, history):
if not message or not message.strip():
return history, history
answer = answer_question(message)
history = history + [
{"role": "user", "content": message},
{"role": "assistant", "content": answer}
]
return history, history
with gr.Blocks(css=custom_css, title="Aniket Sirsikar – Digital Twin") as demo:
# Header
gr.HTML("""
<div style='background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 2.5rem; border-radius: 12px; color: white;
text-align: center; margin-bottom: 1.5rem;'>
<h1 style='margin:0; font-size: 2.5rem;'>Aniket Sirsikar</h1>
<p style='margin:0.8rem 0 0 0; font-size: 1.2rem;'>
Product Manager | Data Analytics | AI Systems
</p>
</div>
""")
with gr.Row():
# Chat column
with gr.Column(scale=6):
gr.HTML("<div class='section-header'><h3>💬 Chat with Aniket's digital twin </h3></div>")
chatbot = gr.Chatbot(label="AI Twin", type="messages")
state = gr.State([])
user_input = gr.Textbox(
placeholder="Ask about skills, projects, experience...",
label="Your Question"
)
with gr.Row():
send = gr.Button("Ask", variant="primary")
clear = gr.Button("Clear")
gr.Markdown("**Quick Questions:**")
with gr.Row():
q1 = gr.Button("My skills ?")
q2 = gr.Button("My projects ?")
with gr.Row():
q3 = gr.Button("My interests ?")
q4 = gr.Button("Suitable roles ?")
# Profile column
with gr.Column(scale=4):
gr.HTML("""
<div class="profile-summary">
<h3>📋 Profile Summary</h3>
<p>
I am an MBA candidate at SPJIMR specializing in Product Management and AI Systems.
My work combines analytical depth, structured thinking, and execution rigor to design
products that solve high-impact, large-scale problems.
</p>
<p>
With experience spanning public sector operations and AI-driven technology environments,
I have led initiatives involving large-scale data analysis, workflow optimization,
and the development of insight-driven dashboards and decision tools.
</p>
<p>
I operate comfortably at the intersection of data, product, and systems thinking —
translating ambiguity into clarity, insights into strategy, and strategy into execution.
</p>
<p>
My long-term focus is on building scalable, AI-enabled platforms that integrate analytics,
automation, and user experience into cohesive, high-leverage product ecosystems.
</p>
</div>
""")
cv_path = get_cv_path()
if cv_path:
gr.DownloadButton("📥 Download CV", value=cv_path)
# Analytics
gr.HTML("<div class='section-header'><h3>📊 Recruiter Insights</h3></div>")
with gr.Accordion("View Analytics", open=False):
gr.Plot(create_skills_chart())
gr.Plot(create_experience_pie())
gr.Plot(create_projects_timeline())
# Contact Form
gr.HTML("<div class='section-header'><h3>📬 Contact</h3></div>")
with gr.Row():
with gr.Column():
name = gr.Textbox(label="Name *")
email = gr.Textbox(label="Email *")
with gr.Column():
company = gr.Textbox(label="Company")
message = gr.Textbox(label="Message *", lines=3)
submit = gr.Button("Send Message")
status = gr.Textbox(show_label=False)
# Events
send.click(respond, [user_input, state], [chatbot, state])
user_input.submit(respond, [user_input, state], [chatbot, state])
clear.click(lambda: ([], []), None, [chatbot, state])
q1.click(lambda: respond("What are my skills?", state.value), None, [chatbot, state])
q2.click(lambda: respond("What projects have I done?", state.value), None, [chatbot, state])
q3.click(lambda: respond("What are my interests?", state.value), None, [chatbot, state])
q4.click(lambda: respond("What role suits me?", state.value), None, [chatbot, state])
submit.click(submit_contact, [name, email, company, message], status)
demo.queue().launch()