diff --git a/backend/ai-insight.js b/backend/ai-insight.js index ab11046..88edaf8 100644 --- a/backend/ai-insight.js +++ b/backend/ai-insight.js @@ -75,13 +75,88 @@ async function analyzeResumeWithData(resumeData, jobDescriptionInput) { Analyze this resume JSON data against the job description and provide constructive feedback. JOB DESCRIPTION: -${jobDescContent?.description || 'No job description provided'} +Description +By applying to this position, your application will only be considered for our summer Software Development Engineer (SDE) internship roles. Our summer intern roles have start dates in May/June 2026 and are 12 weeks in duration. + +Do you want to solve real customer problems through innovative technology? Do you enjoy working on scalable services in a collaborative team environment? Do you want to see your code directly impact millions of customers worldwide? + +At Amazon, we hire the best minds in technology to innovate and build on behalf of our customers. Customer obsession is part of our company DNA, which has made us one of the world's most beloved brands. + +Our SDE interns use modern technology to solve complex problems while seeing their work's impact first-hand. The challenges SDE interns solve at Amazon are meaningful and influence millions of customers, sellers, and products globally. We seek individuals passionate about creating new products, features, and services while managing ambiguity in an environment where development cycles are measured in weeks, not years. + +At Amazon, we believe in ownership at every level. As a SDE intern, you'll own the entire lifecycle of your code - from design through deployment and ongoing operations. This ownership mindset, combined with our commitment to operational excellence, ensures we deliver the highest quality solutions for our customers. + +We're looking for curious minds who think big and want to define tomorrow's technology. At Amazon, you'll grow into the high-impact engineer you know you can be, supported by a culture of learning and mentorship. Every day brings exciting new challenges and opportunities for personal growth. + +Amazon internships across all seasons are full-time positions, and interns should expect to work in office, Monday-Friday, up to 40 hours per week typically between 8am-5pm. Specific team norms around working hours will be communicated by your manager. Interns should not have conflicts such as classes or other employment during the Amazon work-day. Applicants should have a minimum of one quarter/semester/trimester remaining in their studies after their internship concludes. + +We will take your location preferences into consideration. Preferences are based on business availability and are not guaranteed. Applicants will be considered at all locations we host interns in the United States including but not limited to: + +• AZ (Phoenix, Tempe) +• CA (Berkeley, Culver City, Cupertino, East Palo Alto, Irvine, Los Angeles, Manhattan Beach, Palo Alto, San Diego, San Francisco, San Jose, San Luis Obispo, Santa Barbara, Santa Clara, Santa Cruz, Santa Monica, Sunnyvale) +• CO (Boulder, Denver) +• GA (Atlanta, Kennesaw) +• IL (Chicago) +• MA (Boston, Cambridge, Hudson, North Reading, Westborough) +• MD (Baltimore) +• MI (Detroit) +• MN (Minneapolis) +• NJ (Jersey City) +• NY (New York) +• OR (Portland) +• PA (Philadelphia, Pittsburgh) +• TN (Nashville) +• TX (Austin, Dallas) +• VA (Arlington, Herndon) +• WI (Madison) +• WA (Bellevue, Seattle, Redmond) +***Locations are subject to change*** + +During your application, you will have the opportunity to highlight your expertise in one or more of these specialized areas: + +• Machine Learning • Distributed Systems and Data Management • Database Systems • Quantum Computing • Network Development • Query Processing and Optimization • Automated Reasoning • Embedded Systems • Data Engineering • Mobile Development • Game Development + +While team placement is based on business needs, sharing your specific skills and interests helps us better align your experience with potential roles. + + +Key job responsibilities +• Collaborate and communicate effectively with experienced cross-disciplinary Amazonians to design, build, and operate innovative products and services that delight our customers, while participating in technical discussions to drive solutions forward. +• Design and develop scalable solutions using cloud-native architectures and microservices in a large distributed computing environment. +• Participate in code reviews and contribute to technical documentation. +• Build and maintain resilient distributed systems that are scalable, fault-tolerant, and cost-effective. +• Leverage and contribute to the development of GenAI and AI-powered tools to enhance development productivity while staying current with emerging technologies. +• Write clean, maintainable code following best practices and design patterns. +• Work in an agile environment practicing CI/CD principles while participating in operational responsibilities. +• Demonstrate operational excellence through monitoring, troubleshooting, and resolving production issues. + +A day in the life +As an intern, you will be matched to a manager and a mentor and will have the opportunity to influence the evolution of Amazon technology and lead critical projects early in your career. + +In addition to working on an impactful project, you will have the opportunity to engage with Amazonians for both personal and professional development, expand your network, and participate in activities with other interns throughout your internship. No matter the location of your internship, we give you the tools to own your project and learn in a real-world setting. + +Basic Qualifications +- Are 18 years of age or older +- Experience with at least one general-purpose programming language such as Java, Python, C++, C#, Go, Rust, or TypeScript +- Experience with data structure implementation, basic algorithm development, and/or object-oriented design principles +- Are enrolled in a Bachelor's degree or above in Computer Science, Computer Engineering, Data Science, Information Systems, or related STEM fields +- Able to work 40 hours/week and commit to a 12-week internship +- Expected conferral date between October 2026 – September 2029 + +Preferred Qualifications +- Experience from previous technical internship(s) or demonstrated project experience +- Experience with one or more of the following: AI tools for development productivity, Cloud platforms (preferably AWS), Database systems (SQL and NoSQL), Contributing to open-source projects, Version control systems, Debugging and troubleshooting complex systems +- Demonstrated ability to learn and adapt to new technologies quickly +- Basic understanding of software development lifecycle (SDLC) +- Strong problem-solving and analytical skills +- Excellent written and verbal communication skills + +Amazon is an equal opportunity employer and does not discriminate on the basis of protected veteran status, disability, or other legally protected status. + +Our inclusive culture empowers Amazonians to deliver the best results for our customers. If you have a disability and need a workplace accommodation or adjustment during the application and hiring process, including support for the interview or onboarding process, please visit https://amazon.jobs/content/en/how-we-hire/accommodations for more information. If the country/region you’re applying in isn’t listed, please contact your Recruiting Partner. + +Our compensation reflects the cost of labor across several US geographic markets. The base pay for this position ranges from $47.84/hr in our lowest geographic market up to $96.15/hr in our highest geographic market. Pay is based on a number of factors including market location and may vary depending on job-related knowledge, skills, and experience. Amazon is a total compensation company. Dependent on the position offered, equity, sign-on payments, and other forms of compensation may be provided as part of a total compensation package, in addition to a full range of medical, financial, and/or other benefits. For more information, please visit https://www.aboutamazon.com/workplace/employee-benefits. This position will remain posted until filled. Applicants should apply via our internal or external career site. + -Company: ${jobDescContent?.company || 'Not specified'} -Title: ${jobDescContent?.title || 'Not specified'} -Responsibilities: ${JSON.stringify(jobDescContent?.responsibilities || [], null, 2)} -Required Skills: ${JSON.stringify(jobDescContent?.requiredSkills || [], null, 2)} -Eligibility Requirements: ${JSON.stringify(jobDescContent?.eligibilityRequirements || [], null, 2)} COMPLETE RESUME DATA (JSON format): ${JSON.stringify(resumeData, null, 2)} @@ -102,8 +177,10 @@ Then proceed with the analysis. Saying "Areas of Improvement:" and the bullet point the feedback. Then say "Key Strengths:" and bullet point those. -Do not say unnecessary things at the beginning of your answer, be straight to the point and go -immediately into the rating and tips +Make sure to bold and underline any important keywords or skills in your response. + +Do not say unnecessary things at the beginning of your answer, be concise and focus on bullet points +immediately into the rating and tips. Keep your answer within 150 words and make sure to add an emphasis on adding AWS to improve our resume. `; console.log('Calling AI with provided resume and job data...'); diff --git a/backend/package-lock.json b/backend/package-lock.json index c8b8ac3..3950b18 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -3560,6 +3560,12 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, "node_modules/fast-xml-parser": { "version": "5.2.5", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", @@ -4404,6 +4410,12 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", diff --git a/backend/resume-generator/Resume.js b/backend/resume-generator/Resume.js index 517aaef..2c8e5bc 100644 --- a/backend/resume-generator/Resume.js +++ b/backend/resume-generator/Resume.js @@ -186,6 +186,7 @@ class Resume { education: () => this._renderEducation(resumeData.education), experience: () => this._renderExperience(resumeData.experience), projects: () => this._renderProjects(resumeData.projects), + certifications: () => this._renderCertifications(resumeData.certifications), }; order.forEach(key => { @@ -402,6 +403,71 @@ class Resume { // }); // } + _renderCertifications(certs) { + if (!certs) return; + const doc = this.doc; + this._sectionHeader('CERTIFICATIONS'); + + // If certifications is an array of objects, render each entry + if (Array.isArray(certs)) { + certs.forEach(c => { + if (!c) return; + const name = (c.name || c.title || c.certification || '').toString().trim(); + const issuer = (c.issuer || c.organization || '').toString().trim(); + const date = (c.date || c.issued || c.issued_date || '').toString().trim(); + const credential = (c.credentialId || c.credential_id || c.id || '').toString().trim(); + + if (name || issuer || date) { + // Name on left, issuer/date on right + const right = date || issuer || ''; + doc.font('CMUSerif-Bold').fontSize(this.positionTitleFontSize) + .text(`${name}`, { continued: true, indent: this.indentSize }) + .font('CMUSerif').fontSize(this.positionTitleFontSize) + .text(`${right}`, { align: 'right', indent: this.indentSize }); + } + + if (issuer && !(issuer === (date))) { + // If issuer wasn't already shown on the right, show it here as italic secondary + if (!date) { + doc.font('CMUSerif-Italic').fontSize(this.smallTextFontSize) + .text(`${issuer}`, { indent: this.indentSize }); + } + } + + if (credential) { + doc.font('CMUSerif').fontSize(this.smallTextFontSize) + .text(`Credential: ${credential}`, { indent: this.indentSize }); + } + + doc.moveDown(this.gapBetweenEachItem); + }); + return; + } + + // If certifications is an object mapping categories -> arrays or strings + if (typeof certs === 'object') { + Object.entries(certs).forEach(([label, items]) => { + if (!items) return; + if (Array.isArray(items)) { + doc.font('CMUSerif-Bold').fontSize(this.smallTextFontSize) + .text(label.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()) + ':', { continued: true , indent: this.indentSize }) + .font('CMUSerif').fontSize(this.smallTextFontSize) + .text(` ${items.join(', ')}`, { indent: this.indentSize }); + doc.moveDown(this.gapBetweenEachItem); + } else if (typeof items === 'string') { + doc.font('CMUSerif').fontSize(this.smallTextFontSize) + .text(`${label.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}: ${items}`, { indent: this.indentSize }); + doc.moveDown(this.gapBetweenEachItem); + } + }); + return; + } + + // Fallback: primitive value + doc.font('CMUSerif').fontSize(this.smallTextFontSize) + .text(String(certs), { indent: this.indentSize }); + } + /** * Convert a JSON section key into a human-friendly title. * e.g. 'leadership_experience' -> 'Leadership Experience' diff --git a/frontend/src/BranchPage.tsx b/frontend/src/BranchPage.tsx index e777d63..079622a 100644 --- a/frontend/src/BranchPage.tsx +++ b/frontend/src/BranchPage.tsx @@ -1,5 +1,4 @@ import Sidebar from "./Sidebar"; - import React, { useState, useCallback, useEffect } from "react"; import { useNavigate } from "react-router-dom"; @@ -17,6 +16,17 @@ import type { Node, Edge, Connection } from "reactflow"; import "reactflow/dist/style.css"; import { Plus, X, Trash2, Menu } from "lucide-react"; +const fileNameMap: Record = { + branch_001: "Nvidia 2026", + branch_002: "Meta 2026", + branch_003: "Netflix Data Analyst 2026", + branch_004: "Apple Data Analyst 2026", + branch_005: "EOG SWE 2026", + branch_006: "Roblox SWE 2026", + branch_008: "Amazon Data Analyst 2026", + branch_009: "TMobile SWE 2026", +}; + const CustomNode = ({ data, style }: any) => { const [isHovered, setIsHovered] = useState(false); const baseColor = style?.backgroundColor || "#10B981"; @@ -105,6 +115,7 @@ const CustomNode = ({ data, style }: any) => { × )} + {/* Tooltip for branch nodes */} {!isCategory && isHovered && data.branchId && (
{ pointerEvents: "none", }} > - {data.branchId} + {data.fileName} {/* Show file name */}
- {data.categoryParents && data.categoryParents.length > 1 && ( - <> - Categories: {data.categoryParents.join(", ")} -
- - )} - {"Date created: 11/12/2025"} + {"Date created: 12/3/2025"}
)} {/* Handles for connectivity */} {isCategory ? ( - // Category nodes: Only source handle (connections start from them) { isConnectable={true} /> ) : ( - // Branch nodes: Both source and target handles <> { position={Position.Right} style={{ background: "#555", - borderRadius: "50%", + borderRadius: "100%", transform: "translate(50%, -50%)", }} isConnectable={true} @@ -188,7 +191,8 @@ type BranchNode = { children_branch_ids: (string | null)[]; }; categoryId: string; - categoryParents?: string[]; // Track multiple category parents + categoryParents?: string[]; + fileName?: string; }; type GraphData = { @@ -200,15 +204,17 @@ const sampleData: GraphData = { categories: [ { id: "cat-1", label: "Summer 2026 intern", color: "#2D5016" }, { id: "cat-2", label: "Data Analyst", color: "#2D5016" }, + { id: "cat-3", label: "Software Engineering", color: "#2D5016" }, ], nodes: [ { branch_info: { branch_id: "branch_001", parent_branch_id: [null], - children_branch_ids: ["branch_002", "branch_005"], + children_branch_ids: ["branch_002", "branch_004"], }, categoryId: "cat-1", + fileName: fileNameMap["branch_001"], }, { branch_info: { @@ -217,78 +223,52 @@ const sampleData: GraphData = { children_branch_ids: ["branch_006"], }, categoryId: "cat-1", + fileName: fileNameMap["branch_002"], }, { branch_info: { branch_id: "branch_003", parent_branch_id: [null], - children_branch_ids: ["branch_004", "branch_007"], + children_branch_ids: ["branch_004"], }, categoryId: "cat-2", + fileName: fileNameMap["branch_003"], }, { branch_info: { branch_id: "branch_004", - parent_branch_id: ["branch_003"], - children_branch_ids: ["branch_008"], + parent_branch_id: ["branch_003", "branch_001"], + children_branch_ids: [null], }, categoryId: "cat-2", + fileName: fileNameMap["branch_004"], }, { branch_info: { branch_id: "branch_005", - parent_branch_id: ["branch_002"], + parent_branch_id: [null], children_branch_ids: ["branch_009"], }, - categoryId: "cat-1", + categoryId: "cat-3", + fileName: fileNameMap["branch_005"], }, { branch_info: { branch_id: "branch_006", parent_branch_id: ["branch_002"], - children_branch_ids: ["branch_010"], + children_branch_ids: [null], }, categoryId: "cat-1", - }, - { - branch_info: { - branch_id: "branch_007", - parent_branch_id: ["branch_003"], - children_branch_ids: ["branch_010"], - }, - categoryId: "cat-2", - }, - { - branch_info: { - branch_id: "branch_008", - parent_branch_id: ["branch_004"], - children_branch_ids: ["branch_final"], - }, - categoryId: "cat-2", + fileName: fileNameMap["branch_006"], }, { branch_info: { branch_id: "branch_009", parent_branch_id: ["branch_005"], - children_branch_ids: ["branch_final"], - }, - categoryId: "cat-1", - }, - { - branch_info: { - branch_id: "branch_010", - parent_branch_id: ["branch_006", "branch_007"], - children_branch_ids: ["branch_final"], - }, - categoryId: "cat-1", - }, - { - branch_info: { - branch_id: "branch_final", - parent_branch_id: ["branch_008", "branch_009", "branch_010"], children_branch_ids: [null], }, - categoryId: "cat-1", + categoryId: "cat-3", + fileName: fileNameMap["branch_009"], }, ], }; @@ -387,6 +367,7 @@ function generateLayout( display: "flex", alignItems: "center", justifyContent: "center", + fontSize: 13, }, }); }); @@ -401,24 +382,45 @@ function generateLayout( node.categoryParents = [node.categoryId]; } - // const color = categoryColors.get(node.categoryId) || '#999'; - const color = - node.categoryId === "" - ? "#90EE90" // Light green for unconnected nodes - : categoryColors.get(node.categoryId) || "#999"; + // // const color = categoryColors.get(node.categoryId) || '#999'; + // const color = + // node.categoryId === "" + // ? "#90EE90" // Light green for unconnected nodes + // : categoryColors.get(node.categoryId) || "#999"; + + // Determine node color + let color = "#90EE90"; // default light green + + if (node.categoryId && categoryColors.has(node.categoryId)) { + color = categoryColors.get(node.categoryId)!; + } + + // If node has categoryParents (multi-category), use the first as primary color + if ( + node.categoryParents && + node.categoryParents.length > 0 && + categoryColors.has(node.categoryParents[0]) + ) { + color = categoryColors.get(node.categoryParents[0])!; + } const x = CATEGORY_WIDTH + 100 + levelIdx * LEVEL_SPACING; const y = nodeIdx * NODE_SPACING + 25; reactFlowNodes.push({ id: nodeId, + // key: `${nodeId}-${color}`, type: "custom", data: { label: "", isCircle: true, branchId: nodeId, - categoryParents: node.categoryParents, + fileName: node.fileName || nodeId, // ← add this + + categoryParents: [...(node.categoryParents ?? [])], // ← new array reference onRemove: onRemoveNode, + color, + updateKey: color, }, position: { x, y }, style: { @@ -429,6 +431,7 @@ function generateLayout( display: "flex", alignItems: "center", justifyContent: "center", + // ...{} }, }); @@ -571,59 +574,64 @@ const FlowDiagram: React.FC = ({ // Update graph data setGraphData((prevData) => { - const newData: GraphData = { ...prevData, nodes: [...prevData.nodes] }; + const newData: GraphData = { + ...prevData, + nodes: prevData.nodes.map((n) => ({ ...n })), + }; - // Check if source is a category node const isSourceCategory = params.source?.startsWith("cat-"); - // Only update branch node relationships if source is not a category - if (!isSourceCategory) { - const sourceNode = newData.nodes.find( - (n) => n.branch_info.branch_id === params.source - ); - if (sourceNode && params.target) { - const childrenIds = - sourceNode.branch_info.children_branch_ids.filter( - (id): id is string => id !== null - ); - if (!childrenIds.includes(params.target)) { - sourceNode.branch_info.children_branch_ids = [ - ...childrenIds, - params.target, - ]; - } - } - } - - // Update target node's parent + const sourceNode = newData.nodes.find( + (n) => n.branch_info.branch_id === params.source + ); const targetNode = newData.nodes.find( (n) => n.branch_info.branch_id === params.target ); - if (targetNode && params.source) { - // If source is a category, add it as a parent category (allow multiple) - if (isSourceCategory) { - // Initialize categoryParents if this is a new unconnected node - if (!targetNode.categoryParents || targetNode.categoryId === "") { - targetNode.categoryParents = []; // Start fresh for unconnected nodes - } - if (!targetNode.categoryParents.includes(params.source)) { - targetNode.categoryParents.push(params.source); - } - // Set primary category (changes color from light green) - targetNode.categoryId = params.source; - // Keep parent_branch_id as null for category connections - if (!targetNode.branch_info.parent_branch_id.includes(null)) { - targetNode.branch_info.parent_branch_id = [null]; - } - } else { - const parentIds = targetNode.branch_info.parent_branch_id.filter( - (id): id is string => id !== null + if (!targetNode) return newData; + + // CATEGORY → NODE connection + if (isSourceCategory) { + // ensure categoryParents array exists + if (!targetNode.categoryParents) { + targetNode.categoryParents = []; + } + + // add category to parents + if (!targetNode.categoryParents.includes(params.source!)) { + targetNode.categoryParents = [ + ...targetNode.categoryParents, + params.source!, + ]; + } + + // IMPORTANT: update categoryId so layout gets correct color + targetNode.categoryId = params.source!; + + // Keep parent_branch_id as [null] + targetNode.branch_info.parent_branch_id = [null]; + } else { + // NODE → NODE connection + const parentIds = targetNode.branch_info.parent_branch_id.filter( + (id): id is string => id !== null + ); + + if (!parentIds.includes(params.source!)) { + targetNode.branch_info.parent_branch_id = [ + ...parentIds, + params.source!, + ]; + } + + if (sourceNode) { + const children = sourceNode.branch_info.children_branch_ids.filter( + (c): c is string => c !== null ); - if (!parentIds.includes(params.source)) { - targetNode.branch_info.parent_branch_id = [ - ...parentIds, - params.source, + + if (!children.includes(params.target!)) { + sourceNode.branch_info.children_branch_ids = [ + ...children, + params.target!, ]; } } @@ -752,17 +760,19 @@ const FlowDiagram: React.FC = ({ const onNodeClick = useCallback( (_: any, node: Node) => { setSelectedNode(node.id); + + // Do filtering for both categories & nodes handleGenerate(node.id); - // Navigate to CreatePage and pass the clicked node id in location state + + // 🚫 Prevent category nodes from navigating to CreatePage + const isCategory = node.id.startsWith("cat-"); + if (isCategory) return; + + // ✔ Only non-category nodes navigate to CreatePage try { navigate("/CreatePage", { state: { branchId: node.id } }); - } catch (e) { - // Fallback: set hash directly if navigation fails - try { - location.hash = `#/CreatePage`; - } catch (err) { - console.warn("Navigation to CreatePage failed", err); - } + } catch { + location.hash = `#/CreatePage`; } }, [graphData, navigate] @@ -773,7 +783,7 @@ const FlowDiagram: React.FC = ({ }, [graphData, filteredFrom]); return ( -
+
{ - const newBranchId = `branch_${Date.now()}`; + const newBranchId = `New Resume`; // Create new node with no category (will be light green until connected to a category) const newNode: BranchNode = { @@ -887,7 +897,7 @@ function BranchPage() {
@@ -903,7 +913,7 @@ function BranchPage() { flex: 1, display: "flex", flexDirection: "column", - overflow: "hidden", + overflow: "visible", transition: "all 0.3s ease", }} > @@ -995,7 +1005,7 @@ function BranchPage() { }} > - Add Node + Add