Download static/vhelp.html from vsmdvic/sge: direct link, hf CLI and curl.
- Browser
- Download file 21.1 kB
-
https://huggingface.co/spaces/vsmdvic/sge/resolve/main/static/vhelp.html
- Command line
-
hf download hf://spaces/vsmdvic/sge/static/vhelp.html
-
curl -L -o vhelp.html https://huggingface.co/spaces/vsmdvic/sge/resolve/main/static/vhelp.html
21.1 kB
| <html lang="ro"> | |
| <head> | |
| <link rel="icon" type="image/svg+xml" href="favicon.svg"> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> | |
| <title>SGE | VHelp</title> | |
| <link rel="stylesheet" href="style.css"> | |
| <style> | |
| /* ── VHelp layout ── */ | |
| body { display:flex; flex-direction:column; min-height:100dvh; } | |
| .chat-wrap { | |
| max-width:680px; margin:0 auto; width:100%; | |
| padding:16px 14px 100px; flex:1; | |
| } | |
| /* Mesaje */ | |
| .msg { display:flex; gap:10px; margin-bottom:18px; animation:fadeIn 0.3s ease; } | |
| .msg.user { flex-direction:row-reverse; } | |
| .msg-avatar { | |
| width:32px; height:32px; border-radius:50%; flex-shrink:0; | |
| display:flex; align-items:center; justify-content:center; | |
| background:rgba(255,255,255,0.06); border:1px solid rgba(255,255,255,0.1); | |
| font-size:11px; letter-spacing:1px; color:var(--white-dim); | |
| align-self:flex-end; | |
| } | |
| .msg-avatar img { width:18px; height:18px; opacity:0.6; } | |
| .msg-bubble { | |
| max-width:82%; padding:12px 14px; | |
| background:rgba(255,255,255,0.04); | |
| border:1px solid rgba(255,255,255,0.08); | |
| font-size:12px; line-height:1.8; color:var(--white); | |
| } | |
| .msg.user .msg-bubble { | |
| background:rgba(255,255,255,0.09); | |
| border-color:rgba(255,255,255,0.15); | |
| text-align:right; | |
| } | |
| .msg-time { font-size:8px; color:var(--white-faint); letter-spacing:1px; margin-top:5px; } | |
| .msg.user .msg-time { text-align:right; } | |
| /* Typing indicator */ | |
| .typing-dots { display:flex; gap:4px; padding:4px 0; align-items:center; } | |
| .typing-dots span { | |
| width:6px; height:6px; border-radius:50%; | |
| background:rgba(255,255,255,0.35); | |
| animation:typing-bounce 1.4s ease-in-out infinite; | |
| } | |
| .typing-dots span:nth-child(2) { animation-delay:0.2s; } | |
| .typing-dots span:nth-child(3) { animation-delay:0.4s; } | |
| @keyframes typing-bounce { | |
| 0%,60%,100% { transform:translateY(0); opacity:0.35; } | |
| 30% { transform:translateY(-5px); opacity:1; } | |
| } | |
| /* Typewriter cursor */ | |
| .tw-cursor::after { | |
| content:'|'; animation:blink-cur 0.7s step-end infinite; | |
| color:rgba(255,255,255,0.5); margin-left:1px; | |
| } | |
| @keyframes blink-cur { 0%,100%{opacity:1;} 50%{opacity:0;} } | |
| /* Error badge */ | |
| .err-badge { | |
| display:inline-block; font-size:9px; letter-spacing:2px; | |
| padding:2px 8px; background:rgba(180,60,60,0.15); | |
| border:1px solid rgba(180,60,60,0.3); color:rgba(220,100,100,0.9); | |
| margin-bottom:6px; | |
| } | |
| /* Input bar */ | |
| .input-bar { | |
| position:fixed; bottom:0; left:0; right:0; | |
| background:rgba(10,10,10,0.95); | |
| backdrop-filter:blur(1px); | |
| border-top:1px solid rgba(255,255,255,0.07); | |
| padding:12px 14px; z-index:100; | |
| } | |
| .input-inner { | |
| max-width:680px; margin:0 auto; | |
| display:flex; gap:8px; align-items:flex-end; | |
| } | |
| .input-inner textarea { | |
| flex:1; resize:none; min-height:40px; max-height:120px; | |
| padding:10px 12px; font-size:12px; line-height:1.6; | |
| background:rgba(255,255,255,0.04); border:1px solid rgba(255,255,255,0.1); | |
| color:var(--white); font-family:'DM Mono',monospace; | |
| outline:none; transition:border-color 0.2s; overflow-y:auto; | |
| } | |
| .input-inner textarea:focus { border-color:rgba(255,255,255,0.3); } | |
| .input-inner textarea::placeholder { color:var(--white-faint); } | |
| .btn-send { | |
| width:40px; height:40px; background:var(--white); border:none; | |
| display:flex; align-items:center; justify-content:center; | |
| cursor:pointer; flex-shrink:0; transition:opacity 0.2s; | |
| } | |
| .btn-send:hover { opacity:0.85; } | |
| .btn-send svg { width:16px; height:16px; } | |
| /* Chips — suggestii rapide */ | |
| .chips { display:flex; gap:6px; flex-wrap:wrap; margin-bottom:14px; } | |
| .chip { | |
| background:transparent; border:1px solid rgba(255,255,255,0.1); | |
| color:var(--white-dim); padding:5px 10px; | |
| font-family:'DM Mono',monospace; font-size:9px; letter-spacing:1px; | |
| cursor:pointer; transition:all 0.2s; | |
| } | |
| .chip:hover { border-color:rgba(255,255,255,0.3); color:var(--white); background:rgba(255,255,255,0.04); } | |
| /* Header VHelp */ | |
| .vhelp-header { | |
| display:flex; align-items:center; gap:10px; padding:14px 14px 0; | |
| max-width:680px; margin:0 auto; margin-bottom:16px; | |
| } | |
| .vhelp-logo { | |
| width:36px; height:36px; border-radius:50%; | |
| background:rgba(255,255,255,0.06); border:1px solid rgba(255,255,255,0.12); | |
| display:flex; align-items:center; justify-content:center; | |
| } | |
| .vhelp-logo img { width:20px; height:20px; } | |
| .vhelp-name { font-family:'Cormorant Garamond',serif; font-size:18px; letter-spacing:2px; } | |
| .vhelp-sub { font-size:9px; color:var(--white-dim); letter-spacing:2px; margin-top:1px; } | |
| .vhelp-badge { margin-left:auto; font-size:8px; letter-spacing:2px; padding:3px 8px; border:1px solid rgba(74,138,74,0.5); color:rgba(100,180,100,0.9); } | |
| @keyframes fadeIn { from{opacity:0;transform:translateY(4px);}to{opacity:1;transform:translateY(0);} } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="topbar"> | |
| <a href="javascript:history.back()" class="topbar-logo" style="text-decoration:none;"> | |
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="1.5" stroke-linecap="round" style="margin-right:2px;"><polyline points="15 18 9 12 15 6"/></svg> | |
| <img src="logo.svg" alt="VS" style="margin-left:4px;"> | |
| <span class="topbar-name">SGE</span> | |
| </a> | |
| <div class="topbar-divider"></div> | |
| <span class="topbar-section">VHELP</span> | |
| <div class="topbar-right"> | |
| <span class="role-tag" id="user-tag">—</span> | |
| </div> | |
| </div> | |
| <!-- VHelp header --> | |
| <div class="vhelp-header fade-in"> | |
| <div class="vhelp-logo"><img src="logo.svg" alt="VHelp"></div> | |
| <div> | |
| <div class="vhelp-name">VHelp</div> | |
| <div class="vhelp-sub">Asistent suport SGE</div> | |
| </div> | |
| <div class="vhelp-badge">ONLINE</div> | |
| </div> | |
| <!-- Chat --> | |
| <div class="chat-wrap" id="chat-wrap"> | |
| <div class="chips" id="quick-chips"> | |
| <button class="chip" onclick="sendChip('err-001')">err-001</button> | |
| <button class="chip" onclick="sendChip('err-003')">err-003</button> | |
| <button class="chip" onclick="sendChip('err-009')">err-009</button> | |
| <button class="chip" onclick="sendChip('err-013')">err-013</button> | |
| <button class="chip" onclick="sendChip('err-025')">err-025</button> | |
| <button class="chip" onclick="sendChip('err-027')">err-027</button> | |
| </div> | |
| </div> | |
| <!-- Input --> | |
| <div class="input-bar"> | |
| <div class="input-inner"> | |
| <textarea id="msg-input" placeholder="Scrie codul erorii... (ex: err-003)" rows="1" | |
| onkeydown="handleKey(event)" oninput="autoResize(this)"></textarea> | |
| <button class="btn-send" onclick="sendMsg()"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round"> | |
| <line x1="22" y1="2" x2="11" y2="13"/> | |
| <polygon points="22 2 15 22 11 13 2 9 22 2"/> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| <script> | |
| // ── Baza de cunostinte VHelp ────────────────────────────────── | |
| const ERR_DB = { | |
| "001": { title:"Firebase conexiune eșuată", cauza:"Serverul Firebase este indisponibil sau cheia API este invalidă.", sfat:"Verifică dacă ai conexiune la internet. Dacă problema persistă, serverul Firebase poate fi momentan oprit — încearcă din nou în câteva minute." }, | |
| "002": { title:"Elev negăsit în baza de date", cauza:"ID-ul selectat nu există în Firestore sau a fost șters.", sfat:"Cere adminului să verifice că ești în lista elevilor. Dacă tocmai ți-a fost creat contul, reîncarcă pagina de login." }, | |
| "003": { title:"Cod VPass incorect", cauza:"Ai introdus un PIN greșit de 6 cifre.", sfat:"Încearcă să reintroduci codul VPass atent. Dacă l-ai uitat, folosește opțiunea 'Am uitat parola' de pe pagina de login." }, | |
| "004": { title:"Cont fără parolă", cauza:"Exiști în baza de date dar nu ți-ai activat contul.", sfat:"Apasă butonul ÎNREGISTRARE de pe pagina de login și urmează cei 4 pași pentru activarea contului." }, | |
| "005": { title:"Cerere de înregistrare în așteptare", cauza:"Ai solicitat deja un cod de confirmare, dar acesta nu a fost validat.", sfat:"Așteaptă ca administratorul să proceseze cererea ta. Dacă a trecut mai mult de 10 minute, încearcă din nou din pagina de login." }, | |
| "006": { title:"Cod de confirmare expirat", cauza:"Au trecut mai mult de 10 minute de la generarea codului.", sfat:"Revino la login și apasă din nou ÎNREGISTRARE pentru a solicita un cod nou." }, | |
| "007": { title:"Cod de confirmare incorect", cauza:"Cele 4 cifre introduse nu corespund codului trimis.", sfat:"Verifică SMS-ul sau emailul primit și introdu exact cele 4 cifre. Atenție la spații sau cifre lipsă." }, | |
| "008": { title:"Parolă prea scurtă", cauza:"Parola aleasă are mai puțin de 6 caractere.", sfat:"Alege o parolă de minimum 6 cifre sau caractere. Recomandăm o combinație de cifre ușor de reținut." }, | |
| "009": { title:"Upload eșuat — eroare rețea", cauza:"Conexiunea la Google Drive s-a întrerupt în timpul încărcării.", sfat:"Verifică conexiunea la internet și încearcă din nou. Dacă fișierul e mare, încearcă cu o conexiune Wi-Fi stabilă." }, | |
| "010": { title:"Fișier prea mare", cauza:"Fișierul selectat depășește limita de 50MB.", sfat:"Comprimă fișierul sau împarte-l în mai multe părți. Poți folosi un site de compresie online pentru PDF-uri sau arhive ZIP." }, | |
| "011": { title:"Niciun fișier selectat", cauza:"Ai apăsat upload fără să selectezi un fișier.", sfat:"Apasă zona de upload sau trage fișierul din calculator în zona marcată, apoi încearcă din nou." }, | |
| "012": { title:"Materie neselectată", cauza:"Nu ai selectat materia înainte de a încărca fișierul.", sfat:"Apasă pe una dintre materiile din grila de sus, apoi încearcă din nou upload-ul." }, | |
| "013": { title:"Sesiune expirată", cauza:"Tab-ul a fost reîncărcat sau sesiunea s-a închis.", sfat:"Revino la pagina de login și conectează-te din nou. Sesiunea este activă doar cât tabul e deschis." }, | |
| "014": { title:"Acces neautorizat", cauza:"Rolul din sesiune nu corespunde paginii accesate.", sfat:"Deconectează-te apăsând Ieșire și loghează-te din nou cu contul corect." }, | |
| "015": { title:"Timeout server", cauza:"Serverul nu a răspuns în 30 de secunde.", sfat:"Reîncarcă pagina. Dacă serverul HuggingFace e pornit recent, poate dura 30-60 secunde să se inițializeze." }, | |
| "016": { title:"B2 autentificare eșuată", cauza:"Cheia API Backblaze B2 este invalidă (versiune veche).", sfat:"Contactează administratorul. Sistemul folosește acum Google Drive, această eroare apare doar pe versiuni vechi." }, | |
| "017": { title:"B2 upload URL indisponibil", cauza:"Server Backblaze indisponibil (versiune veche).", sfat:"Contactează administratorul — sistemul a migrat la Google Drive în versiunea curentă." }, | |
| "018": { title:"Listare fișiere eșuată", cauza:"Nu s-a putut obține lista fișierelor din Drive.", sfat:"Reîncarcă pagina. Dacă problema persistă, verifică conexiunea la internet sau contactează adminul." }, | |
| "019": { title:"Ștergere fișier eșuată", cauza:"Fișierul nu a putut fi șters din Drive.", sfat:"Încearcă din nou. Dacă nu funcționează, contactează administratorul cu ID-ul fișierului." }, | |
| "020": { title:"Parolă administrator incorectă", cauza:"Parola introdusă în panoul admin este greșită.", sfat:"Verifică parola de admin. Dacă ai uitat-o, contactează arhitectul sistemului." }, | |
| "021": { title:"Câmp obligatoriu lipsă", cauza:"Nu ai completat toate câmpurile formularului.", sfat:"Verifică toate câmpurile marcate și asigură-te că niciun câmp nu e gol." }, | |
| "022": { title:"PIN trebuie să fie exact 6 cifre", cauza:"PIN-ul introdus are mai mult sau mai puțin de 6 cifre.", sfat:"Introdu exact 6 cifre pentru PIN. Fără litere sau spații." }, | |
| "023": { title:"Elev deja înregistrat", cauza:"Ai deja o parolă setată pentru acest cont.", sfat:"Folosește loginul normal. Dacă nu îți amintești parola, apasă 'Am uitat parola' pe pagina de login." }, | |
| "024": { title:"Cerere respinsă de admin", cauza:"Administratorul a respins cererea ta de înregistrare.", sfat:"Contactează administratorul pentru a afla motivul și pentru a solicita o nouă înregistrare." }, | |
| "025": { title:"Eroare Firestore — scriere", cauza:"Nu s-a putut salva în baza de date Firebase.", sfat:"Verifică conexiunea la internet. Dacă ești admin, verifică regulile Firestore în consolă." }, | |
| "026": { title:"Eroare Firestore — citire", cauza:"Nu s-au putut citi datele din Firebase.", sfat:"Verifică conexiunea la internet. Problema poate fi și la regulile de securitate Firestore." }, | |
| "027": { title:"Eroare rețea generală", cauza:"Conexiunea la internet este întreruptă sau instabilă.", sfat:"Verifică Wi-Fi sau datele mobile. Reîncarcă pagina după ce conexiunea e restabilită." }, | |
| "028": { title:"Notificare negăsită", cauza:"Notificarea a fost deja procesată sau ștearsă.", sfat:"Reîncarcă tab-ul Notificări din admin dashboard." }, | |
| "029": { title:"Cod format invalid", cauza:"Codul introdus nu are exact 4 cifre numerice.", sfat:"Codul de confirmare trebuie să fie exact 4 cifre (ex: 4821). Fără litere sau spații." }, | |
| "030": { title:"Sesiune signup expirată", cauza:"Pagina de înregistrare a stat inactivă prea mult timp.", sfat:"Revino la login și apasă din nou ÎNREGISTRARE pentru a relua procesul de la început." }, | |
| "404": { title:"Pagină negăsită / Mentenanță", cauza:"Această eroare apare fie că pagina nu există, fie că serverul este în modul mentenanță.", sfat:"Cel mai probabil serverul SGE este temporar oprit pentru reparații. Acesta va fi funcțional în aproximativ 15 minute. Dacă problema persistă după 15 minute, contactează administratorul." }, | |
| "503": { title:"Server în mentenanță", cauza:"Administratorul a activat modul de mentenanță al serverului.", sfat:"Serverul SGE este în reparație temporară. Revino în aproximativ 15 minute. Nu este nevoie să faci nimic — sistemul se va reactiva automat." }, | |
| }; | |
| // Extrage prenumele din "Rosca Victor" → "Victor" | |
| function getFirstName(fullName) { | |
| if (!fullName) return "utilizator"; | |
| const parts = fullName.trim().split(/\s+/); | |
| return parts.length >= 2 ? parts[parts.length - 1] : parts[0]; | |
| } | |
| function parseErrCode(input) { | |
| const m = input.replace(/[\s\-_]/g,'').match(/(?:err|error)?(\d{3})/i); | |
| return m ? m[1] : null; | |
| } | |
| function nowStr() { | |
| return new Date().toLocaleTimeString('ro', {hour:'2-digit',minute:'2-digit'}); | |
| } | |
| function autoResize(el) { | |
| el.style.height='auto'; el.style.height=Math.min(el.scrollHeight,120)+'px'; | |
| } | |
| function handleKey(e) { | |
| if (e.key==='Enter' && !e.shiftKey) { e.preventDefault(); sendMsg(); } | |
| } | |
| // ── Sunet feedback ───────────────────────────────────────── | |
| function playReplySound() { | |
| try { | |
| const ctx = new (window.AudioContext||window.webkitAudioContext)(); | |
| const o = ctx.createOscillator(); | |
| const g = ctx.createGain(); | |
| o.type = 'sine'; o.frequency.value = 880; | |
| g.gain.setValueAtTime(0, ctx.currentTime); | |
| g.gain.linearRampToValueAtTime(0.04, ctx.currentTime + 0.02); | |
| g.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.18); | |
| o.connect(g); g.connect(ctx.destination); | |
| o.start(); o.stop(ctx.currentTime + 0.18); | |
| } catch(e) {} | |
| } | |
| // ── Adauga mesaj in chat ─────────────────────────────────── | |
| let _userName = ''; | |
| let _initialized = false; | |
| function addMsg(role, html, animate=false) { | |
| const wrap = document.getElementById('chat-wrap'); | |
| const div = document.createElement('div'); | |
| div.className = 'msg ' + role; | |
| const initials = role === 'user' ? (_userName[0]||'U') : ''; | |
| div.innerHTML = ` | |
| ${role==='vhelp' ? `<div class="msg-avatar"><img src="logo.svg" alt="VH"></div>` : ''} | |
| <div> | |
| <div class="msg-bubble" id="bubble-${Date.now()}">${animate ? '' : html}</div> | |
| <div class="msg-time">${nowStr()}</div> | |
| </div> | |
| ${role==='user' ? `<div class="msg-avatar">${initials.toUpperCase()}</div>` : ''} | |
| `; | |
| wrap.appendChild(div); | |
| wrap.scrollTop = wrap.scrollHeight; | |
| if (animate) { | |
| const bubble = div.querySelector('.msg-bubble'); | |
| typewriter(bubble, html, 18); | |
| } | |
| return div; | |
| } | |
| function addTypingIndicator() { | |
| const wrap = document.getElementById('chat-wrap'); | |
| const div = document.createElement('div'); | |
| div.className = 'msg vhelp'; div.id = 'typing-indicator'; | |
| div.innerHTML = ` | |
| <div class="msg-avatar"><img src="logo.svg" alt="VH"></div> | |
| <div> | |
| <div class="msg-bubble"> | |
| <div class="typing-dots"><span></span><span></span><span></span></div> | |
| </div> | |
| </div>`; | |
| wrap.appendChild(div); | |
| wrap.scrollTop = wrap.scrollHeight; | |
| } | |
| function removeTypingIndicator() { | |
| const el = document.getElementById('typing-indicator'); | |
| if (el) el.remove(); | |
| } | |
| // ── Typewriter animation ───────────────────────────────── | |
| function typewriter(el, html, speed=18) { | |
| // Strip HTML tags pentru typewriter, apoi re-inserez formatat | |
| const tmp = document.createElement('div'); | |
| tmp.innerHTML = html; | |
| const plain = tmp.textContent; | |
| el.innerHTML = ''; | |
| el.classList.add('tw-cursor'); | |
| let i = 0; | |
| const iv = setInterval(() => { | |
| if (i >= plain.length) { | |
| clearInterval(iv); | |
| el.classList.remove('tw-cursor'); | |
| el.innerHTML = html; // switch la HTML complet la final | |
| return; | |
| } | |
| // Afiseaza plain text pana la final | |
| el.textContent = plain.slice(0, ++i); | |
| }, speed); | |
| } | |
| // ── Build raspuns VHelp ─────────────────────────────────── | |
| function buildReply(code) { | |
| const info = ERR_DB[code]; | |
| if (!info) return null; | |
| return `<span class="err-badge">err-${code}</span><br> | |
| <strong>${info.title}</strong><br><br> | |
| <span style="color:var(--white-dim);font-size:11px;">Cauza:</span> ${info.cauza}<br><br> | |
| <span style="color:rgba(100,200,100,0.8);font-size:11px;">Recomandare:</span> ${info.sfat}`; | |
| } | |
| // ── Send ────────────────────────────────────────────────── | |
| function sendMsg() { | |
| const inp = document.getElementById('msg-input'); | |
| const raw = inp.value.trim(); | |
| if (!raw) return; | |
| inp.value = ''; inp.style.height='auto'; | |
| // Ascunde chips dupa primul mesaj | |
| document.getElementById('quick-chips').style.display = 'none'; | |
| addMsg('user', raw); | |
| setTimeout(() => { | |
| addTypingIndicator(); | |
| const delay = 1200 + Math.random() * 800; | |
| setTimeout(() => { | |
| removeTypingIndicator(); | |
| const code = parseErrCode(raw); | |
| let reply; | |
| if (code && ERR_DB[code]) { | |
| reply = buildReply(code); | |
| } else { | |
| reply = `Scuze, eu sunt doar un asistent suport.<br><br>Nu pot înțelege altceva în afara codurilor de eroare SGE.<br><br><span style="color:var(--white-dim);">Îmi pare rău, sunt încă în curs de dezvoltare...</span><br><br>Ai primit vreo eroare și nu te-am putut ajuta? Scrie codul în format <strong>err-001</strong> și îți explic imediat.`; | |
| } | |
| addMsg('vhelp', reply, true); | |
| playReplySound(); | |
| }, delay); | |
| }, 100); | |
| } | |
| function sendChip(code) { | |
| document.getElementById('msg-input').value = code; | |
| sendMsg(); | |
| } | |
| // ── Init ────────────────────────────────────────────────── | |
| // ── Sterge mesajele cand se inchide pagina ──────────────── | |
| document.addEventListener('visibilitychange', () => { | |
| if (document.visibilityState === 'hidden') { | |
| // Curata toate mesajele din chat (mai putin chips-uri) | |
| const wrap = document.getElementById('chat-wrap'); | |
| const chips = document.getElementById('quick-chips'); | |
| wrap.innerHTML = ''; | |
| if (chips) { chips.style.display='flex'; wrap.appendChild(chips); } | |
| } | |
| }); | |
| window.addEventListener('DOMContentLoaded', () => { | |
| const role = sessionStorage.getItem('vs_role'); | |
| const name = sessionStorage.getItem('vs_name') || | |
| sessionStorage.getItem('vs_name') || 'utilizator'; | |
| _userName = name; | |
| const firstName = getFirstName(name); | |
| const roleLabel = role === 'elev' ? 'ELEV' : role === 'profesor' ? 'PROFESOR' : role === 'admin' ? 'ADMIN' : '—'; | |
| document.getElementById('user-tag').textContent = roleLabel; | |
| // Mesaj de bun venit cu delay | |
| setTimeout(() => { | |
| addTypingIndicator(); | |
| setTimeout(() => { | |
| removeTypingIndicator(); | |
| const greeting = `Bună, <strong>${firstName}</strong>! Eu sunt <strong>VHelp</strong>, asistentul tău de suport SGE.<br><br>Ce cod de eroare ai primit acum?<br><br><span style="color:var(--white-dim);font-size:11px;">Poți scrie în orice format: err-003, ERR 003, err003 — le înțeleg pe toate.</span>`; | |
| addMsg('vhelp', greeting, true); | |
| playReplySound(); | |
| _initialized = true; | |
| }, 1400); | |
| }, 500); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |