diff --git a/public/.well-known/ai-plugin.json b/public/.well-known/ai-plugin.json index a109886..6712c0b 100644 --- a/public/.well-known/ai-plugin.json +++ b/public/.well-known/ai-plugin.json @@ -12,7 +12,7 @@ "url": "https://rahulap.vercel.app/openapi.yaml", "is_user_authenticated": false }, - "logo_url": "https://rahulap.vercel.app/favicon-192x192.png", - "contact_email": "rahulap.js@example.com", - "legal_info_url": "https://rahulap.vercel.app/contact" + "logo_url": "https://rahulap.vercel.app/favicon192.png", + "contact_email": "itsrahulap@gmail.com", + "legal_info_url": "https://rahulap.vercel.app/" } \ No newline at end of file diff --git a/public/data/projects.json b/public/data/projects.json new file mode 100644 index 0000000..c8d8e60 --- /dev/null +++ b/public/data/projects.json @@ -0,0 +1,86 @@ +[ + { + "name": "EnvScope", + "subtitle": "Context-Aware Frontend Security & Secret Detection Engine", + "description": "A Chrome extension that scans live JavaScript bundles for exposed secrets, combining regex and AST analysis to catch high-risk leaks with low false positives.", + "tech": ["JavaScript", "TypeScript", "Chrome Extensions API", "AST (Acorn)", "Regex Engine", "Web APIs"], + "url": "https://github.com/itsrahulap/EnvScope" + }, + { + "name": "TestPilot", + "subtitle": "Intelligent Bug Detection & Telemetry Chrome Extension", + "description": "A silent telemetry layer for web apps that captures console errors, failed requests, and performance metrics in real time, with no backend required.", + "tech": ["JavaScript", "Chrome Extensions API", "Web APIs", "Performance API"], + "url": "https://github.com/itsrahulap/TestPilot" + }, + { + "name": "AskSQLAI", + "subtitle": "Schema-Aware Natural Language to SQL Generation Engine", + "description": "Converts plain-English questions into safe, executable SQL by introspecting the live database schema, with layered guardrails against hallucinated tables or columns.", + "tech": ["React (Vite)", "TypeScript", "FastAPI", "PostgreSQL", "Gemini 2.5 Flash", "Gemini (Google ADK)", "Python"], + "url": "https://github.com/itsrahulap/AskSQLAI" + }, + { + "name": "MeetlyAI", + "subtitle": "AI-Powered Meeting Notes, Decisions & Action Items Generator", + "description": "Turns raw meeting transcripts into structured summaries, decisions, and owned action items using strict JSON-schema-enforced prompting.", + "tech": ["React (Vite)", "TypeScript", "FastAPI", "Gemini 2.5 Flash", "Gemini (Google ADK)", "Python"], + "url": "https://github.com/itsrahulap/MeetlyAI" + }, + { + "name": "SearchlyAI", + "subtitle": "Session-Based AI Search Engine using RAG over Documents & Web", + "description": "A full RAG pipeline for semantic Q&A over uploaded documents and web pages, using FAISS vector search and Gemini responses grounded strictly in retrieved context.", + "tech": ["React (Vite)", "TypeScript", "FastAPI", "FAISS", "Gemini 2.5 Flash", "Gemini (Google ADK)", "Python"], + "url": "https://github.com/itsrahulap/SearchlyAI" + }, + { + "name": "SemanticFeed", + "subtitle": "AI-Powered Tech News Aggregation & Deduplication Platform", + "description": "Aggregates tech news from multiple sources, deduplicates related articles into unified stories, and generates concise AI summaries via scheduled background jobs.", + "tech": ["React (Vite)", "TypeScript", "Redux", "FastAPI", "PostgreSQL", "Gemini (Google ADK)", "Gemini 2.5 Flash", "Python"], + "url": "https://github.com/itsrahulap/SemanticFeed" + }, + { + "name": "QueryDoc", + "subtitle": "Retrieval-Augmented Document Q&A System", + "description": "A secure RAG chat system for a single uploaded PDF, supporting multi-question conversations with session-isolated vector storage and no stored credentials.", + "tech": ["React (Vite)", "TypeScript", "FastAPI", "FAISS", "Gemini (Google ADK)", "Python"], + "url": "https://github.com/itsrahulap/QueryDoc" + }, + { + "name": "AI-Powered SOAP Note Generator", + "subtitle": "Multi-Agent Medical Assistant", + "description": "A multi-agent pipeline that extracts structured clinical data from patient conversations and generates guideline-backed, safety-checked SOAP notes.", + "tech": ["Python", "Google ADK", "Gemini 2.5 Flash Lite", "Google Search Tool", "InMemoryRunner"], + "url": "https://www.kaggle.com/code/itsrahulap/multi-agent-medical-intake-soap-note-generator" + }, + { + "name": "Readme Creator", + "subtitle": "AI-Powered README Generator", + "description": "A web app for building structured, professional READMEs from templates, with live markdown preview and Gemini-powered content optimization.", + "tech": ["React", "Redux", "Gemini", "Material-UI"], + "url": "https://github.com/itsrahulap/readmeGenerator" + }, + { + "name": "Gemini PDF Analyzer", + "subtitle": "Streamlit + GenAI Resume Parsing Tool", + "description": "Extracts and parses resume PDFs into structured JSON, then generates a polished first-person summary using a selectable Gemini model.", + "tech": ["Streamlit", "Python", "Gemini 1.5 Flash/Pro"], + "url": "https://github.com/itsrahulap/ResumeParserAI" + }, + { + "name": "EasyDiagno", + "subtitle": "AI-Powered Symptom Checker", + "description": "A cross-platform symptom-checking app with a chatbot interface, ML-based diagnosis, and a hospital locator with specialization filters.", + "tech": ["Flutter", "Firebase", "Python", "ML"], + "url": "https://github.com/itsrahulap/EasyDiagno" + }, + { + "name": "Streamify", + "subtitle": "Full Stack Chat App", + "description": "A full-stack real-time messaging and video chat app supporting 100+ concurrent users, with screen sharing and image sharing built in.", + "tech": ["React", "Express", "WebRTC"], + "url": "https://github.com/itsrahulap/streamify" + } +] diff --git a/public/data/resume.json b/public/data/resume.json new file mode 100644 index 0000000..8508b43 --- /dev/null +++ b/public/data/resume.json @@ -0,0 +1,62 @@ +{ + "basics": { + "name": "Rahul AP", + "label": "Software Engineer | Full-Stack & Generative AI Developer", + "location": "Kerala, India" + }, + "contact": { + "email": "itsrahulap@gmail.com", + "linkedin": "https://linkedin.com/in/itsrahulap", + "github": "https://github.com/zccott", + "cv": "https://drive.google.com/file/d/1D4oUwmDywLL6vAoz3bP4P1gr9Emsp3ms/view?usp=sharing" + }, + "education": [ + { + "institution": "Kerala Government Polytechnic College", + "degree": "Diploma in Computer Engineering", + "year": "2021–2024" + } + ], + "experience": [ + { + "company": "AOT Technologies", + "role": "Software Engineer", + "year": "2024–Present", + "description": [ + "Worked across frontend + backend for Canadian healthcare platforms.", + "Angular + MUI + reusable UI components.", + "Integrated REST APIs for user onboarding & appointment systems.", + "Implemented NgRx/RxJS application-wide state.", + "AI fax automation using Python + OpenAI/Gemini + Temporal.", + "Real-time SOAP note tool using FastAPI + WebSockets + Twilio + Whisper." + ] + }, + { + "company": "Nexus Technologies", + "role": "Intern", + "year": "2023–2024", + "description": [ + "Healthcare mobile app (Find doctors by symptoms).", + "Designed UX/UI screens.", + "AI symptom analysis feature.", + "Flutter cross-platform development." + ] + } + ], + "skills": { + "frontend": ["React", "Angular", "TypeScript", "JavaScript (ES6+)", "SCSS", "HTML5", "CSS3"], + "backend": ["Node.js", "Express", "FastAPI", "Python", "PostgreSQL", "MongoDB", "REST APIs"], + "state": ["NgRx", "NGXS", "RxJS", "Redux Toolkit"], + "ai_tools": [ + "GitHub Copilot", + "ChatGPT", + "Gemini CLI / AI Studio", + "Cloud Code (AI-assisted development)", + "Antigravity (AI dev tool)" + ], + "ai": ["OpenAI", "Gemini", "Google ADK", "LangChain", "Whisper", "LLM Prompt Engineering"], + "tools": ["Docker", "Temporal", "Git", "Cypress", "Postman", "PyPDF2", "BeautifulSoup"], + "realtime": ["WebSockets", "WebRTC", "Twilio"], + "design": ["Figma", "UI/UX"] + } +} diff --git a/public/openapi.yaml b/public/openapi.yaml index b10e153..3b1abe9 100644 --- a/public/openapi.yaml +++ b/public/openapi.yaml @@ -40,6 +40,51 @@ components: type: string label: type: string + location: + type: string + contact: + type: object + properties: + email: + type: string + linkedin: + type: string + github: + type: string + cv: + type: string + education: + type: array + items: + type: object + properties: + institution: + type: string + degree: + type: string + year: + type: string + experience: + type: array + items: + type: object + properties: + company: + type: string + role: + type: string + year: + type: string + description: + type: array + items: + type: string + skills: + type: object + additionalProperties: + type: array + items: + type: string getProjectsResponse: type: array items: @@ -47,5 +92,13 @@ components: properties: name: type: string + subtitle: + type: string description: + type: string + tech: + type: array + items: + type: string + url: type: string \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml index bede782..5478723 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -2,32 +2,8 @@ https://rahulap.vercel.app/ - 2025-11-28 + 2026-07-02 weekly 1.0 - - https://rahulap.vercel.app/journey - 2025-11-28 - monthly - 0.8 - - - https://rahulap.vercel.app/skills - 2025-11-28 - monthly - 0.8 - - - https://rahulap.vercel.app/projects - 2025-11-28 - monthly - 0.9 - - - https://rahulap.vercel.app/contact - 2025-11-28 - yearly - 0.5 - diff --git a/src/App.tsx b/src/App.tsx index 84e881b..dae1f34 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,10 +3,13 @@ import { AnimatePresence } from 'framer-motion'; import { ThemeProvider } from './context/ThemeContext'; import LoadingScreen from './components/LoadingScreen/LoadingScreen'; import Terminal from './components/Terminal/Terminal'; +import PortfolioView from './components/PortfolioView/PortfolioView'; +import ModeSwitch, { ViewMode } from './components/ModeSwitch/ModeSwitch'; import './styles/global.scss'; const App: React.FC = () => { const [loading, setLoading] = useState(true); + const [view, setView] = useState('terminal'); const handleComplete = useCallback(() => setLoading(false), []); return ( @@ -19,7 +22,17 @@ const App: React.FC = () => { )} - {!loading && } + {!loading && ( + <> + +
+ setView('gui')} /> +
+
+ +
+ + )} ); }; diff --git a/src/components/ModeSwitch/ModeSwitch.scss b/src/components/ModeSwitch/ModeSwitch.scss new file mode 100644 index 0000000..6ed86cd --- /dev/null +++ b/src/components/ModeSwitch/ModeSwitch.scss @@ -0,0 +1,59 @@ +.mode-switch { + position: fixed; + top: 14px; + right: 14px; + z-index: 30; + display: grid; + grid-template-columns: 1fr 1fr; + align-items: stretch; + padding: 3px; + background: var(--glass-bg); + border: 1px solid var(--border-color); + border-radius: 999px; + backdrop-filter: blur(var(--glass-blur, 0px)); + font-family: var(--font-mono); +} + +.mode-switch-option { + position: relative; + z-index: 1; + padding: 6px 14px; + border: none; + background: transparent; + border-radius: 999px; + color: var(--muted); + font-family: inherit; + font-size: 0.72rem; + letter-spacing: 0.02em; + cursor: pointer; + transition: color 0.2s ease; + white-space: nowrap; + + &.is-active { + color: var(--on-primary, var(--bg)); + } + + &:hover:not(.is-active) { + color: var(--fg); + } +} + +.mode-switch-thumb { + position: absolute; + top: 3px; + bottom: 3px; + left: 3px; + width: calc(50% - 3px); + background: var(--primary); + border-radius: 999px; + box-shadow: 0 0 12px 0 color-mix(in srgb, var(--primary) 50%, transparent); + transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1); + + &.is-left { + transform: translateX(0); + } + + &.is-right { + transform: translateX(100%); + } +} diff --git a/src/components/ModeSwitch/ModeSwitch.tsx b/src/components/ModeSwitch/ModeSwitch.tsx new file mode 100644 index 0000000..14c40f7 --- /dev/null +++ b/src/components/ModeSwitch/ModeSwitch.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import './ModeSwitch.scss'; + +export type ViewMode = 'terminal' | 'gui'; + +interface ModeSwitchProps { + mode: ViewMode; + onChange: (mode: ViewMode) => void; +} + +const ModeSwitch: React.FC = ({ mode, onChange }) => { + return ( +
+ + + + ); +}; + +export default ModeSwitch; diff --git a/src/components/PortfolioView/PortfolioView.scss b/src/components/PortfolioView/PortfolioView.scss new file mode 100644 index 0000000..8e1a1f8 --- /dev/null +++ b/src/components/PortfolioView/PortfolioView.scss @@ -0,0 +1,271 @@ +.portfolio { + position: relative; + height: 100dvh; + width: 100%; + background-color: var(--bg); + background-image: var(--bg-gradient); + background-size: var(--bg-size, auto); + color: var(--fg); + font-family: var(--font-main); + overflow-y: auto; + overflow-x: hidden; +} + +.portfolio-theme-toggle { + position: fixed; + top: 14px; + left: 14px; + z-index: 30; + padding: 6px 14px; + background: var(--glass-bg); + border: 1px solid var(--border-color); + border-radius: 999px; + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.72rem; + text-transform: capitalize; + letter-spacing: 0.02em; + cursor: pointer; + transition: color 0.15s ease, border-color 0.15s ease; + + &:hover { + color: var(--primary); + border-color: var(--primary); + } +} + +.portfolio-scroll { + max-width: 860px; + margin: 0 auto; + padding: clamp(56px, 8vw, 88px) clamp(16px, 4vw, 40px) 90px; +} + +.portfolio-hero { + margin-bottom: 52px; + + h1 { + font-size: clamp(2rem, 4.5vw, 2.9rem); + font-weight: 700; + color: var(--primary); + letter-spacing: -0.01em; + margin-bottom: 8px; + } +} + +.portfolio-role { + color: var(--accent); + font-weight: 600; + font-size: 1rem; + margin-bottom: 14px; +} + +.portfolio-bio { + max-width: 60ch; + line-height: 1.65; + margin-bottom: 8px; +} + +.portfolio-muted { + color: var(--muted); +} + +.portfolio-section { + margin-bottom: 48px; + + h2 { + display: flex; + align-items: center; + gap: 10px; + font-size: 0.72rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 2.5px; + color: var(--accent); + margin-bottom: 20px; + + &::after { + content: ''; + flex: 1; + height: 1px; + background: linear-gradient(90deg, var(--border-color), transparent); + } + } +} + +.portfolio-skills { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 24px 28px; +} + +.portfolio-skill-group { + h3 { + font-size: 0.82rem; + font-weight: 600; + margin-bottom: 10px; + color: var(--fg); + } +} + +.portfolio-tags { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.portfolio-tag { + padding: 4px 12px; + background: var(--glass-bg); + border: 1px solid var(--border-color); + border-radius: 999px; + font-size: 0.75rem; + color: var(--muted); + transition: color 0.15s ease, border-color 0.15s ease; + + &:hover { + color: var(--fg); + border-color: var(--accent); + } +} + +.portfolio-card { + padding: 18px 20px; + margin-bottom: 14px; + background: var(--glass-bg); + border: 1px solid var(--border-color); + border-radius: 12px; + transition: border-color 0.2s ease, transform 0.2s ease; + + > * + * { + margin-top: 10px; + } + + &:hover { + border-color: var(--accent); + transform: translateY(-2px); + } +} + +.portfolio-card-header { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; + flex-wrap: wrap; + + h3 { + font-size: 0.95rem; + font-weight: 600; + } + + a { + color: var(--primary); + text-decoration: none; + font-size: 0.8rem; + white-space: nowrap; + + &:hover { + text-decoration: underline; + } + } +} + +.portfolio-subtitle { + color: var(--muted); + font-size: 0.9rem; +} + +.portfolio-card-summary { + color: var(--muted); + line-height: 1.55; + font-size: 0.88rem; +} + +.portfolio-card ul { + margin: 0; + padding-left: 18px; + + li { + margin-bottom: 5px; + color: var(--muted); + line-height: 1.55; + font-size: 0.9rem; + + &:last-child { + margin-bottom: 0; + } + } +} + +.portfolio-projects { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 14px; + + .portfolio-card { + margin-bottom: 0; + } +} + +.portfolio-contact-section { + margin-bottom: 0; + padding-top: 8px; +} + +.portfolio-contact-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 24px; + padding: 28px; + background: var(--glass-bg); + border: 1px solid var(--border-color); + border-radius: 14px; +} + +.portfolio-contact-item { + display: flex; + flex-direction: column; + gap: 8px; + + a, span:not(.portfolio-contact-label) { + color: var(--fg); + text-decoration: none; + font-size: 0.92rem; + } + + a { + color: var(--primary); + + &:hover { + text-decoration: underline; + } + } +} + +.portfolio-contact-label { + font-size: 0.68rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 1.5px; + color: var(--muted); +} + +.portfolio-social-links { + display: flex; + flex-wrap: wrap; + gap: 10px; + + a { + padding: 4px 12px; + background: transparent; + border: 1px solid var(--border-color); + border-radius: 999px; + font-size: 0.8rem; + transition: border-color 0.15s ease, color 0.15s ease; + + &:hover { + border-color: var(--primary); + text-decoration: none; + } + } +} diff --git a/src/components/PortfolioView/PortfolioView.tsx b/src/components/PortfolioView/PortfolioView.tsx new file mode 100644 index 0000000..440f084 --- /dev/null +++ b/src/components/PortfolioView/PortfolioView.tsx @@ -0,0 +1,132 @@ +import React, { useCallback } from 'react'; +import { resumeData } from '../../data/resume'; +import { useTheme, THEME_ORDER } from '../../context/ThemeContext'; +import './PortfolioView.scss'; + +const SKILL_LABELS: Record = { + frontend: 'Frontend', + backend: 'Backend', + state: 'State Management', + ai_tools: 'AI Tools', + ai: 'AI', + tools: 'Tools', + realtime: 'Realtime', + design: 'Design', +}; + +const PortfolioView: React.FC = () => { + const { theme, setTheme } = useTheme(); + + const cycleTheme = useCallback(() => { + const next = THEME_ORDER[(THEME_ORDER.indexOf(theme) + 1) % THEME_ORDER.length]; + setTheme(next); + }, [theme, setTheme]); + + return ( +
+ + +
+
+

{resumeData.name}

+

{resumeData.hero.role1} · {resumeData.hero.role2}

+

{resumeData.hero.bio}

+

{resumeData.location}

+
+ +
+

Skills

+
+ {Object.entries(resumeData.skills).map(([category, items]) => ( +
+

{SKILL_LABELS[category] ?? category.replace(/_/g, ' ')}

+
+ {(items as string[]).map(item => ( + {item} + ))} +
+
+ ))} +
+
+ +
+

Experience

+ {resumeData.experience.map(exp => ( +
+
+

{exp.role} · {exp.company}

+ {exp.year} +
+
    + {exp.description.map(line => ( +
  • {line}
  • + ))} +
+
+ ))} +
+ +
+

Projects

+
+ {resumeData.projects.map(p => ( +
+
+

{p.title}

+ View → +
+

{p.subtitle}

+

{p.summary}

+
+ {p.tech.map(t => ( + {t} + ))} +
+
+ ))} +
+
+ +
+

Education

+ {resumeData.education.map(edu => ( +
+
+

{edu.degree}

+ {edu.year} +
+

{edu.institution}

+
+ ))} +
+ +
+

Contact

+
+ +
+ Phone + {resumeData.contact.phone} +
+
+ Social + +
+
+
+
+
+ ); +}; + +export default PortfolioView; diff --git a/src/components/Terminal/Terminal.tsx b/src/components/Terminal/Terminal.tsx index bbeba17..fac3e7f 100644 --- a/src/components/Terminal/Terminal.tsx +++ b/src/components/Terminal/Terminal.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { useTheme, Theme } from '../../context/ThemeContext'; +import { useTheme, THEME_ORDER } from '../../context/ThemeContext'; import { runCommand, COMMAND_NAMES, OPEN_TARGETS, CommandOutput } from './commands'; import './Terminal.scss'; @@ -9,7 +9,6 @@ interface LineEntry { output: CommandOutput; } -const THEME_ORDER: Theme[] = ['dark', 'neon', 'pastel', 'light']; const PROMPT = 'guest@rahulap:~$'; let idCounter = 0; @@ -39,7 +38,11 @@ const formatLastLogin = () => { return `${get('month')} ${get('day')} ${get('year')} ${get('hour')}:${get('minute')} IST`; }; -const Terminal: React.FC = () => { +interface TerminalProps { + onSwitchToGui: () => void; +} + +const Terminal: React.FC = ({ onSwitchToGui }) => { const { theme, setTheme } = useTheme(); const [lines, setLines] = useState([]); const [input, setInput] = useState(''); @@ -83,6 +86,7 @@ const Terminal: React.FC = () => { cycleTheme, clear: () => setLines([]), triggerMatrix, + switchToGui: onSwitchToGui, }); setLines(ls => [...ls, { id: idCounter++, command, output }]); } diff --git a/src/components/Terminal/commands.ts b/src/components/Terminal/commands.ts index 998f057..ed9ce50 100644 --- a/src/components/Terminal/commands.ts +++ b/src/components/Terminal/commands.ts @@ -8,6 +8,7 @@ export interface CommandContext { cycleTheme: () => void; clear: () => void; triggerMatrix: () => void; + switchToGui: () => void; } export type CommandOutput = React.ReactNode; @@ -248,6 +249,15 @@ export const COMMANDS: CommandDef[] = [ category: 'Terminal', handler: (_args, ctx) => { ctx.clear(); return null; }, }, + { + name: 'gui', + description: 'Switch to minimal UI view', + category: 'Terminal', + handler: (_args, ctx) => { + ctx.switchToGui(); + return null; + }, + }, { name: 'whoami', description: 'Hidden command', diff --git a/src/context/ThemeContext.tsx b/src/context/ThemeContext.tsx index 3ac742b..6bf3809 100644 --- a/src/context/ThemeContext.tsx +++ b/src/context/ThemeContext.tsx @@ -2,6 +2,8 @@ import { createContext, useContext, useEffect, useState, ReactNode, FC } from 'r export type Theme = 'light' | 'dark' | 'neon' | 'pastel'; +export const THEME_ORDER: Theme[] = ['dark', 'neon', 'pastel', 'light']; + interface ThemeContextType { theme: Theme; setTheme: (theme: Theme) => void; diff --git a/src/data/resume.ts b/src/data/resume.ts index 61d9bcf..41dca02 100644 --- a/src/data/resume.ts +++ b/src/data/resume.ts @@ -58,6 +58,7 @@ export const resumeData = { { title: "EnvScope", subtitle: "Context-Aware Frontend Security & Secret Detection Engine", + summary: "A Chrome extension that scans live JavaScript bundles for exposed secrets, combining regex and AST analysis to catch high-risk leaks with low false positives.", tech: [ "JavaScript", "TypeScript", @@ -80,6 +81,7 @@ export const resumeData = { { title: "TestPilot", subtitle: "Intelligent Bug Detection & Telemetry Chrome Extension", + summary: "A silent telemetry layer for web apps that captures console errors, failed requests, and performance metrics in real time, with no backend required.", tech: [ "JavaScript", "Chrome Extensions API", @@ -98,6 +100,7 @@ export const resumeData = { { title: "AskSQLAI", subtitle: "Schema-Aware Natural Language to SQL Generation Engine", + summary: "Converts plain-English questions into safe, executable SQL by introspecting the live database schema, with layered guardrails against hallucinated tables or columns.", tech: [ "React (Vite)", "TypeScript", @@ -120,6 +123,7 @@ export const resumeData = { { title: "MeetlyAI", subtitle: "AI-Powered Meeting Notes, Decisions & Action Items Generator", + summary: "Turns raw meeting transcripts into structured summaries, decisions, and owned action items using strict JSON-schema-enforced prompting.", tech: [ "React (Vite)", "TypeScript", @@ -139,6 +143,7 @@ export const resumeData = { { title: "SearchlyAI", subtitle: "Session-Based AI Search Engine using RAG over Documents & Web", + summary: "A full RAG pipeline for semantic Q&A over uploaded documents and web pages, using FAISS vector search and Gemini responses grounded strictly in retrieved context.", tech: [ "React (Vite)", "TypeScript", @@ -161,6 +166,7 @@ export const resumeData = { { title: "SemanticFeed", subtitle: "AI-Powered Tech News Aggregation & Deduplication Platform", + summary: "Aggregates tech news from multiple sources, deduplicates related articles into unified stories, and generates concise AI summaries via scheduled background jobs.", tech: [ "React (Vite)", "TypeScript", @@ -184,6 +190,7 @@ export const resumeData = { { title: "QueryDoc", subtitle: "Retrieval-Augmented Document Q&A System", + summary: "A secure RAG chat system for a single uploaded PDF, supporting multi-question conversations with session-isolated vector storage and no stored credentials.", tech: [ "React (Vite)", "TypeScript", @@ -205,6 +212,7 @@ export const resumeData = { { title: "AI-Powered SOAP Note Generator", subtitle: "Multi-Agent Medical Assistant", + summary: "A multi-agent pipeline that extracts structured clinical data from patient conversations and generates guideline-backed, safety-checked SOAP notes.", tech: ["Python", "Google ADK", "Gemini 2.5 Flash Lite", "Google Search Tool", "InMemoryRunner"], description: [ "Multi-agent pipeline for medical intake and SOAP note creation", @@ -218,6 +226,7 @@ export const resumeData = { { title: "Readme Creator", subtitle: "AI-Powered README Generator", + summary: "A web app for building structured, professional READMEs from templates, with live markdown preview and Gemini-powered content optimization.", tech: ["React", "Redux", "Gemini", "Material-UI"], description: [ "Web app for creating structured, professional README files", @@ -230,6 +239,7 @@ export const resumeData = { { title: "Gemini PDF Analyzer", subtitle: "Streamlit + GenAI Resume Parsing Tool", + summary: "Extracts and parses resume PDFs into structured JSON, then generates a polished first-person summary using a selectable Gemini model.", tech: ["Streamlit", "Python", "Gemini 1.5 Flash/Pro"], description: [ "Extracts resume text using PyPDF2", @@ -243,6 +253,7 @@ export const resumeData = { { title: "EasyDiagno", subtitle: "AI-Powered Symptom Checker", + summary: "A cross-platform symptom-checking app with a chatbot interface, ML-based diagnosis, and a hospital locator with specialization filters.", tech: ["Flutter", "Firebase", "Python", "ML"], description: [ "AI-powered symptom checker with chatbot interface", @@ -256,6 +267,7 @@ export const resumeData = { { title: "Streamify", subtitle: "Full Stack Chat App", + summary: "A full-stack real-time messaging and video chat app supporting 100+ concurrent users, with screen sharing and image sharing built in.", tech: ["React", "Express", "WebRTC"], description: [ "Real-time messaging + video chat", diff --git a/vercel.json b/vercel.json index 76cadd1..29c0269 100644 --- a/vercel.json +++ b/vercel.json @@ -1,15 +1,4 @@ { - "headers": [ - { - "source": "/(.*)", - "headers": [ - { - "key": "Last-Modified", - "value": "Sun, 23 Jun 2025 12:00:00 GMT" - } - ] - } - ], "rewrites": [ { "source": "/(.*)",