From 17266730fcc1ee156987f4e72c9c037af948a8c8 Mon Sep 17 00:00:00 2001 From: Gelu Mihes Date: Wed, 6 May 2026 10:56:02 +0300 Subject: [PATCH] Changes --- ...agController.cs => CvMatcherController.cs} | 6 +- api/Program.cs | 2 +- api/Settings/OpenAiSettings.cs | 9 - api/Settings/RagSettings.cs | 11 - api/appsettings.Development.json | 16 +- api/appsettings.json | 4 - cv-matcher-api/cv-matcher-api.csproj | 48 + web/wwwroot/cv-matcher/index.html | 2 +- web/wwwroot/index.html | 2 +- web/wwwroot/js/main.js | 966 +++++++++--------- web/wwwroot/js/myai.js | 520 ---------- 11 files changed, 562 insertions(+), 1024 deletions(-) rename api/Controllers/{RagController.cs => CvMatcherController.cs} (98%) delete mode 100644 api/Settings/OpenAiSettings.cs delete mode 100644 api/Settings/RagSettings.cs delete mode 100644 web/wwwroot/js/myai.js diff --git a/api/Controllers/RagController.cs b/api/Controllers/CvMatcherController.cs similarity index 98% rename from api/Controllers/RagController.cs rename to api/Controllers/CvMatcherController.cs index 94fb7d5..ca464c9 100644 --- a/api/Controllers/RagController.cs +++ b/api/Controllers/CvMatcherController.cs @@ -8,8 +8,8 @@ using System.Text.Json; namespace Api.Controllers; [ApiController] -[Route("api/rag")] -[EnableRateLimiting("rag")] +[Route("api/cv-matcher")] +[EnableRateLimiting("cv-matcher")] public sealed class RagController : ControllerBase { private readonly IHttpClientFactory _httpClientFactory; @@ -26,7 +26,7 @@ public sealed class RagController : ControllerBase _logger = logger; } - [HttpPost("cv")] + [HttpPost("upload")] [RequestSizeLimit(8 * 1024 * 1024)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] diff --git a/api/Program.cs b/api/Program.cs index 3ad17ec..493590c 100644 --- a/api/Program.cs +++ b/api/Program.cs @@ -164,7 +164,7 @@ try }); // Policy: CV matcher, expensive because it calls AI APIs. - options.AddPolicy("rag", httpContext => + options.AddPolicy("cv-matcher", httpContext => { var ip = httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown"; return RateLimitPartition.GetFixedWindowLimiter( diff --git a/api/Settings/OpenAiSettings.cs b/api/Settings/OpenAiSettings.cs deleted file mode 100644 index c6762b6..0000000 --- a/api/Settings/OpenAiSettings.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Api.Settings; - -public sealed class OpenAiSettings -{ - public string ApiKey { get; set; } = string.Empty; - public string ChatModel { get; set; } = "gpt-4o-mini"; - public string EmbeddingModel { get; set; } = "text-embedding-3-small"; - public int TimeoutSeconds { get; set; } = 60; -} diff --git a/api/Settings/RagSettings.cs b/api/Settings/RagSettings.cs deleted file mode 100644 index 405ecb8..0000000 --- a/api/Settings/RagSettings.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Api.Settings; - -public sealed class RagSettings -{ - public int MaxPdfSizeMb { get; set; } = 5; - public int ChunkSize { get; set; } = 900; - public int ChunkOverlap { get; set; } = 150; - public int CvTtlMinutes { get; set; } = 60; - public int MaxJobTextChars { get; set; } = 20000; - public int TopK { get; set; } = 6; -} diff --git a/api/appsettings.Development.json b/api/appsettings.Development.json index c39ae92..f3cde72 100644 --- a/api/appsettings.Development.json +++ b/api/appsettings.Development.json @@ -76,18 +76,8 @@ "FromEmail": "", "SubjectPrefix": "[File Download]" }, - "OpenAI": { - "ApiKey": "", - "ChatModel": "gpt-4o-mini", - "EmbeddingModel": "text-embedding-3-small", - "TimeoutSeconds": 60 - }, - "Rag": { - "MaxPdfSizeMb": 5, - "ChunkSize": 900, - "ChunkOverlap": 150, - "CvTtlMinutes": 60, - "MaxJobTextChars": 20000, - "TopK": 6 + "CvMatcherApi": { + "BaseUrl": "", + "InternalApiKey": "" } } diff --git a/api/appsettings.json b/api/appsettings.json index 80f5c9a..6fb2ddd 100644 --- a/api/appsettings.json +++ b/api/appsettings.json @@ -105,9 +105,5 @@ "ToEmail": "", "FromEmail": "", "SubjectPrefix": "[File Download]" - }, - "CvMatcherApi": { - "BaseUrl": "", - "InternalApiKey": "" } } \ No newline at end of file diff --git a/cv-matcher-api/cv-matcher-api.csproj b/cv-matcher-api/cv-matcher-api.csproj index 1ebc13d..b586214 100644 --- a/cv-matcher-api/cv-matcher-api.csproj +++ b/cv-matcher-api/cv-matcher-api.csproj @@ -6,6 +6,54 @@ Linux Api + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/wwwroot/cv-matcher/index.html b/web/wwwroot/cv-matcher/index.html index e149797..5b5a784 100644 --- a/web/wwwroot/cv-matcher/index.html +++ b/web/wwwroot/cv-matcher/index.html @@ -194,6 +194,6 @@ - + \ No newline at end of file diff --git a/web/wwwroot/index.html b/web/wwwroot/index.html index 69c178c..50c6ee4 100644 --- a/web/wwwroot/index.html +++ b/web/wwwroot/index.html @@ -194,6 +194,6 @@ - + \ No newline at end of file diff --git a/web/wwwroot/js/main.js b/web/wwwroot/js/main.js index efad811..26c8802 100644 --- a/web/wwwroot/js/main.js +++ b/web/wwwroot/js/main.js @@ -1,490 +1,534 @@ -var translations = { - ro: { - 'brand.tagline': 'Romania dezvoltare applicatii', - 'nav.products': 'Produse', 'nav.services': 'Servicii', 'nav.contact': 'Contactati-ne', - 'hero.eyebrow': 'Portofoliu software easySoft', - 'hero.title': 'Software pentru cabinete dentare, gestiune de stocuri si salvare sigura a datelor.', - 'hero.text': 'Aplicatii practice construite pentru fluxuri reale de lucru: managementul pacientilor, contabilitate si gestiune, plus backup automatizat pentru fisiere importante.', - 'hero.ctaPrimary': 'Vezi produsele', 'hero.ctaSecondary': 'Contactati-ne', - 'hero.metric1': 'aplicații software', 'hero.metric2': 'ani experiență în dezvoltare', 'hero.metric3': 'instalări active', - 'hero.cardLabel': 'Portofoliu software', 'hero.badge1': 'cabinete dentare', 'hero.badge2': 'gestiune si contabilitate', 'hero.badge3': 'salvare automata', - 'products.eyebrow': 'Produse', 'products.title': 'Aplicatii software pentru activitati de zi cu zi', 'products.text': 'Portofoliul actual include aplicatii pentru cabinete stomatologice, operatiuni comerciale si protectia datelor.', - 'products.easydent.title': 'Soft pentru cabinete stomatologice', - 'products.easydent.desc': 'easyDent este un program destinat cabinetelor stomatologice si clinicilor dentare. Puteti urmari pacienti, plati, interventii, pacienti restantieri si profitul pe perioade de timp.', - 'products.easydent.feature1': 'Planificarea pacientilor intr-o sectiune simplu de utilizat', 'products.easydent.feature2': 'Imagini dentare, istoric pe dinte si poze atasate pacientilor', 'products.easydent.feature3': 'Raport lunar CNAS si configurare pe specializari', - 'products.easyerp.title': 'Soft de contabilitate si gestiunea stocurilor', - 'products.easyerp.desc': 'easyERP este un program client-server, bazat pe SQL, compus din module pentru diferite divizii ale companiei: gestiune, contabilitate, facturare, livrari, comenzi si promotii.', - 'products.easyerp.feature1': 'Receptie de marfa, inventar si cautare rapida in nomenclatoare', 'products.easyerp.feature2': 'Control pe roluri si drepturi de acces pe module', 'products.easyerp.feature3': 'Documente comerciale si rapoarte operationale', - 'products.easybackup.title': 'Utilitar pentru salvarea fisierelor', - 'products.easybackup.desc': 'easyBackup salveaza fisiere in directoare partajate sau pe servere FTP, cu job-uri recurente sau simple, monitorizare in timp si optiuni de compresie si notificare.', - 'products.easybackup.feature1': 'Definire job-uri recurente sau simple', 'products.easybackup.feature2': 'Scanare directoare cu excluderi si filtre', 'products.easybackup.feature3': 'Compresie, parola si notificari prin e-mail', - 'products.download': 'Descarca', - 'services.eyebrow': 'Servicii', 'services.title': 'Servicii software si consultanta IT', - 'services.db.title': 'Proiectare baze de date', 'services.db.text': 'Organizati mai bine informatiile si obtineti rapoartele de care aveti nevoie.', - 'services.it.title': 'Consultanta IT', 'services.it.text': 'Analizam ofertele disponibile si alegem sistemul informatic potrivit pentru activitatea dumneavoastra.', - 'services.dev.title': 'Dezvoltare software', 'services.dev.text': 'Construim aplicatii adaptate fluxului real de lucru, nu invers.', - 'about.eyebrow': 'easySoft', 'about.title': 'Solutii software construite pentru lucru real', - 'about.text1': 'Portofoliul easySoft acopera activitati esentiale pentru cabinete stomatologice, evidenta comerciala si protectia fisierelor importante.', - 'about.text2': 'Aplicatiile sunt gandite pentru utilizare practica, implementare rapida si acces clar la informatiile care conteaza in activitatea zilnica.', - 'about.point1Title': 'Implementare practica', 'about.point1Text': 'Produse software orientate spre utilizare zilnica.', - 'about.point2Title': 'Fluxuri clare', 'about.point2Text': 'Planificare, evidenta, facturare, rapoarte si backup in functii usor de urmarit.', - 'about.point3Title': 'Suport comercial direct', 'about.point3Text': 'Pentru prezentare, oferta sau implementare, puteti lua legatura direct cu easySoft.', - 'contact.eyebrow': 'Contactati-ne', 'contact.title': 'Discutam despre nevoile tale software', - 'contact.text': 'easySoft Romania dezvoltare applicatii. Pentru prezentari, detalii comerciale sau implementare, folositi datele de mai jos.', - 'contact.personLabel': 'Persoana de contact', 'contact.addressLabel': 'Adresa', 'contact.phoneLabel': 'Telefon', 'contact.webLabel': 'Website', - 'contact.form.name': 'Nume', 'contact.form.email': 'Email', 'contact.form.message': 'Mesaj', 'contact.form.send': 'Trimite mesaj', - 'contact.form.yourname': 'Numele dumneavoastra', 'contact.form.youremail': 'nume@companie.ro', 'contact.form.yourmessage': 'Spuneti-ne ce produs sau serviciu va intereseaza.', - 'contact.form.success': 'Va multumim pentru mesaj.', 'contact.form.submissionfailed': 'A aparut o eroare la transmiterea mesajului.', 'contact.form.verificationfailed': 'A aparut o eroare la verificare Captcha.', - 'footer.backToTop': 'Inapoi sus', - 'cookie.text': 'Folosim cookie-uri pentru a imbunatati experienta pe site, a analiza traficul si a personaliza continutul. Puteti accepta toate cookie-urile sau doar cele necesare.', - 'cookie.privacy': 'Politica de confidentialitate', - 'cookie.reject': 'Respinge', - 'cookie.necessary': 'Doar necesare', - 'cookie.accept': 'Accepta analitice', - 'footer.rights': 'Toate drepturile rezervate' - }, - en: { - 'brand.tagline': 'Romania software development', - 'nav.products': 'Products', 'nav.services': 'Services', 'nav.contact': 'Contact us', - 'hero.eyebrow': 'easySoft software portfolio', - 'hero.title': 'Software for dental offices, stock management and secure data backup.', - 'hero.text': 'Practical applications built for real workflows: patient management, accounting and inventory, plus automated backup for critical files.', - 'hero.ctaPrimary': 'View products', 'hero.ctaSecondary': 'Contact us', - 'hero.metric1': 'software solutions', 'hero.metric2': 'years experience in software development', 'hero.metric3': 'active installations', - 'hero.cardLabel': 'Software portfolio', 'hero.badge1': 'dental offices', 'hero.badge2': 'inventory and accounting', 'hero.badge3': 'automatic backup', - 'products.eyebrow': 'Products', 'products.title': 'Software applications for daily operations', 'products.text': 'The current portfolio includes applications for dental offices, business operations and data protection.', - 'products.easydent.title': 'Software for dental offices', - 'products.easydent.desc': 'easyDent is built for dental offices and clinics. It helps track patients, payments, interventions, outstanding balances and profit over time.', - 'products.easydent.feature1': 'Simple patient scheduling section', 'products.easydent.feature2': 'Dental images, tooth history and attached patient photos', 'products.easydent.feature3': 'Monthly reports and specialization-based setup', - 'products.easyerp.title': 'Accounting and stock management software', - 'products.easyerp.desc': 'easyERP is a client-server SQL-based application with modules for company divisions: inventory, accounting, invoicing, deliveries, orders and promotions.', - 'products.easyerp.feature1': 'Receiving merchandise, inventory and fast search', 'products.easyerp.feature2': 'Role-based permissions for modules', 'products.easyerp.feature3': 'Commercial documents and operational reports', - 'products.easybackup.title': 'File backup utility', - 'products.easybackup.desc': 'easyBackup saves files to shared folders or FTP servers using recurring or one-time jobs, change tracking, compression and notifications.', - 'products.easybackup.feature1': 'Recurring or one-time backup jobs', 'products.easybackup.feature2': 'Directory scanning with exclusions and filters', 'products.easybackup.feature3': 'Compression, password protection and email alerts', - 'products.download': 'Download', - 'services.eyebrow': 'Services', 'services.title': 'Software services and IT consulting', - 'services.db.title': 'Database design', 'services.db.text': 'Organize information better and get the reports you actually need.', - 'services.it.title': 'IT consulting', 'services.it.text': 'We review available systems and help choose the right software solution.', - 'services.dev.title': 'Software development', 'services.dev.text': 'We build applications around the real workflow, not the other way around.', - 'about.eyebrow': 'easySoft', 'about.title': 'Software solutions built for real work', - 'about.text1': 'The easySoft portfolio covers essential workflows for dental offices, commercial operations and protection of important files.', - 'about.text2': 'The applications are built for practical use, fast implementation and clear access to the information that matters every day.', - 'about.point1Title': 'Practical implementation', 'about.point1Text': 'Software products focused on daily use.', - 'about.point2Title': 'Clear workflows', 'about.point2Text': 'Scheduling, records, invoicing, reports and backup in functions that are easy to follow.', - 'about.point3Title': 'Direct commercial support', 'about.point3Text': 'For presentation, pricing or implementation, you can contact easySoft directly.', - 'contact.eyebrow': 'Contact us', 'contact.title': 'Let’s discuss your software needs', - 'contact.text': 'easySoft Romania software development. For product presentations, commercial details or implementation, use the contact details below.', - 'contact.personLabel': 'Contact person', 'contact.addressLabel': 'Address', 'contact.phoneLabel': 'Phone', 'contact.webLabel': 'Website', - 'contact.form.name': 'Name', 'contact.form.email': 'Email', 'contact.form.message': 'Message', 'contact.form.send': 'Send message', - 'contact.form.yourname': 'Your name', 'contact.form.youremail': 'name@company.com', 'contact.form.yourmessage': 'Let us know how we can help you.', - 'contact.form.success': 'Thank you for your message.', 'contact.form.submissionfailed': 'Failed to send the message.', 'contact.form.verificationfailed': 'Captcha verification failed.', - 'footer.backToTop': 'Back to top', - 'cookie.text': 'We use cookies to enhance your experience, analyze traffic and personalize content. You can accept all cookies or just the necessary ones.', - 'cookie.privacy': 'Privacy policy', - 'cookie.reject': 'Reject', - 'cookie.necessary': 'Necessary only', - 'cookie.accept': 'Accept analytics', - 'footer.rights': 'All rights reserved' - } -}; - -function updateLegalLinks(lang) { - $('.legal-link').each(function () { - var $link = $(this); - - if (lang === 'ro') { - $link.attr('href', $link.attr('data-ro-href')); - $link.text($link.attr('data-ro-text')); - } else { - $link.attr('href', $link.attr('data-en-href')); - $link.text($link.attr('data-en-text')); - } - }); -} - -function applyLanguage(lang) { - var dict = translations[lang] || translations.en; - - $('[data-i18n]').each(function () { - var key = $(this).data('i18n'); - - if (!key) return; - - // Handle special attributes like [placeholder] - var match = key.match(/^\[(.*?)\](.*)$/); - - if (match) { - var attr = match[1]; // e.g. "placeholder" - var realKey = match[2]; // e.g. "contact.form.message" - - if (dict[realKey]) { - $(this).attr(attr, dict[realKey]); - } - } else { - if (dict[key]) { - $(this).text(dict[key]); - } - } - }); - - updateLegalLinks(lang); - - $('html').attr('lang', lang); - localStorage.setItem('easysoft-language', lang); - - $('.lang-flag').each(function () { - var isActive = $(this).data('lang') === lang; - $(this).attr('aria-pressed', isActive ? 'true' : 'false'); - $(this).toggleClass('is-active', isActive); - }); -} - -function detectLanguage() { - var saved = localStorage.getItem('easysoft-language'); - if (saved && translations[saved]) { - return saved; - } - - var browserLang = ((navigator.languages && navigator.languages[0]) || navigator.language || navigator.userLanguage || 'en').toLowerCase(); - if (browserLang.indexOf('ro') === 0) { - return 'ro'; - } - - return 'en'; -} - -function closeMobileMenu() { - $('#mainNav').removeClass('is-open'); - $('#menuToggle').attr('aria-expanded', 'false'); -} - -function initCarousels() { - $('[data-carousel]').each(function () { - var $carousel = $(this); - var $slides = $carousel.find('.carousel-slide'); - var $dotsWrap = $carousel.find('.carousel-dots'); - var index = 0; - var timer = null; - - function renderDots() { - $dotsWrap.empty(); - $slides.each(function (i) { - var $dot = $('