ASHU_AI / app.py
AnubhaParashar's picture
Update app.py
3f57af9 verified
Raw
History Blame Contribute Delete
22.2 kB
import csv
import datetime as dt
import os
import re
import tempfile
import textwrap
import zipfile
from collections import Counter
from pathlib import Path
import gradio as gr
APP_TITLE = "ASHU AI Mentor Studio"
OUT_DIR = Path("outputs")
OUT_DIR.mkdir(exist_ok=True)
SKILLS = sorted(set("""
python java c++ javascript typescript sql mysql postgresql mongodb snowflake excel powerbi tableau
pandas numpy scikit-learn sklearn tensorflow pytorch keras opencv yolo ultralytics nlp computer vision
machine learning deep learning llm rag langchain llamaindex openai huggingface transformers gradio streamlit
flask fastapi docker kubernetes git github linux bash aws azure gcp airflow mlflow dvc cicd rest api
microservices prompt engineering data analysis data science statistics regression classification clustering xgboost
lightgbm random forest svm cnn rnn lstm transformer bert gpt vector database faiss chromadb pinecone
elasticsearch html css react nodejs django pytest monitoring grafana prometheus agile scrum communication leadership
documentation research writing latex
""".split()))
STOPWORDS = set("""
a an the and or but if then else with without for from into onto in on at by to of is are was were be been
being this that these those as it its your you we our they them their candidate role job work experience skills
using use used will can should could would may might about across within strong good excellent ability knowledge
hands-on years year team teams project projects responsibilities requirements preferred required
""".split())
def clean_text(text):
return re.sub(r"\s+", " ", text or "").strip()
def tokens(text):
return [t.lower() for t in re.findall(r"[A-Za-z][A-Za-z0-9+.#/-]{1,}", text or "")]
def keywords(text, n=30):
toks = [t for t in tokens(text) if t not in STOPWORDS and len(t) > 2]
return [w for w, _ in Counter(toks).most_common(n)]
def detect_skills(text):
hay = " " + re.sub(r"[^a-z0-9+#./-]+", " ", (text or "").lower()) + " "
found = []
for skill in SKILLS:
pattern = r"(?<![a-z0-9+#./-])" + re.escape(skill.lower()) + r"(?![a-z0-9+#./-])"
if re.search(pattern, hay):
found.append(skill)
return sorted(found)
def read_uploaded_file(file_obj):
if file_obj is None:
return ""
try:
path = Path(file_obj.name if hasattr(file_obj, "name") else str(file_obj))
suffix = path.suffix.lower()
if suffix in [".txt", ".md", ".csv", ".py", ".json", ".log"]:
return path.read_text(encoding="utf-8", errors="ignore")
return "Unsupported file type for this stable build. Paste resume/JD text in the textbox for PDF/DOCX."
except Exception as exc:
return f"Could not read uploaded file: {exc}"
def timestamp_name(prefix, ext):
ts = dt.datetime.now().strftime("%Y%m%d_%H%M%S")
return OUT_DIR / f"{prefix}_{ts}.{ext}"
def write_text(prefix, content, ext="txt"):
path = timestamp_name(prefix, ext)
path.write_text(content or "", encoding="utf-8")
return str(path)
def write_csv(prefix, rows):
path = timestamp_name(prefix, "csv")
if not rows:
rows = [{"message": "No rows generated"}]
with path.open("w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
writer.writeheader()
writer.writerows(rows)
return str(path)
def zip_outputs(prefix, files):
path = timestamp_name(prefix, "zip")
with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as z:
for f in files:
if f and Path(f).exists():
z.write(f, arcname=Path(f).name)
return str(path)
def similarity_score(a, b):
ka = set(keywords(a, 120))
kb = set(keywords(b, 120))
if not ka or not kb:
return 0.0
return len(ka & kb) / max(1, len(kb))
def ats_analyze(resume_file, resume_text, jd_text, target_role):
resume = clean_text((resume_text or "") + "\n" + read_uploaded_file(resume_file))
jd = clean_text(jd_text or "")
if not resume:
return "Paste resume text or upload a TXT/CSV/MD resume file first.", None
if not jd:
return "Paste the job description first.", None
r_skills = detect_skills(resume)
j_skills = detect_skills(jd)
matched = sorted(set(r_skills) & set(j_skills))
missing = sorted(set(j_skills) - set(r_skills))
keyword_match = similarity_score(resume, jd)
skill_score = len(matched) / max(1, len(j_skills))
length_score = min(1.0, len(resume.split()) / 450)
role_bonus = 0.08 if target_role and target_role.lower() in resume.lower() else 0.0
score = round(100 * min(1.0, 0.55 * skill_score + 0.30 * keyword_match + 0.15 * length_score + role_bonus), 1)
verdict = "Strong match" if score >= 75 else "Moderate match" if score >= 55 else "Needs tailoring"
jd_kw = keywords(jd, 20)
resume_kw = set(keywords(resume, 80))
missing_kw = [k for k in jd_kw if k not in resume_kw][:15]
report = f"""# ATS Resume + JD Analysis
**Target role:** {target_role or 'Not specified'}
**ATS-style score:** **{score}/100**
**Verdict:** **{verdict}**
## Skill Coverage
- JD skills detected: {len(j_skills)}
- Resume skills detected: {len(r_skills)}
- Matched skills: {len(matched)}
- Missing JD skills: {len(missing)}
## Matched Skills
{', '.join(matched) if matched else 'No direct technical skill matches detected.'}
## Missing Skills to Add/Improve
{', '.join(missing) if missing else 'No major missing skills detected.'}
## Missing JD Keywords
{', '.join(missing_kw) if missing_kw else 'No important missing JD keywords detected.'}
## Immediate Improvements
1. Add a role-aligned summary using the exact job title.
2. Put matched technical skills in a clear skills section.
3. Add quantified project bullets: problem, tool/model, metric, business impact.
4. Add missing JD keywords only where truthful.
5. Avoid tables/images for ATS-friendly formatting.
"""
rows = [
{"metric": "ATS score", "value": str(score)},
{"metric": "verdict", "value": verdict},
{"metric": "matched skills", "value": ", ".join(matched)},
{"metric": "missing skills", "value": ", ".join(missing)},
{"metric": "missing keywords", "value": ", ".join(missing_kw)},
]
txt_path = write_text("ashu_ats_report", report, "md")
csv_path = write_csv("ashu_ats_report", rows)
return report, zip_outputs("ashu_ats_outputs", [txt_path, csv_path])
def generate_cover_letter(name, company, role, resume_file, resume_text, jd_text):
resume = clean_text((resume_text or "") + "\n" + read_uploaded_file(resume_file))
jd = clean_text(jd_text or "")
matched = sorted(set(detect_skills(resume)) & set(detect_skills(jd)))[:8]
name = name or "Candidate"
company = company or "your organization"
role = role or "the advertised role"
skills_line = ", ".join(matched) if matched else "AI, analytics, problem solving, and practical project execution"
letter = f"""Dear Hiring Team,
I am writing to express my interest in the {role} position at {company}. My background aligns well with the role requirements, especially in {skills_line}.
Across my work, I have focused on building practical solutions that connect technical execution with measurable outcomes. I bring experience in understanding requirements, designing reliable workflows, implementing systems, evaluating results, and communicating insights clearly to stakeholders.
What attracts me to this opportunity is the chance to contribute to a team where ownership, learning, and impact matter. I would be excited to apply my experience to the problems your team is solving.
Thank you for considering my application. I would welcome the opportunity to discuss how my experience can contribute to {company}.
Sincerely,
{name}
"""
return letter, write_text("ashu_cover_letter", letter, "txt")
def interview_questions(role, skills, difficulty, count):
role = role or "AI/ML Engineer"
difficulty = difficulty or "Medium"
skill_list = [s.strip() for s in re.split(r"[,\n]", skills or "") if s.strip()] or ["Python", "Machine Learning", "System Design", "Communication"]
count = int(count)
rows = []
lines = ["# Interview Questions"]
for i in range(1, count + 1):
skill = skill_list[(i - 1) % len(skill_list)]
if i % 4 == 1:
question = f"Explain a project where you used {skill}. What was the problem, your approach, and the final impact?"
elif i % 4 == 2:
question = f"For a {role}, how would you design a reliable workflow using {skill} in production?"
elif i % 4 == 3:
question = f"What can go wrong while using {skill}, and how would you validate or debug it?"
else:
question = f"Give a {difficulty.lower()}-level scenario where {skill} must be optimized for accuracy, latency, or cost."
rows.append({"No": i, "Skill": skill, "Difficulty": difficulty, "Question": question})
lines.append(f"{i}. **[{skill}]** {question}")
csv_path = write_csv("ashu_interview_questions", rows)
md_path = write_text("ashu_interview_questions", "\n".join(lines), "md")
return "\n\n".join(lines), zip_outputs("ashu_interview_outputs", [csv_path, md_path])
def score_answer(question, answer):
q = clean_text(question)
a = clean_text(answer)
if not q or not a:
return "Add both the interview question and your answer."
qk = set(keywords(q, 20))
ak = set(keywords(a, 80))
coverage = len(qk & ak) / max(1, len(qk))
structure = sum(1 for x in ["problem", "approach", "result", "impact", "metric", "learned"] if x in a.lower()) / 6
length = min(1.0, len(a.split()) / 120)
score = round(100 * (0.45 * coverage + 0.35 * structure + 0.20 * length), 1)
feedback = []
if structure < 0.5:
feedback.append("Use STAR format: Situation, Task, Action, Result.")
if coverage < 0.5:
feedback.append("Answer the exact question terms more directly.")
if len(a.split()) < 80:
feedback.append("Add more detail and at least one measurable result.")
if not feedback:
feedback.append("Good structure. Add one stronger metric if possible.")
return f"# Answer Score: {score}/100\n\n## Feedback\n- " + "\n- ".join(feedback)
def training_plan(goal, level, weeks, hours_per_week):
goal = goal or "AI/ML and interview preparation"
level = level or "Beginner"
weeks = int(weeks)
hours_per_week = int(hours_per_week)
topics = keywords(goal, 10) or ["python", "machine learning", "projects", "interview"]
rows = []
lines = [f"# {weeks}-Week Training Plan", f"**Goal:** {goal}", f"**Level:** {level}", f"**Time:** {hours_per_week} hours/week"]
for w in range(1, weeks + 1):
topic = topics[(w - 1) % len(topics)].title()
deliverable = f"Week {w} output: notes + one exercise + 3 interview answers"
rows.append({"Week": w, "Topic": topic, "Hours": hours_per_week, "Deliverable": deliverable})
lines.append(f"\n## Week {w}: {topic}\n- Learn/revise fundamentals\n- Build one mini exercise\n- Create 5 flashcards\n- Practice 3 interview questions\n- **Deliverable:** {deliverable}")
md = "\n".join(lines)
md_path = write_text("ashu_training_plan", md, "md")
csv_path = write_csv("ashu_training_plan", rows)
return md, zip_outputs("ashu_training_plan", [md_path, csv_path])
def summarize_document(file_obj, pasted_text, style):
text = clean_text((pasted_text or "") + "\n" + read_uploaded_file(file_obj))
if not text:
return "Paste text or upload TXT/CSV/MD file first.", None
sentences = re.split(r"(?<=[.!?])\s+", text)
words = keywords(text, 25)
scored = []
for s in sentences:
sc = sum(1 for w in words if w in s.lower())
if sc > 0 and len(s.split()) > 5:
scored.append((sc, s))
selected = [s for _, s in sorted(scored, reverse=True)[:8]] or sentences[:6]
if style == "Study notes":
output = "# Study Notes\n\n## Key Terms\n" + ", ".join(words[:15]) + "\n\n## Notes\n" + "\n".join(f"- {clean_text(s)}" for s in selected)
elif style == "Executive summary":
output = "# Executive Summary\n\n" + " ".join(selected[:5]) + "\n\n## Key Terms\n" + ", ".join(words[:12])
else:
output = "# Bullet Summary\n" + "\n".join(f"- {clean_text(s)}" for s in selected)
return output, write_text("ashu_summary", output, "md")
def flashcards_mcqs(file_obj, pasted_text, count):
text = clean_text((pasted_text or "") + "\n" + read_uploaded_file(file_obj))
if not text:
return "Paste text or upload TXT/CSV/MD file first.", None
kws = keywords(text, int(count) + 10)
rows = []
lines = ["# Flashcards and MCQs"]
for i, kw in enumerate(kws[: int(count)], 1):
rows.append({"type": "flashcard", "question": f"What is {kw}?", "answer": f"Explain {kw} using the given material and add one example."})
rows.append({"type": "mcq", "question": f"Which statement best relates to {kw}?", "answer": "A"})
lines.append(f"## {i}. {kw.title()}\n**Flashcard:** What is {kw}?\n\n**MCQ:** Which statement best relates to {kw}?\nA. Most relevant concept from the material\nB. Unrelated term\nC. Random process\nD. None\n\n**Answer:** A")
md = "\n\n".join(lines)
md_path = write_text("ashu_flashcards_mcqs", md, "md")
csv_path = write_csv("ashu_flashcards_mcqs", rows)
return md, zip_outputs("ashu_flashcards_outputs", [md_path, csv_path])
def presenter_script(topic, audience, minutes):
topic = topic or "AI Mentor Platform"
audience = audience or "students and professionals"
minutes = int(minutes)
section_names = ["Hook", "Problem", "Solution", "Workflow", "Demo", "Benefits", "Closing"]
sections = max(3, min(7, minutes // 2 + 1))
lines = [f"# Digital Presenter Script: {topic}", f"**Audience:** {audience}", f"**Duration:** {minutes} minutes"]
for i in range(sections):
name = section_names[i]
lines.append(f"\n## Scene {i + 1}: {name}\nPresenter says: Today we discuss **{topic}** for {audience}. Explain this section clearly, show one practical example, and connect it to value.\n\nOn-screen visual: title card, workflow diagram, or short bullet animation.")
script = "\n".join(lines)
return script, write_text("ashu_presenter_script", script, "md")
def candidate_scorecard(name, role, resume_file, resume_text, interview_notes):
text = clean_text((resume_text or "") + "\n" + read_uploaded_file(resume_file) + "\n" + (interview_notes or ""))
found = detect_skills(text)
dimensions = {
"Technical fit": min(100, 30 + len(found) * 5),
"Communication": 75 if len((interview_notes or "").split()) > 60 else 55,
"Project depth": 80 if any(w in text.lower() for w in ["project", "built", "developed", "implemented"]) else 50,
"Role alignment": 85 if role and role.lower() in text.lower() else 60,
"Learning potential": 78,
}
final = round(sum(dimensions.values()) / len(dimensions), 1)
rows = [{"Dimension": k, "Score": v} for k, v in dimensions.items()]
md = f"# Candidate Scorecard\n\n**Name:** {name or 'Candidate'}\n\n**Role:** {role or 'Not specified'}\n\n**Final score:** **{final}/100**\n\n"
for k, v in dimensions.items():
md += f"- **{k}:** {v}/100\n"
md += "\n## Detected Strengths\n" + (", ".join(found[:20]) if found else "Add more evidence from resume/interview.")
md_path = write_text("ashu_candidate_scorecard", md, "md")
csv_path = write_csv("ashu_candidate_scorecard", rows)
return md, zip_outputs("ashu_candidate_scorecard", [md_path, csv_path])
def architecture_diagram(system_name, features):
system_name = system_name or "ASHU AI Mentor Studio"
feature_list = [f.strip() for f in re.split(r"[,\n]", features or "") if f.strip()] or ["Resume Analyzer", "Training Engine", "Interview Engine", "Report Generator", "Download Center"]
nodes = []
for i, feature in enumerate(feature_list, 1):
nodes.append(f"UI --> F{i}[{feature}]")
nodes.append(f"F{i} --> R[Reports and Downloads]")
mermaid = "flowchart TD\nU[User] --> UI[" + system_name + " UI]\n" + "\n".join(nodes) + "\nR --> D[TXT CSV ZIP Outputs]"
md = f"# Architecture Diagram\n\n```mermaid\n{mermaid}\n```\n\n## Components\n" + "\n".join(f"- {f}" for f in feature_list)
return md, write_text("ashu_architecture_mermaid", mermaid, "mmd")
def health_check():
return "✅ ASHU Gradio Space is running. App loaded successfully."
with gr.Blocks(title=APP_TITLE) as demo:
gr.Markdown(f"# 🚀 {APP_TITLE}\nStable Hugging Face Gradio app with resume/JD analysis, training, interview prep, summaries, quizzes, scripts, scorecards, and diagrams.")
with gr.Tab("Health Check"):
btn = gr.Button("Check app")
out = gr.Markdown()
btn.click(health_check, outputs=out)
with gr.Tab("Resume + JD Analyzer"):
role = gr.Textbox(label="Target Role", placeholder="AI/ML Engineer")
resume_file = gr.File(label="Resume file: TXT/CSV/MD only in this stable build")
resume_text = gr.Textbox(label="Or paste resume text", lines=8)
jd_text = gr.Textbox(label="Paste job description", lines=8)
analyze_btn = gr.Button("Analyze ATS Match")
ats_out = gr.Markdown()
ats_zip = gr.File(label="Download ATS outputs")
analyze_btn.click(ats_analyze, inputs=[resume_file, resume_text, jd_text, role], outputs=[ats_out, ats_zip])
with gr.Tab("Cover Letter"):
name = gr.Textbox(label="Candidate Name")
company = gr.Textbox(label="Company")
cover_role = gr.Textbox(label="Role")
cover_btn = gr.Button("Generate Cover Letter")
cover_out = gr.Textbox(label="Cover Letter", lines=12)
cover_file = gr.File(label="Download")
cover_btn.click(generate_cover_letter, inputs=[name, company, cover_role, resume_file, resume_text, jd_text], outputs=[cover_out, cover_file])
with gr.Tab("Interview Prep"):
int_role = gr.Textbox(label="Role", value="AI/ML Engineer")
int_skills = gr.Textbox(label="Skills", value="Python, Machine Learning, SQL, System Design")
difficulty = gr.Dropdown(["Easy", "Medium", "Hard"], value="Medium", label="Difficulty")
q_count = gr.Slider(5, 30, value=12, step=1, label="Number of Questions")
q_btn = gr.Button("Generate Questions")
q_out = gr.Markdown()
q_file = gr.File(label="Download")
q_btn.click(interview_questions, inputs=[int_role, int_skills, difficulty, q_count], outputs=[q_out, q_file])
gr.Markdown("## Answer Scoring")
question = gr.Textbox(label="Interview Question", lines=3)
answer = gr.Textbox(label="Your Answer", lines=8)
score_btn = gr.Button("Score Answer")
score_out = gr.Markdown()
score_btn.click(score_answer, inputs=[question, answer], outputs=score_out)
with gr.Tab("Training Plan"):
goal = gr.Textbox(label="Learning Goal", value="AI ML job preparation with Python and projects")
level = gr.Dropdown(["Beginner", "Intermediate", "Advanced"], value="Intermediate", label="Level")
weeks = gr.Slider(1, 24, value=8, step=1, label="Weeks")
hours = gr.Slider(1, 20, value=6, step=1, label="Hours per week")
train_btn = gr.Button("Create Plan")
train_out = gr.Markdown()
train_zip = gr.File(label="Download")
train_btn.click(training_plan, inputs=[goal, level, weeks, hours], outputs=[train_out, train_zip])
with gr.Tab("Summarizer"):
doc_file = gr.File(label="TXT/CSV/MD file")
doc_text = gr.Textbox(label="Or paste document text", lines=10)
summary_style = gr.Dropdown(["Bullet summary", "Study notes", "Executive summary"], value="Bullet summary", label="Style")
sum_btn = gr.Button("Summarize")
sum_out = gr.Markdown()
sum_file = gr.File(label="Download")
sum_btn.click(summarize_document, inputs=[doc_file, doc_text, summary_style], outputs=[sum_out, sum_file])
with gr.Tab("Flashcards + MCQs"):
card_count = gr.Slider(5, 30, value=10, step=1, label="Count")
card_btn = gr.Button("Generate Flashcards and MCQs")
card_out = gr.Markdown()
card_zip = gr.File(label="Download")
card_btn.click(flashcards_mcqs, inputs=[doc_file, doc_text, card_count], outputs=[card_out, card_zip])
with gr.Tab("Presenter Script"):
topic = gr.Textbox(label="Topic", value="ASHU AI Mentor Studio")
audience = gr.Textbox(label="Audience", value="students and professionals")
minutes = gr.Slider(2, 30, value=8, step=1, label="Duration in minutes")
script_btn = gr.Button("Generate Script")
script_out = gr.Markdown()
script_file = gr.File(label="Download")
script_btn.click(presenter_script, inputs=[topic, audience, minutes], outputs=[script_out, script_file])
with gr.Tab("Candidate Scorecard"):
cand_name = gr.Textbox(label="Candidate Name")
cand_role = gr.Textbox(label="Role")
notes = gr.Textbox(label="Interview Notes", lines=8)
scorecard_btn = gr.Button("Generate Scorecard")
scorecard_out = gr.Markdown()
scorecard_zip = gr.File(label="Download")
scorecard_btn.click(candidate_scorecard, inputs=[cand_name, cand_role, resume_file, resume_text, notes], outputs=[scorecard_out, scorecard_zip])
with gr.Tab("Architecture Diagram"):
sys_name = gr.Textbox(label="System Name", value="ASHU AI Mentor Studio")
feats = gr.Textbox(label="Features, one per line", lines=6, value="Resume Analyzer\nTraining Engine\nInterview Engine\nReport Generator\nDownload Center")
arch_btn = gr.Button("Generate Mermaid Architecture")
arch_out = gr.Markdown()
arch_file = gr.File(label="Download Mermaid")
arch_btn.click(architecture_diagram, inputs=[sys_name, feats], outputs=[arch_out, arch_file])
if __name__ == "__main__":
demo.launch()