+735
-1
File diff suppressed because one or more lines are too long
@@ -11,6 +11,8 @@
|
|||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:url" content="https://myai.ro/cv-matcher/" />
|
<meta property="og:url" content="https://myai.ro/cv-matcher/" />
|
||||||
<meta name="theme-color" content="#071326" />
|
<meta name="theme-color" content="#071326" />
|
||||||
|
<link rel="icon" href="/favicon.ico" sizes="any" />
|
||||||
|
<link rel="icon" type="image/png" href="/img/favicon-256.png" />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||||
@@ -21,79 +23,177 @@
|
|||||||
<div class="site-shell">
|
<div class="site-shell">
|
||||||
<header class="header" id="top">
|
<header class="header" id="top">
|
||||||
<div class="container nav-wrap">
|
<div class="container nav-wrap">
|
||||||
<a class="brand" href="/" aria-label="MyAi.ro home"><span class="brand-mark ai-mark">AI</span><span><span class="brand-text">MyAi.ro</span><small>CV Matcher</small></span></a>
|
<a class="brand" href="/" aria-label="MyAi.ro home">
|
||||||
<nav class="nav" id="mainNav" aria-label="Primary navigation"><a href="/">Navigator</a><a href="#matcher">Matcher</a><a href="#contact">Contact</a></nav>
|
<span class="brand-mark">
|
||||||
<button class="menu-toggle" id="menuToggle" aria-expanded="false" aria-controls="mainNav"><span></span><span></span><span></span></button>
|
<img src="/img/myai-logo.svg" alt="MyAi.ro">
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<span class="brand-text">MyAi.ro</span>
|
||||||
|
<small data-i18n="cv.brand">CV Matcher</small>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<nav class="nav" id="mainNav" aria-label="Primary navigation">
|
||||||
|
<a href="/" data-i18n="nav.navigator">Navigator</a>
|
||||||
|
<a href="#matcher" data-i18n="nav.matcher">Matcher</a>
|
||||||
|
<a href="#contact" data-i18n="nav.contact">Contact</a>
|
||||||
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<div class="lang-switch" aria-label="Language selector">
|
||||||
|
<button class="lang-flag" data-lang="ro" aria-label="Română">
|
||||||
|
<img src="/img/flags/ro.svg" alt="RO">
|
||||||
|
</button>
|
||||||
|
<button class="lang-flag" data-lang="en" aria-label="English">
|
||||||
|
<img src="/img/flags/en.svg" alt="EN">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="menu-toggle" id="menuToggle" aria-expanded="false" aria-controls="mainNav">
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<section class="hero matcher-hero">
|
<section class="hero matcher-hero">
|
||||||
<div class="container hero-grid">
|
<div class="container hero-grid">
|
||||||
<div class="hero-copy">
|
<div class="hero-copy">
|
||||||
<span class="eyebrow">AI CV Matcher</span>
|
<span class="eyebrow" data-i18n="cv.eyebrow">AI CV Matcher</span>
|
||||||
<h1>Upload your CV, add a job link, and see how well they match.</h1>
|
<h1 data-i18n="cv.title">Upload your CV, add a job link, and see how well they match.</h1>
|
||||||
<p class="hero-text">The backend should extract text from the PDF, create RAG context from your CV, retrieve relevant experience for the job, then score strengths, gaps and next actions.</p>
|
<p class="hero-text" data-i18n="cv.text">The backend should extract text from the PDF, create RAG context from your CV, retrieve relevant experience for the job, then score strengths, gaps and next actions.</p>
|
||||||
<div class="hero-actions"><a class="btn btn-primary" href="#matcher">Try matcher</a><a class="btn btn-secondary" href="/">Back to navigator</a></div>
|
<div class="hero-actions">
|
||||||
|
<a class="btn btn-primary" href="#matcher" data-i18n="cv.try">Try matcher</a>
|
||||||
|
<a class="btn btn-secondary" href="/" data-i18n="cv.back">Back to navigator</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hero-card ai-console-card">
|
<div class="hero-card ai-console-card banner-card">
|
||||||
<div class="console-line"><span>1</span> PDF text extraction</div>
|
<img class="showcase-banner" src="/img/myai-banner.svg" alt="MyAi.ro AI engineering banner">
|
||||||
<div class="console-line"><span>2</span> CV chunking + embeddings</div>
|
<div class="console-line">
|
||||||
<div class="console-line"><span>3</span> Job URL/description parsing</div>
|
<span>1</span>
|
||||||
<div class="console-line"><span>4</span> Match score + evidence</div>
|
<b data-i18n="cv.step1">PDF text extraction</b>
|
||||||
|
</div>
|
||||||
|
<div class="console-line">
|
||||||
|
<span>2</span>
|
||||||
|
<b data-i18n="cv.step2">CV chunking + embeddings</b>
|
||||||
|
</div>
|
||||||
|
<div class="console-line">
|
||||||
|
<span>3</span>
|
||||||
|
<b data-i18n="cv.step3">Job URL/description parsing</b>
|
||||||
|
</div>
|
||||||
|
<div class="console-line">
|
||||||
|
<span>4</span>
|
||||||
|
<b data-i18n="cv.step4">Match score + evidence</b>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section" id="matcher">
|
<section class="section" id="matcher">
|
||||||
<div class="container matcher-grid">
|
<div class="container matcher-grid">
|
||||||
<form class="ai-panel" id="cvMatcherForm">
|
<form class="ai-panel" id="cvMatcherForm">
|
||||||
<span class="eyebrow">Input</span>
|
<span class="eyebrow" data-i18n="cv.input">Input</span>
|
||||||
<h2>CV and job details</h2>
|
<h2 data-i18n="cv.details">CV and job details</h2>
|
||||||
<label class="file-drop" for="cvFile"><strong>Upload CV PDF</strong><span id="cvFileName">PDF only, max size handled by backend</span><input type="file" id="cvFile" accept="application/pdf" required /></label>
|
<label class="file-drop" for="cvFile">
|
||||||
<label><span>Job link</span><input type="url" id="jobUrl" placeholder="https://company.com/careers/job" /></label>
|
<strong data-i18n="cv.upload">Upload CV PDF</strong>
|
||||||
<label><span>Or paste job description</span><textarea id="jobDescription" rows="8" placeholder="Paste the job description if the page cannot be crawled."></textarea></label>
|
<span id="cvFileName" data-i18n="cv.fileHint">PDF only, max size handled by backend</span>
|
||||||
<div class="consent-inline"><input type="checkbox" id="gdprConsent" required /><label for="gdprConsent">I agree that my CV is processed for this matching demo. Do not upload sensitive documents unless you trust the deployment.</label></div>
|
<input type="file" id="cvFile" accept="application/pdf" required />
|
||||||
<button id="matchSubmit" type="submit" class="btn btn-primary">Extract CV and match job</button>
|
</label>
|
||||||
|
<label>
|
||||||
|
<span data-i18n="cv.jobLink">Job link</span>
|
||||||
|
<input type="url" id="jobUrl" placeholder="https://company.com/careers/job" />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span data-i18n="cv.jobDescription">Or paste job description</span>
|
||||||
|
<textarea id="jobDescription" rows="8" data-i18n-placeholder="cv.jobPlaceholder" placeholder="Paste the job description if the page cannot be crawled."></textarea>
|
||||||
|
</label>
|
||||||
|
<div class="consent-inline">
|
||||||
|
<input type="checkbox" id="gdprConsent" required />
|
||||||
|
<label for="gdprConsent" data-i18n="cv.gdpr">I agree that my CV is processed for this matching demo. Do not upload sensitive documents unless you trust the deployment.</label>
|
||||||
|
</div>
|
||||||
|
<button id="matchSubmit" type="submit" class="btn btn-primary" data-i18n="cv.submit">Extract CV and match job</button>
|
||||||
<strong id="matcherMsg" class="form-message"></strong>
|
<strong id="matcherMsg" class="form-message"></strong>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<aside class="ai-panel result-panel">
|
<aside class="ai-panel result-panel">
|
||||||
<span class="eyebrow">Result</span>
|
<span class="eyebrow" data-i18n="cv.result">Result</span>
|
||||||
<h2>Match analysis</h2>
|
<h2 data-i18n="cv.analysis">Match analysis</h2>
|
||||||
<div id="matchResult" class="empty-result">Upload a CV and provide a job link or description to generate a result.</div>
|
<div id="matchResult" class="empty-result" data-i18n="cv.empty">Upload a CV and provide a job link or description to generate a result.</div>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section contact" id="contact">
|
<section class="section contact" id="contact">
|
||||||
<div class="container contact-grid">
|
<div class="container contact-grid">
|
||||||
<div>
|
<div>
|
||||||
<span class="eyebrow">Contact</span>
|
<span class="eyebrow" data-i18n="nav.contact">Contact</span>
|
||||||
<h2>Want this adapted for your workflow?</h2>
|
<h2 data-i18n="cv.contactTitle">Want this adapted for your workflow?</h2>
|
||||||
<p>This form uses the existing template contact API endpoint.</p>
|
<p data-i18n="cv.contactText">This form uses the existing template contact API endpoint.</p>
|
||||||
<div class="contact-list"><div><span>Contact person</span><strong>Mihes Gelu</strong></div><div><span>Phone</span><strong><a href="tel:+40722523764">+40 722-523-764</a></strong></div></div>
|
<div class="contact-list">
|
||||||
|
<div>
|
||||||
|
<span data-i18n="contact.person">Contact person</span>
|
||||||
|
<strong>Mihes Gelu</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span data-i18n="contact.phone">Phone</span>
|
||||||
|
<strong>
|
||||||
|
<a href="tel:+40722523764">+40 722-523-764</a>
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form class="contact-form" id="contactForm">
|
<form class="contact-form" id="contactForm">
|
||||||
<label><span>Name</span><input type="text" id="name" placeholder="Your name" required /></label>
|
<label>
|
||||||
<label><span>Email</span><input type="email" id="email" placeholder="name@company.com" required /></label>
|
<span data-i18n="form.name">Name</span>
|
||||||
<label><span>Message</span><textarea id="message" rows="6" placeholder="Tell me what you want to build." required></textarea></label>
|
<input type="text" id="name" data-i18n-placeholder="form.namePlaceholder" placeholder="Your name" required />
|
||||||
<button id="submit" type="submit" class="btn btn-primary">Send message</button>
|
</label>
|
||||||
|
<label>
|
||||||
|
<span data-i18n="form.email">Email</span>
|
||||||
|
<input type="email" id="email" data-i18n-placeholder="form.emailPlaceholder" placeholder="name@company.com" required />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span data-i18n="form.message">Message</span>
|
||||||
|
<textarea id="message" rows="6" data-i18n-placeholder="form.messagePlaceholder" placeholder="Tell me what you want to build." required></textarea>
|
||||||
|
</label>
|
||||||
|
<button id="submit" type="submit" class="btn btn-primary" data-i18n="form.send">Send message</button>
|
||||||
<strong id="msgSubmit" class="form-message"></strong>
|
<strong id="msgSubmit" class="form-message"></strong>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
<footer class="footer">
|
||||||
<footer class="footer"><div class="container footer-wrap"><p>© <span id="year"></span> MyAi.ro · All rights reserved</p><div class="footer-links footer-legal"><a href="/legal/terms-en.html" target="_blank">Terms</a><a href="/legal/privacy-en.html" target="_blank">Privacy</a><a href="/legal/cookies-en.html" target="_blank">Cookies</a></div><a href="#top" class="back-to-top btn btn-dark btn-sm shadow">Back to top</a></div></footer>
|
<div class="container footer-wrap">
|
||||||
|
<p>
|
||||||
|
©
|
||||||
|
<span id="year"></span> MyAi.ro ·
|
||||||
|
<span data-i18n="footer.rights">All rights reserved</span>
|
||||||
|
</p>
|
||||||
|
<div class="footer-links footer-legal">
|
||||||
|
<a data-legal="terms" href="/legal/terms-en.html" target="_blank" data-i18n="legal.terms">Terms</a>
|
||||||
|
<a data-legal="privacy" href="/legal/privacy-en.html" target="_blank" data-i18n="legal.privacy">Privacy</a>
|
||||||
|
<a data-legal="cookies" href="/legal/cookies-en.html" target="_blank" data-i18n="legal.cookies">Cookies</a>
|
||||||
|
</div>
|
||||||
|
<a href="#top" class="back-to-top btn btn-dark btn-sm shadow" data-i18n="footer.top">Back to top</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="contactLoader" class="loader-overlay" style="display:none;">
|
||||||
<div id="contactLoader" class="loader-overlay" style="display:none;"><div class="loader-box">Sending...</div></div>
|
<div class="loader-box" data-i18n="status.sending">Sending...</div>
|
||||||
<div id="cookieBanner" class="cookie-overlay" style="display:none;"><div class="cookie-box"><div class="cookie-text"><strong>Cookies</strong><br>We use necessary cookies and, with your consent, analytics through Google Tag Manager. <a href="/legal/privacy-en.html" target="_blank">Privacy policy</a>.</div><div class="cookie-actions"><button id="cookieReject" class="btn btn-warning btn-sm">Reject</button><button id="cookieNecessary" class="btn btn-warning btn-sm">Necessary only</button><button id="cookieAccept" class="btn btn-primary btn-sm">Accept analytics</button></div></div></div>
|
</div>
|
||||||
<a href="#" id="cookieManage" class="cookie-manage btn btn-dark btn-sm shadow" style="display:none;">Cookie settings</a>
|
<div id="cookieBanner" class="cookie-overlay" style="display:none;">
|
||||||
|
<div class="cookie-box">
|
||||||
|
<div class="cookie-text">
|
||||||
|
<strong data-i18n="cookies.title">Cookies</strong>
|
||||||
|
<br>
|
||||||
|
<span data-i18n="cookies.text">We use necessary cookies and, with your consent, analytics through Google Tag Manager.</span>
|
||||||
|
<a data-legal="privacy" href="/legal/privacy-en.html" target="_blank" data-i18n="cookies.policy">Privacy policy</a>.
|
||||||
|
</div>
|
||||||
|
<div class="cookie-actions">
|
||||||
|
<button id="cookieReject" class="btn btn-warning btn-sm" data-i18n="cookies.reject">Reject</button>
|
||||||
|
<button id="cookieNecessary" class="btn btn-warning btn-sm" data-i18n="cookies.necessary">Necessary only</button>
|
||||||
|
<button id="cookieAccept" class="btn btn-primary btn-sm" data-i18n="cookies.accept">Accept analytics</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="#" id="cookieManage" class="cookie-manage btn btn-dark btn-sm shadow" style="display:none;" data-i18n="cookies.settings">Cookie settings</a>
|
||||||
<script src="/js/vendor/jquery-1.12.4.min.js"></script>
|
<script src="/js/vendor/jquery-1.12.4.min.js"></script>
|
||||||
<script src="/js/bootstrap.min.js"></script>
|
<script src="/js/bootstrap.min.js"></script>
|
||||||
<script src="/js/myai.js"></script>
|
<script src="/js/myai.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,17 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 360" role="img" aria-label="MyAi AI engineering banner">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg" x1="0" x2="960" y1="0" y2="360" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#06152B"/><stop offset=".5" stop-color="#0A2B54"/><stop offset="1" stop-color="#2F1F74"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="line" x1="120" x2="850" y1="40" y2="320" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#20E3B2"/><stop offset=".5" stop-color="#5FA0FF"/><stop offset="1" stop-color="#8B6CFF"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="960" height="360" rx="42" fill="url(#bg)"/>
|
||||||
|
<g opacity=".18" stroke="#fff"><path d="M0 70h960M0 140h960M0 210h960M0 280h960M140 0v360M280 0v360M420 0v360M560 0v360M700 0v360M840 0v360"/></g>
|
||||||
|
<path d="M110 250 C240 100, 360 280, 500 142 S720 84, 850 205" fill="none" stroke="url(#line)" stroke-width="18" stroke-linecap="round"/>
|
||||||
|
<g fill="#fff"><circle cx="110" cy="250" r="18"/><circle cx="500" cy="142" r="18"/><circle cx="850" cy="205" r="18"/></g>
|
||||||
|
<text x="84" y="138" font-family="Inter, Arial, sans-serif" font-size="58" font-weight="800" fill="#fff">MyAi.ro</text>
|
||||||
|
<text x="86" y="188" font-family="Inter, Arial, sans-serif" font-size="26" font-weight="600" fill="#BFD1F0">Applied AI engineering showcase</text>
|
||||||
|
<g transform="translate(700 76)"><rect width="150" height="64" rx="22" fill="rgba(255,255,255,.08)" stroke="rgba(255,255,255,.18)"/><text x="30" y="42" font-family="Inter, Arial" font-size="25" font-weight="800" fill="#fff">RAG</text></g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,18 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-label="MyAi logo">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="g" x1="80" x2="420" y1="80" y2="420" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#5FA0FF"/>
|
||||||
|
<stop offset="0.55" stop-color="#8B6CFF"/>
|
||||||
|
<stop offset="1" stop-color="#20E3B2"/>
|
||||||
|
</linearGradient>
|
||||||
|
<filter id="s" x="-20%" y="-20%" width="140%" height="140%">
|
||||||
|
<feDropShadow dx="0" dy="18" stdDeviation="22" flood-color="#2b6bff" flood-opacity=".32"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<rect x="44" y="44" width="424" height="424" rx="116" fill="#06152b"/>
|
||||||
|
<path d="M126 327V185h31l55 80 55-80h31v142h-34v-88l-42 61h-21l-42-61v88h-33Z" fill="#fff"/>
|
||||||
|
<path d="M318 327V217h34v110h-34Zm17-124c-11 0-20-8-20-19s9-19 20-19 20 8 20 19-9 19-20 19Z" fill="#fff" opacity=".92"/>
|
||||||
|
<path d="M92 113c70-55 177-62 250-13 74 50 102 145 68 226" fill="none" stroke="url(#g)" stroke-width="24" stroke-linecap="round" filter="url(#s)"/>
|
||||||
|
<circle cx="94" cy="113" r="18" fill="#20E3B2"/>
|
||||||
|
<circle cx="410" cy="326" r="18" fill="#5FA0FF"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
+117
-62
@@ -11,134 +11,189 @@
|
|||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:url" content="https://myai.ro/" />
|
<meta property="og:url" content="https://myai.ro/" />
|
||||||
<meta name="theme-color" content="#071326" />
|
<meta name="theme-color" content="#071326" />
|
||||||
|
<link rel="icon" href="/favicon.ico" sizes="any" />
|
||||||
|
<link rel="icon" type="image/png" href="/img/favicon-256.png" />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||||
<link rel="stylesheet" href="css/myai.css" />
|
<link rel="stylesheet" href="/css/myai.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="site-shell">
|
<div class="site-shell">
|
||||||
<header class="header" id="top">
|
<header class="header" id="top">
|
||||||
<div class="container nav-wrap">
|
<div class="container nav-wrap">
|
||||||
<a class="brand" href="/" aria-label="MyAi.ro home">
|
<a class="brand" href="/" aria-label="MyAi.ro home">
|
||||||
<span class="brand-mark ai-mark">AI</span>
|
<span class="brand-mark">
|
||||||
|
<img src="/img/myai-logo.svg" alt="MyAi.ro">
|
||||||
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<span class="brand-text">MyAi.ro</span>
|
<span class="brand-text">MyAi.ro</span>
|
||||||
<small>AI engineering showcase</small>
|
<small data-i18n="brand.subtitle">AI engineering showcase</small>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<nav class="nav" id="mainNav" aria-label="Primary navigation">
|
<nav class="nav" id="mainNav" aria-label="Primary navigation">
|
||||||
<a href="#demos">Demos</a>
|
<a href="#demos" data-i18n="nav.demos">Demos</a>
|
||||||
<a href="#contact">Contact</a>
|
<a href="#contact" data-i18n="nav.contact">Contact</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
<div class="nav-actions">
|
||||||
|
<div class="lang-switch" aria-label="Language selector">
|
||||||
|
<button class="lang-flag" data-lang="ro" aria-label="Română">
|
||||||
|
<img src="/img/flags/ro.svg" alt="RO">
|
||||||
|
</button>
|
||||||
|
<button class="lang-flag" data-lang="en" aria-label="English">
|
||||||
|
<img src="/img/flags/en.svg" alt="EN">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<button class="menu-toggle" id="menuToggle" aria-expanded="false" aria-controls="mainNav">
|
<button class="menu-toggle" id="menuToggle" aria-expanded="false" aria-controls="mainNav">
|
||||||
<span></span><span></span><span></span>
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<section class="hero navigator-hero">
|
<section class="hero navigator-hero">
|
||||||
<div class="container hero-grid">
|
<div class="container hero-grid">
|
||||||
<div class="hero-copy">
|
<div class="hero-copy">
|
||||||
<span class="eyebrow">Applied AI lab</span>
|
<span class="eyebrow" data-i18n="home.eyebrow">Applied AI lab</span>
|
||||||
<h1>Production-minded AI demos, not generic chatbot wrappers.</h1>
|
<h1 data-i18n="home.title">Production-minded AI demos, not generic chatbot wrappers.</h1>
|
||||||
<p class="hero-text">MyAi.ro is a technical showcase for practical AI systems: document understanding, retrieval, matching, automation and decision support.</p>
|
<p class="hero-text" data-i18n="home.text">MyAi.ro is a technical showcase for practical AI systems: document understanding, retrieval, matching, automation and decision support.</p>
|
||||||
<div class="hero-actions">
|
<div class="hero-actions">
|
||||||
<a class="btn btn-primary" href="/cv-matcher/">Open CV Matcher</a>
|
<a class="btn btn-primary" href="/cv-matcher/" data-i18n="home.openCv">Open CV Matcher</a>
|
||||||
<a class="btn btn-secondary" href="#contact">Contact</a>
|
<a class="btn btn-secondary" href="#contact" data-i18n="nav.contact">Contact</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hero-card ai-console-card">
|
<div class="hero-card ai-console-card banner-card">
|
||||||
<div class="console-line"><span>upload</span> CV.pdf</div>
|
<img class="showcase-banner" src="/img/myai-banner.svg" alt="MyAi.ro AI engineering banner">
|
||||||
<div class="console-line"><span>extract</span> skills, projects, experience</div>
|
<div class="console-line">
|
||||||
<div class="console-line"><span>retrieve</span> relevant CV context</div>
|
<span>upload</span>
|
||||||
<div class="console-line"><span>score</span> job match + gaps</div>
|
<b data-i18n="home.step1">CV.pdf</b>
|
||||||
|
</div>
|
||||||
|
<div class="console-line">
|
||||||
|
<span>extract</span>
|
||||||
|
<b data-i18n="home.step2">skills, projects, experience</b>
|
||||||
|
</div>
|
||||||
|
<div class="console-line">
|
||||||
|
<span>retrieve</span>
|
||||||
|
<b data-i18n="home.step3">relevant CV context</b>
|
||||||
|
</div>
|
||||||
|
<div class="console-line">
|
||||||
|
<span>score</span>
|
||||||
|
<b data-i18n="home.step4">job match + gaps</b>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section" id="demos">
|
<section class="section" id="demos">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-heading">
|
<div class="section-heading">
|
||||||
<span class="eyebrow">Navigator</span>
|
<span class="eyebrow" data-i18n="home.navigator">Navigator</span>
|
||||||
<h2>Select an AI demo</h2>
|
<h2 data-i18n="home.selectDemo">Select an AI demo</h2>
|
||||||
<p>Start with the CV Matcher. More demos can be added here without changing the site structure.</p>
|
<p data-i18n="home.selectText">Start with the CV Matcher. More demos can be added here without changing the site structure.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="demo-grid">
|
<div class="demo-grid">
|
||||||
<a class="demo-card active" href="/cv-matcher/">
|
<a class="demo-card active" href="/cv-matcher/">
|
||||||
<span class="product-tag">Available</span>
|
<span class="product-tag" data-i18n="tag.available">Available</span>
|
||||||
<h3>CV Matcher</h3>
|
<h3 data-i18n="demo.cv.title">CV Matcher</h3>
|
||||||
<p>Upload a CV PDF, provide a job link or description, extract RAG context and generate a match score with strengths and gaps.</p>
|
<p data-i18n="demo.cv.text">Upload a CV PDF, provide a job link or description, extract RAG context and generate a match score with strengths and gaps.</p>
|
||||||
<strong>Open demo →</strong>
|
<strong data-i18n="demo.open">Open demo →</strong>
|
||||||
</a>
|
</a>
|
||||||
<article class="demo-card muted-card">
|
<article class="demo-card muted-card">
|
||||||
<span class="product-tag">Next</span>
|
<span class="product-tag" data-i18n="tag.next">Next</span>
|
||||||
<h3>RAG Playground</h3>
|
<h3 data-i18n="demo.rag.title">RAG Playground</h3>
|
||||||
<p>Experiment with chunk size, retrieval count and source context transparency.</p>
|
<p data-i18n="demo.rag.text">Experiment with chunk size, retrieval count and source context transparency.</p>
|
||||||
</article>
|
</article>
|
||||||
<article class="demo-card muted-card">
|
<article class="demo-card muted-card">
|
||||||
<span class="product-tag">Next</span>
|
<span class="product-tag" data-i18n="tag.next">Next</span>
|
||||||
<h3>Agent Automation</h3>
|
<h3 data-i18n="demo.agent.title">Agent Automation</h3>
|
||||||
<p>Job discovery, filtering, ranking and notification workflows.</p>
|
<p data-i18n="demo.agent.text">Job discovery, filtering, ranking and notification workflows.</p>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section contact" id="contact">
|
<section class="section contact" id="contact">
|
||||||
<div class="container contact-grid">
|
<div class="container contact-grid">
|
||||||
<div>
|
<div>
|
||||||
<span class="eyebrow">Contact</span>
|
<span class="eyebrow" data-i18n="nav.contact">Contact</span>
|
||||||
<h2>Discuss an AI integration or custom software project</h2>
|
<h2 data-i18n="contact.title">Discuss an AI integration or custom software project</h2>
|
||||||
<p>Use the form and it will submit through the existing contact API endpoint from the template.</p>
|
<p data-i18n="contact.text">Use the form and it will submit through the existing contact API endpoint from the template.</p>
|
||||||
<div class="contact-list">
|
<div class="contact-list">
|
||||||
<div><span>Contact person</span><strong>Mihes Gelu</strong></div>
|
<div>
|
||||||
<div><span>Phone</span><strong><a href="tel:+40722523764">+40 722-523-764</a></strong></div>
|
<span data-i18n="contact.person">Contact person</span>
|
||||||
<div><span>WhatsApp</span><strong><a href="https://wa.me/40744564177" target="_blank" rel="noreferrer">+40 744-564-177</a></strong></div>
|
<strong>Mihes Gelu</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span data-i18n="contact.phone">Phone</span>
|
||||||
|
<strong>
|
||||||
|
<a href="tel:+40722523764">+40 722-523-764</a>
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>WhatsApp</span>
|
||||||
|
<strong>
|
||||||
|
<a href="https://wa.me/40744564177" target="_blank" rel="noreferrer">+40 744-564-177</a>
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form class="contact-form" id="contactForm">
|
<form class="contact-form" id="contactForm">
|
||||||
<label><span>Name</span><input type="text" id="name" placeholder="Your name" required /></label>
|
<label>
|
||||||
<label><span>Email</span><input type="email" id="email" placeholder="name@company.com" required /></label>
|
<span data-i18n="form.name">Name</span>
|
||||||
<label><span>Message</span><textarea id="message" rows="6" placeholder="Tell me what you want to build." required></textarea></label>
|
<input type="text" id="name" data-i18n-placeholder="form.namePlaceholder" placeholder="Your name" required />
|
||||||
<button id="submit" type="submit" class="btn btn-primary">Send message</button>
|
</label>
|
||||||
|
<label>
|
||||||
|
<span data-i18n="form.email">Email</span>
|
||||||
|
<input type="email" id="email" data-i18n-placeholder="form.emailPlaceholder" placeholder="name@company.com" required />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span data-i18n="form.message">Message</span>
|
||||||
|
<textarea id="message" rows="6" data-i18n-placeholder="form.messagePlaceholder" placeholder="Tell me what you want to build." required></textarea>
|
||||||
|
</label>
|
||||||
|
<button id="submit" type="submit" class="btn btn-primary" data-i18n="form.send">Send message</button>
|
||||||
<strong id="msgSubmit" class="form-message"></strong>
|
<strong id="msgSubmit" class="form-message"></strong>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="container footer-wrap">
|
<div class="container footer-wrap">
|
||||||
<p>© <span id="year"></span> MyAi.ro · All rights reserved</p>
|
<p>
|
||||||
|
©
|
||||||
|
<span id="year"></span> MyAi.ro ·
|
||||||
|
<span data-i18n="footer.rights">All rights reserved</span>
|
||||||
|
</p>
|
||||||
<div class="footer-links footer-legal">
|
<div class="footer-links footer-legal">
|
||||||
<a href="/legal/terms-en.html" target="_blank">Terms</a>
|
<a data-legal="terms" href="/legal/terms-en.html" target="_blank" data-i18n="legal.terms">Terms</a>
|
||||||
<a href="/legal/privacy-en.html" target="_blank">Privacy</a>
|
<a data-legal="privacy" href="/legal/privacy-en.html" target="_blank" data-i18n="legal.privacy">Privacy</a>
|
||||||
<a href="/legal/cookies-en.html" target="_blank">Cookies</a>
|
<a data-legal="cookies" href="/legal/cookies-en.html" target="_blank" data-i18n="legal.cookies">Cookies</a>
|
||||||
</div>
|
</div>
|
||||||
<a href="#top" class="back-to-top btn btn-dark btn-sm shadow">Back to top</a>
|
<a href="#top" class="back-to-top btn btn-dark btn-sm shadow" data-i18n="footer.top">Back to top</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="contactLoader" class="loader-overlay" style="display:none;">
|
||||||
<div id="contactLoader" class="loader-overlay" style="display:none;"><div class="loader-box">Sending...</div></div>
|
<div class="loader-box" data-i18n="status.sending">Sending...</div>
|
||||||
|
</div>
|
||||||
<div id="cookieBanner" class="cookie-overlay" style="display:none;">
|
<div id="cookieBanner" class="cookie-overlay" style="display:none;">
|
||||||
<div class="cookie-box">
|
<div class="cookie-box">
|
||||||
<div class="cookie-text"><strong>Cookies</strong><br>We use necessary cookies and, with your consent, analytics through Google Tag Manager. <a href="/legal/privacy-en.html" target="_blank">Privacy policy</a>.</div>
|
<div class="cookie-text">
|
||||||
|
<strong data-i18n="cookies.title">Cookies</strong>
|
||||||
|
<br>
|
||||||
|
<span data-i18n="cookies.text">We use necessary cookies and, with your consent, analytics through Google Tag Manager.</span>
|
||||||
|
<a data-legal="privacy" href="/legal/privacy-en.html" target="_blank" data-i18n="cookies.policy">Privacy policy</a>.
|
||||||
|
</div>
|
||||||
<div class="cookie-actions">
|
<div class="cookie-actions">
|
||||||
<button id="cookieReject" class="btn btn-warning btn-sm">Reject</button>
|
<button id="cookieReject" class="btn btn-warning btn-sm" data-i18n="cookies.reject">Reject</button>
|
||||||
<button id="cookieNecessary" class="btn btn-warning btn-sm">Necessary only</button>
|
<button id="cookieNecessary" class="btn btn-warning btn-sm" data-i18n="cookies.necessary">Necessary only</button>
|
||||||
<button id="cookieAccept" class="btn btn-primary btn-sm">Accept analytics</button>
|
<button id="cookieAccept" class="btn btn-primary btn-sm" data-i18n="cookies.accept">Accept analytics</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a href="#" id="cookieManage" class="cookie-manage btn btn-dark btn-sm shadow" style="display:none;">Cookie settings</a>
|
<a href="#" id="cookieManage" class="cookie-manage btn btn-dark btn-sm shadow" style="display:none;" data-i18n="cookies.settings">Cookie settings</a>
|
||||||
|
<script src="/js/vendor/jquery-1.12.4.min.js"></script>
|
||||||
<script src="js/vendor/jquery-1.12.4.min.js"></script>
|
<script src="/js/bootstrap.min.js"></script>
|
||||||
<script src="js/bootstrap.min.js"></script>
|
<script src="/js/myai.js"></script>
|
||||||
<script src="js/myai.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+470
-214
@@ -1,243 +1,499 @@
|
|||||||
(function ($) {
|
(function ($) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var reCaptchaSiteKey = null;
|
var reCaptchaSiteKey = null;
|
||||||
var gTagManagerId = null;
|
var gTagManagerId = null;
|
||||||
var CONSENT_KEY = "myai_cookie_consent";
|
var CONSENT_KEY = "myai_cookie_consent";
|
||||||
|
var LANG_KEY = "myai_lang";
|
||||||
|
|
||||||
$('#year').text(new Date().getFullYear());
|
var i18n = {
|
||||||
|
en: {
|
||||||
|
"brand.subtitle": "AI engineering showcase",
|
||||||
|
"nav.demos": "Demos",
|
||||||
|
"nav.contact": "Contact",
|
||||||
|
"nav.navigator": "Navigator",
|
||||||
|
"nav.matcher": "Matcher",
|
||||||
|
"home.eyebrow": "Applied AI lab",
|
||||||
|
"home.title": "Production-minded AI demos, not generic chatbot wrappers.",
|
||||||
|
"home.text": "MyAi.ro is a technical showcase for practical AI systems: document understanding, retrieval, matching, automation and decision support.",
|
||||||
|
"home.openCv": "Open CV Matcher",
|
||||||
|
"home.step1": "CV.pdf",
|
||||||
|
"home.step2": "skills, projects, experience",
|
||||||
|
"home.step3": "relevant CV context",
|
||||||
|
"home.step4": "job match + gaps",
|
||||||
|
"home.navigator": "Navigator",
|
||||||
|
"home.selectDemo": "Select an AI demo",
|
||||||
|
"home.selectText": "Our first steps in AI integrations.",
|
||||||
|
"tag.available": "Available",
|
||||||
|
"tag.next": "Next",
|
||||||
|
"demo.cv.title": "CV Matcher",
|
||||||
|
"demo.cv.text": "Upload a CV PDF, provide a job link or description, extract RAG context and generate a match score with strengths and gaps.",
|
||||||
|
"demo.open": "Open demo →",
|
||||||
|
"demo.rag.title": "RAG Playground",
|
||||||
|
"demo.rag.text": "Experiment with chunk size, retrieval count and source context transparency.",
|
||||||
|
"demo.agent.title": "Agent Automation",
|
||||||
|
"demo.agent.text": "Job discovery, filtering, ranking and notification workflows.",
|
||||||
|
"contact.title": "Discuss an AI integration or custom software project",
|
||||||
|
"contact.text": "Fill in the form fields and will contact you.",
|
||||||
|
"contact.person": "Contact person",
|
||||||
|
"contact.phone": "Phone",
|
||||||
|
"form.name": "Name",
|
||||||
|
"form.namePlaceholder": "Your name",
|
||||||
|
"form.email": "Email",
|
||||||
|
"form.emailPlaceholder": "name@company.com",
|
||||||
|
"form.message": "Message",
|
||||||
|
"form.messagePlaceholder": "Tell me what you want to build.",
|
||||||
|
"form.send": "Send message",
|
||||||
|
"form.thanks": "Thank you for your message.",
|
||||||
|
"form.captchaFailed": "Captcha verification failed.",
|
||||||
|
"form.failed": "Failed to send the message.",
|
||||||
|
"footer.rights": "All rights reserved",
|
||||||
|
"footer.top": "Back to top",
|
||||||
|
"legal.terms": "Terms",
|
||||||
|
"legal.privacy": "Privacy",
|
||||||
|
"legal.cookies": "Cookies",
|
||||||
|
"status.sending": "Sending...",
|
||||||
|
"cookies.title": "Cookies",
|
||||||
|
"cookies.text": "We use necessary cookies and, with your consent, analytics through Google Tag Manager.",
|
||||||
|
"cookies.policy": "Privacy policy",
|
||||||
|
"cookies.reject": "Reject",
|
||||||
|
"cookies.necessary": "Necessary only",
|
||||||
|
"cookies.accept": "Accept analytics",
|
||||||
|
"cookies.settings": "Cookie settings",
|
||||||
|
"cv.brand": "CV Matcher",
|
||||||
|
"cv.eyebrow": "AI CV Matcher",
|
||||||
|
"cv.title": "Upload your CV, add a job link, and see how well they match.",
|
||||||
|
"cv.text": "The backend should extract text from the PDF, create RAG context from your CV, retrieve relevant experience for the job, then score strengths, gaps and next actions.",
|
||||||
|
"cv.try": "Try matcher",
|
||||||
|
"cv.back": "Back to navigator",
|
||||||
|
"cv.step1": "PDF text extraction",
|
||||||
|
"cv.step2": "CV chunking + embeddings",
|
||||||
|
"cv.step3": "Job URL/description parsing",
|
||||||
|
"cv.step4": "Match score + evidence",
|
||||||
|
"cv.input": "Input",
|
||||||
|
"cv.details": "CV and job details",
|
||||||
|
"cv.upload": "Upload CV PDF",
|
||||||
|
"cv.fileHint": "PDF only, max size handled by backend",
|
||||||
|
"cv.jobLink": "Job link",
|
||||||
|
"cv.jobDescription": "Or paste job description",
|
||||||
|
"cv.jobPlaceholder": "Paste the job description if the page cannot be crawled.",
|
||||||
|
"cv.gdpr": "I agree that my CV is processed for this matching demo. Do not upload sensitive documents unless you trust the deployment.",
|
||||||
|
"cv.submit": "Extract CV and match job",
|
||||||
|
"cv.result": "Result",
|
||||||
|
"cv.analysis": "Match analysis",
|
||||||
|
"cv.empty": "Upload a CV and provide a job link or description to generate a result.",
|
||||||
|
"cv.contactTitle": "Want this adapted for your workflow?",
|
||||||
|
"cv.contactText": "This form uses the existing template contact API endpoint.",
|
||||||
|
"cv.noFile": "Please upload a CV PDF.",
|
||||||
|
"cv.noJob": "Add a job link or paste a job description.",
|
||||||
|
"cv.noConsent": "GDPR consent is required.",
|
||||||
|
"cv.processing": "Processing...",
|
||||||
|
"cv.extracting": "Extracting CV and matching job...",
|
||||||
|
"cv.processingLong": "Processing CV PDF and job input. Backend endpoints must be available.",
|
||||||
|
"cv.cvFailed": "CV extraction failed",
|
||||||
|
"cv.matchFailed": "Job matching failed",
|
||||||
|
"cv.completed": "Match completed.",
|
||||||
|
"cv.backendMissing": "The frontend is ready, but the backend endpoints /api/rag/cv and /api/rag/match-job must be implemented.",
|
||||||
|
"cv.noSummary": "No summary returned.",
|
||||||
|
"cv.noItems": "No items returned.",
|
||||||
|
"cv.strengths": "Strengths",
|
||||||
|
"cv.gaps": "Gaps",
|
||||||
|
"cv.evidence": "Retrieved CV evidence"
|
||||||
|
},
|
||||||
|
ro: {
|
||||||
|
"brand.subtitle": "prezentare inginerie AI",
|
||||||
|
"nav.demos": "Demo-uri",
|
||||||
|
"nav.contact": "Contact",
|
||||||
|
"nav.navigator": "Navigator",
|
||||||
|
"nav.matcher": "Matcher",
|
||||||
|
"home.eyebrow": "Laborator AI aplicat",
|
||||||
|
"home.title": "Demo-uri AI orientate spre producție, nu simple wrapper-e de chatbot.",
|
||||||
|
"home.text": "MyAi.ro este o prezentare tehnică pentru sisteme AI practice: înțelegere documente, retrieval, potrivire, automatizare și suport decizional.",
|
||||||
|
"home.openCv": "Deschide CV Matcher",
|
||||||
|
"home.step1": "CV.pdf",
|
||||||
|
"home.step2": "competențe, proiecte, experiență",
|
||||||
|
"home.step3": "context relevant din CV",
|
||||||
|
"home.step4": "potrivire job + lipsuri",
|
||||||
|
"home.navigator": "Navigator",
|
||||||
|
"home.selectDemo": "Alege un demo AI",
|
||||||
|
"home.selectText": "Primele noastre projecte",
|
||||||
|
"tag.available": "Disponibil",
|
||||||
|
"tag.next": "Urmează",
|
||||||
|
"demo.cv.title": "CV Matcher",
|
||||||
|
"demo.cv.text": "Încarcă un CV PDF, adaugă un link sau o descriere de job, extrage context RAG și generează un scor de potrivire cu puncte forte și lipsuri.",
|
||||||
|
"demo.open": "Deschide demo →",
|
||||||
|
"demo.rag.title": "RAG Playground",
|
||||||
|
"demo.rag.text": "Experimentează cu dimensiunea chunk-urilor, numărul de rezultate și transparența surselor.",
|
||||||
|
"demo.agent.title": "Automatizare cu agenți",
|
||||||
|
"demo.agent.text": "Fluxuri pentru descoperire joburi, filtrare, ranking și notificări.",
|
||||||
|
"contact.title": "Discută o integrare AI sau un proiect software custom",
|
||||||
|
"contact.text": "Complecteaza formularul si te vom contacta.",
|
||||||
|
"contact.person": "Persoană de contact",
|
||||||
|
"contact.phone": "Telefon",
|
||||||
|
"form.name": "Nume",
|
||||||
|
"form.namePlaceholder": "Numele tău",
|
||||||
|
"form.email": "Email",
|
||||||
|
"form.emailPlaceholder": "nume@companie.ro",
|
||||||
|
"form.message": "Mesaj",
|
||||||
|
"form.messagePlaceholder": "Spune-mi ce vrei să construiești.",
|
||||||
|
"form.send": "Trimite mesajul",
|
||||||
|
"form.thanks": "Mulțumesc pentru mesaj.",
|
||||||
|
"form.captchaFailed": "Verificarea Captcha a eșuat.",
|
||||||
|
"form.failed": "Mesajul nu a putut fi trimis.",
|
||||||
|
"footer.rights": "Toate drepturile rezervate",
|
||||||
|
"footer.top": "Înapoi sus",
|
||||||
|
"legal.terms": "Termeni",
|
||||||
|
"legal.privacy": "Confidențialitate",
|
||||||
|
"legal.cookies": "Cookies",
|
||||||
|
"status.sending": "Se trimite...",
|
||||||
|
"cookies.title": "Cookies",
|
||||||
|
"cookies.text": "Folosim cookies necesare și, cu acordul tău, analytics prin Google Tag Manager.",
|
||||||
|
"cookies.policy": "Politica de confidențialitate",
|
||||||
|
"cookies.reject": "Respinge",
|
||||||
|
"cookies.necessary": "Doar necesare",
|
||||||
|
"cookies.accept": "Accept analytics",
|
||||||
|
"cookies.settings": "Setări cookies",
|
||||||
|
"cv.brand": "CV Matcher",
|
||||||
|
"cv.eyebrow": "AI CV Matcher",
|
||||||
|
"cv.title": "Încarcă CV-ul, adaugă un link de job și vezi cât de bine se potrivesc.",
|
||||||
|
"cv.text": "Backend-ul ar trebui să extragă textul din PDF, să creeze context RAG din CV, să recupereze experiența relevantă pentru job, apoi să calculeze punctele forte, lipsurile și pașii următori.",
|
||||||
|
"cv.try": "Încearcă matcherul",
|
||||||
|
"cv.back": "Înapoi la navigator",
|
||||||
|
"cv.step1": "Extragere text PDF",
|
||||||
|
"cv.step2": "Chunking CV + embeddings",
|
||||||
|
"cv.step3": "Parsare URL/descriere job",
|
||||||
|
"cv.step4": "Scor potrivire + dovezi",
|
||||||
|
"cv.input": "Date de intrare",
|
||||||
|
"cv.details": "CV și detalii job",
|
||||||
|
"cv.upload": "Încarcă CV PDF",
|
||||||
|
"cv.fileHint": "Doar PDF, limita de mărime este gestionată de backend",
|
||||||
|
"cv.jobLink": "Link job",
|
||||||
|
"cv.jobDescription": "Sau lipește descrierea jobului",
|
||||||
|
"cv.jobPlaceholder": "Lipește descrierea jobului dacă pagina nu poate fi citită automat.",
|
||||||
|
"cv.gdpr": "Sunt de acord ca CV-ul meu să fie procesat pentru acest demo de matching. Nu încărca documente sensibile dacă nu ai încredere în deployment.",
|
||||||
|
"cv.submit": "Extrage CV și compară jobul",
|
||||||
|
"cv.result": "Rezultat",
|
||||||
|
"cv.analysis": "Analiză potrivire",
|
||||||
|
"cv.empty": "Încarcă un CV și adaugă un link sau o descriere de job pentru a genera rezultatul.",
|
||||||
|
"cv.contactTitle": "Vrei să adaptezi asta pentru workflow-ul tău?",
|
||||||
|
"cv.contactText": "Formularul folosește endpoint-ul existent de contact din template.",
|
||||||
|
"cv.noFile": "Te rog încarcă un CV PDF.",
|
||||||
|
"cv.noJob": "Adaugă un link de job sau lipește descrierea jobului.",
|
||||||
|
"cv.noConsent": "Consimțământul GDPR este obligatoriu.",
|
||||||
|
"cv.processing": "Se procesează...",
|
||||||
|
"cv.extracting": "Se extrage CV-ul și se compară jobul...",
|
||||||
|
"cv.processingLong": "Se procesează PDF-ul și informațiile despre job. Endpoint-urile backend trebuie să fie disponibile.",
|
||||||
|
"cv.cvFailed": "Extragerea CV-ului a eșuat",
|
||||||
|
"cv.matchFailed": "Matching-ul jobului a eșuat",
|
||||||
|
"cv.completed": "Matching finalizat.",
|
||||||
|
"cv.backendMissing": "Frontend-ul este pregătit, dar endpoint-urile backend /api/rag/cv și /api/rag/match-job trebuie implementate.",
|
||||||
|
"cv.noSummary": "Nu a fost returnat niciun sumar.",
|
||||||
|
"cv.noItems": "Nu au fost returnate elemente.",
|
||||||
|
"cv.strengths": "Puncte forte",
|
||||||
|
"cv.gaps": "Lipsuri",
|
||||||
|
"cv.evidence": "Dovezi recuperate din CV"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$('#menuToggle').on('click', function () {
|
function browserLang() {
|
||||||
var $nav = $('#mainNav');
|
return ((navigator.language || navigator.userLanguage || 'en').toLowerCase().indexOf('ro') === 0) ? 'ro' : 'en';
|
||||||
var open = !$nav.hasClass('is-open');
|
}
|
||||||
$nav.toggleClass('is-open', open);
|
|
||||||
$(this).attr('aria-expanded', open ? 'true' : 'false');
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.nav a').on('click', function () {
|
function currentLang() {
|
||||||
$('#mainNav').removeClass('is-open');
|
return localStorage.getItem(LANG_KEY) || browserLang();
|
||||||
$('#menuToggle').attr('aria-expanded', 'false');
|
}
|
||||||
});
|
|
||||||
|
|
||||||
function getRecaptchaWebKey() {
|
function t(key) {
|
||||||
return $.get('/api/contact').done(function (res) {
|
var lang = currentLang();
|
||||||
reCaptchaSiteKey = res;
|
return (i18n[lang] && i18n[lang][key]) || i18n.en[key] || key;
|
||||||
if (reCaptchaSiteKey && !window.__recaptcha_loaded) {
|
}
|
||||||
window.__recaptcha_loaded = true;
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.setAttribute('src', 'https://www.google.com/recaptcha/api.js?render=' + reCaptchaSiteKey);
|
|
||||||
document.head.appendChild(script);
|
|
||||||
}
|
|
||||||
}).fail(function () {
|
|
||||||
console.warn('Could not load reCaptcha site key from /api/contact');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGoogleTagManagerId() {
|
function updateLegalLinks(lang) {
|
||||||
return $.get('/api/google/tagmanager').done(function (res) {
|
$('[data-legal]').each(function () {
|
||||||
gTagManagerId = res;
|
var page = $(this).data('legal');
|
||||||
}).fail(function () {
|
$(this).attr('href', '/legal/' + page + '-' + lang + '.html');
|
||||||
console.warn('Could not load Google Tag Manager id from /api/google/tagmanager');
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function loadGoogleTagManager() {
|
function applyLanguage(lang) {
|
||||||
if (window.__gtm_loaded || !gTagManagerId) return;
|
localStorage.setItem(LANG_KEY, lang);
|
||||||
window.__gtm_loaded = true;
|
document.documentElement.lang = lang;
|
||||||
window.dataLayer = window.dataLayer || [];
|
updateLegalLinks(lang);
|
||||||
window.dataLayer.push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
|
$('[data-i18n]').each(function () {
|
||||||
var script = document.createElement('script');
|
$(this).text(t($(this).data('i18n')));
|
||||||
script.async = true;
|
});
|
||||||
script.src = 'https://www.googletagmanager.com/gtm/js?id=' + gTagManagerId;
|
$('[data-i18n-placeholder]').each(function () {
|
||||||
document.head.appendChild(script);
|
$(this).attr('placeholder', t($(this).data('i18n-placeholder')));
|
||||||
}
|
});
|
||||||
|
$('.lang-flag').attr('aria-pressed', 'false');
|
||||||
|
$('.lang-flag[data-lang="' + lang + '"]').attr('aria-pressed', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
function getConsent() {
|
$('#year').text(new Date().getFullYear());
|
||||||
try { return JSON.parse(localStorage.getItem(CONSENT_KEY)); } catch { return null; }
|
applyLanguage(currentLang());
|
||||||
}
|
$('.lang-flag').on('click', function () {
|
||||||
|
applyLanguage($(this).data('lang'));
|
||||||
|
});
|
||||||
|
|
||||||
function setConsent(consent) {
|
$('#menuToggle').on('click', function () {
|
||||||
localStorage.setItem(CONSENT_KEY, JSON.stringify(consent));
|
var $nav = $('#mainNav');
|
||||||
}
|
var open = !$nav.hasClass('is-open');
|
||||||
|
$nav.toggleClass('is-open', open);
|
||||||
|
$(this).attr('aria-expanded', open ? 'true' : 'false');
|
||||||
|
});
|
||||||
|
$('.nav a').on('click', function () {
|
||||||
|
$('#mainNav').removeClass('is-open');
|
||||||
|
$('#menuToggle').attr('aria-expanded', 'false');
|
||||||
|
});
|
||||||
|
|
||||||
function applyConsent(consent) {
|
function getRecaptchaWebKey() {
|
||||||
if (consent && consent.analytics === true) loadGoogleTagManager();
|
return $.get('/api/contact').done(function (res) {
|
||||||
}
|
reCaptchaSiteKey = res;
|
||||||
|
if (reCaptchaSiteKey && !window.__recaptcha_loaded) {
|
||||||
|
window.__recaptcha_loaded = true;
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.setAttribute('src', 'https://www.google.com/recaptcha/api.js?render=' + reCaptchaSiteKey);
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
}).fail(function () {
|
||||||
|
console.warn('Could not load reCaptcha site key from /api/contact');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function showBanner() { $('#cookieBanner').fadeIn(200); }
|
function getGoogleTagManagerId() {
|
||||||
function hideBanner() { $('#cookieBanner').fadeOut(200); }
|
return $.get('/api/google/tagmanager').done(function (res) {
|
||||||
function showManage() { $('#cookieManage').show(); }
|
gTagManagerId = res;
|
||||||
|
}).fail(function () {
|
||||||
|
console.warn('Could not load Google Tag Manager id from /api/google/tagmanager');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$('#cookieReject, #cookieNecessary').on('click', function () {
|
function loadGoogleTagManager() {
|
||||||
setConsent({ necessary: true, analytics: false, ts: new Date().toISOString() });
|
if (window.__gtm_loaded || !gTagManagerId) return;
|
||||||
hideBanner();
|
window.__gtm_loaded = true;
|
||||||
showManage();
|
window.dataLayer = window.dataLayer || [];
|
||||||
});
|
window.dataLayer.push({
|
||||||
|
'gtm.start': new Date().getTime(),
|
||||||
|
event: 'gtm.js'
|
||||||
|
});
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.async = true;
|
||||||
|
script.src = 'https://www.googletagmanager.com/gtm/js?id=' + gTagManagerId;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
$('#cookieAccept').on('click', function () {
|
function getConsent() {
|
||||||
var consent = { necessary: true, analytics: true, ts: new Date().toISOString() };
|
try {
|
||||||
setConsent(consent);
|
return JSON.parse(localStorage.getItem(CONSENT_KEY));
|
||||||
applyConsent(consent);
|
} catch (e) {
|
||||||
hideBanner();
|
return null;
|
||||||
showManage();
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
$('#cookieManage').on('click', function (e) {
|
function setConsent(consent) {
|
||||||
e.preventDefault();
|
localStorage.setItem(CONSENT_KEY, JSON.stringify(consent));
|
||||||
showBanner();
|
}
|
||||||
});
|
|
||||||
|
|
||||||
function initConsent() {
|
function applyConsent(consent) {
|
||||||
var consent = getConsent();
|
if (consent && consent.analytics === true) loadGoogleTagManager();
|
||||||
if (!consent) showBanner();
|
}
|
||||||
else { applyConsent(consent); showManage(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitMSG(valid, msg) {
|
function showBanner() {
|
||||||
var msgClasses = valid ? 'form-message text-success' : 'form-message text-danger';
|
$('#cookieBanner').fadeIn(200);
|
||||||
$('#msgSubmit').removeClass().addClass(msgClasses).text(msg);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function formSuccess() {
|
function hideBanner() {
|
||||||
$('#contactForm')[0].reset();
|
$('#cookieBanner').fadeOut(200);
|
||||||
submitMSG(true, 'Thank you for your message.');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function formError() {
|
function showManage() {
|
||||||
$('#contactForm').removeClass().addClass('contact-form shake').one('animationend', function () {
|
$('#cookieManage').show();
|
||||||
$(this).removeClass('shake');
|
}
|
||||||
});
|
$('#cookieReject, #cookieNecessary').on('click', function () {
|
||||||
}
|
setConsent({
|
||||||
|
necessary: true,
|
||||||
|
analytics: false,
|
||||||
|
ts: new Date().toISOString()
|
||||||
|
});
|
||||||
|
hideBanner();
|
||||||
|
showManage();
|
||||||
|
});
|
||||||
|
$('#cookieAccept').on('click', function () {
|
||||||
|
var consent = {
|
||||||
|
necessary: true,
|
||||||
|
analytics: true,
|
||||||
|
ts: new Date().toISOString()
|
||||||
|
};
|
||||||
|
setConsent(consent);
|
||||||
|
applyConsent(consent);
|
||||||
|
hideBanner();
|
||||||
|
showManage();
|
||||||
|
});
|
||||||
|
$('#cookieManage').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
showBanner();
|
||||||
|
});
|
||||||
|
|
||||||
$('#contactForm').on('submit', function (event) {
|
function initConsent() {
|
||||||
event.preventDefault();
|
var consent = getConsent();
|
||||||
var loader = $('#contactLoader');
|
if (!consent) showBanner();
|
||||||
var button = $('#submit');
|
else {
|
||||||
loader.css('display', 'flex');
|
applyConsent(consent);
|
||||||
button.prop('disabled', true);
|
showManage();
|
||||||
$('#msgSubmit').text('');
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function postContact(token) {
|
function submitMSG(valid, msg) {
|
||||||
var message = {
|
$('#msgSubmit').removeClass().addClass(valid ? 'form-message text-success' : 'form-message text-danger').text(msg);
|
||||||
Name: $('#name').val(),
|
}
|
||||||
Email: $('#email').val(),
|
|
||||||
Subject: '[MyAi.ro contact request]',
|
|
||||||
Message: $('#message').val(),
|
|
||||||
CaptchaToken: token || ''
|
|
||||||
};
|
|
||||||
$.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: '/api/contact',
|
|
||||||
data: JSON.stringify(message),
|
|
||||||
contentType: 'application/json; charset=utf-8',
|
|
||||||
dataType: 'json'
|
|
||||||
}).done(function (resp) {
|
|
||||||
if (resp && resp.ok === true) formSuccess();
|
|
||||||
else submitMSG(false, 'Captcha verification failed.');
|
|
||||||
}).fail(function () {
|
|
||||||
submitMSG(false, 'Failed to send the message.');
|
|
||||||
formError();
|
|
||||||
}).always(function () {
|
|
||||||
loader.hide();
|
|
||||||
button.prop('disabled', false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.grecaptcha && reCaptchaSiteKey) {
|
function formSuccess() {
|
||||||
grecaptcha.ready(function () {
|
$('#contactForm')[0].reset();
|
||||||
grecaptcha.execute(reCaptchaSiteKey, { action: 'contact' }).then(postContact);
|
submitMSG(true, t('form.thanks'));
|
||||||
});
|
}
|
||||||
} else {
|
|
||||||
postContact('');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#cvFile').on('change', function () {
|
function formError() {
|
||||||
var file = this.files && this.files[0];
|
$('#contactForm').removeClass().addClass('contact-form shake').one('animationend', function () {
|
||||||
$('#cvFileName').text(file ? file.name : 'PDF only, max size handled by backend');
|
$(this).removeClass('shake');
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$('#cvMatcherForm').on('submit', async function (event) {
|
$('#contactForm').on('submit', function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var file = $('#cvFile')[0] && $('#cvFile')[0].files[0];
|
var loader = $('#contactLoader'),
|
||||||
var jobUrl = $('#jobUrl').val();
|
button = $('#submit');
|
||||||
var jobDescription = $('#jobDescription').val();
|
loader.css('display', 'flex');
|
||||||
var consent = $('#gdprConsent').is(':checked');
|
button.prop('disabled', true);
|
||||||
var $msg = $('#matcherMsg');
|
$('#msgSubmit').text('');
|
||||||
var $button = $('#matchSubmit');
|
|
||||||
var $result = $('#matchResult');
|
|
||||||
|
|
||||||
if (!file) { $msg.removeClass().addClass('form-message text-danger').text('Please upload a CV PDF.'); return; }
|
function postContact(token) {
|
||||||
if (!jobUrl && !jobDescription) { $msg.removeClass().addClass('form-message text-danger').text('Add a job link or paste a job description.'); return; }
|
var message = {
|
||||||
if (!consent) { $msg.removeClass().addClass('form-message text-danger').text('GDPR consent is required.'); return; }
|
Name: $('#name').val(),
|
||||||
|
Email: $('#email').val(),
|
||||||
|
Subject: '[MyAi.ro contact request]',
|
||||||
|
Message: $('#message').val(),
|
||||||
|
CaptchaToken: token || ''
|
||||||
|
};
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '/api/contact',
|
||||||
|
data: JSON.stringify(message),
|
||||||
|
contentType: 'application/json; charset=utf-8',
|
||||||
|
dataType: 'json'
|
||||||
|
}).done(function (resp) {
|
||||||
|
if (resp && resp.ok === true) formSuccess();
|
||||||
|
else submitMSG(false, t('form.captchaFailed'));
|
||||||
|
}).fail(function () {
|
||||||
|
submitMSG(false, t('form.failed'));
|
||||||
|
formError();
|
||||||
|
}).always(function () {
|
||||||
|
loader.hide();
|
||||||
|
button.prop('disabled', false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (window.grecaptcha && reCaptchaSiteKey) {
|
||||||
|
grecaptcha.ready(function () {
|
||||||
|
grecaptcha.execute(reCaptchaSiteKey, {
|
||||||
|
action: 'contact'
|
||||||
|
}).then(postContact);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
postContact('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$button.prop('disabled', true).text('Processing...');
|
$('#cvFile').on('change', function () {
|
||||||
$msg.removeClass().addClass('form-message').text('Extracting CV and matching job...');
|
var file = this.files && this.files[0];
|
||||||
$result.html('<div class="empty-result">Processing CV PDF and job input. Backend endpoints must be available.</div>');
|
$('#cvFileName').text(file ? file.name : t('cv.fileHint'));
|
||||||
|
});
|
||||||
|
$('#cvMatcherForm').on('submit', async function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var file = $('#cvFile')[0] && $('#cvFile')[0].files[0];
|
||||||
|
var jobUrl = $('#jobUrl').val();
|
||||||
|
var jobDescription = $('#jobDescription').val();
|
||||||
|
var consent = $('#gdprConsent').is(':checked');
|
||||||
|
var $msg = $('#matcherMsg'),
|
||||||
|
$button = $('#matchSubmit'),
|
||||||
|
$result = $('#matchResult');
|
||||||
|
if (!file) {
|
||||||
|
$msg.removeClass().addClass('form-message text-danger').text(t('cv.noFile'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!jobUrl && !jobDescription) {
|
||||||
|
$msg.removeClass().addClass('form-message text-danger').text(t('cv.noJob'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!consent) {
|
||||||
|
$msg.removeClass().addClass('form-message text-danger').text(t('cv.noConsent'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$button.prop('disabled', true).text(t('cv.processing'));
|
||||||
|
$msg.removeClass().addClass('form-message').text(t('cv.extracting'));
|
||||||
|
$result.html('<div class="empty-result">' + escapeHtml(t('cv.processingLong')) + '</div>');
|
||||||
|
try {
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append('cv', file);
|
||||||
|
formData.append('gdprConsent', String(consent));
|
||||||
|
var cvResponse = await fetch('/api/rag/cv', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
if (!cvResponse.ok) throw new Error(t('cv.cvFailed'));
|
||||||
|
var cvData = await cvResponse.json();
|
||||||
|
var matchResponse = await fetch('/api/rag/match-job', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
cvDocumentId: cvData.documentId || cvData.cvDocumentId,
|
||||||
|
jobUrl: jobUrl,
|
||||||
|
jobDescription: jobDescription,
|
||||||
|
gdprConsent: consent
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (!matchResponse.ok) throw new Error(t('cv.matchFailed'));
|
||||||
|
var match = await matchResponse.json();
|
||||||
|
renderMatchResult(match);
|
||||||
|
$msg.removeClass().addClass('form-message text-success').text(t('cv.completed'));
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
$msg.removeClass().addClass('form-message text-danger').text(err.message || t('cv.matchFailed'));
|
||||||
|
$result.html('<div class="empty-result">' + escapeHtml(t('cv.backendMissing')) + '</div>');
|
||||||
|
} finally {
|
||||||
|
$button.prop('disabled', false).text(t('cv.submit'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
function renderMatchResult(match) {
|
||||||
var formData = new FormData();
|
var score = match.score || match.matchScore || 0;
|
||||||
formData.append('cv', file);
|
var summary = match.summary || t('cv.noSummary');
|
||||||
formData.append('gdprConsent', String(consent));
|
var strengths = match.strengths || [];
|
||||||
|
var gaps = match.gaps || match.missingSkills || [];
|
||||||
|
var evidence = match.evidence || match.retrievedChunks || [];
|
||||||
|
|
||||||
var cvResponse = await fetch('/api/rag/cv', { method: 'POST', body: formData });
|
function list(items) {
|
||||||
if (!cvResponse.ok) throw new Error('CV extraction failed');
|
if (!items || !items.length) return '<p class="empty-result">' + escapeHtml(t('cv.noItems')) + '</p>';
|
||||||
var cvData = await cvResponse.json();
|
return '<ul class="result-list">' + items.map(function (x) {
|
||||||
|
var text = typeof x === 'string' ? x : (x.text || x.title || JSON.stringify(x));
|
||||||
|
return '<li>' + escapeHtml(text) + '</li>';
|
||||||
|
}).join('') + '</ul>';
|
||||||
|
}
|
||||||
|
$('#matchResult').html('<div class="score-badge">' + Number(score).toFixed(0) + '%</div><p>' + escapeHtml(summary) + '</p><h3>' + t('cv.strengths') + '</h3>' + list(strengths) + '<h3>' + t('cv.gaps') + '</h3>' + list(gaps) + '<h3>' + t('cv.evidence') + '</h3>' + list(evidence));
|
||||||
|
}
|
||||||
|
|
||||||
var matchResponse = await fetch('/api/rag/match-job', {
|
function escapeHtml(value) {
|
||||||
method: 'POST',
|
return String(value).replace(/[&<>'"]/g, function (char) {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
return ({
|
||||||
body: JSON.stringify({
|
'&': '&',
|
||||||
cvDocumentId: cvData.documentId || cvData.cvDocumentId,
|
'<': '<',
|
||||||
jobUrl: jobUrl,
|
'>': '>',
|
||||||
jobDescription: jobDescription,
|
"'": ''',
|
||||||
gdprConsent: consent
|
'"': '"'
|
||||||
})
|
})[char];
|
||||||
});
|
});
|
||||||
if (!matchResponse.ok) throw new Error('Job matching failed');
|
}
|
||||||
var match = await matchResponse.json();
|
$(window).on('load', function () {
|
||||||
renderMatchResult(match);
|
$.when(getRecaptchaWebKey(), getGoogleTagManagerId()).always(initConsent);
|
||||||
$msg.removeClass().addClass('form-message text-success').text('Match completed.');
|
});
|
||||||
} catch (err) {
|
})(jQuery);
|
||||||
console.error(err);
|
|
||||||
$msg.removeClass().addClass('form-message text-danger').text(err.message || 'Failed to run the matcher.');
|
|
||||||
$result.html('<div class="empty-result">The frontend is ready, but the backend endpoints /api/rag/cv and /api/rag/match-job must be implemented.</div>');
|
|
||||||
} finally {
|
|
||||||
$button.prop('disabled', false).text('Extract CV and match job');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function renderMatchResult(match) {
|
|
||||||
var score = match.score || match.matchScore || 0;
|
|
||||||
var summary = match.summary || 'No summary returned.';
|
|
||||||
var strengths = match.strengths || [];
|
|
||||||
var gaps = match.gaps || match.missingSkills || [];
|
|
||||||
var evidence = match.evidence || match.retrievedChunks || [];
|
|
||||||
|
|
||||||
function list(items) {
|
|
||||||
if (!items || !items.length) return '<p class="empty-result">No items returned.</p>';
|
|
||||||
return '<ul class="result-list">' + items.map(function (x) {
|
|
||||||
var text = typeof x === 'string' ? x : (x.text || x.title || JSON.stringify(x));
|
|
||||||
return '<li>' + escapeHtml(text) + '</li>';
|
|
||||||
}).join('') + '</ul>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#matchResult').html(
|
|
||||||
'<div class="score-badge">' + Number(score).toFixed(0) + '%</div>' +
|
|
||||||
'<p>' + escapeHtml(summary) + '</p>' +
|
|
||||||
'<h3>Strengths</h3>' + list(strengths) +
|
|
||||||
'<h3>Gaps</h3>' + list(gaps) +
|
|
||||||
'<h3>Retrieved CV evidence</h3>' + list(evidence)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function escapeHtml(value) {
|
|
||||||
return String(value).replace(/[&<>'"]/g, function (char) {
|
|
||||||
return ({ '&': '&', '<': '<', '>': '>', "'": ''', '"': '"' })[char];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$(window).on('load', function () {
|
|
||||||
$.when(getRecaptchaWebKey(), getGoogleTagManagerId()).always(initConsent);
|
|
||||||
});
|
|
||||||
})(jQuery);
|
|
||||||
@@ -9,22 +9,24 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<a class="brand" href="\" aria-label="myAi home">
|
<a class="brand" href="/" aria-label="Back">
|
||||||
<div class="brand-badge">
|
<span class="brand-mark">
|
||||||
<img src="\logo.png" alt="myAi">
|
<img src="/img/myai-logo.svg" alt="MyAi.ro">
|
||||||
</div>
|
</span>
|
||||||
<div class="brand-copy">myAi<small>Legal pages</small></div>
|
<span>
|
||||||
</a>
|
<span class="brand-text">Back</span>
|
||||||
<div class="switcher">
|
</span>
|
||||||
<a href="cookies-ro.html" class="lang-link " data-lang="ro" aria-label="Română">
|
</a>
|
||||||
<img src="img/flags/ro.svg" alt="Română">
|
<div class="switcher">
|
||||||
</a>
|
<a href="cookies-ro.html" class="lang-link " data-lang="ro" aria-label="Română">
|
||||||
<a href="cookies-en.html" class="lang-link active" data-lang="en" aria-label="English">
|
<img src="img/flags/ro.svg" alt="Română">
|
||||||
<img src="img/flags/en.svg" alt="English">
|
</a>
|
||||||
</a>
|
<a href="cookies-en.html" class="lang-link active" data-lang="en" aria-label="English">
|
||||||
|
<img src="img/flags/en.svg" alt="English">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hero">
|
<div class="hero">
|
||||||
<div class="kicker">Cookies</div>
|
<div class="kicker">Cookies</div>
|
||||||
|
|||||||
@@ -10,11 +10,13 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<a class="brand" href="\" aria-label="myAi home">
|
<a class="brand" href="/" aria-label="Inapoi">
|
||||||
<div class="brand-badge">
|
<span class="brand-mark">
|
||||||
<img src="\logo.png" alt="myAi">
|
<img src="/img/myai-logo.svg" alt="MyAi.ro">
|
||||||
</div>
|
</span>
|
||||||
<div class="brand-copy">myAi<small>Pagini legale</small></div>
|
<span>
|
||||||
|
<span class="brand-text">Inapoi</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="switcher">
|
<div class="switcher">
|
||||||
<a href="cookies-ro.html" class="lang-link active" data-lang="ro" aria-label="Română">
|
<a href="cookies-ro.html" class="lang-link active" data-lang="ro" aria-label="Română">
|
||||||
|
|||||||
+205
-75
@@ -1,86 +1,216 @@
|
|||||||
|
|
||||||
:root{
|
:root {
|
||||||
--bg:#07192f;
|
--bg: #07192f;
|
||||||
--bg2:#0a2441;
|
--bg2: #0a2441;
|
||||||
--card:#0e1f37;
|
--card: #0e1f37;
|
||||||
--text:#eaf2ff;
|
--text: #eaf2ff;
|
||||||
--muted:#b4c5dd;
|
--muted: #b4c5dd;
|
||||||
--line:rgba(255,255,255,.10);
|
--line: rgba(255,255,255,.10);
|
||||||
--accent:#7eb7ff;
|
--accent: #7eb7ff;
|
||||||
}
|
|
||||||
*{box-sizing:border-box}
|
|
||||||
body{
|
|
||||||
margin:0;
|
|
||||||
font-family:Arial,Helvetica,sans-serif;
|
|
||||||
background:
|
|
||||||
radial-gradient(circle at top left, rgba(79,140,255,.18), transparent 28%),
|
|
||||||
linear-gradient(180deg, var(--bg) 0%, #05111f 100%);
|
|
||||||
color:var(--text);
|
|
||||||
line-height:1.75;
|
|
||||||
}
|
|
||||||
a{color:var(--accent);text-decoration:none}
|
|
||||||
a:hover{text-decoration:none}
|
|
||||||
.wrap{max-width:1100px;margin:0 auto;padding:28px 20px 60px}
|
|
||||||
.topbar{
|
|
||||||
display:flex;justify-content:space-between;align-items:center;gap:16px;
|
|
||||||
padding:10px 0 22px;margin-bottom:24px;border-bottom:1px solid var(--line);
|
|
||||||
}
|
|
||||||
.brand{display:flex;align-items:center;gap:14px;}
|
|
||||||
.brand-badge {
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
background: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand-badge img {
|
* {
|
||||||
width: 100%;
|
box-sizing: border-box
|
||||||
height: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand-copy small{display:block;color:var(--muted);font-weight:400}
|
body {
|
||||||
.switcher{display:flex;align-items:center;gap:10px}
|
margin: 0;
|
||||||
.switcher a{
|
font-family: Arial,Helvetica,sans-serif;
|
||||||
display:inline-flex;align-items:center;justify-content:center;
|
background: radial-gradient(circle at top left, rgba(79,140,255,.18), transparent 28%), linear-gradient(180deg, var(--bg) 0%, #05111f 100%);
|
||||||
width:44px;height:44px;border-radius:999px;border:1px solid var(--line);
|
color: var(--text);
|
||||||
background:rgba(255,255,255,.04);transition:.2s ease;
|
line-height: 1.75;
|
||||||
}
|
}
|
||||||
.switcher a:hover{text-decoration:none;transform:translateY(-1px)}
|
|
||||||
.switcher a.active{border-color:rgba(126,183,255,.65);box-shadow:0 0 0 3px rgba(126,183,255,.13)}
|
a {
|
||||||
.switcher img{width:24px;height:24px;display:block}
|
color: var(--accent);
|
||||||
.hero,.content,.footer{
|
text-decoration: none
|
||||||
background:linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,255,255,.02));
|
|
||||||
border:1px solid var(--line);
|
|
||||||
border-radius:22px;
|
|
||||||
box-shadow:0 25px 60px rgba(0,0,0,.18);
|
|
||||||
}
|
}
|
||||||
.hero{padding:28px 30px;margin-bottom:18px}
|
|
||||||
.kicker{
|
a:hover {
|
||||||
display:inline-block;padding:8px 12px;border-radius:999px;
|
text-decoration: none
|
||||||
background:rgba(255,255,255,.04);border:1px solid var(--line);color:var(--muted);
|
}
|
||||||
font-size:13px;margin-bottom:12px
|
|
||||||
|
.wrap {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 28px 20px 60px
|
||||||
}
|
}
|
||||||
.hero h1{margin:0 0 8px;font-size:40px;line-height:1.08}
|
|
||||||
.hero p{margin:0;color:var(--muted);max-width:780px}
|
.topbar {
|
||||||
.content{padding:30px}
|
display: flex;
|
||||||
.content h2{font-size:28px;line-height:1.15;margin:28px 0 10px}
|
justify-content: space-between;
|
||||||
.content h2:first-child{margin-top:0}
|
align-items: center;
|
||||||
.content p{margin:0 0 14px;color:#deebff}
|
gap: 16px;
|
||||||
.content ul{margin:0 0 18px 22px;padding:0}
|
padding: 10px 0 22px;
|
||||||
.content li{margin-bottom:8px;color:#deebff}
|
margin-bottom: 24px;
|
||||||
.notice{
|
border-bottom: 1px solid var(--line);
|
||||||
margin:16px 0 18px;padding:16px 18px;border-radius:18px;
|
|
||||||
background:rgba(126,183,255,.08);border:1px solid rgba(126,183,255,.18)
|
|
||||||
}
|
}
|
||||||
.footer{
|
|
||||||
margin-top:18px;padding:22px 26px;display:flex;justify-content:space-between;gap:16px;align-items:center;flex-wrap:wrap
|
.brand {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
}
|
}
|
||||||
.footer-links{display:flex;gap:18px;flex-wrap:wrap}
|
|
||||||
.footer small{color:var(--muted)}
|
.brand-text {
|
||||||
.meta{color:var(--muted);font-size:14px}
|
font-size: 1.35rem
|
||||||
@media (max-width:768px){
|
}
|
||||||
.hero h1{font-size:32px}
|
|
||||||
.content{padding:22px}
|
.brand small {
|
||||||
.content h2{font-size:24px}
|
display: none
|
||||||
.topbar{align-items:flex-start;flex-direction:column}
|
}
|
||||||
|
|
||||||
|
.brand-mark {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px
|
||||||
|
}
|
||||||
|
|
||||||
|
.switcher {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
.switcher a {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: rgba(255,255,255,.04);
|
||||||
|
transition: .2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switcher a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
transform: translateY(-1px)
|
||||||
|
}
|
||||||
|
|
||||||
|
.switcher a.active {
|
||||||
|
border-color: rgba(126,183,255,.65);
|
||||||
|
box-shadow: 0 0 0 3px rgba(126,183,255,.13)
|
||||||
|
}
|
||||||
|
|
||||||
|
.switcher img {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
display: block
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero, .content, .footer {
|
||||||
|
background: linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,255,255,.02));
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 22px;
|
||||||
|
box-shadow: 0 25px 60px rgba(0,0,0,.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
padding: 28px 30px;
|
||||||
|
margin-bottom: 18px
|
||||||
|
}
|
||||||
|
|
||||||
|
.kicker {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255,255,255,.04);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
font-size: 40px;
|
||||||
|
line-height: 1.08
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
max-width: 780px
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 30px
|
||||||
|
}
|
||||||
|
|
||||||
|
.content h2 {
|
||||||
|
font-size: 28px;
|
||||||
|
line-height: 1.15;
|
||||||
|
margin: 28px 0 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
.content h2:first-child {
|
||||||
|
margin-top: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.content p {
|
||||||
|
margin: 0 0 14px;
|
||||||
|
color: #deebff
|
||||||
|
}
|
||||||
|
|
||||||
|
.content ul {
|
||||||
|
margin: 0 0 18px 22px;
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.content li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #deebff
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice {
|
||||||
|
margin: 16px 0 18px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(126,183,255,.08);
|
||||||
|
border: 1px solid rgba(126,183,255,.18)
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin-top: 18px;
|
||||||
|
padding: 22px 26px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links {
|
||||||
|
display: flex;
|
||||||
|
gap: 18px;
|
||||||
|
flex-wrap: wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer small {
|
||||||
|
color: var(--muted)
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:768px) {
|
||||||
|
.hero h1 {
|
||||||
|
font-size: 32px
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 22px
|
||||||
|
}
|
||||||
|
|
||||||
|
.content h2 {
|
||||||
|
font-size: 24px
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,22 +9,24 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<a class="brand" href="\" aria-label="myAi home">
|
<a class="brand" href="/" aria-label="Back">
|
||||||
<div class="brand-badge">
|
<span class="brand-mark">
|
||||||
<img src="\logo.png" alt="myAi">
|
<img src="/img/myai-logo.svg" alt="MyAi.ro">
|
||||||
</div>
|
</span>
|
||||||
<div class="brand-copy">myAi<small>Legal pages</small></div>
|
<span>
|
||||||
</a>
|
<span class="brand-text">Back</span>
|
||||||
<div class="switcher">
|
</span>
|
||||||
<a href="privacy-ro.html" class="lang-link " data-lang="ro" aria-label="Română">
|
</a>
|
||||||
<img src="img/flags/ro.svg" alt="Română">
|
<div class="switcher">
|
||||||
</a>
|
<a href="privacy-ro.html" class="lang-link " data-lang="ro" aria-label="Română">
|
||||||
<a href="privacy-en.html" class="lang-link active" data-lang="en" aria-label="English">
|
<img src="img/flags/ro.svg" alt="Română">
|
||||||
<img src="img/flags/en.svg" alt="English">
|
</a>
|
||||||
</a>
|
<a href="privacy-en.html" class="lang-link active" data-lang="en" aria-label="English">
|
||||||
|
<img src="img/flags/en.svg" alt="English">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hero">
|
<div class="hero">
|
||||||
<div class="kicker">Data protection</div>
|
<div class="kicker">Data protection</div>
|
||||||
|
|||||||
@@ -10,11 +10,13 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<a class="brand" href="\" aria-label="myAi home">
|
<a class="brand" href="/" aria-label="Inapoi">
|
||||||
<div class="brand-badge">
|
<span class="brand-mark">
|
||||||
<img src="\logo.png" alt="myAi">
|
<img src="/img/myai-logo.svg" alt="MyAi.ro">
|
||||||
</div>
|
</span>
|
||||||
<div class="brand-copy">myAi<small>Pagini legale</small></div>
|
<span>
|
||||||
|
<span class="brand-text">Inapoi</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="switcher">
|
<div class="switcher">
|
||||||
<a href="privacy-ro.html" class="lang-link active" data-lang="ro" aria-label="Română">
|
<a href="privacy-ro.html" class="lang-link active" data-lang="ro" aria-label="Română">
|
||||||
|
|||||||
@@ -10,11 +10,13 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<a class="brand" href="\" aria-label="myAi home">
|
<a class="brand" href="/" aria-label="Back">
|
||||||
<div class="brand-badge">
|
<span class="brand-mark">
|
||||||
<img src="\logo.png" alt="myAi">
|
<img src="/img/myai-logo.svg" alt="MyAi.ro">
|
||||||
</div>
|
</span>
|
||||||
<div class="brand-copy">myAi<small>Legal pages</small></div>
|
<span>
|
||||||
|
<span class="brand-text">Back</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="switcher">
|
<div class="switcher">
|
||||||
<a href="terms-ro.html" class="lang-link " data-lang="ro" aria-label="Română">
|
<a href="terms-ro.html" class="lang-link " data-lang="ro" aria-label="Română">
|
||||||
|
|||||||
@@ -10,11 +10,13 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<a class="brand" href="\" aria-label="myAi home">
|
<a class="brand" href="/" aria-label="Inapoi">
|
||||||
<div class="brand-badge">
|
<span class="brand-mark">
|
||||||
<img src="\logo.png" alt="myAi">
|
<img src="/img/myai-logo.svg" alt="MyAi.ro">
|
||||||
</div>
|
</span>
|
||||||
<div class="brand-copy">myAi<small>Pagini legale</small></div>
|
<span>
|
||||||
|
<span class="brand-text">Inapoi</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="switcher">
|
<div class="switcher">
|
||||||
<a href="terms-ro.html" class="lang-link active" data-lang="ro" aria-label="Română">
|
<a href="terms-ro.html" class="lang-link active" data-lang="ro" aria-label="Română">
|
||||||
|
|||||||
Reference in New Issue
Block a user