Smart Response

/* Smart Response Styling */ .response-header { display: flex; align-items: center; } .response-title { font-size: 16px; font-weight: 700; margin: 0 0 0 0; } .spinner { border: 2px solid #f3f3f3; border-top: 2px solid #3498db; border-radius: 50%; width: 16px; height: 16px; animation: spin 1s linear infinite; display: flex; align-items: center; justify-content: center; } .hidden { display: none; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .smartResponse { transition: display 0.5s ease; } .smartResponseHeader { display: flex; justify-content: space-between } .switch { position: relative; width: 50px; height: 25px; background-color: #3498db; /* Initial “on” color */ border-radius: 25px; cursor: pointer; transition: background-color 0.3s ease; } .switch:before { content: ”; position: absolute; width: 23px; height: 23px; border-radius: 50%; background-color: white; top: 1px; left: 26px; /* Initial “on” position */ transition: transform 0.3s ease; } .switch.off { background-color: #ccc; } .switch.off:before { transform: translateX(-25px); } .smartinnercontainer { width: 100% } .query-suggestions { display: none } .smartcontainer { text-align: left; background-color: #ffffff; border: 1px solid #ccc; font-family: Avenir, Helvetica, Arial, sans-serif; margin-top: 16px; margin-bottom: 16px; border-left-color: #109FF7; border-left-width: 5px; padding: 12px 12px 12px 8px; display: flex; justify-content: flex-start; align-items: flex-start; gap: 8px; } .ai-link-container { display: flex; justify-content: center; align-items: center; gap: 20px; /* Space between buttons */ flex-grow: 1; /* Allow container to grow */ } .link-button { display: flex; flex-direction: column; align-items: center; padding: 20px; font-size: 16px; color: black; background-color: white; text-align: center; text-decoration: none; border: 1px solid black; border-radius: 5px; transition: background-color 0.3s, box-shadow 0.3s; width: 300px; /* Limit width to 300px */ overflow: hidden; opacity: 0; animation: fadeIn 1s forwards; position: relative; } .link-button:nth-child(1) { animation-delay: 0s; } .link-button:nth-child(2) { animation-delay: 0.5s; } .link-button:nth-child(3) { animation-delay: 1s; } .link-button:hover { background-color: #f0f0f0; } .link-button:hover .main-text { background-color: #f0f0f0; } .link-button .thumbnail { width: 100%; height: auto; max-height: 150px; /* Adjust as needed for PDF thumbnail */ object-fit: contain; /* Ensure the image maintains its aspect ratio */ } .link-button .main-text { display: -webkit-box; -webkit-line-clamp: 2; /* Limit to 2 lines */ -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; font-weight: bold; /* Make title bold */ margin-top: auto; /* Push the title to the bottom */ height: 3.6em; /* Approximate height for 2 lines */ width: 100%; /* Ensure full width */ text-align: center; padding-top: 10px; /* Space between thumbnail and title */ background-color: #fff; /* Ensure background color matches */ transition: background-color 0.3s; /* Smooth transition */ } @keyframes fadeIn { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); } } body { font-family: Arial, Helvetica, sans-serif; font-size: 16px; } .smartsearchdemo__container { margin: 0 auto; min-width: 340px; max-width: 1280px; } .smartsearchdemo__container .search-field__container, .smartsearchdemo__container .conceptsearch-field__container { display: flex; justify-content: space-around; gap: 12px; } .smartsearchdemo__container .search-field__bar { display: flex; justify-content: space-around; background-color: #f5f7fa; padding: 0px 16px; align-items: center; flex: 1 0 0; border-radius: 100px; border: 1px solid #e6e9ed; transition: all .25s ease-in-out; } .smartsearchdemo__container .search-field__bar:focus, .smartsearchdemo__container .search-field__bar:hover, .smartsearchdemo__container .search-field__bar:focus-within, .smartsearchdemo__container .search-field__bar:target, .smartsearchdemo__container .search-field__bar:focus-visible, .smartsearchdemo__container .search-field__actions .search-field__actions__button:focus, .smartsearchdemo__container .search-field__actions .search-field__actions__button:hover, .smartsearchdemo__container .search-field__actions .search-field__actions-button:focus-within, .smartsearchdemo__container .search-field__actions .search-field__actions__button:target, .smartsearchdemo__container .search-field__actions .search-field__actions__button:focus-visible { border: 1px solid #119FF7; background: #FFF; } .smartsearchdemo__container .search-field__bar .search-field__bar__icon { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; margin: 0; max-width: 7.5rem; vertical-align: top; } .smartsearchdemo__container .search-field__bar .search-field__bar__link { color: #656D78; padding: 16px 24px; cursor: pointer; } .smartsearchdemo__container .search-field__bar .search-field__bar__divider { display: flex; border-left: 1px solid #e6e9ed; height: 100%; } .smartsearchdemo__container .search-field__actions .search-field__actions__button { display: flex; padding: 16px; align-items: center; align-self: stretch; border-radius: 100px; border: 1px solid #e6e9ed; background: #f5f7fa; transition: all .25s ease-in-out; cursor: pointer; } .smartsearchdemo__container .search-field__actions .search-field__actions__icon { width: 20px; height: 20px; } .smartsearchdemo__container .imagesearch-field__dialog { display: flex; position: relative; box-sizing: border-box; width: 1280px; padding: 32px; flex-direction: column; justify-content: center; align-items: flex-start; gap: 32px; border-radius: 25px; border: 1px solid #119ff7; background: #fff; } .smartsearchdemo__container .imagesearch-field__dialog .imagesearch-field__dialog__title { display: flex; justify-content: space-between; width: 100%; } .smartsearchdemo__container .imagesearch-field__dialog .imagesearch-field__dialog__title>h2 { display: block; margin: 0; color: #353b48 !important; font-size: 18px; font-style: normal; font-weight: 700; line-height: 100%; letter-spacing: .2px; } .smartsearchdemo__container .imagesearch-field__dialog .imagesearch-field__dialog__body { display: flex; width: 100%; flex-direction: column; } .smartsearchdemo__container .imagesearch-field__close { display: flex; align-items: center; justify-content: center; width: 56px; height: 56px; margin: 0; position: absolute; top: 1px; right: 1px; box-sizing: border-box; vertical-align: top; border: none; background: #fff; border-radius: 50%; cursor: pointer; } .smartsearchdemo__container .imagesearch-field__close:hover { background-color: #F5F7FA } function getRequestTypeIndex(e) { const t = e.get(“requestType”); return t ? “ConceptSearch” === t ? 1 : “ImageSearch” === t ? 2 : 0 : 0 } document.addEventListener(“DOMContentLoaded”, (function () { let e = getRequestTypeIndex(new URL(document.location).searchParams) || 0; function t(t) { if (t.preventDefault(), “keypress” === t.type && 13 === t.which || “click” === t.type) { let t = parseInt(this.dataset.tabIndex); t !== e && document.querySelectorAll(“.smartsearchdemo__container .tab-container”).forEach((function (n) { if (parseInt(n.dataset.tabIndex) === t) return document.querySelectorAll(“.tab-container”).forEach((function (e) { e.style.display = “none” })), n.style.display = “block”, void (e = parseInt(n.dataset.tabIndex)) })) } } document.querySelectorAll(“.tab-container”).forEach((function (t) { parseInt(t.dataset.tabIndex) === e ? t.style.display = “block” : t.style.display = “none” })), document.querySelectorAll(“.tab-switcher”).forEach((function (e) { e.addEventListener(“click”, t), e.addEventListener(“keypress”, t) })) }));
input[type=”text”]:not(.facet__search) { border: none; background-color: transparent; } input[type=”text”]:not(.facet__search):focus, input[type=”text”]:not(.facet__search):hover, input[type=”text”]:not(.facet__search):focus-within, input[type=”text”]:not(.facet__search):target, input[type=”text”]:not(.facet__search):focus-visible { outline: none; border: none; background-color: transparent; } .imagesearch-field__drop-area { display: flex; padding: 40px 24px; flex-direction: column; align-items: center; gap: 24px; align-self: stretch; border-radius: 8px; border: 1px solid #e6e9ed; } .imagesearch-field__drop-area.dragging-state { border: 1px dashed #119ff7; background: #f2faff; } .imagesearch-field__drop-area__icon { width: 100px; height: 100px; } .imagesearch-field__drop-area.dragging-state>.imagesearch-field__drop-area__prompt-msg, .imagesearch-field__drop-area.dragging-state>.imagesearch-field__drop-area__upload-button, .imagesearch-field__drop-area.dragging-state>.imagesearch-field__drop-area__icon { pointer-events: none; visibility: hidden; } .imagesearch-field__drop-area__upload-button { display: flex; padding: 12px 40px 12px 32px; align-items: center; gap: 10px; color: #fff !important; background-color: #000; cursor: pointer; } .imagesearch-field__drop-area__prompt-msg { color: #000; text-align: center; font-size: 18px; font-style: normal; font-weight: 700; line-height: 100%; letter-spacing: .2px; } .imagesearch-field__drop-area__drop-msg { pointer-events: none; color: #119ff7 !important; text-align: center; font-size: 18px; font-style: normal; font-weight: 700; line-height: 100%; letter-spacing: .2px; } <!– CUSTOM TEMPLATE TO MODIFY THE VISUALS OF COMPONENT –>
Drop image

{{strings.dragImageMessage}}

{{strings.dropImageMessage}}

<!– CUSTOM TEMPLATE TO MODIFY THE VISUALS OF COMPONENT –>
{{#if pinned}} {{/if}} {{#if (lt salePrice price)}} {{strings.sale}} {{/if}} {{#if rating}} {{/if}} {{#unless (eq price undefined)}}
{{#if (lt salePrice price)}} {{currency price}} {{currency salePrice}} {{else}} {{currency price}} {{/if}}
{{/unless}}
addEventListener(‘hawksearch:loaded’, () => { HawkSearch.init({ clientId: “3953cf87e0aa4a4eb9496a24d5a0fa84″, components: { ‘search-field’: { strings: { placeholder: ‘Search by Keyword’ } }, ‘conceptsearch-field’: { strings: { placeholder: ‘Search by a Concept’ } }, ‘imagesearch-field’: { strings: { placeholder: ‘Describe an image’ } }, ‘visualsearch-field’: { template: ‘visualsearch-field__template’, strings: { dragImageMessage: ‘Search By Image’, dropImageMessage: ‘Drop an image here’ } }, ‘search-results-item’: { template: ‘search-results-item__template’ }, ‘query-suggestions’: { template: ” }, }, search: { url: window.location.pathname, endpointUrl: “https://essearchapi-na.hawksearch.com”, itemTypes: { default: “product” } }, urlPrefixes: { assets: “https://dashboard-na.hawksearch.com”, content: “https://preview.hawksearch.net/outdoordemo”, }, css: { customStyles: ‘custom-styles__template’ }, fieldMappings: { imageUrl: ‘image’ }, debug: true }); }); // Switch Loading document.addEventListener(‘DOMContentLoaded’, function () { const switchToggle = document.querySelector(‘.switch’); const content = document.querySelector(‘.smartResponse’); switchToggle.classList.remove(‘off’); content.style.display = “block”; switchToggle.addEventListener(‘click’, function () { switchToggle.classList.toggle(‘off’); if (content.style.display == “block”) { content.style.display = “none”; } else { content.style.display = “block”; } }); }); addEventListener(‘hawksearch:after-search-executed’, function (e) { UpdateSummary(e.detail); }); function ClearSummary() { var summaryDiv = document.getElementById(“smartResponseMessage”); var recommendationsDiv = document.getElementById(“recommendationsContainer”); summaryDiv.innerHTML = “”; recommendationsDiv.innerHTML = “”; } function AddSpinner() { const spinner = document.getElementById(“spinner”); const sparkles = document.getElementById(“sparkles”); sparkles.classList.add(“hidden”); spinner.classList.remove(“hidden”); } function HideSpinner() { const spinner = document.getElementById(“spinner”); const sparkles = document.getElementById(“sparkles”); sparkles.classList.remove(“hidden”); spinner.classList.add(“hidden”); } function ComposeFacetObject(facets) { if (facets) { var newFacets = facets.map((facet) => { var newValues = facet.Values.map((value) => { var searchParams = new URLSearchParams(window.location.search); searchParams.set(facet.Field, value.Value); return { Label: value.Label, Value: value.Value, url: location.toString().replace(location.search, “”) + ‘?’ + searchParams.toString() }; }); return { Name: facet.Name, Field: facet.Name, Values: newValues }; }); return { …newFacets } } else { return {} } } function ComposeResultObject(results, max = 2) { var limit = Math.min(results.length, max); var limitedResults = results.slice(0, limit) var newResults = limitedResults.map((item) => { return { title: item?.Document?.title?.[0], description: item?.Document?.description?.[0], category: item?.Document?.category?.[0], color: item?.Document?.color?.[0], brand: item?.Document?.brand?.[0], url: item?.Document?.url?.[0], } }) return newResults; } function ComposeSearchObject() { var urlParams = new URLSearchParams(window.location.search); let allParams = []; urlParams.forEach((value, key) => { if (!!!key.includes(‘query’)) allParams.push({ [key]: value }); }) var searchParam = urlParams.get(‘query’); return { Search: searchParam, Facets: allParams } } async function request(messages) { let openAIUrl = ‘https://api.openai.com/v1/chat/completions’ let openAIAPIKey = ‘sk-grVFHM1ryiJDw5MjrLHVOYp3UyzKZB0it4nS1kYWgQT3BlbkFJV8E3C5xx8Io66AgS9vvwNEWiBK0Bqpao647Hh0ck0A’ var r = await fetch(openAIUrl, { method: ‘POST’, headers: { ‘Authorization’: `Bearer ${openAIAPIKey}`, ‘Accept’: ‘application/json’, ‘Content-Type’: ‘application/json’ }, body: JSON.stringify({ “stream”: false, “model”: “gpt-4o-mini”, “messages”:messages, “response_format”: { “type”: “json_object” }, }), }) var x = await r.json() return x } async function UpdateSummary(eventDetails) { var search = ComposeSearchObject(); // var lps = await getLandingPages(); if (!eventDetails.Results || !eventDetails.Keyword) { return; } AddSpinner(); let aiUrl = “https://aipoc.bridgeline.com/API”; // make multiple searches on behalf of the user and choose the search that would return the most relevant results to the users intentions let systemPrompt = ` Always Respond in formatted html utilize bold fonts, lists, and even headers when needed. You are a helpful salesperson assisting a user find products they want within an ecommerce search page. Make ONLY one specific recommendation and give some good reasoning why the user should purchase it based on their search. Do not provide any information that is not passed to you in the prompt. Your response should be in the “message” field of the JSON object. Do not tell the user to leave the site for any reason. The goal is to help them engage more with the search. The user messages are two parted, ‘user’ is question posed by the user, ‘context’ are the results that came back from their initial search. within the context object their are two sub-objects The Search object contains the search performed by the user as well as any additional search queries. The Results object contains search results. Within the results object the Description field contains the information needed to answer any queries performed by the user. Also within the Results object there is a field called url which contains the url to the document that contains the description in the same object. Provide this url as a link anytime it is used. There is also a name field on results` let promptStart = ` user: “${eventDetails.Keyword}”. context: ` var messages = []; var contentList = []; // Take the content from the first 3 items var facets = ComposeFacetObject(eventDetails?.Facets); var results = ComposeResultObject(eventDetails?.Results, 15); var promptJsonObject = { Facets: facets, Results: results, Search: search, } var fullPrompt = promptStart + JSON.stringify(promptJsonObject); messages.push({ “role”: “system”, “content”: systemPrompt },); messages.push({ “role”: “user”, “content”: fullPrompt }) var r = await request(messages) var summaryDiv = document.getElementById(“smartResponseMessage”); var recommendationsDiv = document.getElementById(“recommendationsContainer”); var summary = GetSmartResponseSummary(r); var parsed = JSON.parse(summary) HideSpinner(); console.log(“Hello”) animateText2(summaryDiv, parsed?.message) recommendationsDiv.innerHTML = ” } function GetSmartResponseSummary(genAiResponse) { return (genAiResponse?.choices?.[0].message?.content ?? “”); } function animateText2(container, htmlContent, delay = 10) { container.innerHTML = ”; // Clear existing content const tempContainer = document.createElement(‘div’); tempContainer.innerHTML = htmlContent; const nodes = Array.from(tempContainer.childNodes); function typeNode(index) { if (index >= nodes.length) return; // Stop if there are no more nodes const node = nodes[index]; if (node.nodeType === Node.TEXT_NODE) { // Animate text node const text = node.textContent; let charIndex = 0; const textNode = document.createTextNode(”); container.appendChild(textNode); function typeCharacter() { if (charIndex < text.length) { textNode.textContent += text[charIndex]; charIndex++; setTimeout(typeCharacter, delay); } else { typeNode(index + 1); // Move to the next node after current text animation completes } } typeCharacter(); } else if (node.nodeType === Node.ELEMENT_NODE) { // Clone the element and animate its children const newElement = document.createElement(node.tagName); for (let i = 0; i < node.attributes.length; i++) { const attr = node.attributes[i]; newElement.setAttribute(attr.name, attr.value); } container.appendChild(newElement); const childNodes = Array.from(node.childNodes); let childIndex = 0; function typeChildNode() { if (childIndex { childIndex++; typeChildNode(); }); } else { typeNode(index + 1); // Move to the next sibling node after children are done } } typeChildNode(); } } function typeNodeRecursive(node, parent, callback) { if (node.nodeType === Node.TEXT_NODE) { // Animate text node const text = node.textContent; let charIndex = 0; const textNode = document.createTextNode(”); parent.appendChild(textNode); function typeCharacter() { if (charIndex < text.length) { textNode.textContent += text[charIndex]; charIndex++; setTimeout(typeCharacter, delay); } else { callback(); // Call the callback after current text animation completes } } typeCharacter(); } else if (node.nodeType === Node.ELEMENT_NODE) { // Clone the element and animate its children const newElement = document.createElement(node.tagName); for (let i = 0; i < node.attributes.length; i++) { const attr = node.attributes[i]; newElement.setAttribute(attr.name, attr.value); } parent.appendChild(newElement); const childNodes = Array.from(node.childNodes); let childIndex = 0; function typeChildNode() { if (childIndex { childIndex++; typeChildNode(); }); } else { callback(); // Call the callback after children are done } } typeChildNode(); } } typeNode(0); // Start the animation }
Close

Image Search

search

Smart Response