Skip to content
Merged

V2 #27

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions public/.well-known/ai-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -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/"
}
86 changes: 86 additions & 0 deletions public/data/projects.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
62 changes: 62 additions & 0 deletions public/data/resume.json
Original file line number Diff line number Diff line change
@@ -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"]
}
}
53 changes: 53 additions & 0 deletions public/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,65 @@ 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:
type: object
properties:
name:
type: string
subtitle:
type: string
description:
type: string
tech:
type: array
items:
type: string
url:
type: string
26 changes: 1 addition & 25 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,8 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://rahulap.vercel.app/</loc>
<lastmod>2025-11-28</lastmod>
<lastmod>2026-07-02</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://rahulap.vercel.app/journey</loc>
<lastmod>2025-11-28</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://rahulap.vercel.app/skills</loc>
<lastmod>2025-11-28</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://rahulap.vercel.app/projects</loc>
<lastmod>2025-11-28</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://rahulap.vercel.app/contact</loc>
<lastmod>2025-11-28</lastmod>
<changefreq>yearly</changefreq>
<priority>0.5</priority>
</url>
</urlset>
15 changes: 14 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<ViewMode>('terminal');
const handleComplete = useCallback(() => setLoading(false), []);

return (
Expand All @@ -19,7 +22,17 @@ const App: React.FC = () => {
)}
</AnimatePresence>

{!loading && <Terminal />}
{!loading && (
<>
<ModeSwitch mode={view} onChange={setView} />
<div style={{ display: view === 'terminal' ? 'contents' : 'none' }}>
<Terminal onSwitchToGui={() => setView('gui')} />
</div>
<div style={{ display: view === 'gui' ? 'contents' : 'none' }}>
<PortfolioView />
</div>
</>
)}
</ThemeProvider>
);
};
Expand Down
59 changes: 59 additions & 0 deletions src/components/ModeSwitch/ModeSwitch.scss
Original file line number Diff line number Diff line change
@@ -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%);
}
}
37 changes: 37 additions & 0 deletions src/components/ModeSwitch/ModeSwitch.tsx
Original file line number Diff line number Diff line change
@@ -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<ModeSwitchProps> = ({ mode, onChange }) => {
return (
<div className="mode-switch" role="tablist" aria-label="View mode">
<button
type="button"
role="tab"
aria-selected={mode === 'gui'}
className={`mode-switch-option ${mode === 'gui' ? 'is-active' : ''}`}
onClick={() => onChange('gui')}
>
Website
</button>
<button
type="button"
role="tab"
aria-selected={mode === 'terminal'}
className={`mode-switch-option ${mode === 'terminal' ? 'is-active' : ''}`}
onClick={() => onChange('terminal')}
>
Terminal
</button>
<div className={`mode-switch-thumb ${mode === 'terminal' ? 'is-right' : 'is-left'}`} aria-hidden="true" />
</div>
);
};

export default ModeSwitch;
Loading
Loading