cv
Browse files- .env.example +0 -3
- README.md +16 -54
- agents +0 -1
- app.py +235 -9
- app/__init__.py +0 -83
- app/__pycache__/__init__.cpython-311.pyc +0 -0
- app/__pycache__/agent.cpython-311.pyc +0 -0
- app/__pycache__/retriever.cpython-311.pyc +0 -0
- app/agent.py +0 -89
- app/main.py +0 -19
- app/retriever.py +0 -64
- data/knowledge/invoice.txt +0 -10
- data/knowledge/resume.txt +0 -11
- data/knowledge/support_ticket.txt +0 -10
- requirements.txt +3 -1
- space.yaml +0 -4
.env.example
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
HF_EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
|
| 2 |
-
HF_GENERATION_MODEL=google/flan-t5-small
|
| 3 |
-
CHROMA_DB_DIR=.chroma_db
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
|
@@ -1,70 +1,32 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
python_version: "3.11"
|
| 9 |
app_file: app.py
|
| 10 |
-
suggested_hardware: cpu-basic
|
| 11 |
pinned: false
|
| 12 |
---
|
| 13 |
|
| 14 |
-
|
| 15 |
|
| 16 |
-
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
3. A free open-source language model answers using the reranked evidence.
|
| 23 |
-
|
| 24 |
-
## Why this architecture
|
| 25 |
-
|
| 26 |
-
### Chunking strategy
|
| 27 |
-
|
| 28 |
-
The knowledge base is split with `RecursiveCharacterTextSplitter` at roughly 600 characters with 120 characters of overlap. This balances two goals:
|
| 29 |
-
|
| 30 |
-
- keep local context coherent for one business record or ticket
|
| 31 |
-
- avoid chunking too aggressively, which would lose important references and reduce answer quality
|
| 32 |
-
|
| 33 |
-
### Retrieval method
|
| 34 |
-
|
| 35 |
-
The app uses Chroma as the vector database and Hugging Face embeddings to create dense vector representations of each chunk. This is a good fit for a small demo because it is fast, local, and easy to inspect in the browser or terminal.
|
| 36 |
-
|
| 37 |
-
### Why rerank
|
| 38 |
-
|
| 39 |
-
Dense retrieval alone is often noisy. The rerank step gives a second signal by rewarding passages that are not only semantically close but also relevant to the literal question. That makes the final answer more grounded and less likely to hallucinate.
|
| 40 |
-
|
| 41 |
-
## Files
|
| 42 |
-
|
| 43 |
-
- `app/main.py` — runs the full demo
|
| 44 |
-
- `app/agent.py` — the agent graph and prompt orchestration
|
| 45 |
-
- `app/retriever.py` — vector store creation + retrieval + reranking
|
| 46 |
-
- `data/knowledge/` — sample documents such as an invoice, resume, and support ticket
|
| 47 |
|
| 48 |
## Run locally
|
| 49 |
|
| 50 |
```bash
|
| 51 |
pip install -r requirements.txt
|
| 52 |
-
|
| 53 |
-
python app/main.py
|
| 54 |
```
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
## Deploy to Hugging Face Space
|
| 59 |
-
|
| 60 |
-
1. Push this repository to a GitHub repo.
|
| 61 |
-
2. Create a new Hugging Face Space.
|
| 62 |
-
3. Choose `Gradio` as the SDK.
|
| 63 |
-
4. Point the Space at the repo.
|
| 64 |
-
5. Keep the Space free-model path only; no API key is needed for the default deployment.
|
| 65 |
-
|
| 66 |
-
The default Space behavior uses Hugging Face-hosted free models for both embeddings and generation, which keeps the app portable and cheap to run.
|
| 67 |
-
|
| 68 |
-
The included `space.yaml` file tells Hugging Face to launch the Gradio app from `app.py`. The app is intentionally designed to run without any special server-only configuration.
|
| 69 |
|
| 70 |
-
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Angkit Sarma — Living CV
|
| 3 |
+
emoji: 🟡
|
| 4 |
+
colorFrom: gray
|
| 5 |
+
colorTo: yellow
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 5.9.1
|
|
|
|
| 8 |
app_file: app.py
|
|
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Angkit Sarma — Living CV (Gradio)
|
| 13 |
|
| 14 |
+
An interactive résumé with a self-querying "Ask the CV" chat panel.
|
| 15 |
|
| 16 |
+
The retrieval engine is a real TF-IDF + cosine-similarity ranker (scikit-learn)
|
| 17 |
+
built directly over this résumé's own content — no external API keys, no
|
| 18 |
+
LLM calls, entirely self-contained in `app.py`. It's a small, visible version
|
| 19 |
+
of the same semantic-search thinking described in the Experience section.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
## Run locally
|
| 22 |
|
| 23 |
```bash
|
| 24 |
pip install -r requirements.txt
|
| 25 |
+
python app.py
|
|
|
|
| 26 |
```
|
| 27 |
|
| 28 |
+
## Deploy to Hugging Face Spaces
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
+
1. Create a new Space → SDK: **Gradio**
|
| 31 |
+
2. Upload `app.py`, `requirements.txt`, and this `README.md`
|
| 32 |
+
3. The Space builds and launches automatically — no secrets required
|
agents
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
Subproject commit 250a96691bb4265cc0d0709cba2a88a701945c8e
|
|
|
|
|
|
app.py
CHANGED
|
@@ -1,13 +1,239 @@
|
|
| 1 |
-
|
|
|
|
| 2 |
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Angkit Sarma — Living CV (Gradio edition)
|
| 3 |
|
| 4 |
+
An interactive resume with a self-querying "Ask the CV" panel. The retrieval
|
| 5 |
+
engine is a real TF-IDF + cosine-similarity ranker over the resume's own
|
| 6 |
+
content (scikit-learn) — the same underlying idea as the semantic-search
|
| 7 |
+
optimization work described in the Experience section below, just visible
|
| 8 |
+
and playable instead of buried in a bullet point.
|
| 9 |
+
"""
|
| 10 |
|
| 11 |
+
import gradio as gr
|
| 12 |
+
import numpy as np
|
| 13 |
+
from sklearn.feature_extraction.text import TfidfVectorizer
|
| 14 |
+
from sklearn.metrics.pairwise import cosine_similarity
|
| 15 |
|
| 16 |
+
# ---------------------------------------------------------------------------
|
| 17 |
+
# Resume content — the single source of truth the retrieval engine indexes.
|
| 18 |
+
# ---------------------------------------------------------------------------
|
| 19 |
+
CORPUS = [
|
| 20 |
+
{"tag": "Experience · Flexday AI", "text": "Built and pitched INFERA, an AI-powered agentic solution that maps sales projects to real-world opportunities, winning 1st place at the Flexday AI Hackathon."},
|
| 21 |
+
{"tag": "Experience · Flexday AI", "text": "Optimized a semantic search system using LLM and embedding based techniques, improving retrieval performance by 50 percent and enhancing user experience."},
|
| 22 |
+
{"tag": "Experience · Flexday AI", "text": "Designed and implemented automated AI assisted workflows across departments, cutting process cycle time by 5 percent and freeing up 10 or more hours per month."},
|
| 23 |
+
{"tag": "Experience · Flexday AI", "text": "Implemented OCR based data extraction pipelines across diverse image collections, improving data extraction accuracy and processing efficiency."},
|
| 24 |
+
{"tag": "Experience · Flexday AI", "text": "Identified and remediated critical application security vulnerabilities, mitigating million dollar risk exposure and strengthening system security."},
|
| 25 |
+
{"tag": "Experience · Flexday AI", "text": "Streamlined CI/CD build pipelines by reducing redundant steps, accelerating deployment times, using Git, GitHub, Jira and Azure DevOps."},
|
| 26 |
+
{"tag": "Experience · Leokraft", "text": "Designed, trained and deployed end to end machine learning models into production, improving model accuracy by 8 percent while cutting infrastructure costs by 20 percent."},
|
| 27 |
+
{"tag": "Experience · Leokraft", "text": "Engineered a key target variable feature that improved model accuracy by 5 percent."},
|
| 28 |
+
{"tag": "Experience · Leokraft", "text": "Developed an end to end application for managing model scores and usage statistics, driving higher stakeholder engagement."},
|
| 29 |
+
{"tag": "Experience · CodingZen", "text": "Taught over 100 students full stack web development with Node.js, from foundational HTML and CSS to advanced backend engineering, while supervising a team of teaching staff."},
|
| 30 |
+
{"tag": "Project · INFERA", "text": "INFERA is an agentic AI system built with large language models that autonomously analyzes sales pipeline data and maps projects to real world business opportunities. Won first place at the Flexday AI Hackathon."},
|
| 31 |
+
{"tag": "Project · Analytica", "text": "Analytica is a full stack data analytics platform built with React, Python, Azure and SQL, showing machine learning model performance and usage statistics."},
|
| 32 |
+
{"tag": "Project · Predictive Allocation", "text": "Predictive Allocation re-engineered an end to end model training and deployment pipeline on Azure SQL and Azure Blob, hardened with Snyk and Wiz security scanning, and modernized legacy code."},
|
| 33 |
+
{"tag": "Skills · AI/ML", "text": "Core AI and machine learning skills include large language models, generative AI, agentic AI and AI agents, prompt engineering, semantic search, classification, regression, decision trees, and SMOTE."},
|
| 34 |
+
{"tag": "Skills · Cloud & MLOps", "text": "Cloud and MLOps skills include Microsoft Azure, Azure SQL, Azure Blob Storage, serverless architecture, virtual machines, and CI/CD pipelines."},
|
| 35 |
+
{"tag": "Skills · Programming", "text": "Programming languages and runtimes include Python, JavaScript and Node.js."},
|
| 36 |
+
{"tag": "Certifications", "text": "Certifications include Building with the Claude API, Generative AI professional certificate, AI Fluency Framework and Foundations, Machine Learning for Leaders, and Analyze Box Office Data with Seaborn and Python."},
|
| 37 |
+
{"tag": "Education", "text": "M.Tech in Information Technology from Tezpur University, graduated with distinction at 8.69 CGPA, with a full time AICTE scholarship. B.Tech in Computer Science and Engineering from KIET, first division."},
|
| 38 |
+
]
|
| 39 |
+
|
| 40 |
+
_texts = [c["text"] for c in CORPUS]
|
| 41 |
+
_vectorizer = TfidfVectorizer(stop_words="english")
|
| 42 |
+
_doc_matrix = _vectorizer.fit_transform(_texts)
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def retrieve(query: str, top_k: int = 3):
|
| 46 |
+
"""Rank resume chunks against a query using TF-IDF cosine similarity."""
|
| 47 |
+
if not query or not query.strip():
|
| 48 |
+
return []
|
| 49 |
+
q_vec = _vectorizer.transform([query])
|
| 50 |
+
sims = cosine_similarity(q_vec, _doc_matrix)[0]
|
| 51 |
+
ranked_idx = np.argsort(sims)[::-1]
|
| 52 |
+
results = []
|
| 53 |
+
for i in ranked_idx[:top_k]:
|
| 54 |
+
if sims[i] <= 0:
|
| 55 |
+
continue
|
| 56 |
+
results.append({**CORPUS[i], "score": float(sims[i])})
|
| 57 |
+
return results
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def ask_the_cv(query, history):
|
| 61 |
+
history = history or []
|
| 62 |
+
results = retrieve(query)
|
| 63 |
+
|
| 64 |
+
if not results:
|
| 65 |
+
answer = ("No strong match in the résumé index for that — try asking about "
|
| 66 |
+
"experience, projects, skills, or certifications.")
|
| 67 |
+
else:
|
| 68 |
+
top = results[0]
|
| 69 |
+
answer = f"**{top['tag']}** — {top['text']}"
|
| 70 |
+
if len(results) > 1:
|
| 71 |
+
answer += "\n\n**Also relevant:**\n"
|
| 72 |
+
for r in results[1:]:
|
| 73 |
+
answer += f"\n- _{r['tag']}_ ({r['score']*100:.0f}% match): {r['text']}"
|
| 74 |
+
|
| 75 |
+
history.append({"role": "user", "content": query})
|
| 76 |
+
history.append({"role": "assistant", "content": answer})
|
| 77 |
+
return history, ""
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
EXAMPLE_QUERIES = [
|
| 81 |
+
"What is your experience with LLMs and generative AI?",
|
| 82 |
+
"Tell me about INFERA",
|
| 83 |
+
"What are your cloud and deployment skills?",
|
| 84 |
+
"Have you done any teaching or mentoring?",
|
| 85 |
+
"What certifications do you have?",
|
| 86 |
+
]
|
| 87 |
+
|
| 88 |
+
# ---------------------------------------------------------------------------
|
| 89 |
+
# Styling — dark "console" theme matching the static-site edition
|
| 90 |
+
# ---------------------------------------------------------------------------
|
| 91 |
+
CUSTOM_CSS = """
|
| 92 |
+
:root {
|
| 93 |
+
--amber: #f5b841;
|
| 94 |
+
--teal: #4fd1c5;
|
| 95 |
+
}
|
| 96 |
+
.gradio-container {
|
| 97 |
+
background: radial-gradient(ellipse 1200px 800px at 20% -10%, #1a2130 0%, #12151c 55%) !important;
|
| 98 |
+
font-family: 'Inter', sans-serif !important;
|
| 99 |
+
}
|
| 100 |
+
#hero-name {
|
| 101 |
+
font-family: 'Space Grotesk', sans-serif !important;
|
| 102 |
+
font-weight: 700 !important;
|
| 103 |
+
font-size: 42px !important;
|
| 104 |
+
margin-bottom: 0 !important;
|
| 105 |
+
}
|
| 106 |
+
#hero-headline { color: var(--amber) !important; font-weight: 600 !important; margin-top: 4px !important; }
|
| 107 |
+
.status-badge {
|
| 108 |
+
display: inline-flex; align-items: center; gap: 8px;
|
| 109 |
+
font-family: monospace; font-size: 12px; letter-spacing: 0.1em;
|
| 110 |
+
color: #9aa3b5; text-transform: uppercase; margin-bottom: 10px;
|
| 111 |
+
}
|
| 112 |
+
.dot {
|
| 113 |
+
width: 8px; height: 8px; border-radius: 50%; background: var(--amber);
|
| 114 |
+
display: inline-block; animation: pulse 2.2s infinite;
|
| 115 |
+
}
|
| 116 |
+
@keyframes pulse {
|
| 117 |
+
0% { box-shadow: 0 0 0 0 rgba(245,184,65,.55); }
|
| 118 |
+
70% { box-shadow: 0 0 0 9px rgba(245,184,65,0); }
|
| 119 |
+
100% { box-shadow: 0 0 0 0 rgba(245,184,65,0); }
|
| 120 |
+
}
|
| 121 |
+
.section-label {
|
| 122 |
+
font-family: monospace !important; color: var(--amber) !important;
|
| 123 |
+
letter-spacing: 0.1em !important; text-transform: uppercase; font-size: 13px !important;
|
| 124 |
+
}
|
| 125 |
+
"""
|
| 126 |
+
|
| 127 |
+
with gr.Blocks(title="Angkit Sarma — Living CV") as demo:
|
| 128 |
+
|
| 129 |
+
gr.HTML(
|
| 130 |
+
"""
|
| 131 |
+
<div class="status-badge"><span class="dot"></span> resume · live · self-querying</div>
|
| 132 |
+
<div id="hero-name">Angkit Sarma</div>
|
| 133 |
+
<div id="hero-headline">AI/ML Engineer — Agentic Systems & LLM Applications</div>
|
| 134 |
+
<p style="color:#9aa3b5; max-width:680px; margin-top:14px;">
|
| 135 |
+
4+ years building and shipping ML and generative AI systems — from a 50%-faster semantic
|
| 136 |
+
search pipeline to <b style="color:#eef0f4">INFERA</b>, an agentic AI tool that won 1st place
|
| 137 |
+
at the Flexday AI Hackathon. Ask the panel below anything about my experience — it's a live
|
| 138 |
+
TF-IDF retrieval engine running over this résumé's own content.
|
| 139 |
+
</p>
|
| 140 |
+
<p style="font-family:monospace; font-size:13px; color:#9aa3b5;">
|
| 141 |
+
+91 9990797061 · angkit93@gmail.com ·
|
| 142 |
+
<a href="https://www.linkedin.com/in/angkit-s-81b7131b0/" target="_blank" style="color:#4fd1c5;">LinkedIn</a>
|
| 143 |
+
· Hyderabad, India
|
| 144 |
+
</p>
|
| 145 |
+
"""
|
| 146 |
)
|
| 147 |
+
|
| 148 |
+
gr.HTML('<p class="section-label">// ask the cv</p>')
|
| 149 |
+
chatbot = gr.Chatbot(label=None, height=320, show_label=False)
|
| 150 |
+
with gr.Row():
|
| 151 |
+
query_box = gr.Textbox(placeholder="e.g. What's your experience with LLMs?", scale=5, show_label=False, container=False)
|
| 152 |
+
ask_btn = gr.Button("Ask", variant="primary", scale=1)
|
| 153 |
+
|
| 154 |
+
with gr.Row():
|
| 155 |
+
for q in EXAMPLE_QUERIES:
|
| 156 |
+
gr.Button(q, size="sm").click(fn=ask_the_cv, inputs=[gr.State(q), chatbot], outputs=[chatbot, query_box])
|
| 157 |
+
|
| 158 |
+
ask_btn.click(fn=ask_the_cv, inputs=[query_box, chatbot], outputs=[chatbot, query_box])
|
| 159 |
+
query_box.submit(fn=ask_the_cv, inputs=[query_box, chatbot], outputs=[chatbot, query_box])
|
| 160 |
+
|
| 161 |
+
gr.HTML('<p class="section-label">// summary</p>')
|
| 162 |
+
gr.Markdown(
|
| 163 |
+
"Results-driven AI/ML Engineer with 4+ years designing, training, and deploying machine "
|
| 164 |
+
"learning and generative AI systems that solve real business problems. Proven track record "
|
| 165 |
+
"building agentic AI and LLM-powered applications, optimizing semantic search and NLP "
|
| 166 |
+
"pipelines, and automating end-to-end ML workflows from data processing to production "
|
| 167 |
+
"deployment. Combines strong ML engineering fundamentals with cloud deployment, MLOps, and "
|
| 168 |
+
"application security expertise to ship secure, scalable, high-impact AI solutions."
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
gr.HTML('<p class="section-label">// experience</p>')
|
| 172 |
+
with gr.Accordion("Software Developer (AI/ML Focus) — Flexday AI, Hyderabad · Nov 2022 – Present", open=True):
|
| 173 |
+
gr.Markdown(
|
| 174 |
+
"- Built and pitched **INFERA**, an AI-powered agentic solution that maps sales projects "
|
| 175 |
+
"to real-world opportunities — 1st place at the Flexday AI Hackathon\n"
|
| 176 |
+
"- Optimized a semantic search system using LLM/embedding-based techniques, improving "
|
| 177 |
+
"retrieval performance by **50%**\n"
|
| 178 |
+
"- Designed automated, AI-assisted workflows across departments, cutting process cycle "
|
| 179 |
+
"time by 5% and freeing 10+ hours/month\n"
|
| 180 |
+
"- Implemented OCR-based data extraction pipelines across diverse image collections\n"
|
| 181 |
+
"- Identified and remediated critical security vulnerabilities, mitigating million-dollar "
|
| 182 |
+
"risk exposure\n"
|
| 183 |
+
"- Streamlined CI/CD build pipelines using Git, GitHub, Jira, and Azure DevOps"
|
| 184 |
+
)
|
| 185 |
+
with gr.Accordion("Machine Learning Engineer — Leokraft Technologies, Bangalore · Dec 2021 – Dec 2022", open=False):
|
| 186 |
+
gr.Markdown(
|
| 187 |
+
"- Designed, trained, and deployed end-to-end ML models into production, improving "
|
| 188 |
+
"accuracy by **8%** while cutting infrastructure costs by **20%**\n"
|
| 189 |
+
"- Engineered a key target-variable feature that improved model accuracy by 5%\n"
|
| 190 |
+
"- Built an end-to-end application for managing model scores and usage statistics"
|
| 191 |
+
)
|
| 192 |
+
with gr.Accordion("Senior Faculty — CodingZen, Delhi · Jul 2018 – Jul 2019", open=False):
|
| 193 |
+
gr.Markdown(
|
| 194 |
+
"- Taught 100+ students full-stack web development with Node.js\n"
|
| 195 |
+
"- Supervised and mentored a team of teaching staff"
|
| 196 |
+
)
|
| 197 |
+
|
| 198 |
+
gr.HTML('<p class="section-label">// projects</p>')
|
| 199 |
+
with gr.Row():
|
| 200 |
+
with gr.Column():
|
| 201 |
+
gr.Markdown("**INFERA** — Agentic AI Sales-Opportunity Mapper\n\n*LLMs · AI Agents · Python*\n\nAn AI agent that analyzes sales pipeline data and autonomously maps projects to real-world business opportunities.\n\n🏆 1st Place — Flexday AI Hackathon")
|
| 202 |
+
with gr.Column():
|
| 203 |
+
gr.Markdown("**Analytica** — End-to-End ML Analytics Platform\n\n*React · Python · Azure · SQL*\n\nFull-stack analytics tool surfacing ML model performance metrics and usage statistics.")
|
| 204 |
+
with gr.Column():
|
| 205 |
+
gr.Markdown("**Predictive Allocation** — ML Deployment Pipeline\n\n*Python · Azure SQL · Azure Blob · DevOps*\n\nRe-engineered end-to-end training/deployment pipeline; hardened security with Snyk and Wiz.")
|
| 206 |
+
|
| 207 |
+
gr.HTML('<p class="section-label">// skills</p>')
|
| 208 |
+
gr.Markdown(
|
| 209 |
+
"**AI/ML & GenAI:** LLMs · Generative AI · Agentic AI · Prompt Engineering · Semantic Search · "
|
| 210 |
+
"Classification · Regression · Decision Trees · SMOTE · OCR/NLP\n\n"
|
| 211 |
+
"**Programming:** Python · JavaScript · Node.js\n\n"
|
| 212 |
+
"**Cloud & MLOps:** Microsoft Azure · Azure SQL · Azure Blob · Serverless · Virtual Machines · CI/CD\n\n"
|
| 213 |
+
"**Tools & Practices:** Git · GitHub · Jira · Azure DevOps · Snyk · Wiz · Agile"
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
gr.HTML('<p class="section-label">// certifications & education</p>')
|
| 217 |
+
with gr.Row():
|
| 218 |
+
with gr.Column():
|
| 219 |
+
gr.Markdown(
|
| 220 |
+
"**Certifications & Honors**\n\n"
|
| 221 |
+
"- Building with the Claude API\n"
|
| 222 |
+
"- Generative AI (Professional Certificate)\n"
|
| 223 |
+
"- AI Fluency: Framework & Foundations\n"
|
| 224 |
+
"- Machine Learning for Leaders\n"
|
| 225 |
+
"- Analyze Box Office Data with Seaborn and Python\n"
|
| 226 |
+
"- 1st Place — Flexday AI Hackathon (INFERA)"
|
| 227 |
+
)
|
| 228 |
+
with gr.Column():
|
| 229 |
+
gr.Markdown(
|
| 230 |
+
"**Education**\n\n"
|
| 231 |
+
"**M.Tech, Information Technology** — Tezpur University · 2019–2021\n"
|
| 232 |
+
"- Graduated with Distinction — 8.69 CGPA\n"
|
| 233 |
+
"- Full-time AICTE scholarship recipient\n\n"
|
| 234 |
+
"**B.Tech, Computer Science & Engineering** — KIET · 2012–2016\n"
|
| 235 |
+
"- Secured First Division"
|
| 236 |
+
)
|
| 237 |
+
|
| 238 |
+
if __name__ == "__main__":
|
| 239 |
+
demo.launch(css=CUSTOM_CSS, theme=gr.themes.Base(primary_hue="amber", neutral_hue="slate"))
|
app/__init__.py
DELETED
|
@@ -1,83 +0,0 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
from pathlib import Path
|
| 4 |
-
import re
|
| 5 |
-
|
| 6 |
-
import gradio as gr
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
DATA_DIR = Path(__file__).resolve().parent.parent / "data" / "knowledge"
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
def _load_documents() -> list[tuple[str, str]]:
|
| 13 |
-
docs: list[tuple[str, str]] = []
|
| 14 |
-
for file_path in sorted(DATA_DIR.glob("*.txt")):
|
| 15 |
-
content = file_path.read_text(encoding="utf-8").strip()
|
| 16 |
-
if content:
|
| 17 |
-
docs.append((file_path.name, content))
|
| 18 |
-
return docs
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
DOCUMENTS = _load_documents()
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
def _match_lines(question: str, text: str) -> list[str]:
|
| 25 |
-
tokens = {token.lower() for token in re.findall(r"[a-zA-Z]+", question) if token}
|
| 26 |
-
if not tokens:
|
| 27 |
-
return []
|
| 28 |
-
|
| 29 |
-
lines = [line.strip() for line in text.splitlines() if line.strip()]
|
| 30 |
-
matched: list[str] = []
|
| 31 |
-
for line in lines:
|
| 32 |
-
line_lower = line.lower()
|
| 33 |
-
if any(token in line_lower for token in tokens):
|
| 34 |
-
matched.append(line)
|
| 35 |
-
return matched[:3]
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
def answer_question(question: str) -> str:
|
| 39 |
-
if not question.strip():
|
| 40 |
-
return "Please enter a question about the invoice, resume, or support ticket files."
|
| 41 |
-
|
| 42 |
-
answers: list[str] = []
|
| 43 |
-
for source, text in DOCUMENTS:
|
| 44 |
-
matches = _match_lines(question, text)
|
| 45 |
-
if matches:
|
| 46 |
-
answers.append(f"From {source}:\n" + "\n".join(matches))
|
| 47 |
-
|
| 48 |
-
if not answers:
|
| 49 |
-
return (
|
| 50 |
-
"No strong matches were found in the local knowledge files. "
|
| 51 |
-
"Try asking about an invoice, a resume, or a support ticket entry."
|
| 52 |
-
)
|
| 53 |
-
|
| 54 |
-
return "Grounded answer (evidence from local knowledge files):\n\n" + "\n\n".join(answers[:3])
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
def create_demo() -> gr.Blocks:
|
| 58 |
-
with gr.Blocks(title="Agentic RAG Demo") as demo:
|
| 59 |
-
gr.Markdown(
|
| 60 |
-
"""
|
| 61 |
-
# Agentic RAG Demo
|
| 62 |
-
|
| 63 |
-
Ask a question about the sample invoice, resume, or support ticket set.
|
| 64 |
-
This lightweight Spaces version uses the local knowledge files directly and stays compatible with the default CPU runtime.
|
| 65 |
-
"""
|
| 66 |
-
)
|
| 67 |
-
|
| 68 |
-
question = gr.Textbox(
|
| 69 |
-
label="Question",
|
| 70 |
-
placeholder="Example: Which support ticket mentions a missing trailing slash?",
|
| 71 |
-
lines=2,
|
| 72 |
-
)
|
| 73 |
-
submit = gr.Button("Run agent")
|
| 74 |
-
answer = gr.Textbox(label="Answer", lines=10)
|
| 75 |
-
|
| 76 |
-
submit.click(fn=answer_question, inputs=question, outputs=answer)
|
| 77 |
-
|
| 78 |
-
return demo
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
demo = create_demo()
|
| 82 |
-
|
| 83 |
-
__all__ = ["answer_question", "create_demo", "demo"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/__pycache__/__init__.cpython-311.pyc
DELETED
|
Binary file (200 Bytes)
|
|
|
app/__pycache__/agent.cpython-311.pyc
DELETED
|
Binary file (5.99 kB)
|
|
|
app/__pycache__/retriever.cpython-311.pyc
DELETED
|
Binary file (5.11 kB)
|
|
|
app/agent.py
DELETED
|
@@ -1,89 +0,0 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
from typing import TypedDict
|
| 4 |
-
|
| 5 |
-
from dotenv import load_dotenv
|
| 6 |
-
from langgraph.graph import END, START, StateGraph
|
| 7 |
-
|
| 8 |
-
from app.retriever import build_vectorstore, retrieve_and_rerank
|
| 9 |
-
|
| 10 |
-
load_dotenv()
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
class AgentState(TypedDict):
|
| 14 |
-
question: str
|
| 15 |
-
documents: list
|
| 16 |
-
answer: str
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
def _build_vectorstore() -> object:
|
| 20 |
-
return build_vectorstore()
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
def retrieve_node(state: AgentState) -> dict:
|
| 24 |
-
vectorstore = _build_vectorstore()
|
| 25 |
-
docs = retrieve_and_rerank(state["question"], vectorstore, k=5)
|
| 26 |
-
return {"documents": docs}
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
def _dedupe_documents(documents: list) -> list:
|
| 30 |
-
unique: list = []
|
| 31 |
-
seen_sources: set[str] = set()
|
| 32 |
-
|
| 33 |
-
for doc in documents:
|
| 34 |
-
source = doc.metadata.get("source") if hasattr(doc, "metadata") else None
|
| 35 |
-
if source and source in seen_sources:
|
| 36 |
-
continue
|
| 37 |
-
if source:
|
| 38 |
-
seen_sources.add(source)
|
| 39 |
-
unique.append(doc)
|
| 40 |
-
|
| 41 |
-
return unique
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
def _grounded_summary(question: str, documents: list) -> str:
|
| 45 |
-
if not documents:
|
| 46 |
-
return "No relevant passages were retrieved for that question."
|
| 47 |
-
|
| 48 |
-
question_tokens = {token.lower() for token in question.replace("\n", " ").split() if token.isalpha()}
|
| 49 |
-
unique_docs = _dedupe_documents(documents)
|
| 50 |
-
selected_parts: list[str] = []
|
| 51 |
-
|
| 52 |
-
for doc in unique_docs:
|
| 53 |
-
text = doc.page_content.strip()
|
| 54 |
-
lines = [line.strip() for line in text.splitlines() if line.strip()]
|
| 55 |
-
matched_lines = [
|
| 56 |
-
line for line in lines if any(token.lower() in line.lower() for token in question_tokens)
|
| 57 |
-
]
|
| 58 |
-
if matched_lines:
|
| 59 |
-
selected_parts.append("\n".join(matched_lines))
|
| 60 |
-
else:
|
| 61 |
-
selected_parts.append("\n".join(lines))
|
| 62 |
-
|
| 63 |
-
return (
|
| 64 |
-
"Grounded answer (evidence-based summary):\n\n"
|
| 65 |
-
+ "\n\n".join(selected_parts[:3])
|
| 66 |
-
)
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
def answer_node(state: AgentState) -> dict:
|
| 70 |
-
evidence = "\n\n".join(doc.page_content for doc in state["documents"])
|
| 71 |
-
answer = _grounded_summary(state["question"], state["documents"])
|
| 72 |
-
|
| 73 |
-
if not evidence.strip():
|
| 74 |
-
answer = "No evidence was retrieved for that question."
|
| 75 |
-
|
| 76 |
-
return {"answer": answer}
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
def run_agent(question: str) -> str:
|
| 80 |
-
graph = StateGraph(AgentState)
|
| 81 |
-
graph.add_node("retrieve", retrieve_node)
|
| 82 |
-
graph.add_node("answer", answer_node)
|
| 83 |
-
graph.add_edge(START, "retrieve")
|
| 84 |
-
graph.add_edge("retrieve", "answer")
|
| 85 |
-
graph.add_edge("answer", END)
|
| 86 |
-
|
| 87 |
-
app = graph.compile()
|
| 88 |
-
result = app.invoke({"question": question, "documents": [], "answer": ""})
|
| 89 |
-
return result["answer"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/main.py
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
import sys
|
| 4 |
-
|
| 5 |
-
from app.agent import run_agent
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
def main() -> None:
|
| 9 |
-
question = " ".join(sys.argv[1:])
|
| 10 |
-
if not question:
|
| 11 |
-
question = "Which ticket mentions a missing trailing slash and what was the resolution?"
|
| 12 |
-
|
| 13 |
-
answer = run_agent(question)
|
| 14 |
-
print("\nAnswer:\n")
|
| 15 |
-
print(answer)
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
if __name__ == "__main__":
|
| 19 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/retriever.py
DELETED
|
@@ -1,64 +0,0 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
import os
|
| 4 |
-
from collections import Counter
|
| 5 |
-
from pathlib import Path
|
| 6 |
-
|
| 7 |
-
from dotenv import load_dotenv
|
| 8 |
-
from langchain_chroma import Chroma
|
| 9 |
-
from langchain_core.documents import Document
|
| 10 |
-
from langchain_huggingface import HuggingFaceEmbeddings
|
| 11 |
-
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
| 12 |
-
|
| 13 |
-
load_dotenv()
|
| 14 |
-
|
| 15 |
-
DATA_DIR = Path(__file__).resolve().parent.parent / "data" / "knowledge"
|
| 16 |
-
DB_DIR = Path(os.getenv("CHROMA_DB_DIR", ".chroma_db"))
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
def _load_documents() -> list[Document]:
|
| 20 |
-
docs: list[Document] = []
|
| 21 |
-
for file_path in sorted(DATA_DIR.glob("*.txt")):
|
| 22 |
-
content = file_path.read_text(encoding="utf-8")
|
| 23 |
-
docs.append(Document(page_content=content, metadata={"source": file_path.name}))
|
| 24 |
-
return docs
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
def build_vectorstore() -> Chroma:
|
| 28 |
-
splitter = RecursiveCharacterTextSplitter(chunk_size=600, chunk_overlap=120)
|
| 29 |
-
raw_docs = _load_documents()
|
| 30 |
-
chunks = splitter.split_documents(raw_docs)
|
| 31 |
-
|
| 32 |
-
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
|
| 33 |
-
vectorstore = Chroma.from_documents(
|
| 34 |
-
documents=chunks,
|
| 35 |
-
embedding=embeddings,
|
| 36 |
-
persist_directory=str(DB_DIR),
|
| 37 |
-
collection_name="agentic-rag-demo",
|
| 38 |
-
)
|
| 39 |
-
return vectorstore
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
def _normalize_text(text: str) -> list[str]:
|
| 43 |
-
return [token.lower() for token in text.replace("\n", " ").split() if token.isalpha()]
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
def _keyword_overlap_score(question: str, chunk: str) -> float:
|
| 47 |
-
question_tokens = Counter(_normalize_text(question))
|
| 48 |
-
chunk_tokens = Counter(_normalize_text(chunk))
|
| 49 |
-
overlap = sum(min(question_tokens[token], chunk_tokens[token]) for token in question_tokens)
|
| 50 |
-
if overlap == 0:
|
| 51 |
-
return 0.0
|
| 52 |
-
return overlap / max(1, len(question_tokens))
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
def retrieve_and_rerank(question: str, vectorstore: Chroma, k: int = 5) -> list[Document]:
|
| 56 |
-
hits = vectorstore.similarity_search(question, k=k)
|
| 57 |
-
scored = []
|
| 58 |
-
for doc in hits:
|
| 59 |
-
score = _keyword_overlap_score(question, doc.page_content)
|
| 60 |
-
scored.append((score, doc))
|
| 61 |
-
|
| 62 |
-
scored.sort(key=lambda item: item[0], reverse=True)
|
| 63 |
-
reranked = [doc for _, doc in scored if doc.page_content.strip()]
|
| 64 |
-
return reranked[:3]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data/knowledge/invoice.txt
DELETED
|
@@ -1,10 +0,0 @@
|
|
| 1 |
-
Invoice #INV-2048
|
| 2 |
-
Vendor: Northwind Data Services
|
| 3 |
-
Date: 2026-04-10
|
| 4 |
-
Total: $2,480.00
|
| 5 |
-
Status: Paid
|
| 6 |
-
Line items:
|
| 7 |
-
- Managed analytics platform: $1,940.00
|
| 8 |
-
- Support retention: $540.00
|
| 9 |
-
Notes:
|
| 10 |
-
The customer requested quarterly reporting for March and April. The account owner is Dana Lewis.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data/knowledge/resume.txt
DELETED
|
@@ -1,11 +0,0 @@
|
|
| 1 |
-
Candidate: Maya Thompson
|
| 2 |
-
Role: Senior Data Analyst
|
| 3 |
-
Experience:
|
| 4 |
-
- 7 years in BI and forecasting
|
| 5 |
-
- Built a revenue dashboard for a logistics firm
|
| 6 |
-
- Led migration from Excel-based reporting to a Snowflake pipeline
|
| 7 |
-
Skills:
|
| 8 |
-
Python, SQL, dbt, Power BI, stakeholder communication
|
| 9 |
-
Availability: Immediate
|
| 10 |
-
Reference note:
|
| 11 |
-
Maya is a strong fit for roles involving analytics modernization and cross-functional communication.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data/knowledge/support_ticket.txt
DELETED
|
@@ -1,10 +0,0 @@
|
|
| 1 |
-
Support ticket #ST-882
|
| 2 |
-
Customer: Harbor Logistics
|
| 3 |
-
Priority: High
|
| 4 |
-
Issue: The dashboard stopped refreshing after the nightly data import.
|
| 5 |
-
Steps taken:
|
| 6 |
-
- Verified permissions on the warehouse connector.
|
| 7 |
-
- Restarted the ingestion job.
|
| 8 |
-
- Confirmed the export path was missing a trailing slash.
|
| 9 |
-
Resolution: Updated the path and reran the import. The dashboard became healthy again.
|
| 10 |
-
Owner: Omar Patel
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
|
@@ -1 +1,3 @@
|
|
| 1 |
-
gradio>=
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio>=5.0
|
| 2 |
+
scikit-learn>=1.3
|
| 3 |
+
numpy>=1.24
|
space.yaml
DELETED
|
@@ -1,4 +0,0 @@
|
|
| 1 |
-
sdk: gradio
|
| 2 |
-
app_file: app.py
|
| 3 |
-
python_version: "3.11"
|
| 4 |
-
suggested_hardware: cpu-basic
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|