sajith-0701 commited on
Commit
3d40e5f
·
1 Parent(s): 15145f6

prepare for huggingface deployment

Browse files
.dockerignore ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Environment
2
+ .env
3
+
4
+ # Python cache
5
+ __pycache__/
6
+ *.pyc
7
+ *.pyo
8
+ *.pyd
9
+
10
+ # Virtual environments
11
+ venv/
12
+ .venv/
13
+ env/
14
+ inter/
15
+
16
+ # Node / frontend (not needed for backend deploy)
17
+ frontend/
18
+ node_modules/
19
+
20
+ # Uploads (runtime data)
21
+ uploads/
22
+
23
+ # Git
24
+ .git/
25
+ .gitignore
26
+
27
+ # OS / IDE junk
28
+ .DS_Store
29
+ Thumbs.db
30
+ .idea/
31
+ .vscode/
32
+ *.swp
33
+
34
+ backend/.env
.gitignore CHANGED
@@ -15,3 +15,4 @@ WORKFLOW.md
15
  voice_name_list_xtts.txt
16
 
17
 
 
 
15
  voice_name_list_xtts.txt
16
 
17
 
18
+ SYSTEM_ARCHITECTURE.md
Dockerfile ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ ENV PYTHONUNBUFFERED=1
4
+ ENV PYTHONDONTWRITEBYTECODE=1
5
+
6
+ WORKDIR /app
7
+
8
+ RUN apt-get update && apt-get install -y \
9
+ gcc \
10
+ ffmpeg \
11
+ libglib2.0-0 \
12
+ libsm6 \
13
+ libxext6 \
14
+ libxrender-dev \
15
+ && rm -rf /var/lib/apt/lists/*
16
+
17
+ # Copy ONLY backend requirements
18
+ COPY backend/requirements.txt .
19
+
20
+ RUN pip install --no-cache-dir --upgrade pip \
21
+ && pip install --no-cache-dir -r requirements.txt
22
+
23
+ # Copy backend code into container
24
+ COPY backend/ .
25
+
26
+ EXPOSE 7860
27
+
28
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
backend/.dockerignore DELETED
@@ -1,73 +0,0 @@
1
- # Environments
2
- .env
3
-
4
- # Byte-compiled / optimized / DLL files
5
- __pycache__/
6
- *.py[cod]
7
- *$py.class
8
-
9
- # Virtual environments
10
- venv/
11
- .venv/
12
- env/
13
- .env/
14
-
15
- # Distribution / packaging
16
- build/
17
- develop-eggs/
18
- dist/
19
- downloads/
20
- eggs/
21
- .eggs/
22
- lib/
23
- lib64/
24
- parts/
25
- sdist/
26
- var/
27
- wheels/
28
- share/python-wheels/
29
- *.egg-info/
30
- .installed.cfg
31
- *.egg
32
-
33
- # PyInstaller
34
- *.manifest
35
- *.spec
36
-
37
- # Installer logs
38
- pip-log.txt
39
- pip-delete-this-directory.txt
40
-
41
- # Unit test / coverage reports
42
- htmlcov/
43
- .tox/
44
- .nox/
45
- .coverage
46
- .coverage.*
47
- .cache
48
- nosetests.xml
49
- coverage.xml
50
- *.cover
51
- *.py,cover
52
- .hypothesis/
53
- .pytest_cache/
54
- cover/
55
-
56
- # IDEs
57
- .idea/
58
- .vscode/
59
- *.swp
60
- *.swo
61
-
62
- # OS generated files
63
- .DS_Store
64
- .DS_Store?
65
- ._*
66
- .Spotlight-V100
67
- .Trashes
68
- ehthumbs.db
69
- Thumbs.db
70
-
71
- # Git
72
- .git/
73
- .gitignore
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/Dockerfile DELETED
@@ -1,24 +0,0 @@
1
- # Use the official Python base image
2
- FROM python:3.10-slim
3
-
4
- # Set environment variables
5
- ENV PYTHONDONTWRITEBYTECODE=1
6
- ENV PYTHONUNBUFFERED=1
7
-
8
- # Set the working directory in the container
9
- WORKDIR /app
10
-
11
- # Copy the requirements file into the container
12
- COPY requirements.txt .
13
-
14
- # Install dependencies
15
- RUN pip install --no-cache-dir -r requirements.txt
16
-
17
- # Copy the rest of the application code
18
- COPY . .
19
-
20
- # Expose port 8000
21
- EXPOSE 8000
22
-
23
- # Command to run the application
24
- CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/routers/admin.py CHANGED
@@ -563,7 +563,66 @@ from services.chatbot_service import (
563
  process_chatbot_query,
564
  update_student_info,
565
  generate_excel,
 
566
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567
 
568
 
569
  @router.post("/chatbot/query")
 
563
  process_chatbot_query,
564
  update_student_info,
565
  generate_excel,
566
+ filter_students_structured,
567
  )
568
+ from schemas.admin import StudentFilterRequest, StudentFilterExportRequest
569
+
570
+
571
+ @router.post("/students/filter")
572
+ async def students_filter(
573
+ request: StudentFilterRequest,
574
+ current_user: dict = Depends(require_role("admin")),
575
+ ):
576
+ """Structured student filter — no AI, direct params (sort + date range + multi-test)."""
577
+ try:
578
+ result = await filter_students_structured(
579
+ group_test_ids=request.group_test_ids,
580
+ jd_id=request.jd_id,
581
+ start_date=request.start_date,
582
+ end_date=request.end_date,
583
+ top_k=request.top_k,
584
+ min_score=request.min_score,
585
+ sort_fields=request.sort_fields,
586
+ sort_orders=request.sort_orders,
587
+ )
588
+ return result
589
+ except Exception as e:
590
+ raise HTTPException(status_code=500, detail=str(e))
591
+
592
+
593
+ @router.post("/students/export-excel")
594
+ async def students_export_excel(
595
+ request: StudentFilterExportRequest,
596
+ current_user: dict = Depends(require_role("admin")),
597
+ ):
598
+ """Generate styled Excel for structured student filter results."""
599
+ try:
600
+ bio = generate_excel(
601
+ rows=request.rows,
602
+ topic_columns=request.topic_columns,
603
+ group_test_name=request.group_test_name,
604
+ )
605
+ safe_name = request.group_test_name.replace(" ", "_").replace("/", "-")[:40]
606
+ filename = f"{safe_name}_students.xlsx"
607
+ return StreamingResponse(
608
+ bio,
609
+ media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
610
+ headers={"Content-Disposition": f'attachment; filename="{filename}"'},
611
+ )
612
+ except Exception as e:
613
+ raise HTTPException(status_code=500, detail=str(e))
614
+
615
+
616
+ @router.patch("/students")
617
+ async def update_student(
618
+ request: ChatbotStudentUpdate,
619
+ current_user: dict = Depends(require_role("admin")),
620
+ ):
621
+ """Admin corrects a student's reg_no or name (shared by both filter endpoints)."""
622
+ try:
623
+ return await update_student_info(request.user_id, request.reg_no, request.name)
624
+ except ValueError as e:
625
+ raise HTTPException(status_code=400, detail=str(e))
626
 
627
 
628
  @router.post("/chatbot/query")
backend/schemas/admin.py CHANGED
@@ -111,7 +111,7 @@ class RoleRequirementResponse(BaseModel):
111
  level: str
112
 
113
 
114
- # ── Chatbot ───────────────────────────────────────────────────────────────────
115
 
116
  class ChatbotQueryRequest(BaseModel):
117
  query: str
@@ -128,3 +128,22 @@ class ChatbotStudentUpdate(BaseModel):
128
  user_id: str
129
  reg_no: Optional[str] = None
130
  name: Optional[str] = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  level: str
112
 
113
 
114
+ # ── Chatbot (legacy) ──────────────────────────────────────────────────────────
115
 
116
  class ChatbotQueryRequest(BaseModel):
117
  query: str
 
128
  user_id: str
129
  reg_no: Optional[str] = None
130
  name: Optional[str] = None
131
+
132
+
133
+ # ── Structured Student Filter ─────────────────────────────────────────────────
134
+
135
+ class StudentFilterRequest(BaseModel):
136
+ group_test_ids: Optional[List[str]] = None # None = all tests
137
+ jd_id: Optional[str] = None
138
+ start_date: Optional[str] = None # "YYYY-MM-DD"
139
+ end_date: Optional[str] = None # "YYYY-MM-DD"
140
+ top_k: Optional[int] = None
141
+ min_score: Optional[float] = None
142
+ sort_fields: List[str] = ["time"] # ordered priority: "time"|"score"|"duration"
143
+ sort_orders: List[str] = ["desc"] # matching orders: "asc"|"desc"
144
+
145
+
146
+ class StudentFilterExportRequest(BaseModel):
147
+ rows: List[dict]
148
+ topic_columns: List[dict]
149
+ group_test_name: str
backend/services/chatbot_service.py CHANGED
@@ -3,6 +3,7 @@
3
  import json
4
  import re
5
  from collections import defaultdict
 
6
  from io import BytesIO
7
 
8
  from bson import ObjectId
@@ -403,3 +404,263 @@ def generate_excel(rows: list[dict], topic_columns: list[dict], group_test_name:
403
  wb.save(bio)
404
  bio.seek(0)
405
  return bio
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import json
4
  import re
5
  from collections import defaultdict
6
+ from datetime import datetime, timezone, timedelta
7
  from io import BytesIO
8
 
9
  from bson import ObjectId
 
404
  wb.save(bio)
405
  bio.seek(0)
406
  return bio
407
+
408
+
409
+ # ─── Structured Student Filter (no Gemini) ───────────────────────────────────
410
+
411
+ def _parse_date(date_str: str | None, end_of_day: bool = False):
412
+ """Parse YYYY-MM-DD string to UTC-aware datetime, or None."""
413
+ if not date_str:
414
+ return None
415
+ try:
416
+ dt = datetime.strptime(date_str.strip(), "%Y-%m-%d").replace(tzinfo=timezone.utc)
417
+ if end_of_day:
418
+ dt = dt + timedelta(days=1)
419
+ return dt
420
+ except ValueError:
421
+ return None
422
+
423
+
424
+ def _compute_duration(started_at, completed_at) -> float | None:
425
+ """Duration in minutes, rounded to 1 dp. Returns None if either timestamp missing."""
426
+ if started_at is None or completed_at is None:
427
+ return None
428
+ try:
429
+ # Handle both datetime objects and ISO strings
430
+ if isinstance(started_at, str):
431
+ started_at = datetime.fromisoformat(started_at.replace("Z", "+00:00"))
432
+ if isinstance(completed_at, str):
433
+ completed_at = datetime.fromisoformat(completed_at.replace("Z", "+00:00"))
434
+ delta = completed_at - started_at
435
+ return round(max(delta.total_seconds(), 0) / 60, 1)
436
+ except Exception:
437
+ return None
438
+
439
+
440
+ async def filter_students_structured(
441
+ group_test_ids: list[str] | None,
442
+ jd_id: str | None,
443
+ start_date: str | None,
444
+ end_date: str | None,
445
+ top_k: int | None,
446
+ min_score: float | None,
447
+ sort_fields: list[str] | None = None,
448
+ sort_orders: list[str] | None = None,
449
+ ) -> dict:
450
+ """Structured student filter — no Gemini, explicit params, composable."""
451
+ db = get_db()
452
+
453
+ # ── Fetch all group tests for metadata ────────────────────────────────────
454
+ gt_cursor = db[GROUP_TESTS].find({}).sort("created_at", -1)
455
+ gt_docs = await gt_cursor.to_list(length=300)
456
+ all_group_tests: dict[str, dict] = {
457
+ str(d["_id"]): {
458
+ "id": str(d["_id"]),
459
+ "name": d.get("name", ""),
460
+ "topic_ids": d.get("topic_ids") or [],
461
+ }
462
+ for d in gt_docs
463
+ }
464
+
465
+ # ── Fetch JD info if provided ─────────────────────────────────────────────
466
+ jd_content, jd_req_skills = (None, [])
467
+ if jd_id:
468
+ jd_content, jd_req_skills = await _jd_skills(jd_id, db)
469
+ use_jd_ranking = bool(jd_req_skills)
470
+
471
+ # ── Build MongoDB query ───────────────────────────────────────────────────
472
+ results_filter: dict = {}
473
+
474
+ if group_test_ids:
475
+ results_filter["group_test_id"] = {"$in": group_test_ids}
476
+
477
+ start_dt = _parse_date(start_date, end_of_day=False)
478
+ end_dt = _parse_date(end_date, end_of_day=True)
479
+ if start_dt or end_dt:
480
+ date_filter: dict = {}
481
+ if start_dt:
482
+ date_filter["$gte"] = start_dt
483
+ if end_dt:
484
+ date_filter["$lt"] = end_dt
485
+ results_filter["started_at"] = date_filter
486
+
487
+ results_cursor = db[GROUP_TEST_RESULTS].find(results_filter)
488
+ results_docs = await results_cursor.to_list(length=3000)
489
+
490
+ # ── Collect topic columns from selected group tests ───────────────────────
491
+ selected_gt_ids: set[str] = (
492
+ set(group_test_ids) if group_test_ids
493
+ else {str(d["_id"]) for d in gt_docs}
494
+ )
495
+
496
+ topic_columns: list[dict] = []
497
+ topic_seen: set[str] = set()
498
+ group_test_name = "All Group Tests"
499
+
500
+ if group_test_ids and len(group_test_ids) == 1:
501
+ gt = all_group_tests.get(group_test_ids[0])
502
+ if gt:
503
+ group_test_name = gt["name"]
504
+ for tid in gt["topic_ids"]:
505
+ if tid not in topic_seen:
506
+ topic_seen.add(tid)
507
+ try:
508
+ t = await db[TOPICS].find_one({"_id": ObjectId(tid)})
509
+ except Exception:
510
+ t = None
511
+ if t:
512
+ topic_columns.append({"id": tid, "name": t.get("name", tid)})
513
+ elif group_test_ids and len(group_test_ids) > 1:
514
+ names = [all_group_tests[gid]["name"] for gid in group_test_ids if gid in all_group_tests]
515
+ group_test_name = ", ".join(names) if names else "Multiple Tests"
516
+ for gid in group_test_ids:
517
+ gt = all_group_tests.get(gid)
518
+ if not gt:
519
+ continue
520
+ for tid in gt["topic_ids"]:
521
+ if tid not in topic_seen:
522
+ topic_seen.add(tid)
523
+ try:
524
+ t = await db[TOPICS].find_one({"_id": ObjectId(tid)})
525
+ except Exception:
526
+ t = None
527
+ if t:
528
+ topic_columns.append({"id": tid, "name": t.get("name", tid)})
529
+
530
+ # ── Group by (user_id, group_test_id) → pick best attempt ────────────────
531
+ attempts_map: dict[tuple, list] = defaultdict(list)
532
+ for r in results_docs:
533
+ uid = r.get("user_id", "")
534
+ gtid = r.get("group_test_id", "")
535
+ if uid:
536
+ attempts_map[(uid, gtid)].append(r)
537
+
538
+ rows: list[dict] = []
539
+
540
+ for (uid, gt_id), attempts in attempts_map.items():
541
+ best = None
542
+ for attempt in attempts:
543
+ attempt = await _refresh_topic_statuses(attempt, db)
544
+ score = attempt.get("overall_score") or 0
545
+ if best is None or score > (best.get("overall_score") or 0):
546
+ best = attempt
547
+
548
+ user = await _user_info(uid, db)
549
+
550
+ # Per-topic scores
551
+ topic_scores: dict[str, dict] = {}
552
+ for tr in best.get("topic_results") or []:
553
+ tid = tr.get("topic_id", "")
554
+ topic_scores[tid] = {
555
+ "topic_name": tr.get("topic_name", ""),
556
+ "score": tr.get("overall_score"),
557
+ "status": tr.get("status", "pending"),
558
+ }
559
+
560
+ # JD skill match
561
+ skill_match: float | None = None
562
+ if use_jd_ranking:
563
+ skills_doc = await db[SKILLS].find_one({"user_id": uid})
564
+ student_skills = (skills_doc or {}).get("skills") or []
565
+ skill_match = _skill_match_pct(student_skills, jd_req_skills)
566
+
567
+ # Attempt time & duration
568
+ started_at = best.get("started_at")
569
+ completed_at = best.get("completed_at")
570
+ attempt_time: str | None = None
571
+ if started_at is not None:
572
+ try:
573
+ attempt_time = started_at.isoformat() if isinstance(started_at, datetime) else str(started_at)
574
+ except Exception:
575
+ attempt_time = None
576
+
577
+ # Collect topic columns dynamically when showing all tests
578
+ if not group_test_ids:
579
+ gt = all_group_tests.get(gt_id)
580
+ if gt:
581
+ for tid in gt["topic_ids"]:
582
+ if tid not in topic_seen:
583
+ topic_seen.add(tid)
584
+ try:
585
+ t = await db[TOPICS].find_one({"_id": ObjectId(tid)})
586
+ except Exception:
587
+ t = None
588
+ if t:
589
+ topic_columns.append({"id": tid, "name": t.get("name", tid)})
590
+
591
+ gt_info = all_group_tests.get(gt_id, {})
592
+
593
+ row = {
594
+ "user_id": uid,
595
+ "reg_no": user["reg_no"],
596
+ "name": user["name"],
597
+ "email": user["email"],
598
+ "group_test_id": gt_id,
599
+ "group_test_name": best.get("group_test_name") or gt_info.get("name", ""),
600
+ "overall_score": round(best.get("overall_score") or 0, 1),
601
+ "total_attempts": len(attempts),
602
+ "status": best.get("status", "in_progress"),
603
+ "topic_scores": topic_scores,
604
+ "skill_match": skill_match,
605
+ "rank": 0,
606
+ "attempt_time": attempt_time,
607
+ "duration_minutes": _compute_duration(started_at, completed_at),
608
+ }
609
+ rows.append(row)
610
+
611
+ # ── Min score filter ──────────────────────────────────────────────────────
612
+ if min_score is not None:
613
+ rows = [r for r in rows if (r["overall_score"] or 0) >= min_score]
614
+
615
+ # ── Multi-sort ────────────────────────────────────────────────────────────
616
+ _fields = sort_fields if sort_fields else ["time"]
617
+ _orders = sort_orders if sort_orders else ["desc"]
618
+ _INF = float("inf")
619
+ _NEG_INF = float("-inf")
620
+
621
+ def _row_key(r: dict, field: str, order: str):
622
+ """Return a comparable key, handling None with order-aware sentinel."""
623
+ desc = order.lower() == "desc"
624
+ if field == "score":
625
+ v = r.get("overall_score") or 0
626
+ return -v if desc else v
627
+ elif field == "duration":
628
+ v = r.get("duration_minutes")
629
+ if v is None:
630
+ return _INF # always sort None to end
631
+ return -v if desc else v
632
+ else: # "time"
633
+ v = r.get("attempt_time") or ""
634
+ # For strings, desc means we negate via reverse tuple trick below
635
+ return v
636
+
637
+ # Apply sorts in reverse priority order (stable sort)
638
+ paired = list(zip(_fields, _orders))
639
+ for field, order in reversed(paired):
640
+ desc = order.lower() == "desc"
641
+ if field == "time":
642
+ rows.sort(key=lambda r: r.get("attempt_time") or "", reverse=desc)
643
+ elif field == "score":
644
+ rows.sort(key=lambda r: r.get("overall_score") or 0, reverse=desc)
645
+ elif field == "duration":
646
+ rows.sort(
647
+ key=lambda r: r["duration_minutes"] if r["duration_minutes"] is not None
648
+ else (_NEG_INF if desc else _INF),
649
+ reverse=desc,
650
+ )
651
+
652
+ # ── Assign ranks ──────────────────────────────────────────────────────────
653
+ for i, row in enumerate(rows):
654
+ row["rank"] = i + 1
655
+
656
+ # ── Top-K slice ───────────────────────────────────────────────────────────
657
+ if top_k and top_k > 0:
658
+ rows = rows[:top_k]
659
+
660
+ return {
661
+ "group_test_name": group_test_name,
662
+ "group_test_id": group_test_ids[0] if group_test_ids and len(group_test_ids) == 1 else None,
663
+ "topic_columns": topic_columns,
664
+ "rows": rows,
665
+ "total": len(rows),
666
+ }
resume-jd-verification-2026-04-10T05-15-44-248Z.pdf DELETED
@@ -1,646 +0,0 @@
1
- %PDF-1.3
2
- %�߬�
3
- 3 0 obj
4
- <</Type /Page
5
- /Parent 1 0 R
6
- /Resources 2 0 R
7
- /MediaBox [0 0 595.2799999999999727 841.8899999999999864]
8
- /Contents 4 0 R
9
- >>
10
- endobj
11
- 4 0 obj
12
- <<
13
- /Length 5607
14
- >>
15
- stream
16
- 0.200025 w
17
- 0 G
18
- BT
19
- /F2 16 Tf
20
- 18.3999999999999986 TL
21
- 0 g
22
- 40. 795.8899999999999864 Td
23
- (Resume vs Job Description Verification) Tj
24
- ET
25
- BT
26
- /F2 11 Tf
27
- 12.6499999999999986 TL
28
- 0 g
29
- 40. 771.8899999999999864 Td
30
- (Verification ID:) Tj
31
- ET
32
- BT
33
- /F1 11 Tf
34
- 12.6499999999999986 TL
35
- 0 g
36
- 130. 771.8899999999999864 Td
37
- (b5519c4e-2ab1-4bbd-a5ca-ff133b558b5b) Tj
38
- ET
39
- BT
40
- /F2 11 Tf
41
- 12.6499999999999986 TL
42
- 0 g
43
- 40. 753.8899999999999864 Td
44
- (Saved At:) Tj
45
- ET
46
- BT
47
- /F1 11 Tf
48
- 12.6499999999999986 TL
49
- 0 g
50
- 130. 753.8899999999999864 Td
51
- (4/10/2026, 10:45:29 AM) Tj
52
- ET
53
- BT
54
- /F2 11 Tf
55
- 12.6499999999999986 TL
56
- 0 g
57
- 40. 735.8899999999999864 Td
58
- (Role:) Tj
59
- ET
60
- BT
61
- /F1 11 Tf
62
- 12.6499999999999986 TL
63
- 0 g
64
- 130. 735.8899999999999864 Td
65
- (Generative AI Engineer) Tj
66
- ET
67
- BT
68
- /F2 16 Tf
69
- 18.3999999999999986 TL
70
- 0 g
71
- 40. 711.8899999999999864 Td
72
- (Job Description Snapshot) Tj
73
- ET
74
- BT
75
- /F2 11 Tf
76
- 12.6499999999999986 TL
77
- 0 g
78
- 40. 687.8899999999999864 Td
79
- (JD Title:) Tj
80
- ET
81
- BT
82
- /F1 11 Tf
83
- 12.6499999999999986 TL
84
- 0 g
85
- 130. 687.8899999999999864 Td
86
- (AI Engineering Intern) Tj
87
- ET
88
- BT
89
- /F2 11 Tf
90
- 12.6499999999999986 TL
91
- 0 g
92
- 40. 669.8899999999999864 Td
93
- (Company:) Tj
94
- ET
95
- BT
96
- /F1 11 Tf
97
- 12.6499999999999986 TL
98
- 0 g
99
- 130. 669.8899999999999864 Td
100
- (-) Tj
101
- ET
102
- BT
103
- /F2 11 Tf
104
- 12.6499999999999986 TL
105
- 0 g
106
- 40. 651.8899999999999864 Td
107
- (Required Skills:) Tj
108
- ET
109
- BT
110
- /F1 11 Tf
111
- 12.6499999999999986 TL
112
- 0 g
113
- 130. 651.8899999999999864 Td
114
- (Basic understanding of Machine Learning concepts \(supervised/unsupervised learning\),) Tj
115
- T* (Familiarity with Python and libraries like NumPy, Pandas, Scikit-learn, Knowledge of) Tj
116
- T* (deep learning frameworks \(e.g., TensorFlow or PyTorch\) is a plus Strong analytical and) Tj
117
- T* (problem-solving skills) Tj
118
- ET
119
- BT
120
- /F2 11 Tf
121
- 12.6499999999999986 TL
122
- 0 g
123
- 40. 595.8899999999999864 Td
124
- (JD Description:) Tj
125
- ET
126
- BT
127
- /F1 11 Tf
128
- 12.6499999999999986 TL
129
- 0 g
130
- 130. 595.8899999999999864 Td
131
- (Key Responsibilities) Tj
132
- T* () Tj
133
- T* (Assist in developing and implementing AI/ML models and algorithms) Tj
134
- T* (Work on data preprocessing, cleaning, and analysis) Tj
135
- T* (Support model training, evaluation, and optimization) Tj
136
- T* (Conduct research on the latest AI trends and technologies) Tj
137
- T* (Collaborate with engineers and product teams to integrate AI solutions) Tj
138
- T* (Document experiments, processes, and results) Tj
139
- T* (Participate in brainstorming and problem-solving sessions) Tj
140
- ET
141
- BT
142
- /F2 16 Tf
143
- 18.3999999999999986 TL
144
- 0 g
145
- 40. 463.8899999999999864 Td
146
- (Resume Snapshot) Tj
147
- ET
148
- BT
149
- /F2 11 Tf
150
- 12.6499999999999986 TL
151
- 0 g
152
- 40. 439.8899999999999864 Td
153
- (Resume File:) Tj
154
- ET
155
- BT
156
- /F1 11 Tf
157
- 12.6499999999999986 TL
158
- 0 g
159
- 130. 439.8899999999999864 Td
160
- (Resume.pdf) Tj
161
- ET
162
- BT
163
- /F2 11 Tf
164
- 12.6499999999999986 TL
165
- 0 g
166
- 40. 421.8899999999999864 Td
167
- (Candidate:) Tj
168
- ET
169
- BT
170
- /F1 11 Tf
171
- 12.6499999999999986 TL
172
- 0 g
173
- 130. 421.8899999999999864 Td
174
- (SAJITH J) Tj
175
- ET
176
- BT
177
- /F2 11 Tf
178
- 12.6499999999999986 TL
179
- 0 g
180
- 40. 403.8899999999999864 Td
181
- (Email:) Tj
182
- ET
183
- BT
184
- /F1 11 Tf
185
- 12.6499999999999986 TL
186
- 0 g
187
- 130. 403.8899999999999864 Td
188
- (jsajith76@gmail.com) Tj
189
- ET
190
- BT
191
- /F2 11 Tf
192
- 12.6499999999999986 TL
193
- 0 g
194
- 40. 385.8899999999999864 Td
195
- (Phone:) Tj
196
- ET
197
- BT
198
- /F1 11 Tf
199
- 12.6499999999999986 TL
200
- 0 g
201
- 130. 385.8899999999999864 Td
202
- (+91 8637440071) Tj
203
- ET
204
- BT
205
- /F2 11 Tf
206
- 12.6499999999999986 TL
207
- 0 g
208
- 40. 367.8899999999999864 Td
209
- (Location:) Tj
210
- ET
211
- BT
212
- /F1 11 Tf
213
- 12.6499999999999986 TL
214
- 0 g
215
- 130. 367.8899999999999864 Td
216
- (Coimbatore, India) Tj
217
- ET
218
- BT
219
- /F2 11 Tf
220
- 12.6499999999999986 TL
221
- 0 g
222
- 40. 349.8899999999999864 Td
223
- (Extracted Skills:) Tj
224
- ET
225
- BT
226
- /F1 11 Tf
227
- 12.6499999999999986 TL
228
- 0 g
229
- 130. 349.8899999999999864 Td
230
- (Python, SQL, RAG Pipelines, Semantic Search, Embedding Models, Vector Similarity) Tj
231
- T* (Search, Prompt Engineering, LangChain, LangGraph, LangSmith, CNN, Transformers,) Tj
232
- T* (BERT Fine-tuning, RNN, LSTM, GRU, Encoder Decoder, GAN, Pinecone, ChromaDB,) Tj
233
- T* (MySQL, FastAPI, Docker, Git, Github, Sentence Transformers, Scikit-learn, Llama 4,) Tj
234
- T* (Gemini API, E5 Multilingual Embeddings, OCR Based Extraction, PyTorch, BERT) Tj
235
- ET
236
- BT
237
- /F2 11 Tf
238
- 12.6499999999999986 TL
239
- 0 g
240
- 40. 279.8899999999999864 Td
241
- (Experience Summary:) Tj
242
- ET
243
- BT
244
- /F1 11 Tf
245
- 12.6499999999999986 TL
246
- 0 g
247
- 130. 279.8899999999999864 Td
248
- (AI & Data Science undergraduate with practical experience in architecting and) Tj
249
- T* (deploying end-to-end AI systems, specializing in Deep Learning, RAG pipelines, and) Tj
250
- T* (multimodal modeling.) Tj
251
- ET
252
- BT
253
- /F2 16 Tf
254
- 18.3999999999999986 TL
255
- 0 g
256
- 40. 231.8899999999999864 Td
257
- (Alignment Result) Tj
258
- ET
259
- BT
260
- /F2 11 Tf
261
- 12.6499999999999986 TL
262
- 0 g
263
- 40. 207.8899999999999864 Td
264
- (Fit Summary:) Tj
265
- ET
266
- BT
267
- /F1 11 Tf
268
- 12.6499999999999986 TL
269
- 0 g
270
- 130. 207.8899999999999864 Td
271
- (The student presents an exceptional fit for the Generative AI Engineer Intern role,) Tj
272
- T* (showcasing a strong academic foundation in AI/Data Science, practical deployment) Tj
273
- T* (experience, and highly specialized skills in Generative AI, RAG pipelines, and LLM) Tj
274
- T* (development. Their demonstrated proficiency in PyTorch and MLOps tools directly) Tj
275
- T* (aligns with the job's core responsibilities and 'plus' qualifications.) Tj
276
- ET
277
- BT
278
- /F2 12 Tf
279
- 13.7999999999999989 TL
280
- 0 g
281
- 40. 137.8899999999999864 Td
282
- (Meeting Expectations) Tj
283
- ET
284
- BT
285
- /F1 11 Tf
286
- 12.6499999999999986 TL
287
- 0 g
288
- 46. 121.8899999999999864 Td
289
- (- Strong foundation in Python and deep learning frameworks, specifically PyTorch, aligning with the) Tj
290
- T* ('Knowledge of deep learning frameworks \(e.g., TensorFlow or PyTorch\) is a plus' requirement.) Tj
291
- ET
292
- BT
293
- /F1 11 Tf
294
- 12.6499999999999986 TL
295
- 0 g
296
- 46. 93.8899999999999864 Td
297
- (- Extensive experience with Machine Learning concepts and models, including CNN, Transformers,) Tj
298
- T* (BERT, RNN, LSTM, GRU, Encoder Decoder, and GANs, demonstrating a robust understanding of AI/ML) Tj
299
- T* (models and algorithms.) Tj
300
- ET
301
- endstream
302
- endobj
303
- 5 0 obj
304
- <</Type /Page
305
- /Parent 1 0 R
306
- /Resources 2 0 R
307
- /MediaBox [0 0 595.2799999999999727 841.8899999999999864]
308
- /Contents 6 0 R
309
- >>
310
- endobj
311
- 6 0 obj
312
- <<
313
- /Length 3330
314
- >>
315
- stream
316
- 0.200025 w
317
- 0 G
318
- BT
319
- /F1 11 Tf
320
- 12.6499999999999986 TL
321
- 0 g
322
- 46. 795.8899999999999864 Td
323
- (- Direct and highly relevant skills in Generative AI, RAG Pipelines, Semantic Search, Embedding) Tj
324
- T* (Models, Vector Similarity Search, and Prompt Engineering, which directly supports 'developing and) Tj
325
- T* (implementing AI/ML models and algorithms' for a Generative AI role.) Tj
326
- ET
327
- BT
328
- /F1 11 Tf
329
- 12.6499999999999986 TL
330
- 0 g
331
- 46. 753.8899999999999864 Td
332
- (- Familiarity with key ML/DL libraries like Scikit-learn, which is explicitly mentioned as a required skill.) Tj
333
- ET
334
- BT
335
- /F1 11 Tf
336
- 12.6499999999999986 TL
337
- 0 g
338
- 46. 739.8899999999999864 Td
339
- (- Practical experience with MLOps and deployment tools such as FastAPI, Docker, Git, and Github,) Tj
340
- T* (indicating the ability to 'integrate AI solutions'.) Tj
341
- ET
342
- BT
343
- /F1 11 Tf
344
- 12.6499999999999986 TL
345
- 0 g
346
- 46. 711.8899999999999864 Td
347
- (- Experience with LLMs like Llama 4, Gemini API, and fine-tuning BERT, showing proactive 'research on) Tj
348
- T* (the latest AI trends and technologies'.) Tj
349
- ET
350
- BT
351
- /F1 11 Tf
352
- 12.6499999999999986 TL
353
- 0 g
354
- 46. 683.8899999999999864 Td
355
- (- Skills in managing data for AI, including Pinecone, ChromaDB, MySQL, and OCR Based Extraction,) Tj
356
- T* (relevant to 'data preprocessing, cleaning, and analysis' and 'model training, evaluation, and optimization'.) Tj
357
- ET
358
- BT
359
- /F1 11 Tf
360
- 12.6499999999999986 TL
361
- 0 g
362
- 46. 655.8899999999999864 Td
363
- (- The resume summary highlights 'architecting and deploying end-to-end AI systems', which implies) Tj
364
- T* (strong analytical and problem-solving skills, as well as the ability to 'collaborate with engineers and) Tj
365
- T* (product teams'.) Tj
366
- ET
367
- BT
368
- /F2 12 Tf
369
- 13.7999999999999989 TL
370
- 0 g
371
- 40. 607.8899999999999864 Td
372
- (Missing Expectations) Tj
373
- ET
374
- BT
375
- /F1 11 Tf
376
- 12.6499999999999986 TL
377
- 0 g
378
- 46. 591.8899999999999864 Td
379
- (- While likely used, specific mention of 'NumPy' and 'Pandas' as explicit skills is absent from the resume.) Tj
380
- ET
381
- BT
382
- /F1 11 Tf
383
- 12.6499999999999986 TL
384
- 0 g
385
- 46. 577.8899999999999864 Td
386
- (- The resume could more explicitly detail experience in 'data preprocessing, cleaning, and analysis' for) Tj
387
- T* (diverse datasets, beyond what's implied by 'RAG Pipelines' and 'OCR Based Extraction'.) Tj
388
- ET
389
- BT
390
- /F2 12 Tf
391
- 13.7999999999999989 TL
392
- 0 g
393
- 40. 543.8899999999999864 Td
394
- (Improvement Suggestions) Tj
395
- ET
396
- BT
397
- /F1 11 Tf
398
- 12.6499999999999986 TL
399
- 0 g
400
- 46. 527.8899999999999864 Td
401
- (- Add 'NumPy' and 'Pandas' to your skills list if you have experience with them, as they are foundational) Tj
402
- T* (for data manipulation in Python.) Tj
403
- ET
404
- BT
405
- /F1 11 Tf
406
- 12.6499999999999986 TL
407
- 0 g
408
- 46. 499.8899999999999864 Td
409
- (- Prepare specific examples from past projects where you handled significant 'data preprocessing,) Tj
410
- T* (cleaning, and analysis' challenges, detailing the techniques used and the impact.) Tj
411
- ET
412
- BT
413
- /F1 11 Tf
414
- 12.6499999999999986 TL
415
- 0 g
416
- 46. 471.8899999999999864 Td
417
- (- When discussing projects, explicitly highlight your contributions to 'documenting experiments,) Tj
418
- T* (processes, and results' and examples of 'collaborating with engineers and product teams' to showcase) Tj
419
- T* (teamwork and communication skills.) Tj
420
- ET
421
- BT
422
- /F1 11 Tf
423
- 12.6499999999999986 TL
424
- 0 g
425
- 46. 429.8899999999999864 Td
426
- (- Quantify your experience where possible \(e.g., 'deployed X RAG pipelines serving Y users', 'improved) Tj
427
- T* (model performance by Z%'\), to demonstrate impact and scale.) Tj
428
- ET
429
- endstream
430
- endobj
431
- 1 0 obj
432
- <</Type /Pages
433
- /Kids [3 0 R 5 0 R ]
434
- /Count 2
435
- >>
436
- endobj
437
- 7 0 obj
438
- <<
439
- /Type /Font
440
- /BaseFont /Helvetica
441
- /Subtype /Type1
442
- /Encoding /WinAnsiEncoding
443
- /FirstChar 32
444
- /LastChar 255
445
- >>
446
- endobj
447
- 8 0 obj
448
- <<
449
- /Type /Font
450
- /BaseFont /Helvetica-Bold
451
- /Subtype /Type1
452
- /Encoding /WinAnsiEncoding
453
- /FirstChar 32
454
- /LastChar 255
455
- >>
456
- endobj
457
- 9 0 obj
458
- <<
459
- /Type /Font
460
- /BaseFont /Helvetica-Oblique
461
- /Subtype /Type1
462
- /Encoding /WinAnsiEncoding
463
- /FirstChar 32
464
- /LastChar 255
465
- >>
466
- endobj
467
- 10 0 obj
468
- <<
469
- /Type /Font
470
- /BaseFont /Helvetica-BoldOblique
471
- /Subtype /Type1
472
- /Encoding /WinAnsiEncoding
473
- /FirstChar 32
474
- /LastChar 255
475
- >>
476
- endobj
477
- 11 0 obj
478
- <<
479
- /Type /Font
480
- /BaseFont /Courier
481
- /Subtype /Type1
482
- /Encoding /WinAnsiEncoding
483
- /FirstChar 32
484
- /LastChar 255
485
- >>
486
- endobj
487
- 12 0 obj
488
- <<
489
- /Type /Font
490
- /BaseFont /Courier-Bold
491
- /Subtype /Type1
492
- /Encoding /WinAnsiEncoding
493
- /FirstChar 32
494
- /LastChar 255
495
- >>
496
- endobj
497
- 13 0 obj
498
- <<
499
- /Type /Font
500
- /BaseFont /Courier-Oblique
501
- /Subtype /Type1
502
- /Encoding /WinAnsiEncoding
503
- /FirstChar 32
504
- /LastChar 255
505
- >>
506
- endobj
507
- 14 0 obj
508
- <<
509
- /Type /Font
510
- /BaseFont /Courier-BoldOblique
511
- /Subtype /Type1
512
- /Encoding /WinAnsiEncoding
513
- /FirstChar 32
514
- /LastChar 255
515
- >>
516
- endobj
517
- 15 0 obj
518
- <<
519
- /Type /Font
520
- /BaseFont /Times-Roman
521
- /Subtype /Type1
522
- /Encoding /WinAnsiEncoding
523
- /FirstChar 32
524
- /LastChar 255
525
- >>
526
- endobj
527
- 16 0 obj
528
- <<
529
- /Type /Font
530
- /BaseFont /Times-Bold
531
- /Subtype /Type1
532
- /Encoding /WinAnsiEncoding
533
- /FirstChar 32
534
- /LastChar 255
535
- >>
536
- endobj
537
- 17 0 obj
538
- <<
539
- /Type /Font
540
- /BaseFont /Times-Italic
541
- /Subtype /Type1
542
- /Encoding /WinAnsiEncoding
543
- /FirstChar 32
544
- /LastChar 255
545
- >>
546
- endobj
547
- 18 0 obj
548
- <<
549
- /Type /Font
550
- /BaseFont /Times-BoldItalic
551
- /Subtype /Type1
552
- /Encoding /WinAnsiEncoding
553
- /FirstChar 32
554
- /LastChar 255
555
- >>
556
- endobj
557
- 19 0 obj
558
- <<
559
- /Type /Font
560
- /BaseFont /ZapfDingbats
561
- /Subtype /Type1
562
- /FirstChar 32
563
- /LastChar 255
564
- >>
565
- endobj
566
- 20 0 obj
567
- <<
568
- /Type /Font
569
- /BaseFont /Symbol
570
- /Subtype /Type1
571
- /FirstChar 32
572
- /LastChar 255
573
- >>
574
- endobj
575
- 2 0 obj
576
- <<
577
- /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
578
- /Font <<
579
- /F1 7 0 R
580
- /F2 8 0 R
581
- /F3 9 0 R
582
- /F4 10 0 R
583
- /F5 11 0 R
584
- /F6 12 0 R
585
- /F7 13 0 R
586
- /F8 14 0 R
587
- /F9 15 0 R
588
- /F10 16 0 R
589
- /F11 17 0 R
590
- /F12 18 0 R
591
- /F13 19 0 R
592
- /F14 20 0 R
593
- >>
594
- /XObject <<
595
- >>
596
- >>
597
- endobj
598
- 21 0 obj
599
- <<
600
- /Producer (jsPDF 4.2.1)
601
- /CreationDate (D:20260410104544+05'30')
602
- >>
603
- endobj
604
- 22 0 obj
605
- <<
606
- /Type /Catalog
607
- /Pages 1 0 R
608
- /OpenAction [3 0 R /FitH null]
609
- /PageLayout /OneColumn
610
- >>
611
- endobj
612
- xref
613
- 0 23
614
- 0000000000 65535 f
615
- 0000009330 00000 n
616
- 0000011155 00000 n
617
- 0000000015 00000 n
618
- 0000000152 00000 n
619
- 0000005811 00000 n
620
- 0000005948 00000 n
621
- 0000009393 00000 n
622
- 0000009518 00000 n
623
- 0000009648 00000 n
624
- 0000009781 00000 n
625
- 0000009919 00000 n
626
- 0000010043 00000 n
627
- 0000010172 00000 n
628
- 0000010304 00000 n
629
- 0000010440 00000 n
630
- 0000010568 00000 n
631
- 0000010695 00000 n
632
- 0000010824 00000 n
633
- 0000010957 00000 n
634
- 0000011059 00000 n
635
- 0000011405 00000 n
636
- 0000011491 00000 n
637
- trailer
638
- <<
639
- /Size 23
640
- /Root 22 0 R
641
- /Info 21 0 R
642
- /ID [ <95A654D90B03BE650BD8733007BC1C07> <95A654D90B03BE650BD8733007BC1C07> ]
643
- >>
644
- startxref
645
- 11595
646
- %%EOF