PageSourceSearch

https://keshanaroshaka-dynamic-resume-builder.hf.space/script.js

js keshanaroshaka-dynamic-resume-builder.hf.space collected 2026-10-03 17:01:23 UTC 15,747 bytes, 316 lines download raw bytes

1// DOM Elements Selection
2const templateSelect = document.getElementById('templateSelect');
3const templateBadge = document.getElementById('templateBadge');
4
5const fullNameInput = document.getElementById('fullName');
6const locationInput = document.getElementById('location');
7const emailInput = document.getElementById('email');
8const phoneInput = document.getElementById('phone');
9const githubInput = document.getElementById('github');
10const titleInput = document.getElementById('title');
11
12const eduUniInput = document.getElementById('eduUni');
13const eduDegreeInput = document.getElementById('eduDegree');
14const eduALInput = document.getElementById('eduAL');
15const eduOLInput = document.getElementById('eduOL');
16
17const projectsTextInput = document.getElementById('projectsText');
18const skillsLangInput = document.getElementById('skillsLang');
19const skillsCloudInput = document.getElementById('skillsCloud');
20const accomplishmentsTextInput = document.getElementById('accomplishmentsText');
21const referencesTextInput = document.getElementById('referencesText');
22
23const generateBtn = document.getElementById('generateBtn');
24const loadSampleBtn = document.getElementById('loadSampleBtn');
25const resultContainer = document.getElementById('resultContainer');
26const statusText = document.getElementById('statusText');
27const progressBar = document.getElementById('progressBar');
28const downloadLink = document.getElementById('downloadLink');
29
30const tabHtmlBtn = document.getElementById('tabHtmlBtn');
31const tabMdBtn = document.getElementById('tabMdBtn');
32const htmlPreviewContainer = document.getElementById('htmlPreviewContainer');
33const mdPreviewContainer = document.getElementById('mdPreviewContainer');
34const htmlPreviewArea = document.getElementById('htmlPreviewArea');
35const markdownEditor = document.getElementById('markdownEditor');
36
37const BACKEND_URL = '/api/v1/vault/generate-pdf';
38let isManualMarkdownEdit = false;
39
40// Sample Moratuwa CSE Resume Dataset
41const sampleCseData = {
42    fullName: "Keshana Dewranga",
43    location: "Moratuwa, Sri Lanka",
44    email: "[email protected]",
45    phone: "+94 76 903 3466",
46    github: "KeshRD",
47    title: "Computer Science and Engineering Undergraduate",
48    eduUni: "University of Moratuwa (2024 – 2028 Expected)",
49    eduDegree: "BSc Engineering(Hons), Computer Science and Engineering",
50    eduAL: "Physical Science Stream – Combined Maths, Physics, Chemistry | Results: 3A's, Island Rank: 335 (2023)",
51    eduOL: "Results: 9A's",
52    projectsText: `### Resource Coordination Platform (RCP) (Disaster Relief System) *(2026 – Present)*
53- **Backend API & Database Modeling:** Designed relational database schemas using SQLAlchemy ORM (PostgreSQL) and developed efficient RESTful API routes using FastAPI for core microservices.
54- **Mobile App Development:** Built the Volunteer Mobile Application using React Native (Expo), integrating live map navigation, secure JWT authentication, and REST API endpoints.
55- **Real-Time Data Integration:** Upgraded the notification system to a real-time push architecture by establishing live WebSocket (Go) connections to frontend clients.
56- **Event-Driven Architecture:** Gained hands-on experience in consuming asynchronous data streams routed through RabbitMQ message brokers for instant disaster alerts.
57- **Tech Stack:** React Native, Next.js, FastAPI, SQLAlchemy, PostgreSQL, WebSockets, RabbitMQ, Docker
58
59### Lume (Mindfulness & Habit Tracker Mobile App) *(2026)*
60- Developed a modern Sinhala-language mindfulness application featuring a meditation timer, reflective journaling, and 7-day mental well-being challenges.
61- Integrated Google Gemini API to build a context-aware AI chatbot delivering guidance rooted in Buddhist philosophy.
62- Implemented secure user authentication and cloud storage architecture using Supabase for tracking daily progress, photo uploads, and habit formations.
63- **Tech Stack:** React Native, Expo, Supabase, Google Gemini API
64
65### PregmaAI (AI Pregnancy Companion) *(2025, 2026)*
66#### Web App Version *(2026)*
67- Developed an AI-powered healthcare platform for expectant mothers to track daily symptoms, fetal movements, and manage pregnancy milestones efficie
67ntly.
68- Integrated an intelligent NLP-based AI assistant analyzing user-logged health vitals to generate personalized wellness plans and risk factor alerts.
69- Implemented a real-time vital sign tracking dashboard with dynamic data visualization and a localized RAG pipeline providing medically relevant healthcare information.
70- **Tech Stack:** React, Tailwind CSS, FastAPI, Gemini API, Recharts, LangChain, PostgreSQL, Git
71
72#### Android Mobile App *(2025)*
73- Architected an AI Speech-to-Summary pipeline integrating Android SpeechRecognizer with Hugging Face API (bart-large-cnn-samsum) for real-time doctor consultation summarization, cached locally via Room DB.
74- Implemented Firebase Auth and Cloud Firestore real-time listeners for live tracking of pregnancy progress, kick counter, contraction timer, and appointment calendar.
75
76### Bright-Buy (Team Project) *(2025)*
77- Developed a full-stack e-commerce application featuring a modern user interface, secure JWT-based authentication, and product image upload capabilities.
78- Integrated an AI-powered chatbot to assist customers with real-time product inquiries, enhancing customer support.
79- Implemented robust database architecture utilizing PostgreSQL with stored procedures, views, and triggers.
80- **Tech Stack:** React, PostgreSQL, Node.js, Express, Chart.js, Axios`,
81    skillsLang: "JavaScript, TypeScript, Python, SQL, Go, Java, React.js, FastAPI, Next.js, React Native",
82    skillsCloud: "PostgreSQL, MySQL, AWS, Docker, Kubernetes, Supabase, Firebase, Git, GitHub, Postman, Figma",
83    accomplishmentsText: `- **Finalist**, **SLIOT 2025** national IoT competition (contributed to "Ceylon Riya" Kotlin Mobile app development) *(2025)*
84- **Semi-Finalist**, **IDEALIZE 2025** Web and App Development Competition, organized by AIESEC *(2025)*
85- **Certifications:** SLIOT Finalist – SLT MOBITEL | Semi-Finalist - IDEALIZE 2025
86- **Volunteer Experience:** Compering Team Lead (Gammaddata IEEE API), MC - Octwave 2.0 Finals, OC Member (SLT Robogames, SLIOT, Hit the Ground)`,
87    referencesText: `**Prof. Dulani Meedeniya**
88Department of Computer Science and Engineering, Faculty of Engineering, University of Moratuwa, Sri Lanka.
89*Email:* [email protected]
90
91**Dr. Adeesha Wijayasiri**
92Department of Computer Science and Engineering, Faculty of Engineering, University of Moratuwa, Sri Lanka.
93*Email:* [email protected]`
94};
95
96// Fill inputs with data object
97function loadDataIntoInputs(data) {
98    fullNameInput.value = data.fullName || '';
99    locationInput.value = data.location || '';
100    emailInput.value = data.email || '';
101    phoneInput.value = data.phone || '';
102    githubInput.value = data.github || '';
103    titleInput.value = data.title || '';
104
105    eduUniInput.value = data.eduUni || '';
106    eduDegreeInput.value = data.eduDegree || '';
107    eduALInput.value = data.eduAL || '';
108    eduOLInput.value = data.eduOL || '';
109
110    projectsTextInput.value = data.projectsText || '';
111    skillsLangInput.value = data.skillsLang || '';
112    skillsCloudInput.value = data.skillsCloud || '';
113    accomplishmentsTextInput.value = data.accomplishmentsText || '';
114    referencesTextInput.value = data.referencesText || '';
115
116    isManualMarkdownEdit = false;
117    updateMarkdownFromForm();
118}
119
120// Synthesize Markdown text from structured form fields
121function generateMarkdownFromForm() {
122    const name = fullNameInput.value || 'Keshana Dewranga';
123    const title = titleInput.value || 'Computer Science & Engineering Undergraduate';
124    const uni = eduUniInput.value || 'University of Moratuwa (2024 – 2028 Expected)';
125    const degree = eduDegreeInput.value || 'BSc Engineering(Hons), Computer Science and Engineering';
126    const al = eduALInput.value || "Physical Science Stream – Combined Maths, Physics, Chemistry | Results: 3A's, Island Rank: 335";
127    const ol = eduOLInput.value || "Results: 9A's";
128
129    let md = `## Education\n\n`;
130    md += `### ${uni}\n`;
131    md += `**${degree}**\n\n`;
132    if (al) md += `- **G.C.E. Advanced Level (2023):** ${al}\n`;
133    if (ol) md += `- **G.C.E. Ordinary Level:** ${ol}\n`;
134
135    md += `\n---\n\n## Projects\n\n`;
136    md += `${projectsTextInput.value || 'Add project descriptions...'}\n`;
137
138    md += `\n---\n\n## Skills and Technologies\n\n`;
139    if (skillsLangInput.value) md += `- **Languages & Frameworks:** ${skillsLangInput.value}\n`;
140    if (skillsCloudInput.value) md += `- **Databases, DevOps & Tools:** ${skillsCloudInput.value}\n`;
141    md += `- **Core CS:** Data Structures & Algorithms, OOP, Database Systems, Softw
141are Engineering\n`;
142    md += `- **Soft Skills:** Team Collaboration, Problem Solving, Time Management, Technical Communication, Adaptability\n`;
143
144    if (accomplishmentsTextInput.value.trim()) {
145        md += `\n---\n\n## Accomplishments & Leadership\n\n`;
146        md += `${accomplishmentsTextInput.value}\n`;
147    }
148
149    if (referencesTextInput.value.trim()) {
150        md += `\n---\n\n## References\n\n`;
151        md += `${referencesTextInput.value}\n`;
152    }
153
154    return md;
155}
156
157// Update Markdown & Live HTML Preview
158function updateMarkdownFromForm() {
159    if (isManualMarkdownEdit) return;
160
161    const mdContent = generateMarkdownFromForm();
162    markdownEditor.value = mdContent;
163    renderHtmlPreview(mdContent);
164}
165
166// Render HTML Preview in right-hand column
167function renderHtmlPreview(markdownText) {
168    if (window.marked) {
169        htmlPreviewArea.innerHTML = marked.parse(markdownText || '');
170    } else {
171        htmlPreviewArea.textContent = markdownText;
172    }
173}
174
175// Event listeners for structured inputs
176[fullNameInput, locationInput, emailInput, phoneInput, githubInput, titleInput,
177 eduUniInput, eduDegreeInput, eduALInput, eduOLInput,
178 projectsTextInput, skillsLangInput, skillsCloudInput, accomplishmentsTextInput, referencesTextInput].forEach(input => {
179    input.addEventListener('input', () => {
180        isManualMarkdownEdit = false;
181        updateMarkdownFromForm();
182    });
183});
184
185// Markdown direct editor handler
186markdownEditor.addEventListener('input', () => {
187    isManualMarkdownEdit = true;
188    renderHtmlPreview(markdownEditor.value);
189});
190
191// Template selector badge update
192templateSelect.addEventListener('change', () => {
193    const selectedText = templateSelect.options[templateSelect.selectedIndex].text;
194    templateBadge.textContent = `Theme: ${selectedText.split('(')[0].replace(/[^a-zA-Z0-9 ]/g, '').trim()}`;
195});
196
197// Tab switching (Rendered HTML vs Raw Markdown)
198tabHtmlBtn.addEventListener('click', () => {
199    tabHtmlBtn.className = "text-xs font-semibold px-3 py-1.5 rounded-lg bg-blue-600 text-white transition";
200    tabMdBtn.className = "text-xs font-semibold px-3 py-1.5 rounded-lg bg-gray-800 text-gray-400 hover:text-gray-200 transition";
201    htmlPreviewContainer.classList.remove('hidden');
202    mdPreviewContainer.classList.add('hidden');
203});
204
205tabMdBtn.addEventListener('click', () => {
206    tabMdBtn.className = "text-xs font-semibold px-3 py-1.5 rounded-lg bg-blue-600 text-white transition";
207    tabHtmlBtn.className = "text-xs font-semibold px-3 py-1.5 rounded-lg bg-gray-800 text-gray-400 hover:text-gray-200 transition";
208    mdPreviewContainer.classList.remove('hidden');
209    htmlPreviewContainer.classList.add('hidden');
210});
211
212// "Load Moratuwa CSE Sample CV" Button
213loadSampleBtn.addEventListener('click', () => {
214    loadDataIntoInputs(sampleCseData);
215    statusText.textContent = "✨ Moratuwa CSE Sample CV loaded successfully! Click generate to compile PDF.";
216    resultContainer.classList.remove('hidden');
217    downloadLink.classList.add('hidden');
218    progressBar.style.width = "100%";
219});
220
221// Initial sample data load
222loadDataIntoInputs(sampleCseData);
223
224// Asynchronous Job Polling Handler
225async function pollJobStatus(jobId) {
226    const maxAttempts = 35;
227    let attempts = 0;
228
229    const pollInterval = setInterval(async () => {
230        attempts++;
231        try {
232            const response = await fetch(`/api/v1/vault/jobs/${jobId}`);
233            const data = await response.json();
234
235            if (data.status === 'processing') {
236                statusText.textContent = "⚙️ Worker compiling Academic Puppeteer HTML to A4 PDF Buffer...";
237                progressBar.style.width = "65%";
238            } else if (data.status === 'completed' && data.result) {
239                clearInterval(pollInterval);
240                statusText.textContent = "✅ Academic CV Snapshot Sync Complete! Link expires in 15 mins.";
241                progressBar.style.width = "100%";
242                downloadLink.href = data.result.downloadUrl;
243                downloadLink.classList.remove('hidden');
244                generateBtn.disabled = false;
245                generateBtn.innerHTML = "<span>🚀 Dispatch Async Job & Vault PDF</span>";
246            } else if (data.status === 'failed') {
247                clearInterval(pollInterval);
248                statusText.textContent = `❌ Compilation Failed: ${data.error || 'Worker execution error'}`;
249                progressBar.style.width = "0%";
250                generateBtn.disabled = false;
251                generateBtn.innerHTML = "<span>🚀 Dispatch Async Job & Vault PDF</span>";
252            }
253
254            if (attempts >= maxAttempts) {
255                clearInterval(pollInterval);
256                statusText.textContent = "⚠️ Timeout: Job compilation taking longer than expected.";
257                generateBtn.disabled = false;
258                generateBtn.innerHTML = "<span>🚀 Dispatch Async Job & Vault PDF</span>";
259            }
260
261        } catch (err) {
262            console.error("Polling Error:", err);
263        }
264    }, 1000);
265}
266
267// Generate PDF Button Click Handler
268generateBtn.addEventListener('click', async () => {
269    const finalMarkdown = markdownEditor.value || generateMarkdownFromForm();
270
271    resultContainer.classList.remove('hidden');
272    downloadLink.classList.add('hidden');
273    statusText.textContent = "⏳ Job Dispatched to Background Worker Queue...";
274    progressBar.style.width = "20%";
275    generateBtn.disabled = true;
276    generateBtn.innerHTML = "<span>Processing Queue...</span>";
277
278    try {
279        const response = await fetch(BACKEND_URL, {
280            method: 'POST',
281            headers: {
282                'Content-Type': 'application/json'
283            },
284            body: JSON.stringify({
285                markdownContent: finalMarkdown,
286                template: templateSelect.value,
287                metadata: {
288                    fullName: fullNameInput.value,
289                    location: locationInput.value,
290                    email: emailInput.value,
291                    phone: phoneInput.value,
292                    github: githubInput.value,
293                    title: titleInput.value
294                }
295            })
296        });
297
298        const data = await response.json();
299
300        if (data.success && data.jobId) {
301            statusText.textContent = `📥 Job Queued (ID: ${data.jobId.slice(0, 10)}...). Worker rendering PDF...`;
302            progressBar.style.width = "40%";
303            pollJobStatus(data.jobId);
304        } else {
305            statusText.textContent = `❌ Dispatch Failed: ${data.error || 'Unknown error'}`;
306            generateBtn.disabled = false;
307            generateBtn.innerHTML = "<span>🚀 Dispatch Async Job & Vault PDF</span>";
308        }
309
310    } catch (error) {
311        console.error("Frontend Dispatch Error:", error);
312        statusText.textContent = "❌ Network Error: Could not connect to the Vault API Gateway.";
313        generateBtn.disabled = false;
314        generateBtn.innerHTML = "<span>🚀 Dispatch Async Job & Vault PDF</span>";
315    }
316});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.