1/* ========================================================== 2 CrossVision AIè¦ç©ãããã£ãã 3 - APIè¨å®ãã â Bedrockï¼Lambdaçµç±ï¼ 4 - APIæªè¨å®/é害 â ã«ã¼ã«ãã¼ã¹ãã©ã¼ã«ãã㯠5 ========================================================== */ 6 7(function () { 8 "use strict"; 9 10 var config = window.CV_CHAT_CONFIG || {}; 11 var apiUrl = config.apiUrl || ""; 12 var abandonUrl = config.abandonUrl || (apiUrl ? apiUrl.replace(/\/chat\/?$/, "/abandon") : ""); 13 var leadUrl = config.leadUrl || (apiUrl ? apiUrl.replace(/\/chat\/?$/, "/lead") : ""); 14 var useFallback = config.fallback !== false; 15 var apiEnabled = !!apiUrl; 16 17 var fab = document.getElementById("chatFab"); 18 var panel = document.getElementById("chatPanel"); 19 var closeBtn = document.getElementById("chatClose"); 20 var body = document.getElementById("chatBody"); 21 var form = document.getElementById("chatForm"); 22 var input = document.getElementById("chatInput"); 23 var suggestionsEl = document.getElementById("chatSuggestions"); 24 var openChatBtn = document.getElementById("openChatBtn"); 25 var chatProgress = document.getElementById("chatProgress"); 26 27 var opened = false; 28 var greeted = false; 29 var chatStarted = sessionStorage.getItem("cv_chat_started") === "1"; 30 var storyType = sessionStorage.getItem("cv_chat_story") || null; 31 var slotState = loadSlotState(); 32 var sessionId = getSessionId(); 33 var apiMessages = loadApiMessages(); 34 var apiMode = apiEnabled; 35 var leadSubmitted = sessionStorage.getItem("cv_chat_lead") === "1"; 36 var chatDisabled = false; 37 var abandonSent = sessionStorage.getItem("cv_chat_abandon") === "1"; 38 var leadFormShown = false; 39 var leadCtaReady = sessionStorage.getItem("cv_chat_lead_ready") === "1"; 40 var leadBar = document.getElementById("chatLeadBar"); 41 var leadBarBtn = document.getElementById("chatLeadBarBtn"); 42 43 var STORY_OPTIONS = [ 44 { text: "ãããªã·ã¹ãã ãä½ããã", type: "system_dev", label: "ã·ã¹ãã éçºã®ç¸è«" }, 45 { text: "æ°è¦äºæ¥ãç«ã¡ä¸ããã", type: "new_business", label: "æ°è¦äºæ¥æ¯æ´" }, 46 { text: "AIãèªç¤¾ã«åãå ¥ããã", type: "entertainment", label: "ã¨ã³ã¿ã¡äºæ¥ã«é¢ããç¸è«" } 47 ]; 48 49 /* ---------- ã«ã¼ã«ãã¼ã¹ç¥èï¼ãã©ã¼ã«ããã¯ï¼ ---------- */ 50 var knowledge = [ 51 { 52 keys: ["ãµã¼ãã¹", "äºæ¥", "ä½ããã¦", "ã§ãããã¨", "æ¯æ´"], 53 reply: "ç§ãã¡ã¯<strong>AIä¼´èµ°åã®æ°è¦äºæ¥éçºæ¯æ´</strong>ãè¡ã£ã¦ãã¾ããã¢ããã¼ãã¯2ã¤ããæ¢å顧客åºç¤ãèµ·ç¹ã¨ããäºæ¥æ¡å¼µãã¨ãæ°è¦å¸å ´ãæ¢ç´¢ããã¼ãã¤ãäºæ¥éçºãã§ãã", 54 followups: ["ã¢ããªéçºã®è¦ç©ãã", "æéãã©ã³ãæãã¦"] 55 }, 56 { 57 keys: ["è¦ç©", "æé", "è²»ç¨", "ä¾¡æ ¼", "ãã©ã³", "ããã"],
58 reply: "<strong>ã¢ããªéçºãã©ã³</strong><br>ã»ã©ã¤ã 100ä¸åãï¼1ã¶æãï¼<br>ã»ããã« 300ä¸åãï¼èªè¨¼è¦æ¨¡ã3ã¶æãï¼<br>ã»Pro 1,000ä¸åãï¼ãã©ãããã©ã¼ã ã3ã¶æãï¼<br>ã»ãªãã·ã§ã³ï¼ç¤¾å SEã¨ã¼ã¸ã§ã³ã ï¼20ä¸åï¼Î±<br><br>詳ããè¦ä»¶ããèããããã ããã°ãAIãæ¦ç®ããææ¡ãã¾ãã", 59 followups: ["iOS/Android両æ¹", "ã¦ã¼ã¶ã¼èªè¨¼ãã", "社å SEã¨ã¼ã¸ã§ã³ãã«ã¤ãã¦"] 60 }, 61 { 62 keys: ["æè¡", "AI", "ai", "XR", "xr", "Web3", "web3", "çæ", "LLM", "llm"], 63 reply: "ã«ã¹ã¿ãã¼ãµãã¼ãAIãAIæ åè§£æãXRãã¢ãã¤ã«ã¢ããªããªã¼ãã³ã¤ããã¼ã·ã§ã³ãªã©å¹ åºã対å¿ãã¦ãã¾ããDEMOã»ã¯ã·ã§ã³ã«ä¸è¦§ãããã¾ãã", 64 followups: ["ã¢ããªéçºã®è¦ç©ãã", "ä¼ç¤¾ã«ã¤ãã¦æãã¦"] 65 }, 66 { 67 keys: ["ä¼ç¤¾", "æ¦è¦", "ã©ã", "æå¨å°", "è¨ç«", "代表"], 68 reply: "æ ªå¼ä¼ç¤¾CrossVisionï¼2024å¹´è¨ç«ã代表ï¼å¥¥äºé¢¯å¹³ï¼ãdocomo STARTUPçºãæ±äº¬ã»å¤§éªã«æ ç¹ãããã¾ãã", 69 followups: ["ã¢ããªéçºã®è¦ç©ãã", "åãåããããã"] 70 }, 71 { 72 keys: ["åãåãã", "ç¸è«", "é£çµ¡", "ã³ã³ã¿ã¯ã"], 73 reply: "ãã¼ã¸ä¸é¨ã®<strong>ãåãåãããã¿ã³</strong>ãããé£çµ¡ãã ãããç¡æã®å£æã¡ç¸è«ã大æè¿ã§ãã", 74 followups: ["ã¢ããªéçºã®è¦ç©ãã"] 75 }, 76 { 77 keys: ["ããã«ã¡ã¯", "ã¯ããã¾ãã¦", "hello", "hi", "ãã"], 78 reply: "ããã«ã¡ã¯ãCrossVisionã®AIè¦ç©ããã¢ã·ã¹ã¿ã³ãã§ããã¢ããªéçºã®æ¦ç®è¦ç©ãªã©ããæ°è»½ã«ãç¸è«ãã ããã", 79 followups: ["ã¢ããªéçºã®è¦ç©ãã", "ãã©ã³ã®éããæãã¦"] 80 } 81 ]; 82 83 var fallback = { 84 reply: "ãã¾ãçè§£ã§ãã¾ããã§ãããã¢ããªéçºã®è¦ç©ãããæéãã©ã³ãä¼ç¤¾æ¦è¦ãªã©ã«ã¤ãã¦ãçãã§ãã¾ãã", 85 followups: ["ã¢ããªéçºã®è¦ç©ãã", "æéãã©ã³ãæãã¦", "åãåããããã"] 86 }; 87 88 /* ---------- ã»ãã·ã§ã³ç®¡ç ---------- */ 89 function getSessionId() { 90 var key = "cv_chat_session"; 91 var id = sessionStorage.getItem(key); 92 if (!id) { 93 id = "cv-" + Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 9); 94 sessionStorage.setItem(key, id); 95 } 96 return id; 97 } 98 99 function loadApiMessages() { 100 try { 101 return JSON.parse(sessionStorage.getItem("cv_chat_messages") || "[]"); 102 } catch { 103 return []; 104 } 105 } 106 107 function saveApiMessages() { 108 sessionStorage.setItem("cv_chat_messages", JSON.stringify(apiMessages)); 109 } 110 111 function markLeadSubmitted() { 112 leadSubmitted = true; 113 sessionStorage.setItem("cv_chat_lead", "1"); 114 hideLeadCta(); 115 } 116 117 function loadSlotState() { 118 try { 119 return JSON.parse(sessionStorage.getItem("cv_chat_slots") || "{}"); 120 } catch { 121 return {}; 122 } 123 } 124 125 function saveSlotState(slots) { 126 if (!slots) return; 127 var next = Object.assign({}, slotState); 128 slots.forEach(function (s) { 129 if (s.filled && s.value && s.value !== "ï¼ä¼è©±ããåå¾ï¼") { 130 next[s.id] = s.value; 131 } 132 }); 133 slotState = next; 134 sessionStorage.setItem("cv_chat_slots", JSON.stringify(slotState)); 135 } 136 137 function saveStoryType(type) { 138 storyType = type; 139 if (type) sessionStorage.setItem("cv_chat_story", type); 140 } 141 142 function markChatStarted() { 143 chatStarted = true; 144 sessionStorage.setItem("cv_chat_started", "1"); 145 } 146 147 function setInputEnabled(enabled) { 148 if (form) form.classList.toggle("is-disabled", !enabled); 149 if (input) input.disabled = !enabled; 150 } 151 152 function setSuggestionsEnabled(enabled) { 153 if (suggestionsEl) suggestionsEl.classList.toggle("is-disabled", !enabled); 154 } 155 156 function setChatInputEnabled(enabled) { 157 setInputEnabled(enabled); 158 setSuggestionsEnabled(enabled); 159 } 160 161 function storyFromText(text) { 162 var found = STORY_OPTIONS.find(function (s) { 163 return s.text === text; 164 }); 165 return found ? found.type : null; 166 } 167 168 function markAbandonSent() {
169 abandonSent = true; 170 sessionStorage.setItem("cv_chat_abandon", "1"); 171 } 172 173 function updateProgressBar(progress) { 174 var bar = document.getElementById("chatProgressBar"); 175 var label = document.getElementById("chatProgressLabel"); 176 if (!bar || !progress) return; 177 bar.style.width = (progress.percent || 0) + "%"; 178 if (chatProgress) { 179 chatProgress.setAttribute("aria-hidden", progress.slots && progress.slots.length ? "false" : "true"); 180 } 181 if (label) { 182 if (progress.slots && progress.slots.length) { 183 var filled = progress.slots.filter(function (s) { 184 return s.filled; 185 }).length; 186 var req = progress.slots.filter(function (s) { 187 return s.required; 188 }); 189 var reqFilled = req.filter(function (s) { 190 return s.filled; 191 }).length; 192 label.textContent = 193 (progress.stage || "ãã¢ãªã³ã°") + 194 " â å¿ é " + 195 reqFilled + 196 "/" + 197 req.length + 198 " · å ¨ä½ " + 199 filled + 200 "/" + 201 progress.slots.length; 202 } else { 203 label.textContent = progress.stage || ""; 204 } 205 } 206 } 207 208 /* ---------- UI ---------- */ 209 function scrollToBottom() { 210 body.scrollTop = body.scrollHeight; 211 } 212 213 function avatarSpeak(html) { 214 if (!window.cvAvatar) return; 215 var len = html.replace(/<[^>]*>/g, "").length; 216 window.cvAvatar.speak(Math.min(7000, 1200 + len * 55)); 217 } 218 219 function escapeHtml(text) { 220 return text.replace(/[<>&]/g, function (c) { 221 return { "<": "<", ">": ">", "&": "&" }[c]; 222 }); 223 } 224 225 function formatReply(text) { 226 return escapeHtml(text).replace(/\n/g, "<br>"); 227 } 228 229 function addMessage(text, who, isHtml) { 230 var el = document.createElement("div"); 231 el.className = "chat-msg " + who; 232 el.innerHTML = isHtml ? text : formatReply(text); 233 body.appendChild(el); 234 scrollToBottom(); 235 return el; 236 } 237 238 function showTyping() { 239 var el = document.createElement("div"); 240 el.className = "chat-msg bot typing"; 241 el.innerHTML = "<i></i><i></i><i></i>"; 242 body.appendChild(el); 243 scrollToBottom(); 244 return el; 245 } 246 247 function setSuggestions(list, onSelect) { 248 suggestionsEl.replaceChildren(); 249 (list || []).forEach(function (item) { 250 var text = typeof item === "string" ? item : item.text; 251 var btn = document.createElement("button"); 252 btn.type = "button"; 253 btn.textContent = text; 254 btn.addEventListener("click", function () { 255 if (onSelect) { 256 onSelect(item); 257 } else { 258 handleUserMessage(text); 259 } 260 }); 261 suggestionsEl.appendChild(btn); 262 }); 263 } 264 265 function setStorySuggestions() { 266 setSuggestions(STORY_OPTIONS, function (item) { 267 selectStory(item); 268 }); 269 } 270 271 /* ---------- ã»ã¯ã·ã§ã³èªå°ãªã³ã¯ ---------- */ 272 function addSectionLink(link) { 273 if (!link || typeof link.index !== "number") return; 274 /* æºåä¸ã®ã½ãªã¥ã¼ã·ã§ã³ã¸ã¯èªå°ããªã */ 275 var targetTab = document.querySelector( 276 '#solutionTabs [data-index="' + link.index + '"]' 277 ); 278 if (!targetTab || targetTab.disabled) return; 279 var wrap = document.createElement("div"); 280 wrap.className = "chat-msg bot chat-section-link"; 281 var btn = document.createElement("button"); 282 btn.type = "button"; 283 btn.innerHTML = "â¶ äºä¾ãè¦ãï¼<strong>" + escapeHtml(link.title || "") + "</strong>"; 284 btn.addEventListener("click", function () { 285 closePanel(); 286 var target = document.getElementById("solutions"); 287 if (target) target.scrollIntoView({ behavior: "smooth" }); 288 setTimeout(function () { 289 var tab = document.querySelector('#solutionTabs [data-index="' + link.index + '"]'); 290 if (tab) tab.click(); 291 }, 700); 292 }); 293 wrap.appendChild(btn); 294 body.appendChild(wrap); 295 scrollToBottom(); 296 } 297 298 /* ---------- 詳細è¦ç©ä¾é ¼ï¼CTA + ãã©ã¼ã ï¼ ---------- 299 CTAãä¼è©±ã®æµãã«ç½®ãã¨ã次ã®çºè¨ã§ä¸ã¸æµãã¦è¦å¤±ãã 300 ä¸åº¦åºããå ¥åæ¬ã®ä¸ã«åºããã¾ã¾ã«ãã */ 301 function showLeadCta() { 302 if (leadSubmitted || !leadBar) return; 303 if (!leadCtaReady) { 304 leadCtaReady = true; 305 sessionStorage.setItem("cv_chat_lead_ready", "1"); 306 } 307 leadBar.hidden = false;
308 } 309 310 function hideLeadCta() { 311 if (leadBar) leadBar.hidden = true; 312 } 313 314 function showLeadForm() { 315 if (leadSubmitted) return; 316 if (document.getElementById("chatLeadOverlay")) return; 317 leadFormShown = true; 318 319 var overlay = document.createElement("div"); 320 overlay.className = "chat-lead-overlay"; 321 overlay.id = "chatLeadOverlay"; 322 overlay.innerHTML = 323 '<div class="chat-lead-overlay-inner">' + 324 '<button type="button" class="chat-lead-overlay-close" id="leadOverlayClose" aria-label="éãã">Ã</button>' + 325 "<strong>詳細è¦ç©ã®ãä¾é ¼</strong>" + 326 "<p>æ å½è ãããé£çµ¡ãããã¾ãã以ä¸ããå ¥åãã ããã</p>" + 327 '<label>ä¼ç¤¾å <span class="req">å¿ é </span><input type="text" id="leadCompany" placeholder="æ ªå¼ä¼ç¤¾ãã" maxlength="100"></label>' + 328 '<label>å½¹è·<input type="text" id="leadRole" placeholder="ä¾ï¼äºæ¥éçºé¨ é¨é·" maxlength="50"></label>' + 329 '<label>ãäºç®<select id="leadBudget">' + 330 '<option value="">鏿ãã¦ãã ãã</option>' + 331 '<option>ã100ä¸å</option>' + 332 '<option>100ã300ä¸å</option>' + 333 '<option>300ã1,000ä¸å</option>' + 334 '<option>1,000ä¸åã</option>' + 335 '<option>æªå®ã»ç¸è«ããã</option>' + 336 "</select></label>" + 337 '<label>ã¡ã¼ã«ã¢ãã¬ã¹ <span class="req">å¿ é </span><input type="email" id="leadEmail" placeholder="[email protected]" maxlength="100"></label>' + 338 '<p class="chat-lead-error" id="leadError" hidden></p>' + 339 '<button type="button" id="leadSubmitBtn">éä¿¡ãã</button>' + 340 "</div>"; 341 342 panel.appendChild(overlay); 343 requestAnimationFrame(function () { 344 overlay.classList.add("show"); 345 }); 346 347 document.getElementById("leadOverlayClose").addEventListener("click", function () { 348 closeLeadOverlay(overlay); 349 }); 350 document.getElementById("leadSubmitBtn").addEventListener("click", function () { 351 submitLeadForm(overlay); 352 }); 353 setTimeout(function () { 354 var first = document.getElementById("leadCompany"); 355 if (first) first.focus(); 356 }, 300); 357 } 358 359 function closeLeadOverlay(overlay) { 360 leadFormShown = false; 361 overlay.classList.remove("show"); 362 setTimeout(function () { 363 overlay.remove(); 364 }, 300); 365 } 366 367 function submitLeadForm(overlay) { 368 var company = document.getElementById("leadCompany").value.trim(); 369 var role = document.getElementById("leadRole").value.trim(); 370 var budget = document.getElementById("leadBudget").value; 371 var email = document.getElementById("leadEmail").value.trim(); 372 var errEl = document.getElementById("leadError"); 373 var btn = document.getElementById("leadSubmitBtn"); 374 375 var emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; 376 if (!company) { 377 errEl.textContent = "ä¼ç¤¾åãå ¥åãã¦ãã ãã"; 378 errEl.hidden = false; 379 return; 380 } 381 if (!emailRe.test(email)) { 382 errEl.textContent = "ã¡ã¼ã«ã¢ãã¬ã¹ã®å½¢å¼ãæ£ããããã¾ãã"; 383 errEl.hidden = false; 384 return; 385 } 386 errEl.hidden = true; 387 btn.disabled = true; 388 btn.textContent = "éä¿¡ä¸â¦"; 389 390 fetch(leadUrl, { 391 method: "POST", 392 headers: { "Content-Type": "application/json" }, 393 body: JSON.stringify({ 394 sessionId: sessionId, 395 companyName: company, 396 role: role, 397 budget: budget, 398 email: email, 399 messages: apiMessages, 400 storyType: storyType || undefined 401 }) 402 }) 403 .then(function (res) { 404 if (!res.ok) throw new Error("API " + res.status); 405 return res.json(); 406 }) 407 .then(function () { 408 markLeadSubmitted(); 409 overlay.querySelector(".chat-lead-overlay-inner").innerHTML = 410 '<div class="chat-lead-done">' + 411 '<span class="chat-lead-done-icon">â</span>' + 412 "<strong>ãä¾é ¼ãåãä»ãã¾ãã</strong>" + 413 "<p>æ å½è ãã <strong>" + 414 escapeHtml(email) + 415 "</strong> å®ã«ãé£çµ¡ãããã¾ãã</p>" + 416 '<button type="button" id="leadDoneClose">ãã£ããã«æ»ã</button>' + 417 "</div>"; 418 document.getElementById("leadDoneClose").addEventListener("click", function () { 419 overlay.classList.remove("show"); 420 setTimeout(function () { overlay.remove(); }, 300); 421 }); 422 addMessage( 423 '<p class="chat-lead-notice">â 詳細è¦ç©ã®ãä¾é ¼ãåãä»ãã¾ãããæ å½è ãããé£çµ¡ãããã¾ãã</p>', 424 "bot", 425 true 426 ); 427 setSuggestions(["ãããã¨ããããã¾ã", "ä»ã«è³ªåããã"]); 428 }) 429 .catch(function (err) { 430 console.warn("Lead submit error:", err); 431 btn.disabled = false;
432 btn.textContent = "éä¿¡ãã"; 433 errEl.textContent = "éä¿¡ã«å¤±æãã¾ãããæéãããã¦ã試ããã ããã"; 434 errEl.hidden = false; 435 }); 436 } 437 438 /* ---------- ã«ã¼ã«ãã¼ã¹ ---------- */ 439 function findAnswer(text) { 440 var best = null, bestScore = 0; 441 knowledge.forEach(function (item) { 442 var score = 0; 443 item.keys.forEach(function (k) { 444 if (text.indexOf(k) !== -1) score += k.length; 445 }); 446 if (score > bestScore) { bestScore = score; best = item; } 447 }); 448 return best || fallback; 449 } 450 451 function botReplyFallback(text) { 452 var typing = showTyping(); 453 var answer = findAnswer(text); 454 setTimeout(function () { 455 typing.remove(); 456 addMessage(answer.reply, "bot", true); 457 avatarSpeak(answer.reply); 458 setSuggestions(answer.followups); 459 }, 700 + Math.random() * 600); 460 } 461 462 /* ---------- Bedrock API ---------- */ 463 function callChatApi() { 464 return fetch(apiUrl, { 465 method: "POST", 466 headers: { "Content-Type": "application/json" }, 467 body: JSON.stringify({ 468 sessionId: sessionId, 469 messages: apiMessages, 470 storyType: storyType || undefined, 471 slotState: slotState 472 }) 473 }).then(function (res) { 474 if (!res.ok) throw new Error("API " + res.status); 475 return res.json(); 476 }); 477 } 478 479 function botReplyApi(text) { 480 var typing = showTyping(); 481 apiMessages.push({ role: "user", content: text }); 482 saveApiMessages(); 483 484 callChatApi() 485 .then(function (data) { 486 typing.remove(); 487 var reply = data.reply || "ç³ã訳ããã¾ãããããä¸åº¦ã試ããã ããã"; 488 apiMessages.push({ role: "assistant", content: reply }); 489 saveApiMessages(); 490 491 var html = formatReply(reply); 492 if (data.estimate && data.estimate.plan) { 493 html += 494 '<div class="chat-estimate-card">' + 495 "<strong>æ¦ç®è¦ç©</strong><br>" + 496 "ãã©ã³ï¼" + escapeHtml(data.estimate.plan) + "<br>" + 497 "ã¬ã³ã¸ï¼" + escapeHtml(data.estimate.range || "") + 498 "</div>"; 499 } 500 if (data.leadSubmitted) { 501 markLeadSubmitted(); 502 html += '<p class="chat-lead-notice">â æ å½è ã¸æ å ±ãéä¿¡ãã¾ãããæ¹ãã¦ãé£çµ¡ãããã¾ãã</p>'; 503 } 504 505 if (data.chatDisabled) { 506 chatDisabled = true; 507 html += '<p class="chat-lead-notice">ç¾å¨AIãã£ããã®ä¸éã«éãã¦ãã¾ãããåãåãããã©ã¼ã ããå©ç¨ãã ããã</p>'; 508 } 509 510 addMessage(html, "bot", true); 511 avatarSpeak(reply); 512 setSuggestions(data.suggestions || []); 513 updateProgressBar(data.hearingProgress); 514 if (data.hearingProgress && data.hearingProgress.slots) { 515 saveSlotState(data.hearingProgress.slots); 516 } 517 518 if (data.sectionLink) { 519 addSectionLink(data.sectionLink); 520 } 521 if (data.leadFormReady && !data.leadSubmitted) { 522 showLeadCta(); 523 } 524 }) 525 .catch(function (err) { 526 console.warn("Chat API error:", err); 527 typing.remove(); 528 apiMessages.pop(); 529 saveApiMessages(); 530 531 if (useFallback) { 532 apiMode = false; 533 addMessage("ï¼AIæ¥ç¶ã«åé¡ããã£ããããç°¡æã¢ã¼ãã§åçãã¾ãï¼", "bot"); 534 botReplyFallback(text); 535 } else { 536 addMessage("æ¥ç¶ã¨ã©ã¼ãçºçãã¾ããããã°ãããã¦ããã試ããã ããã", "bot"); 537 } 538 }); 539 } 540 541 /* ---------- ã¡ãã»ã¼ã¸å¦ç ---------- */ 542 function handleUserMessage(text) { 543 if (!text.trim()) return; 544 if (chatDisabled) { 545 addMessage("ç¾å¨AIãã£ããã¯å©ç¨ä¸éã®ãã忢ä¸ã§ãããåãåãããã©ã¼ã ãããé£çµ¡ãã ããã", "bot"); 546 return; 547 } 548 549 if (apiMode && apiEnabled && !storyType) { 550 var detected = storyFromText(text); 551 if (detected) saveStoryType(detected); 552 } 553 554 addMessage(text, "user"); 555 if (apiMode && apiEnabled) { 556 botReplyApi(text); 557 } else { 558 botReplyFallback(text); 559 } 560 } 561 562 function sendAbandonmentBeacon() { 563 if (!abandonUrl || !apiEnabled || leadSubmitted || abandonSe
563nt) return; 564 if (apiMessages.length === 0) return; 565 566 var payload = JSON.stringify({ 567 sessionId: sessionId, 568 messages: apiMessages, 569 storyType: storyType || undefined 570 }); 571 572 if (navigator.sendBeacon) { 573 navigator.sendBeacon(abandonUrl, new Blob([payload], { type: "application/json" })); 574 markAbandonSent(); 575 return; 576 } 577 578 fetch(abandonUrl, { 579 method: "POST", 580 headers: { "Content-Type": "application/json" }, 581 body: payload, 582 keepalive: true 583 }).then(function () { 584 markAbandonSent(); 585 }).catch(function () {}); 586 } 587 588 function selectStory(option) { 589 if (!option || storyType) return; 590 saveStoryType(option.type); 591 markChatStarted(); 592 setChatInputEnabled(true); 593 var intro = document.getElementById("chatIntro"); 594 if (intro) intro.remove(); 595 handleUserMessage(option.text); 596 } 597 598 var AVATAR_CHOICES = [ 599 { id: "baku", label: "社é·ã¢ãã¿ã¼" }, 600 { id: "shino", label: "女ã®åã¢ãã¿ã¼" } 601 ]; 602 603 /** ãããã¼ã®åãæ¿ããã¿ã³ããããã¾è¡¨ç¤ºä¸ã®ã¢ãã¿ã¼ãèªã */ 604 function currentAvatar() { 605 var active = document.querySelector(".avatar-choice.active"); 606 return (active && active.dataset.avatar) || AVATAR_CHOICES[0].id; 607 } 608 609 function pickAvatar(id) { 610 /* avatar.js ã®åæååã«é¸ã°ããå ´åã¯ãããè¦ã¦æåã®ã¢ãã«ã決ãã */ 611 window.__cvAvatarPending = id; 612 window.dispatchEvent(new CustomEvent("cv:avatar-select", { detail: { id: id } })); 613 } 614 615 function showIntro() { 616 if (document.getElementById("chatIntro")) return; 617 var active = currentAvatar(); 618 var el = document.createElement("div"); 619 el.className = "chat-intro"; 620 el.id = "chatIntro"; 621 el.innerHTML = 622 "<p>ãã®ãã£ãããéãã¦ãã客æ§ã®èª²é¡ã«å¯¾ãã¦å¼ç¤¾ãæä¾ã§ããã½ãªã¥ã¼ã·ã§ã³ããã®ãè¦ç©ããè¡ããã¨ãã§ãã¾ãã<br>ãç¨ä»¶ããã詳ãããããã¹ããã£ããããæã¡è¾¼ãã§ãã ããã</p>" + 623 '<p class="chat-intro-pick">話ãç¸æãé¸ãã§ã¹ã¿ã¼ã</p>' + 624 '<div class="chat-intro-avatars">' + 625 AVATAR_CHOICES.map(function (a) { 626 return '<button type="button" class="chat-intro-avatar' + 627 (a.id === active ? " is-active" : "") + 628 '" data-avatar="' + a.id + '">' + a.label + "</button>"; 629 }).join("") + 630 "</div>"; 631 body.appendChild(el); 632 scrollToBottom(); 633 634 Array.prototype.forEach.call(el.querySelectorAll(".chat-intro-avatar"), function (btn) { 635 btn.addEventListener("click", function () { 636 pickAvatar(btn.dataset.avatar); 637 startStorySelect(); 638 }); 639 }); 640 641 setInputEnabled(false); 642 setSuggestionsEnabled(false); 643 setSuggestions([]); 644 } 645 646 function startStorySelect() { 647 markChatStarted(); 648 var intro = document.getElementById("chatIntro"); 649 if (intro) intro.remove(); 650 addMessage("ãç¸è«ã®ç¨®é¡ããé¸ã³ãã ããã", "bot"); 651 setInputEnabled(false); 652 setSuggestionsEnabled(true); 653 setStorySuggestions(); 654 } 655 656 function greet() { 657 if (greeted) return; 658 greeted = true; 659 660 if (apiMessages.length > 0 && storyType) { 661 setChatInputEnabled(true); 662 apiMessages.forEach(function (m) { 663 addMessage(m.content, m.role === "user" ? "user" : "bot", m.role !== "user"); 664 }); 665 /* ååãã§ã«æ¡ä»¶ãæºããã¦ãããªãã復å å¾ãCTAãåºãã¦ãã */ 666 if (leadCtaReady && !leadSubmitted) showLeadCta(); 667 return; 668 } 669 670 if (apiMode && apiEnabled) { 671 showIntro(); 672 return; 673 } 674 675 var typing = showTyping(); 676 setTimeout(function () { 677 typing.remove(); 678 var msg = 679 "ããã«ã¡ã¯ãCrossVisionã®<strong>AIè¦ç©ããã¢ã·ã¹ã¿ã³ã</strong>ã§ãã<br>ã¢ããªéçºã®æ¦ç®è¦ç©ãªã©ããæ°è»½ã«ãç¸è«ãã ããã"; 680 addMessage(msg, "bot", true); 681 avatarSpeak(msg); 682 setSuggestions(["ã¢ããªéçºã®è¦ç©ãã", "æéãã©ã³ãæãã¦", "ä¼ç¤¾ã«ã¤ãã¦æãã¦"]); 683 setChatInputEnabled(true); 684 }, 900); 685 } 686
687 function openPanel() { 688 panel.classList.add("open"); 689 opened = true; 690 window.__cvChatOpened = true; 691 window.dispatchEvent(new CustomEvent("cv:chat-open")); 692 greet(); 693 setTimeout(function () { input.focus(); }, 400); 694 } 695 696 function closePanel() { 697 if (embedded) return; /* åãè¾¼ã¿ä¸ã¯ã¢ã¼ãã«å´ã§ç®¡ç */ 698 sendAbandonmentBeacon(); 699 panel.classList.remove("open"); 700 opened = false; 701 } 702 703 /* ---------- ã½ãªã¥ã¼ã·ã§ã³ã¢ã¼ãã«ã¸ã®åã込㿠---------- 704 ãã«ã¹ã¿ãã¼ãµãã¼ãAIããã¢ã¨ãã¦ãæ¬ç©ã®ãã£ããããã«ã 705 ã¢ã¼ãã«å ã«ç§»è¨ãã¦æç»ããï¼ç¶æ ã»ã¤ãã³ãã¯ãã®ã¾ã¾ç¶æï¼ */ 706 var embedded = false; 707 var homeParent = panel.parentElement; 708 709 window.cvChat = { 710 embed: function (container) { 711 if (embedded || !container) return false; 712 embedded = true; 713 container.appendChild(panel); 714 panel.classList.add("embedded", "open"); 715 opened = true; 716 /* avatar.js 㯠cv:chat-open ã§ VRM ãã¼ããéå§ãã */ 717 if (!window.__cvChatOpened) { 718 window.__cvChatOpened = true; 719 window.dispatchEvent(new CustomEvent("cv:chat-open")); 720 } 721 greet(); 722 return true; 723 }, 724 unembed: function () { 725 if (!embedded) return; 726 embedded = false; 727 panel.classList.remove("embedded", "open"); 728 opened = false; 729 homeParent.appendChild(panel); 730 }, 731 isEmbedded: function () { 732 return embedded; 733 } 734 }; 735 736 document.addEventListener("visibilitychange", function () { 737 if (document.visibilityState === "hidden") sendAbandonmentBeacon(); 738 }); 739 740 fab.addEventListener("click", function () { 741 if (embedded) return; 742 opened ? closePanel() : openPanel(); 743 }); 744 closeBtn.addEventListener("click", closePanel); 745 if (openChatBtn) openChatBtn.addEventListener("click", openPanel); 746 if (leadBarBtn) leadBarBtn.addEventListener("click", showLeadForm); 747 748 form.addEventListener("submit", function (e) { 749 e.preventDefault(); 750 var text = input.value; 751 input.value = ""; 752 handleUserMessage(text); 753 }); 754})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.