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 –>
<!– CUSTOM TEMPLATE TO MODIFY THE VISUALS OF COMPONENT –>
{{strings.dragImageMessage}}
{{strings.dropImageMessage}}
{{#if pinned}}
{{/if}}
{{#if (lt salePrice price)}}
{{strings.sale}}
{{/if}}
{{#if rating}}
{{/if}}
{{#unless (eq price undefined)}}
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
}
{{#if (lt salePrice price)}}
{{currency price}}
{{currency salePrice}}
{{else}}
{{currency price}}
{{/if}}
{{/unless}}