Danswer assistant (#96)

Add helper!
This commit is contained in:
Chris Weaver
2023-06-11 17:54:41 -07:00
committed by GitHub
parent 2bfbf037ee
commit 8f5b9c0bcd
14 changed files with 468 additions and 193 deletions

View File

@@ -106,6 +106,9 @@ def json_chat_processor(question: str, documents: list[str]) -> list[dict[str, s
'Start by reading the following documents and responding with "Acknowledged".' 'Start by reading the following documents and responding with "Acknowledged".'
) )
complete_answer_not_found_response = (
'{"answer": "' + UNCERTAINTY_PAT + '", "quotes": []}'
)
task_msg = ( task_msg = (
"Now answer the next user query based on documents above and quote relevant sections.\n" "Now answer the next user query based on documents above and quote relevant sections.\n"
"Respond with a JSON containing the answer and up to three most relevant quotes from the documents.\n" "Respond with a JSON containing the answer and up to three most relevant quotes from the documents.\n"
@@ -113,7 +116,7 @@ def json_chat_processor(question: str, documents: list[str]) -> list[dict[str, s
"Your responses should be informative and concise.\n" "Your responses should be informative and concise.\n"
"You MUST prioritize information from provided documents over internal knowledge.\n" "You MUST prioritize information from provided documents over internal knowledge.\n"
"If the query cannot be answered based on the documents, respond with " "If the query cannot be answered based on the documents, respond with "
'{"answer": "Information not found", "quotes": []}\n' f"{complete_answer_not_found_response}\n"
"If the query requires aggregating whole documents, respond with " "If the query requires aggregating whole documents, respond with "
'{"answer": "Aggregations not supported", "quotes": []}\n' '{"answer": "Aggregations not supported", "quotes": []}\n'
f"Sample response:\n{json.dumps(SAMPLE_JSON_RESPONSE)}" f"Sample response:\n{json.dumps(SAMPLE_JSON_RESPONSE)}"

View File

@@ -63,8 +63,8 @@ def extract_answer_quotes_freeform(
) )
# If model just gives back the uncertainty pattern to signify answer isn't found or nothing at all # If model just gives back the uncertainty pattern to signify answer isn't found or nothing at all
if null_answer_check == UNCERTAINTY_PAT or not null_answer_check: # if null_answer_check == UNCERTAINTY_PAT or not null_answer_check:
return None, None # return None, None
# If no answer section, don't care about the quote # If no answer section, don't care about the quote
if answer_raw.lower().strip().startswith(QUOTE_PAT.lower()): if answer_raw.lower().strip().startswith(QUOTE_PAT.lower()):

178
web/package-lock.json generated
View File

@@ -18,7 +18,7 @@
"eslint-config-next": "13.2.4", "eslint-config-next": "13.2.4",
"formik": "^2.2.9", "formik": "^2.2.9",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"next": "^13.2.4", "next": "^13.4.4",
"postcss": "^8.4.23", "postcss": "^8.4.23",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@@ -172,9 +172,9 @@
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
}, },
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.4.tgz",
"integrity": "sha512-eD6WCBMFjLFooLM19SIhSkWBHtaFrZFfg2Cxnyl3vS3DAdFRfnx5TY2RxlkuKXdIRCC0ySbtK9JXXt8qLCqzZg==" "integrity": "sha512-q/y7VZj/9YpgzDe64Zi6rY1xPizx80JjlU2BTevlajtaE3w1LqweH1gGgxou2N7hdFosXHjGrI4OUvtFXXhGLg=="
}, },
"node_modules/@next/eslint-plugin-next": { "node_modules/@next/eslint-plugin-next": {
"version": "13.2.4", "version": "13.2.4",
@@ -185,9 +185,9 @@
} }
}, },
"node_modules/@next/swc-darwin-arm64": { "node_modules/@next/swc-darwin-arm64": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.4.tgz",
"integrity": "sha512-eF8ARHtYfnoYtDa6xFHriUKA/Mfj/cCbmKb3NofeKhMccs65G6/loZ15a6wYCCx4rPAd6x4t1WmVYtri7EdeBg==", "integrity": "sha512-xfjgXvp4KalNUKZMHmsFxr1Ug+aGmmO6NWP0uoh4G3WFqP/mJ1xxfww0gMOeMeSq/Jyr5k7DvoZ2Pv+XOITTtw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -200,9 +200,9 @@
} }
}, },
"node_modules/@next/swc-darwin-x64": { "node_modules/@next/swc-darwin-x64": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.4.tgz",
"integrity": "sha512-7cmDgF9tGWTgn5Gw+vP17miJbH4wcraMHDCOHTYWkO/VeKT73dUWG23TNRLfgtCNSPgH4V5B4uLHoZTanx9bAw==", "integrity": "sha512-ZY9Ti1hkIwJsxGus3nlubIkvYyB0gNOYxKrfsOrLEqD0I2iCX8D7w8v6QQZ2H+dDl6UT29oeEUdDUNGk4UEpfg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -215,9 +215,9 @@
} }
}, },
"node_modules/@next/swc-linux-arm64-gnu": { "node_modules/@next/swc-linux-arm64-gnu": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.4.tgz",
"integrity": "sha512-qwJqmCri2ie8aTtE5gjTSr8S6O8B67KCYgVZhv9gKH44yvc/zXbAY8u23QGULsYOyh1islWE5sWfQNLOj9iryg==", "integrity": "sha512-+KZnDeMShYkpkqAvGCEDeqYTRADJXc6SY1jWXz+Uo6qWQO/Jd9CoyhTJwRSxvQA16MoYzvILkGaDqirkRNctyA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -230,9 +230,9 @@
} }
}, },
"node_modules/@next/swc-linux-arm64-musl": { "node_modules/@next/swc-linux-arm64-musl": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.4.tgz",
"integrity": "sha512-qcC54tWNGDv/VVIFkazxhqH1Bnagjfs4enzELVRlUOoJPD2BGJTPI7z08pQPbbgxLtRiu8gl2mXvpB8WlOkMeA==", "integrity": "sha512-evC1twrny2XDT4uOftoubZvW3EG0zs0ZxMwEtu/dDGVRO5n5pT48S8qqEIBGBUZYu/Xx4zzpOkIxx1vpWdE+9A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -245,9 +245,9 @@
} }
}, },
"node_modules/@next/swc-linux-x64-gnu": { "node_modules/@next/swc-linux-x64-gnu": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.4.tgz",
"integrity": "sha512-9TeWFlpLsBosZ+tsm/rWBaMwt5It9tPH8m3nawZqFUUrZyGRfGcI67js774vtx0k3rL9qbyY6+3pw9BCVpaYUA==", "integrity": "sha512-PX706XcCHr2FfkyhP2lpf+pX/tUvq6/ke7JYnnr0ykNdEMo+sb7cC/o91gnURh4sPYSiZJhsF2gbIqg9rciOHQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -260,9 +260,9 @@
} }
}, },
"node_modules/@next/swc-linux-x64-musl": { "node_modules/@next/swc-linux-x64-musl": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.4.tgz",
"integrity": "sha512-sNDGaWmSqTS4QRUzw61wl4mVPeSqNIr1OOjLlQTRuyInxMxtqImRqdvzDvFTlDfdeUMU/DZhWGYoHrXLlZXe6A==", "integrity": "sha512-TKUUx3Ftd95JlHV6XagEnqpT204Y+IsEa3awaYIjayn0MOGjgKZMZibqarK3B1FsMSPaieJf2FEAcu9z0yT5aA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -275,9 +275,9 @@
} }
}, },
"node_modules/@next/swc-win32-arm64-msvc": { "node_modules/@next/swc-win32-arm64-msvc": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.4.tgz",
"integrity": "sha512-+CXZC7u1iXdLRudecoUYbhbsXpglYv8KFYsFxKBPn7kg+bk7eJo738wAA4jXIl8grTF2mPdmO93JOQym+BlYGA==", "integrity": "sha512-FP8AadgSq4+HPtim7WBkCMGbhr5vh9FePXiWx9+YOdjwdQocwoCK5ZVC3OW8oh3TWth6iJ0AXJ/yQ1q1cwSZ3A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -290,9 +290,9 @@
} }
}, },
"node_modules/@next/swc-win32-ia32-msvc": { "node_modules/@next/swc-win32-ia32-msvc": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.4.tgz",
"integrity": "sha512-vIoXVVc7UYO68VwVMDKwJC2+HqAZQtCYiVlApyKEeIPIQpz2gpufzGxk1z3/gwrJt/kJ5CDZjlhYDCzd3hdz+g==", "integrity": "sha512-3WekVmtuA2MCdcAOrgrI+PuFiFURtSyyrN1I3UPtS0ckR2HtLqyqmS334Eulf15g1/bdwMteePdK363X/Y9JMg==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -305,9 +305,9 @@
} }
}, },
"node_modules/@next/swc-win32-x64-msvc": { "node_modules/@next/swc-win32-x64-msvc": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.4.tgz",
"integrity": "sha512-n8V5ImLQZibKTu10UUdI3nIeTLkliEXe628qxqW9v8My3BAH2a7H0SaCqkV2OgqFnn8sG1wxKYw9/SNJ632kSA==", "integrity": "sha512-AHRITu/CrlQ+qzoqQtEMfaTu7GHaQ6bziQln/pVWpOYC1wU+Mq6VQQFlsDtMCnDztPZtppAXdvvbNS7pcfRzlw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2742,11 +2742,11 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
}, },
"node_modules/next": { "node_modules/next": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.1.tgz", "resolved": "https://registry.npmjs.org/next/-/next-13.4.4.tgz",
"integrity": "sha512-JBw2kAIyhKDpjhEWvNVoFeIzNp9xNxg8wrthDOtMctfn3EpqGCmW0FSviNyGgOSOSn6zDaX48pmvbdf6X2W9xA==", "integrity": "sha512-C5S0ysM0Ily9McL4Jb48nOQHT1BukOWI59uC3X/xCMlYIh9rJZCv7nzG92J6e1cOBqQbKovlpgvHWFmz4eKKEA==",
"dependencies": { "dependencies": {
"@next/env": "13.4.1", "@next/env": "13.4.4",
"@swc/helpers": "0.5.1", "@swc/helpers": "0.5.1",
"busboy": "1.6.0", "busboy": "1.6.0",
"caniuse-lite": "^1.0.30001406", "caniuse-lite": "^1.0.30001406",
@@ -2761,20 +2761,19 @@
"node": ">=16.8.0" "node": ">=16.8.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@next/swc-darwin-arm64": "13.4.1", "@next/swc-darwin-arm64": "13.4.4",
"@next/swc-darwin-x64": "13.4.1", "@next/swc-darwin-x64": "13.4.4",
"@next/swc-linux-arm64-gnu": "13.4.1", "@next/swc-linux-arm64-gnu": "13.4.4",
"@next/swc-linux-arm64-musl": "13.4.1", "@next/swc-linux-arm64-musl": "13.4.4",
"@next/swc-linux-x64-gnu": "13.4.1", "@next/swc-linux-x64-gnu": "13.4.4",
"@next/swc-linux-x64-musl": "13.4.1", "@next/swc-linux-x64-musl": "13.4.4",
"@next/swc-win32-arm64-msvc": "13.4.1", "@next/swc-win32-arm64-msvc": "13.4.4",
"@next/swc-win32-ia32-msvc": "13.4.1", "@next/swc-win32-ia32-msvc": "13.4.4",
"@next/swc-win32-x64-msvc": "13.4.1" "@next/swc-win32-x64-msvc": "13.4.4"
}, },
"peerDependencies": { "peerDependencies": {
"@opentelemetry/api": "^1.1.0", "@opentelemetry/api": "^1.1.0",
"fibers": ">= 3.1.0", "fibers": ">= 3.1.0",
"node-sass": "^6.0.0 || ^7.0.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"sass": "^1.3.0" "sass": "^1.3.0"
@@ -2786,9 +2785,6 @@
"fibers": { "fibers": {
"optional": true "optional": true
}, },
"node-sass": {
"optional": true
},
"sass": { "sass": {
"optional": true "optional": true
} }
@@ -4254,9 +4250,9 @@
} }
}, },
"@next/env": { "@next/env": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.4.tgz",
"integrity": "sha512-eD6WCBMFjLFooLM19SIhSkWBHtaFrZFfg2Cxnyl3vS3DAdFRfnx5TY2RxlkuKXdIRCC0ySbtK9JXXt8qLCqzZg==" "integrity": "sha512-q/y7VZj/9YpgzDe64Zi6rY1xPizx80JjlU2BTevlajtaE3w1LqweH1gGgxou2N7hdFosXHjGrI4OUvtFXXhGLg=="
}, },
"@next/eslint-plugin-next": { "@next/eslint-plugin-next": {
"version": "13.2.4", "version": "13.2.4",
@@ -4267,57 +4263,57 @@
} }
}, },
"@next/swc-darwin-arm64": { "@next/swc-darwin-arm64": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.4.tgz",
"integrity": "sha512-eF8ARHtYfnoYtDa6xFHriUKA/Mfj/cCbmKb3NofeKhMccs65G6/loZ15a6wYCCx4rPAd6x4t1WmVYtri7EdeBg==", "integrity": "sha512-xfjgXvp4KalNUKZMHmsFxr1Ug+aGmmO6NWP0uoh4G3WFqP/mJ1xxfww0gMOeMeSq/Jyr5k7DvoZ2Pv+XOITTtw==",
"optional": true "optional": true
}, },
"@next/swc-darwin-x64": { "@next/swc-darwin-x64": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.4.tgz",
"integrity": "sha512-7cmDgF9tGWTgn5Gw+vP17miJbH4wcraMHDCOHTYWkO/VeKT73dUWG23TNRLfgtCNSPgH4V5B4uLHoZTanx9bAw==", "integrity": "sha512-ZY9Ti1hkIwJsxGus3nlubIkvYyB0gNOYxKrfsOrLEqD0I2iCX8D7w8v6QQZ2H+dDl6UT29oeEUdDUNGk4UEpfg==",
"optional": true "optional": true
}, },
"@next/swc-linux-arm64-gnu": { "@next/swc-linux-arm64-gnu": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.4.tgz",
"integrity": "sha512-qwJqmCri2ie8aTtE5gjTSr8S6O8B67KCYgVZhv9gKH44yvc/zXbAY8u23QGULsYOyh1islWE5sWfQNLOj9iryg==", "integrity": "sha512-+KZnDeMShYkpkqAvGCEDeqYTRADJXc6SY1jWXz+Uo6qWQO/Jd9CoyhTJwRSxvQA16MoYzvILkGaDqirkRNctyA==",
"optional": true "optional": true
}, },
"@next/swc-linux-arm64-musl": { "@next/swc-linux-arm64-musl": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.4.tgz",
"integrity": "sha512-qcC54tWNGDv/VVIFkazxhqH1Bnagjfs4enzELVRlUOoJPD2BGJTPI7z08pQPbbgxLtRiu8gl2mXvpB8WlOkMeA==", "integrity": "sha512-evC1twrny2XDT4uOftoubZvW3EG0zs0ZxMwEtu/dDGVRO5n5pT48S8qqEIBGBUZYu/Xx4zzpOkIxx1vpWdE+9A==",
"optional": true "optional": true
}, },
"@next/swc-linux-x64-gnu": { "@next/swc-linux-x64-gnu": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.4.tgz",
"integrity": "sha512-9TeWFlpLsBosZ+tsm/rWBaMwt5It9tPH8m3nawZqFUUrZyGRfGcI67js774vtx0k3rL9qbyY6+3pw9BCVpaYUA==", "integrity": "sha512-PX706XcCHr2FfkyhP2lpf+pX/tUvq6/ke7JYnnr0ykNdEMo+sb7cC/o91gnURh4sPYSiZJhsF2gbIqg9rciOHQ==",
"optional": true "optional": true
}, },
"@next/swc-linux-x64-musl": { "@next/swc-linux-x64-musl": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.4.tgz",
"integrity": "sha512-sNDGaWmSqTS4QRUzw61wl4mVPeSqNIr1OOjLlQTRuyInxMxtqImRqdvzDvFTlDfdeUMU/DZhWGYoHrXLlZXe6A==", "integrity": "sha512-TKUUx3Ftd95JlHV6XagEnqpT204Y+IsEa3awaYIjayn0MOGjgKZMZibqarK3B1FsMSPaieJf2FEAcu9z0yT5aA==",
"optional": true "optional": true
}, },
"@next/swc-win32-arm64-msvc": { "@next/swc-win32-arm64-msvc": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.4.tgz",
"integrity": "sha512-+CXZC7u1iXdLRudecoUYbhbsXpglYv8KFYsFxKBPn7kg+bk7eJo738wAA4jXIl8grTF2mPdmO93JOQym+BlYGA==", "integrity": "sha512-FP8AadgSq4+HPtim7WBkCMGbhr5vh9FePXiWx9+YOdjwdQocwoCK5ZVC3OW8oh3TWth6iJ0AXJ/yQ1q1cwSZ3A==",
"optional": true "optional": true
}, },
"@next/swc-win32-ia32-msvc": { "@next/swc-win32-ia32-msvc": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.4.tgz",
"integrity": "sha512-vIoXVVc7UYO68VwVMDKwJC2+HqAZQtCYiVlApyKEeIPIQpz2gpufzGxk1z3/gwrJt/kJ5CDZjlhYDCzd3hdz+g==", "integrity": "sha512-3WekVmtuA2MCdcAOrgrI+PuFiFURtSyyrN1I3UPtS0ckR2HtLqyqmS334Eulf15g1/bdwMteePdK363X/Y9JMg==",
"optional": true "optional": true
}, },
"@next/swc-win32-x64-msvc": { "@next/swc-win32-x64-msvc": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.1.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.4.tgz",
"integrity": "sha512-n8V5ImLQZibKTu10UUdI3nIeTLkliEXe628qxqW9v8My3BAH2a7H0SaCqkV2OgqFnn8sG1wxKYw9/SNJ632kSA==", "integrity": "sha512-AHRITu/CrlQ+qzoqQtEMfaTu7GHaQ6bziQln/pVWpOYC1wU+Mq6VQQFlsDtMCnDztPZtppAXdvvbNS7pcfRzlw==",
"optional": true "optional": true
}, },
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {
@@ -6034,20 +6030,20 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
}, },
"next": { "next": {
"version": "13.4.1", "version": "13.4.4",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.1.tgz", "resolved": "https://registry.npmjs.org/next/-/next-13.4.4.tgz",
"integrity": "sha512-JBw2kAIyhKDpjhEWvNVoFeIzNp9xNxg8wrthDOtMctfn3EpqGCmW0FSviNyGgOSOSn6zDaX48pmvbdf6X2W9xA==", "integrity": "sha512-C5S0ysM0Ily9McL4Jb48nOQHT1BukOWI59uC3X/xCMlYIh9rJZCv7nzG92J6e1cOBqQbKovlpgvHWFmz4eKKEA==",
"requires": { "requires": {
"@next/env": "13.4.1", "@next/env": "13.4.4",
"@next/swc-darwin-arm64": "13.4.1", "@next/swc-darwin-arm64": "13.4.4",
"@next/swc-darwin-x64": "13.4.1", "@next/swc-darwin-x64": "13.4.4",
"@next/swc-linux-arm64-gnu": "13.4.1", "@next/swc-linux-arm64-gnu": "13.4.4",
"@next/swc-linux-arm64-musl": "13.4.1", "@next/swc-linux-arm64-musl": "13.4.4",
"@next/swc-linux-x64-gnu": "13.4.1", "@next/swc-linux-x64-gnu": "13.4.4",
"@next/swc-linux-x64-musl": "13.4.1", "@next/swc-linux-x64-musl": "13.4.4",
"@next/swc-win32-arm64-msvc": "13.4.1", "@next/swc-win32-arm64-msvc": "13.4.4",
"@next/swc-win32-ia32-msvc": "13.4.1", "@next/swc-win32-ia32-msvc": "13.4.4",
"@next/swc-win32-x64-msvc": "13.4.1", "@next/swc-win32-x64-msvc": "13.4.4",
"@swc/helpers": "0.5.1", "@swc/helpers": "0.5.1",
"busboy": "1.6.0", "busboy": "1.6.0",
"caniuse-lite": "^1.0.30001406", "caniuse-lite": "^1.0.30001406",

View File

@@ -19,7 +19,7 @@
"eslint-config-next": "13.2.4", "eslint-config-next": "13.2.4",
"formik": "^2.2.9", "formik": "^2.2.9",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"next": "^13.2.4", "next": "^13.4.4",
"postcss": "^8.4.23", "postcss": "^8.4.23",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",

View File

@@ -8,7 +8,7 @@ import { ApiKeyModal } from "@/components/openai/ApiKeyModal";
import { buildUrl } from "@/lib/utilsSS"; import { buildUrl } from "@/lib/utilsSS";
import { Connector, User } from "@/lib/types"; import { Connector, User } from "@/lib/types";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { SearchType } from "@/components/search/SearchTypeSelector"; import { SearchType } from "@/lib/search/interfaces";
export default async function Home() { export default async function Home() {
const tasks = [ const tasks = [
@@ -35,13 +35,13 @@ export default async function Home() {
// needs to be done in a non-client side component due to nextjs // needs to be done in a non-client side component due to nextjs
const storedSearchType = cookies().get("searchType")?.value as const storedSearchType = cookies().get("searchType")?.value as
| keyof typeof SearchType | string
| undefined; | undefined;
let searchTypeDefault: SearchType = let searchTypeDefault: SearchType =
storedSearchType !== undefined && storedSearchType !== undefined &&
SearchType.hasOwnProperty(storedSearchType) SearchType.hasOwnProperty(storedSearchType)
? SearchType[storedSearchType] ? (storedSearchType as SearchType)
: SearchType.SEMANTIC; // default to semantic search : SearchType.AUTOMATIC; // default to automatic
return ( return (
<> <>

View File

@@ -9,6 +9,8 @@ import {
LinkBreak, LinkBreak,
Link, Link,
Plug, Plug,
Bird,
Brain,
} from "@phosphor-icons/react"; } from "@phosphor-icons/react";
import { SiConfluence, SiGithub, SiGoogledrive, SiSlack } from "react-icons/si"; import { SiConfluence, SiGithub, SiGoogledrive, SiSlack } from "react-icons/si";
import { FaFile, FaGlobe } from "react-icons/fa"; import { FaFile, FaGlobe } from "react-icons/fa";
@@ -117,3 +119,10 @@ export const InfoIcon = ({
}: IconProps) => { }: IconProps) => {
return <Info size={size} className={className} />; return <Info size={size} className={className} />;
}; };
export const BrainIcon = ({
size = "16",
className = defaultTailwindCSS,
}: IconProps) => {
return <Brain size={size} className={className} />;
};

View File

@@ -35,7 +35,7 @@ export function SourceSelector({
}; };
return ( return (
<div className="bg-gray-900 px-6"> <div className="bg-gray-900">
<div className="flex mb-2 pb-1 pl-2 border-b border-gray-800 mx-2"> <div className="flex mb-2 pb-1 pl-2 border-b border-gray-800 mx-2">
<h2 className="font-bold my-auto">Filters</h2> <h2 className="font-bold my-auto">Filters</h2>
<Funnel className="my-auto ml-2" size="20" /> <Funnel className="my-auto ml-2" size="20" />

View File

@@ -2,15 +2,19 @@ import React, { useState, KeyboardEvent, ChangeEvent } from "react";
import { MagnifyingGlass } from "@phosphor-icons/react"; import { MagnifyingGlass } from "@phosphor-icons/react";
interface SearchBarProps { interface SearchBarProps {
onSearch: (searchTerm: string) => void; query: string;
setQuery: (query: string) => void;
onSearch: () => void;
} }
export const SearchBar: React.FC<SearchBarProps> = ({ onSearch }) => { export const SearchBar: React.FC<SearchBarProps> = ({
const [searchTerm, setSearchTerm] = useState<string>(""); query,
setQuery,
onSearch,
}) => {
const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => { const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
const target = event.target; const target = event.target;
setSearchTerm(target.value); setQuery(target.value);
// Resize the textarea to fit the content // Resize the textarea to fit the content
target.style.height = "24px"; target.style.height = "24px";
@@ -20,7 +24,7 @@ export const SearchBar: React.FC<SearchBarProps> = ({ onSearch }) => {
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => { const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
if (event.key === "Enter" && !event.shiftKey) { if (event.key === "Enter" && !event.shiftKey) {
onSearch(searchTerm); onSearch();
event.preventDefault(); event.preventDefault();
} }
}; };
@@ -34,7 +38,7 @@ export const SearchBar: React.FC<SearchBarProps> = ({ onSearch }) => {
role="textarea" role="textarea"
aria-multiline aria-multiline
placeholder="Search..." placeholder="Search..."
value={searchTerm} value={query}
onChange={handleChange} onChange={handleChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
suppressContentEditableWarning={true} suppressContentEditableWarning={true}

View File

@@ -0,0 +1,142 @@
import {
FlowType,
SearchDefaultOverrides,
SearchRequestOverrides,
SearchResponse,
SearchType,
} from "@/lib/search/interfaces";
import { BrainIcon } from "../icons/icons";
const CLICKABLE_CLASS_NAME = "text-blue-400 cursor-pointer";
const NUM_DOCUMENTS_FED_TO_GPT = 5;
interface Props {
isFetching: boolean;
searchResponse: SearchResponse | null;
selectedSearchType: SearchType;
setSelectedSearchType: (searchType: SearchType) => void;
defaultOverrides: SearchDefaultOverrides;
restartSearch: (overrides?: SearchRequestOverrides) => void;
forceQADisplay: () => void;
setOffset: (offset: number) => void;
}
const getAssistantMessage = ({
isFetching,
searchResponse,
selectedSearchType,
setSelectedSearchType,
defaultOverrides,
restartSearch,
forceQADisplay,
setOffset,
}: Props): string | JSX.Element | null => {
if (!searchResponse || !searchResponse.suggestedFlowType) {
return null;
}
if (
searchResponse.suggestedFlowType === FlowType.SEARCH &&
!defaultOverrides.forceDisplayQA &&
!isFetching &&
searchResponse.answer
) {
return (
<div>
This doesn&apos;t seem like a question for a Generative AI. Do you still
want to have{" "}
<span className={CLICKABLE_CLASS_NAME} onClick={forceQADisplay}>
GPT give a response?
</span>
</div>
);
}
console.log(searchResponse.suggestedSearchType);
console.log(selectedSearchType);
if (
selectedSearchType !== SearchType.AUTOMATIC &&
searchResponse.suggestedSearchType !== selectedSearchType
) {
if (searchResponse.suggestedSearchType === SearchType.SEMANTIC) {
return (
<div>
Your query looks more like natural language, Semantic Search may yield
better results. Would you like to{" "}
<span
className={CLICKABLE_CLASS_NAME}
onClick={() => {
setSelectedSearchType(SearchType.SEMANTIC);
restartSearch({ searchType: SearchType.SEMANTIC });
}}
>
try AI search?
</span>
</div>
);
}
return (
<div>
Your query seems to be a better fit for keyword search. Would you like
to{" "}
<span
className={CLICKABLE_CLASS_NAME}
onClick={() => {
setSelectedSearchType(SearchType.KEYWORD);
restartSearch({ searchType: SearchType.KEYWORD });
}}
>
try Keyword search?
</span>
</div>
);
}
if (
(searchResponse.suggestedFlowType === FlowType.QUESTION_ANSWER ||
defaultOverrides.forceDisplayQA) &&
!isFetching &&
searchResponse.answer === ""
) {
return (
<div>
GPT was unable to find an answer in the most relevant{" "}
<b>{` ${(defaultOverrides.offset + 1) * NUM_DOCUMENTS_FED_TO_GPT} `}</b>{" "}
documents. Do you want to{" "}
<span
className={CLICKABLE_CLASS_NAME}
onClick={() => {
const newOffset = defaultOverrides.offset + 1;
setOffset(newOffset);
restartSearch({
offset: newOffset,
});
}}
>
keep searching?
</span>
</div>
);
}
return null;
};
export const SearchHelper: React.FC<Props> = (props) => {
const message = getAssistantMessage(props);
if (!message) {
return null;
}
return (
<div className="border border-gray-800 rounded p-3 text-sm">
<div className="flex">
<BrainIcon size="20" />
<b className="ml-2">AI Assistant</b>
</div>
<p className="mt-1 text-gray-300">{message}</p>
</div>
);
};

View File

@@ -6,8 +6,9 @@ import {
DanswerDocument, DanswerDocument,
SearchResponse, SearchResponse,
Quote, Quote,
FlowType,
SearchDefaultOverrides,
} from "@/lib/search/interfaces"; } from "@/lib/search/interfaces";
import { SearchType } from "./SearchTypeSelector";
const removeDuplicateDocs = (documents: DanswerDocument[]) => { const removeDuplicateDocs = (documents: DanswerDocument[]) => {
const seen = new Set<string>(); const seen = new Set<string>();
@@ -27,11 +28,13 @@ const removeDuplicateDocs = (documents: DanswerDocument[]) => {
interface SearchResultsDisplayProps { interface SearchResultsDisplayProps {
searchResponse: SearchResponse | null; searchResponse: SearchResponse | null;
isFetching: boolean; isFetching: boolean;
defaultOverrides: SearchDefaultOverrides;
} }
export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({ export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
searchResponse, searchResponse,
isFetching, isFetching,
defaultOverrides,
}) => { }) => {
if (!searchResponse) { if (!searchResponse) {
return null; return null;
@@ -66,58 +69,58 @@ export const SearchResultsDisplay: React.FC<SearchResultsDisplayProps> = ({
return ( return (
<> <>
{answer && ( {answer &&
<div className="h-56"> (searchResponse.suggestedFlowType !== FlowType.SEARCH ||
<div className="p-4 border-2 rounded-md border-gray-700"> defaultOverrides.forceDisplayQA) && (
<div className="flex mb-1"> <div className="min-h-[14rem]">
<h2 className="text font-bold my-auto">AI Answer</h2> <div className="p-4 border-2 rounded-md border-gray-700">
</div> <div className="flex mb-1">
<p className="mb-4">{answer}</p> <h2 className="text font-bold my-auto">AI Answer</h2>
</div>
<p className="mb-4">{answer}</p>
{quotes !== null && ( {quotes !== null && (
<> <>
<h2 className="text-sm font-bold mb-2">Sources</h2> <h2 className="text-sm font-bold mb-2">Sources</h2>
{isFetching && dedupedQuotes.length === 0 ? ( {isFetching && dedupedQuotes.length === 0 ? (
<LoadingAnimation text="Finding quotes" size="text-sm" /> <LoadingAnimation text="Finding quotes" size="text-sm" />
) : ( ) : (
<div className="flex"> <div className="flex">
{dedupedQuotes.map((quoteInfo) => ( {dedupedQuotes.map((quoteInfo) => (
<a <a
key={quoteInfo.document_id} key={quoteInfo.document_id}
className="p-2 ml-1 border border-gray-800 rounded-lg text-sm flex max-w-[280px] hover:bg-gray-800" className="p-2 ml-1 border border-gray-800 rounded-lg text-sm flex max-w-[280px] hover:bg-gray-800"
href={quoteInfo.link} href={quoteInfo.link}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
{getSourceIcon(quoteInfo.source_type, "20")} {getSourceIcon(quoteInfo.source_type, "20")}
<p className="truncate break-all ml-2"> <p className="truncate break-all ml-2">
{quoteInfo.semantic_identifier || {quoteInfo.semantic_identifier ||
quoteInfo.document_id} quoteInfo.document_id}
</p> </p>
</a> </a>
))} ))}
</div> </div>
)} )}
</> </>
)} )}
</div>
</div>
)}
{!answer &&
!isFetching &&
searchResponse.searchType === SearchType.SEMANTIC && (
<div className="flex">
<InfoIcon
size="20"
className="text-red-500 my-auto flex flex-shrink-0"
/>
<div className="text-red-500 text-xs my-auto ml-1">
GPT hurt itself in its confusion :(
</div> </div>
</div> </div>
)} )}
{(answer === null || answer === undefined) && !isFetching && (
<div className="flex">
<InfoIcon
size="20"
className="text-red-500 my-auto flex flex-shrink-0"
/>
<div className="text-red-500 text-xs my-auto ml-1">
GPT hurt itself in its confusion :(
</div>
</div>
)}
{documents && documents.length > 0 && ( {documents && documents.length > 0 && (
<div className="mt-4"> <div className="mt-4">
<div className="font-bold border-b mb-4 pb-1 border-gray-800"> <div className="font-bold border-b mb-4 pb-1 border-gray-800">

View File

@@ -5,15 +5,25 @@ import { SearchBar } from "./SearchBar";
import { SearchResultsDisplay } from "./SearchResultsDisplay"; import { SearchResultsDisplay } from "./SearchResultsDisplay";
import { SourceSelector } from "./Filters"; import { SourceSelector } from "./Filters";
import { Connector } from "@/lib/types"; import { Connector } from "@/lib/types";
import { SearchType, SearchTypeSelector } from "./SearchTypeSelector"; import { SearchTypeSelector } from "./SearchTypeSelector";
import { import {
DanswerDocument, DanswerDocument,
Quote, Quote,
SearchResponse, SearchResponse,
Source, Source,
FlowType,
SearchType,
SearchDefaultOverrides,
SearchRequestOverrides,
} from "@/lib/search/interfaces"; } from "@/lib/search/interfaces";
import { aiSearchRequestStreamed } from "@/lib/search/ai"; import { searchRequestStreamed } from "@/lib/search/streaming";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { SearchHelper } from "./SearchHelper";
const SEARCH_DEFAULT_OVERRIDES_START: SearchDefaultOverrides = {
forceDisplayQA: false,
offset: 0,
};
interface SearchSectionProps { interface SearchSectionProps {
connectors: Connector<any>[]; connectors: Connector<any>[];
@@ -24,6 +34,9 @@ export const SearchSection: React.FC<SearchSectionProps> = ({
connectors, connectors,
defaultSearchType, defaultSearchType,
}) => { }) => {
// Search Bar
const [query, setQuery] = useState<string>("");
// Search // Search
const [searchResponse, setSearchResponse] = useState<SearchResponse | null>( const [searchResponse, setSearchResponse] = useState<SearchResponse | null>(
null null
@@ -37,12 +50,17 @@ export const SearchSection: React.FC<SearchSectionProps> = ({
const [selectedSearchType, setSelectedSearchType] = const [selectedSearchType, setSelectedSearchType] =
useState<SearchType>(defaultSearchType); useState<SearchType>(defaultSearchType);
// helpers // Overrides for default behavior that only last a single query
const [defaultOverrides, setDefaultOverrides] =
useState<SearchDefaultOverrides>(SEARCH_DEFAULT_OVERRIDES_START);
// Helpers
const initialSearchResponse: SearchResponse = { const initialSearchResponse: SearchResponse = {
answer: null, answer: null,
quotes: null, quotes: null,
documents: null, documents: null,
searchType: selectedSearchType, suggestedSearchType: null,
suggestedFlowType: null,
}; };
const updateCurrentAnswer = (answer: string) => const updateCurrentAnswer = (answer: string) =>
setSearchResponse((prevState) => ({ setSearchResponse((prevState) => ({
@@ -59,10 +77,42 @@ export const SearchSection: React.FC<SearchSectionProps> = ({
...(prevState || initialSearchResponse), ...(prevState || initialSearchResponse),
documents, documents,
})); }));
const updateSuggestedSearchType = (suggestedSearchType: SearchType) =>
setSearchResponse((prevState) => ({
...(prevState || initialSearchResponse),
suggestedSearchType,
}));
const updateSuggestedFlowType = (suggestedFlowType: FlowType) =>
setSearchResponse((prevState) => ({
...(prevState || initialSearchResponse),
suggestedFlowType,
}));
const onSearch = async ({
searchType,
offset,
}: SearchRequestOverrides = {}) => {
setIsFetching(true);
setSearchResponse(initialSearchResponse);
await searchRequestStreamed({
query,
sources,
updateCurrentAnswer,
updateQuotes,
updateDocs,
updateSuggestedSearchType,
updateSuggestedFlowType,
selectedSearchType: searchType ?? selectedSearchType,
offset: offset ?? defaultOverrides.offset,
});
setIsFetching(false);
};
return ( return (
<div className="relative max-w-[1500px] mx-auto"> <div className="relative max-w-[2000px] xl:max-w-[1400px] mx-auto">
<div className="absolute left-0 ml-24 hidden 2xl:block"> <div className="absolute left-0 hidden 2xl:block w-64">
{connectors.length > 0 && ( {connectors.length > 0 && (
<SourceSelector <SourceSelector
selectedSources={sources} selectedSources={sources}
@@ -70,6 +120,29 @@ export const SearchSection: React.FC<SearchSectionProps> = ({
existingSources={connectors.map((connector) => connector.source)} existingSources={connectors.map((connector) => connector.source)}
/> />
)} )}
<div className="mt-10">
<SearchHelper
isFetching={isFetching}
searchResponse={searchResponse}
selectedSearchType={selectedSearchType}
setSelectedSearchType={setSelectedSearchType}
defaultOverrides={defaultOverrides}
restartSearch={onSearch}
forceQADisplay={() =>
setDefaultOverrides((prevState) => ({
...(prevState || SEARCH_DEFAULT_OVERRIDES_START),
forceDisplayQA: true,
}))
}
setOffset={(offset) => {
setDefaultOverrides((prevState) => ({
...(prevState || SEARCH_DEFAULT_OVERRIDES_START),
offset,
}));
}}
/>
</div>
</div> </div>
<div className="w-[800px] mx-auto"> <div className="w-[800px] mx-auto">
<SearchTypeSelector <SearchTypeSelector
@@ -81,25 +154,11 @@ export const SearchSection: React.FC<SearchSectionProps> = ({
/> />
<SearchBar <SearchBar
onSearch={async (query) => { query={query}
setIsFetching(true); setQuery={setQuery}
setSearchResponse({ onSearch={async () => {
answer: null, setDefaultOverrides(SEARCH_DEFAULT_OVERRIDES_START);
quotes: null, await onSearch({ offset: 0 });
documents: null,
searchType: selectedSearchType,
});
await aiSearchRequestStreamed({
query,
sources,
updateCurrentAnswer,
updateQuotes,
updateDocs,
searchType: selectedSearchType,
});
setIsFetching(false);
}} }}
/> />
@@ -107,6 +166,7 @@ export const SearchSection: React.FC<SearchSectionProps> = ({
<SearchResultsDisplay <SearchResultsDisplay
searchResponse={searchResponse} searchResponse={searchResponse}
isFetching={isFetching} isFetching={isFetching}
defaultOverrides={defaultOverrides}
/> />
</div> </div>
</div> </div>

View File

@@ -1,11 +1,8 @@
import { SearchType } from "@/lib/search/interfaces";
const defaultStyle = const defaultStyle =
"py-1 px-2 border rounded border-gray-700 cursor-pointer font-bold "; "py-1 px-2 border rounded border-gray-700 cursor-pointer font-bold ";
export enum SearchType {
SEMANTIC = "SEMANTIC",
KEYWORD = "KEYWORD",
}
interface Props { interface Props {
selectedSearchType: SearchType; selectedSearchType: SearchType;
setSelectedSearchType: (searchType: SearchType) => void; setSelectedSearchType: (searchType: SearchType) => void;
@@ -20,6 +17,19 @@ export const SearchTypeSelector: React.FC<Props> = ({
<div <div
className={ className={
defaultStyle + defaultStyle +
(selectedSearchType === SearchType.AUTOMATIC
? "bg-blue-500"
: "bg-gray-800 hover:bg-gray-600")
}
onClick={() => setSelectedSearchType(SearchType.AUTOMATIC)}
>
Auto
</div>
<div
className={
defaultStyle +
"ml-2 " +
(selectedSearchType === SearchType.SEMANTIC (selectedSearchType === SearchType.SEMANTIC
? "bg-blue-500" ? "bg-blue-500"
: "bg-gray-800 hover:bg-gray-600") : "bg-gray-800 hover:bg-gray-600")

View File

@@ -1,6 +1,17 @@
import { SearchType } from "@/components/search/SearchTypeSelector";
import { ValidSources } from "../types"; import { ValidSources } from "../types";
export const FlowType = {
SEARCH: "search",
QUESTION_ANSWER: "question-answer",
};
export type FlowType = (typeof FlowType)[keyof typeof FlowType];
export const SearchType = {
SEMANTIC: "semantic",
KEYWORD: "keyword",
AUTOMATIC: "automatic",
};
export type SearchType = (typeof SearchType)[keyof typeof SearchType];
export interface Quote { export interface Quote {
document_id: string; document_id: string;
link: string; link: string;
@@ -18,7 +29,8 @@ export interface DanswerDocument {
} }
export interface SearchResponse { export interface SearchResponse {
searchType: SearchType; suggestedSearchType: SearchType | null;
suggestedFlowType: FlowType | null;
answer: string | null; answer: string | null;
quotes: Record<string, Quote> | null; quotes: Record<string, Quote> | null;
documents: DanswerDocument[] | null; documents: DanswerDocument[] | null;
@@ -29,11 +41,24 @@ export interface Source {
internalName: ValidSources; internalName: ValidSources;
} }
export interface SearchDefaultOverrides {
forceDisplayQA: boolean;
offset: number;
}
export interface SearchRequestArgs { export interface SearchRequestArgs {
query: string; query: string;
sources: Source[]; sources: Source[];
updateCurrentAnswer: (val: string) => void; updateCurrentAnswer: (val: string) => void;
updateQuotes: (quotes: Record<string, Quote>) => void; updateQuotes: (quotes: Record<string, Quote>) => void;
updateDocs: (documents: DanswerDocument[]) => void; updateDocs: (documents: DanswerDocument[]) => void;
searchType: SearchType; updateSuggestedSearchType: (searchType: SearchType) => void;
updateSuggestedFlowType: (flowType: FlowType) => void;
selectedSearchType: SearchType | null;
offset: number | null;
}
export interface SearchRequestOverrides {
searchType?: SearchType;
offset?: number;
} }

View File

@@ -1,5 +1,9 @@
import { SearchType } from "@/components/search/SearchTypeSelector"; import {
import { DanswerDocument, Quote, SearchRequestArgs } from "./interfaces"; DanswerDocument,
Quote,
SearchRequestArgs,
SearchType,
} from "./interfaces";
const processSingleChunk = ( const processSingleChunk = (
chunk: string, chunk: string,
@@ -45,14 +49,22 @@ const processRawChunkString = (
return [parsedChunkSections, currPartialChunk]; return [parsedChunkSections, currPartialChunk];
}; };
export const aiSearchRequestStreamed = async ({ export const searchRequestStreamed = async ({
query, query,
sources, sources,
updateCurrentAnswer, updateCurrentAnswer,
updateQuotes, updateQuotes,
updateDocs, updateDocs,
searchType, updateSuggestedSearchType,
updateSuggestedFlowType,
selectedSearchType,
offset,
}: SearchRequestArgs) => { }: SearchRequestArgs) => {
let useKeyword = null;
if (selectedSearchType !== SearchType.AUTOMATIC) {
useKeyword = selectedSearchType === SearchType.KEYWORD ? true : false;
}
let answer = ""; let answer = "";
let quotes: Record<string, Quote> | null = null; let quotes: Record<string, Quote> | null = null;
let relevantDocuments: DanswerDocument[] | null = null; let relevantDocuments: DanswerDocument[] | null = null;
@@ -62,7 +74,7 @@ export const aiSearchRequestStreamed = async ({
body: JSON.stringify({ body: JSON.stringify({
query, query,
collection: "danswer_index", collection: "danswer_index",
use_keyword: searchType === SearchType.KEYWORD, use_keyword: useKeyword,
...(sources.length > 0 ...(sources.length > 0
? { ? {
filters: [ filters: [
@@ -72,6 +84,7 @@ export const aiSearchRequestStreamed = async ({
], ],
} }
: {}), : {}),
offset: offset,
}), }),
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@@ -113,12 +126,15 @@ export const aiSearchRequestStreamed = async ({
// we're now looking for quotes // we're now looking for quotes
updateQuotes({}); updateQuotes({});
if ( if (
answer &&
!answer.endsWith(".") && !answer.endsWith(".") &&
!answer.endsWith("?") && !answer.endsWith("?") &&
!answer.endsWith("!") !answer.endsWith("!")
) { ) {
answer += "."; answer += ".";
updateCurrentAnswer(answer); updateCurrentAnswer(answer);
} else {
updateCurrentAnswer("");
} }
} else { } else {
if (Object.hasOwn(chunk, "top_documents")) { if (Object.hasOwn(chunk, "top_documents")) {
@@ -129,6 +145,13 @@ export const aiSearchRequestStreamed = async ({
); );
updateDocs(relevantDocuments); updateDocs(relevantDocuments);
} }
if (chunk.predicted_flow) {
updateSuggestedFlowType(chunk.predicted_flow);
}
if (chunk.predicted_search) {
updateSuggestedSearchType(chunk.predicted_search);
}
} else { } else {
quotes = chunk as Record<string, Quote>; quotes = chunk as Record<string, Quote>;
updateQuotes(quotes); updateQuotes(quotes);