|
1 | 1 | import { useEffect, useState } from "react"; |
2 | | -import { Stack, IDropdownOption, Dropdown, IDropdownProps } from "@fluentui/react"; |
| 2 | +import { Stack, IDropdownOption, Dropdown, Checkbox, IDropdownProps } from "@fluentui/react"; |
3 | 3 | import { useId } from "@fluentui/react-hooks"; |
4 | 4 | import { useTranslation } from "react-i18next"; |
5 | 5 |
|
6 | 6 | import styles from "./VectorSettings.module.css"; |
7 | 7 | import { HelpCallout } from "../../components/HelpCallout"; |
8 | | -import { RetrievalMode, VectorFields } from "../../api"; |
| 8 | +import { RetrievalMode } from "../../api"; |
9 | 9 |
|
10 | 10 | interface Props { |
11 | 11 | showImageOptions?: boolean; |
12 | 12 | defaultRetrievalMode: RetrievalMode; |
13 | | - defaultVectorFields?: VectorFields; |
| 13 | + defaultSearchTextEmbeddings?: boolean; |
| 14 | + defaultSearchImageEmbeddings?: boolean; |
14 | 15 | updateRetrievalMode: (retrievalMode: RetrievalMode) => void; |
15 | | - updateVectorFields: (vectorFields: VectorFields) => void; |
| 16 | + updateSearchTextEmbeddings: (searchTextEmbeddings: boolean) => void; |
| 17 | + updateSearchImageEmbeddings: (searchImageEmbeddings: boolean) => void; |
16 | 18 | } |
17 | 19 |
|
18 | | -export const VectorSettings = ({ updateRetrievalMode, updateVectorFields, showImageOptions, defaultRetrievalMode, defaultVectorFields }: Props) => { |
| 20 | +export const VectorSettings = ({ |
| 21 | + updateRetrievalMode, |
| 22 | + updateSearchTextEmbeddings, |
| 23 | + updateSearchImageEmbeddings, |
| 24 | + showImageOptions, |
| 25 | + defaultRetrievalMode, |
| 26 | + defaultSearchTextEmbeddings = true, |
| 27 | + defaultSearchImageEmbeddings = true |
| 28 | +}: Props) => { |
19 | 29 | const [retrievalMode, setRetrievalMode] = useState<RetrievalMode>(defaultRetrievalMode || RetrievalMode.Hybrid); |
20 | | - const [vectorFields, setVectorFields] = useState<VectorFields>(defaultVectorFields || VectorFields.TextAndImageEmbeddings); |
| 30 | + const [searchTextEmbeddings, setSearchTextEmbeddings] = useState<boolean>(defaultSearchTextEmbeddings); |
| 31 | + const [searchImageEmbeddings, setSearchImageEmbeddings] = useState<boolean>(defaultSearchImageEmbeddings); |
21 | 32 |
|
22 | 33 | const onRetrievalModeChange = (_ev: React.FormEvent<HTMLDivElement>, option?: IDropdownOption<RetrievalMode> | undefined) => { |
23 | 34 | setRetrievalMode(option?.data || RetrievalMode.Hybrid); |
24 | 35 | updateRetrievalMode(option?.data || RetrievalMode.Hybrid); |
25 | 36 | }; |
26 | 37 |
|
27 | | - const onVectorFieldsChange = (_ev: React.FormEvent<HTMLDivElement>, option?: IDropdownOption<VectorFields> | undefined) => { |
28 | | - setVectorFields(option?.data || VectorFields.TextAndImageEmbeddings); |
29 | | - updateVectorFields(option?.data || VectorFields.TextAndImageEmbeddings); |
| 38 | + const onSearchTextEmbeddingsChange = (_ev?: React.FormEvent<HTMLElement | HTMLInputElement>, checked?: boolean) => { |
| 39 | + setSearchTextEmbeddings(checked || false); |
| 40 | + updateSearchTextEmbeddings(checked || false); |
| 41 | + }; |
| 42 | + |
| 43 | + const onSearchImageEmbeddingsChange = (_ev?: React.FormEvent<HTMLElement | HTMLInputElement>, checked?: boolean) => { |
| 44 | + setSearchImageEmbeddings(checked || false); |
| 45 | + updateSearchImageEmbeddings(checked || false); |
30 | 46 | }; |
31 | 47 |
|
32 | 48 | // Only run if showImageOptions changes from true to false or false to true |
33 | 49 | useEffect(() => { |
34 | 50 | if (!showImageOptions) { |
35 | | - // If images are disabled, we must force to text-only embeddings |
36 | | - setVectorFields(VectorFields.Embedding); |
37 | | - updateVectorFields(VectorFields.Embedding); |
| 51 | + // If images are disabled, we must disable image embeddings |
| 52 | + setSearchImageEmbeddings(false); |
| 53 | + updateSearchImageEmbeddings(false); |
38 | 54 | } else { |
39 | | - // When image options become available, reset to default or use TextAndImageEmbeddings |
40 | | - setVectorFields(defaultVectorFields || VectorFields.TextAndImageEmbeddings); |
41 | | - updateVectorFields(defaultVectorFields || VectorFields.TextAndImageEmbeddings); |
| 55 | + // When image options become available, reset to default |
| 56 | + setSearchImageEmbeddings(defaultSearchImageEmbeddings); |
| 57 | + updateSearchImageEmbeddings(defaultSearchImageEmbeddings); |
42 | 58 | } |
43 | | - }, [showImageOptions, updateVectorFields, defaultVectorFields]); |
| 59 | + }, [showImageOptions, updateSearchImageEmbeddings, defaultSearchImageEmbeddings]); |
44 | 60 |
|
45 | 61 | const retrievalModeId = useId("retrievalMode"); |
46 | 62 | const retrievalModeFieldId = useId("retrievalModeField"); |
@@ -78,36 +94,43 @@ export const VectorSettings = ({ updateRetrievalMode, updateVectorFields, showIm |
78 | 94 | /> |
79 | 95 |
|
80 | 96 | {showImageOptions && [RetrievalMode.Vectors, RetrievalMode.Hybrid].includes(retrievalMode) && ( |
81 | | - <Dropdown |
82 | | - id={vectorFieldsFieldId} |
83 | | - label={t("labels.vector.label")} |
84 | | - selectedKey={vectorFields} |
85 | | - options={[ |
86 | | - { |
87 | | - key: VectorFields.Embedding, |
88 | | - text: t("labels.vector.options.embedding"), |
89 | | - selected: vectorFields === VectorFields.Embedding, |
90 | | - data: VectorFields.Embedding |
91 | | - }, |
92 | | - { |
93 | | - key: VectorFields.ImageEmbedding, |
94 | | - text: t("labels.vector.options.imageEmbedding"), |
95 | | - selected: vectorFields === VectorFields.ImageEmbedding, |
96 | | - data: VectorFields.ImageEmbedding |
97 | | - }, |
98 | | - { |
99 | | - key: VectorFields.TextAndImageEmbeddings, |
100 | | - text: t("labels.vector.options.both"), |
101 | | - selected: vectorFields === VectorFields.TextAndImageEmbeddings, |
102 | | - data: VectorFields.TextAndImageEmbeddings |
103 | | - } |
104 | | - ]} |
105 | | - onChange={onVectorFieldsChange} |
106 | | - aria-labelledby={vectorFieldsId} |
107 | | - onRenderLabel={(props: IDropdownProps | undefined) => ( |
108 | | - <HelpCallout labelId={vectorFieldsId} fieldId={vectorFieldsFieldId} helpText={t("helpTexts.vectorFields")} label={props?.label} /> |
109 | | - )} |
110 | | - /> |
| 97 | + <fieldset className={styles.fieldset}> |
| 98 | + <legend className={styles.legend}>{t("labels.vector.label")}</legend> |
| 99 | + <Stack tokens={{ childrenGap: 8 }}> |
| 100 | + <Checkbox |
| 101 | + id={vectorFieldsFieldId + "-text"} |
| 102 | + className={styles.settingsSeparator} |
| 103 | + label={t("labels.vector.options.embedding")} |
| 104 | + checked={searchTextEmbeddings} |
| 105 | + onChange={onSearchTextEmbeddingsChange} |
| 106 | + aria-labelledby={vectorFieldsId + "-text"} |
| 107 | + onRenderLabel={props => ( |
| 108 | + <HelpCallout |
| 109 | + labelId={vectorFieldsId + "-text"} |
| 110 | + fieldId={vectorFieldsFieldId + "-text"} |
| 111 | + helpText={t("helpTexts.textEmbeddings")} |
| 112 | + label={props?.label} |
| 113 | + /> |
| 114 | + )} |
| 115 | + /> |
| 116 | + <Checkbox |
| 117 | + id={vectorFieldsFieldId + "-image"} |
| 118 | + className={styles.settingsSeparator} |
| 119 | + label={t("labels.vector.options.imageEmbedding")} |
| 120 | + checked={searchImageEmbeddings} |
| 121 | + onChange={onSearchImageEmbeddingsChange} |
| 122 | + aria-labelledby={vectorFieldsId + "-image"} |
| 123 | + onRenderLabel={props => ( |
| 124 | + <HelpCallout |
| 125 | + labelId={vectorFieldsId + "-image"} |
| 126 | + fieldId={vectorFieldsFieldId + "-image"} |
| 127 | + helpText={t("helpTexts.imageEmbeddings")} |
| 128 | + label={props?.label} |
| 129 | + /> |
| 130 | + )} |
| 131 | + /> |
| 132 | + </Stack> |
| 133 | + </fieldset> |
111 | 134 | )} |
112 | 135 | </Stack> |
113 | 136 | ); |
|
0 commit comments