fix: previous commit redeployed
This commit is contained in:
parent
aa871ff942
commit
9f5cd954e0
@ -7,16 +7,6 @@ type HistoryMessage = {
|
|||||||
content: string
|
content: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Customer is asking whether the store carries / sells a product (not policy/shipping). */
|
|
||||||
function isAskingAboutProductAvailability(query: string) {
|
|
||||||
return /\b(do you have|have any|have you got|carry|carrying|sell|selling|in stock|out of stock|stock|available|got any|do you sell|do you carry|looking for|can i (get|buy)|can you get)\b/i.test(
|
|
||||||
query.trim()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const NO_EVIDENCE_PRODUCT_REPLY =
|
|
||||||
"I do not see that item in this store’s catalog or FAQs I have access to, so I can’t confirm we carry it. If you have another product name or category from this shop, I can check again."
|
|
||||||
|
|
||||||
export async function generateStorefrontReply(params: {
|
export async function generateStorefrontReply(params: {
|
||||||
storeId: string
|
storeId: string
|
||||||
query: string
|
query: string
|
||||||
@ -27,34 +17,6 @@ export async function generateStorefrontReply(params: {
|
|||||||
const { storeId, query, visitorId, history } = params
|
const { storeId, query, visitorId, history } = params
|
||||||
|
|
||||||
const retrieval = await getBlendedStorefrontContext({ storeId, query })
|
const retrieval = await getBlendedStorefrontContext({ storeId, query })
|
||||||
|
|
||||||
// Hard guard: do not invent inventory. If they ask “do you have X?” and we have no product row and no KB/FAQ hit, answer without the LLM.
|
|
||||||
if (
|
|
||||||
isAskingAboutProductAvailability(query) &&
|
|
||||||
retrieval.productCount === 0 &&
|
|
||||||
retrieval.kbCount === 0
|
|
||||||
) {
|
|
||||||
logger.info("[STOREFRONT_AI_REPLY]", {
|
|
||||||
storeId,
|
|
||||||
visitorId,
|
|
||||||
queryLength: query.length,
|
|
||||||
kbHits: retrieval.kbCount,
|
|
||||||
productHits: retrieval.productCount,
|
|
||||||
latencyMs: Date.now() - startedAt,
|
|
||||||
fallbackUsed: true,
|
|
||||||
groundedSkipLlm: true,
|
|
||||||
error: null,
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
content: NO_EVIDENCE_PRODUCT_REPLY,
|
|
||||||
meta: {
|
|
||||||
kbHits: retrieval.kbCount,
|
|
||||||
productHits: retrieval.productCount,
|
|
||||||
fallbackUsed: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const contextLines = retrieval.items.map(
|
const contextLines = retrieval.items.map(
|
||||||
(item, idx) => `[${idx + 1}] (${item.source}) ${item.title}: ${item.content}`
|
(item, idx) => `[${idx + 1}] (${item.source}) ${item.title}: ${item.content}`
|
||||||
)
|
)
|
||||||
@ -68,13 +30,12 @@ export async function generateStorefrontReply(params: {
|
|||||||
})) as GroqChatMessage[]
|
})) as GroqChatMessage[]
|
||||||
|
|
||||||
const system = [
|
const system = [
|
||||||
"You are the JUNO storefront assistant. You ONLY answer using the Context block below (products, FAQs, knowledge chunks).",
|
"You are JUNO storefront assistant for an ecommerce store.",
|
||||||
"If the Context does not clearly support an answer, say you cannot find it in the catalog or docs you have—do NOT guess.",
|
"Use the provided context first (products, FAQs, knowledge).",
|
||||||
"Never claim a product exists, is in stock, or that the store carries a category unless a Context line explicitly supports it.",
|
"If context is insufficient, ask one concise clarifying question.",
|
||||||
"Never invent website layout: no tabs, menus, dropdowns, or navigation paths unless they appear verbatim in Context.",
|
"Do not invent exact prices, stock or policy details that are not present.",
|
||||||
"Never invent URLs or deep links unless they appear in Context.",
|
"Keep responses concise, friendly, and sales-supportive.",
|
||||||
"Do not affirm availability with “yes” unless a PRODUCT line or FAQ/KB line in Context clearly covers what the customer asked.",
|
"Return plain text only.",
|
||||||
"Be concise and friendly. Plain text only.",
|
|
||||||
].join(" ")
|
].join(" ")
|
||||||
|
|
||||||
const user = [
|
const user = [
|
||||||
@ -92,13 +53,13 @@ export async function generateStorefrontReply(params: {
|
|||||||
]
|
]
|
||||||
|
|
||||||
const out = await groqChatCompletion(messages, {
|
const out = await groqChatCompletion(messages, {
|
||||||
temperature: 0.1,
|
temperature: 0.2,
|
||||||
maxTokens: 420,
|
maxTokens: 420,
|
||||||
timeoutMs: 28_000,
|
timeoutMs: 28_000,
|
||||||
})
|
})
|
||||||
|
|
||||||
const fallback =
|
const fallback =
|
||||||
"I don’t have enough in the store’s catalog or FAQ context to answer that accurately. What product name or topic from this shop should I look for?"
|
"Thanks for your message. I do not have enough details right now. Could you share the product name or what exactly you want to know?"
|
||||||
|
|
||||||
const content = (out.content || "").trim() || fallback
|
const content = (out.content || "").trim() || fallback
|
||||||
|
|
||||||
|
|||||||
@ -7,128 +7,12 @@ type RetrievedContextItem = {
|
|||||||
score: number
|
score: number
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Strip generic words so "do you have socks?" does not match random KB via "you"/"do". */
|
|
||||||
const STOPWORDS = new Set([
|
|
||||||
"the",
|
|
||||||
"a",
|
|
||||||
"an",
|
|
||||||
"and",
|
|
||||||
"or",
|
|
||||||
"but",
|
|
||||||
"in",
|
|
||||||
"on",
|
|
||||||
"at",
|
|
||||||
"to",
|
|
||||||
"for",
|
|
||||||
"of",
|
|
||||||
"as",
|
|
||||||
"by",
|
|
||||||
"with",
|
|
||||||
"from",
|
|
||||||
"is",
|
|
||||||
"are",
|
|
||||||
"was",
|
|
||||||
"were",
|
|
||||||
"be",
|
|
||||||
"been",
|
|
||||||
"being",
|
|
||||||
"have",
|
|
||||||
"has",
|
|
||||||
"had",
|
|
||||||
"do",
|
|
||||||
"does",
|
|
||||||
"did",
|
|
||||||
"will",
|
|
||||||
"would",
|
|
||||||
"could",
|
|
||||||
"should",
|
|
||||||
"may",
|
|
||||||
"might",
|
|
||||||
"must",
|
|
||||||
"can",
|
|
||||||
"this",
|
|
||||||
"that",
|
|
||||||
"these",
|
|
||||||
"those",
|
|
||||||
"i",
|
|
||||||
"me",
|
|
||||||
"my",
|
|
||||||
"you",
|
|
||||||
"your",
|
|
||||||
"it",
|
|
||||||
"its",
|
|
||||||
"we",
|
|
||||||
"our",
|
|
||||||
"they",
|
|
||||||
"them",
|
|
||||||
"their",
|
|
||||||
"what",
|
|
||||||
"which",
|
|
||||||
"who",
|
|
||||||
"whom",
|
|
||||||
"whose",
|
|
||||||
"where",
|
|
||||||
"when",
|
|
||||||
"why",
|
|
||||||
"how",
|
|
||||||
"all",
|
|
||||||
"each",
|
|
||||||
"every",
|
|
||||||
"both",
|
|
||||||
"few",
|
|
||||||
"more",
|
|
||||||
"most",
|
|
||||||
"other",
|
|
||||||
"some",
|
|
||||||
"such",
|
|
||||||
"no",
|
|
||||||
"nor",
|
|
||||||
"not",
|
|
||||||
"only",
|
|
||||||
"own",
|
|
||||||
"same",
|
|
||||||
"so",
|
|
||||||
"than",
|
|
||||||
"too",
|
|
||||||
"very",
|
|
||||||
"just",
|
|
||||||
"any",
|
|
||||||
"there",
|
|
||||||
"here",
|
|
||||||
"about",
|
|
||||||
"into",
|
|
||||||
"through",
|
|
||||||
"during",
|
|
||||||
"before",
|
|
||||||
"after",
|
|
||||||
"above",
|
|
||||||
"below",
|
|
||||||
"between",
|
|
||||||
"under",
|
|
||||||
"again",
|
|
||||||
"further",
|
|
||||||
"then",
|
|
||||||
"once",
|
|
||||||
"please",
|
|
||||||
"thanks",
|
|
||||||
"thank",
|
|
||||||
"hello",
|
|
||||||
"hi",
|
|
||||||
"hey",
|
|
||||||
"yes",
|
|
||||||
"no",
|
|
||||||
"tell",
|
|
||||||
"give",
|
|
||||||
"get",
|
|
||||||
"got",
|
|
||||||
])
|
|
||||||
|
|
||||||
function tokenize(text: string) {
|
function tokenize(text: string) {
|
||||||
return text
|
return text
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.split(/[^a-z0-9]+/g)
|
.split(/[^a-z0-9]+/g)
|
||||||
.map((t) => t.trim())
|
.map((t) => t.trim())
|
||||||
.filter((t) => t.length >= 2 && !STOPWORDS.has(t))
|
.filter((t) => t.length >= 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
function scoreByTerms(text: string, terms: string[]) {
|
function scoreByTerms(text: string, terms: string[]) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user