Match any/all keywords in Standard Answers (#2443)

* migration: add column "match_any_keywords" to StandardAnswer

* Implement any/all keyword matching for standard answers

* Add match_any_keywords to non-searchable fields

* Remove stray print

* Simplify Slack messages for any and all cases

---------

Co-authored-by: danswer-trial <danswer-trial@danswer-trials-MacBook-Pro.local>
This commit is contained in:
trial-danswer
2024-09-13 22:28:07 -07:00
committed by GitHub
parent 974f85da66
commit 430c9a47d7
11 changed files with 138 additions and 17 deletions

View File

@@ -9,15 +9,25 @@ import * as Yup from "yup";
import {
createStandardAnswer,
createStandardAnswerCategory,
StandardAnswerCreationRequest,
updateStandardAnswer,
} from "./lib";
import {
TextFormField,
MarkdownFormField,
BooleanFormField,
SelectorFormField,
} from "@/components/admin/connectors/Field";
import MultiSelectDropdown from "@/components/MultiSelectDropdown";
function mapKeywordSelectToMatchAny(keywordSelect: "any" | "all"): boolean {
return keywordSelect == "any";
}
function mapMatchAnyToKeywordSelect(matchAny: boolean): "any" | "all" {
return matchAny ? "any" : "all";
}
export const StandardAnswerCreationForm = ({
standardAnswerCategories,
existingStandardAnswer,
@@ -45,6 +55,11 @@ export const StandardAnswerCreationForm = ({
matchRegex: existingStandardAnswer
? existingStandardAnswer.match_regex
: false,
matchAnyKeywords: existingStandardAnswer
? mapMatchAnyToKeywordSelect(
existingStandardAnswer.match_any_keywords
)
: "all",
}}
validationSchema={Yup.object().shape({
keyword: Yup.string()
@@ -59,8 +74,11 @@ export const StandardAnswerCreationForm = ({
onSubmit={async (values, formikHelpers) => {
formikHelpers.setSubmitting(true);
const cleanedValues = {
const cleanedValues: StandardAnswerCreationRequest = {
...values,
matchAnyKeywords: mapKeywordSelectToMatchAny(
values.matchAnyKeywords
),
categories: values.categories.map((category) => category.id),
};
@@ -98,11 +116,19 @@ export const StandardAnswerCreationForm = ({
tooltip="Triggers if the question matches this regex pattern (using Python `re.search()`)"
placeholder="(?:it|support)\s*ticket"
/>
) : values.matchAnyKeywords == "any" ? (
<TextFormField
name="keyword"
label="Any of these keywords, separated by spaces"
tooltip="A question must match these keywords in order to trigger the answer."
placeholder="ticket problem issue"
autoCompleteDisabled={true}
/>
) : (
<TextFormField
name="keyword"
label="Keywords"
tooltip="Triggers if the question contains all of these keywords, in any order."
label="All of these keywords, in any order, separated by spaces"
tooltip="A question must match these keywords in order to trigger the answer."
placeholder="it ticket"
autoCompleteDisabled={true}
/>
@@ -113,6 +139,27 @@ export const StandardAnswerCreationForm = ({
label="Match regex"
name="matchRegex"
/>
{values.matchRegex ? null : (
<SelectorFormField
defaultValue={`all`}
label="Keyword detection strategy"
subtext="Choose whether to require the user's question to contain any or all of the keywords above to show this answer."
name="matchAnyKeywords"
options={[
{
name: "All keywords",
value: "all",
},
{
name: "Any keywords",
value: "any",
},
]}
onSelect={(selected) => {
setFieldValue("matchAnyKeywords", selected);
}}
/>
)}
<div className="w-full">
<MarkdownFormField
name="answer"

View File

@@ -7,6 +7,7 @@ export interface StandardAnswerCreationRequest {
answer: string;
categories: number[];
matchRegex: boolean;
matchAnyKeywords: boolean;
}
const buildRequestBodyFromStandardAnswerCategoryCreationRequest = (
@@ -50,6 +51,7 @@ const buildRequestBodyFromStandardAnswerCreationRequest = (
answer: request.answer,
categories: request.categories,
match_regex: request.matchRegex,
match_any_keywords: request.matchAnyKeywords,
});
};

View File

@@ -171,8 +171,14 @@ const StandardAnswersTable = ({
];
const filteredStandardAnswers = standardAnswers.filter((standardAnswer) => {
const { answer, id, categories, match_regex, ...fieldsToSearch } =
standardAnswer;
const {
answer,
id,
categories,
match_regex,
match_any_keywords,
...fieldsToSearch
} = standardAnswer;
const cleanedQuery = query.toLowerCase();
const searchMatch = Object.values(fieldsToSearch).some((value) => {
return value.toLowerCase().includes(cleanedQuery);

View File

@@ -162,6 +162,7 @@ export interface StandardAnswer {
keyword: string;
answer: string;
match_regex: boolean;
match_any_keywords: boolean;
categories: StandardAnswerCategory[];
}