{"version":3,"file":"index-f76c3bdb.js","sources":["../../../frontend/src/assets/github.svg","../../../frontend/src/pages/layout/Layout.tsx","../../../frontend/src/pages/NoPage.tsx","../../../frontend/src/api/api.ts","../../../frontend/src/api/models.ts","../../../frontend/src/components/Answer/AnswerParser.tsx","../../../frontend/src/components/Answer/AnswerIcon.tsx","../../../frontend/src/components/Answer/Answer.tsx","../../../frontend/src/components/Answer/AnswerLoading.tsx","../../../frontend/src/components/Answer/AnswerError.tsx","../../../frontend/src/components/QuestionInput/QuestionInput.tsx","../../../frontend/src/components/Example/Example.tsx","../../../frontend/src/components/Example/ExampleList.tsx","../../../frontend/src/components/SupportingContent/SupportingContentParser.ts","../../../frontend/src/components/SupportingContent/SupportingContent.tsx","../../../frontend/src/components/AnalysisPanel/AnalysisPanelTabs.tsx","../../../frontend/src/components/AnalysisPanel/AnalysisPanel.tsx","../../../frontend/src/components/SettingsButton/SettingsButton.tsx","../../../frontend/src/pages/oneshot/OneShot.tsx","../../../frontend/src/components/UserChatMessage/UserChatMessage.tsx","../../../frontend/src/components/ClearChatButton/ClearChatButton.tsx","../../../frontend/src/pages/chat/Chat.tsx","../../../frontend/src/pages/askbing/AskBing.tsx","../../../frontend/src/index.tsx"],"sourcesContent":["export default \"__VITE_ASSET__4e6ad5ae__\"","import { Outlet, NavLink, Link } from \"react-router-dom\";\r\n\r\nimport github from \"../../assets/github.svg\";\r\n\r\nimport styles from \"./Layout.module.css\";\r\n\r\nconst Layout = () => {\r\n return (\r\n
\r\n
\r\n
\r\n \r\n

GPT + Enterprise data | Sample

\r\n \r\n \r\n

Azure OpenAI + Cognitive Search

\r\n
\r\n
\r\n\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default Layout;\r\n","const NoPage = () => {\r\n return

404

;\r\n};\r\n\r\nexport default NoPage;\r\n","import { AskRequest, AskResponse, ChatRequest, ReadRequest, AskBingRequest, AskBingResponse } from \"./models\";\r\nimport {SpeechConfig, AudioConfig, SpeechSynthesizer, ResultReason} from \"microsoft-cognitiveservices-speech-sdk\"\r\n\r\n\r\nexport async function askBing(options: AskBingRequest): Promise {\r\n const response = await fetch(\"/askBing\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\"\r\n },\r\n body: JSON.stringify({\r\n question: options.question,\r\n approach: options.approach,\r\n overrides: {\r\n semantic_ranker: options.overrides?.semanticRanker,\r\n semantic_captions: options.overrides?.semanticCaptions,\r\n top: options.overrides?.top,\r\n temperature: options.overrides?.temperature,\r\n prompt_template: options.overrides?.promptTemplate,\r\n prompt_template_prefix: options.overrides?.promptTemplatePrefix,\r\n prompt_template_suffix: options.overrides?.promptTemplateSuffix,\r\n exclude_category: options.overrides?.excludeCategory\r\n }\r\n })\r\n });\r\n\r\n const parsedResponse: AskBingResponse = await response.json();\r\n if (response.status > 299 || !response.ok) {\r\n throw Error(parsedResponse.error || \"Unknown error\");\r\n }\r\n\r\n return parsedResponse;\r\n}\r\n\r\nexport async function askApi(options: AskRequest): Promise {\r\n const response = await fetch(\"/ask\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\"\r\n },\r\n body: JSON.stringify({\r\n question: options.question,\r\n approach: options.approach,\r\n overrides: {\r\n semantic_ranker: options.overrides?.semanticRanker,\r\n semantic_captions: options.overrides?.semanticCaptions,\r\n top: options.overrides?.top,\r\n temperature: options.overrides?.temperature,\r\n prompt_template: options.overrides?.promptTemplate,\r\n prompt_template_prefix: options.overrides?.promptTemplatePrefix,\r\n prompt_template_suffix: options.overrides?.promptTemplateSuffix,\r\n exclude_category: options.overrides?.excludeCategory\r\n }\r\n })\r\n });\r\n\r\n const parsedResponse: AskResponse = await response.json();\r\n if (response.status > 299 || !response.ok) {\r\n throw Error(parsedResponse.error || \"Unknown error\");\r\n }\r\n\r\n return parsedResponse;\r\n}\r\n\r\nexport async function chatApi(options: ChatRequest): Promise {\r\n const response = await fetch(\"/chat\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\"\r\n },\r\n body: JSON.stringify({\r\n history: options.history,\r\n approach: options.approach,\r\n overrides: {\r\n semantic_ranker: options.overrides?.semanticRanker,\r\n semantic_captions: options.overrides?.semanticCaptions,\r\n top: options.overrides?.top,\r\n temperature: options.overrides?.temperature,\r\n prompt_template: options.overrides?.promptTemplate,\r\n prompt_template_prefix: options.overrides?.promptTemplatePrefix,\r\n prompt_template_suffix: options.overrides?.promptTemplateSuffix,\r\n exclude_category: options.overrides?.excludeCategory,\r\n suggest_followup_questions: options.overrides?.suggestFollowupQuestions\r\n }\r\n })\r\n });\r\n\r\n const parsedResponse: AskResponse = await response.json();\r\n if (response.status > 299 || !response.ok) {\r\n throw Error(parsedResponse.error || \"Unknown error\");\r\n }\r\n\r\n return parsedResponse;\r\n}\r\n\r\nexport async function readApi(options: ReadRequest): Promise{\r\n var speechConfig = SpeechConfig.fromSubscription('','southeastasia');\r\n const audioConfig = AudioConfig.fromDefaultSpeakerOutput();\r\n // The language of the voice that speaks.\r\n speechConfig.speechSynthesisVoiceName = \"zh-CN-YunxiNeural\"; \r\n const synthesizer = new SpeechSynthesizer(speechConfig, audioConfig);\r\n const text = options.answer;\r\n const modified_text = text.replace(/\\[[^\\]]*\\]/g, \"\"); \r\n console.log(options.answer);\r\n synthesizer.speakTextAsync(modified_text,\r\n function (result) {\r\n if (result.reason === ResultReason.SynthesizingAudioCompleted) {\r\n console.log(\"synthesis finished.\");\r\n } else {\r\n console.error(\"Speech synthesis canceled, \" + result.errorDetails +\r\n \"\\nDid you set the speech resource key and region values?\");\r\n }\r\n synthesizer.close();\r\n },\r\n function (err) {\r\n console.trace(\"err - \" + err);\r\n synthesizer.close();\r\n });\r\n\r\n}\r\nexport function getCitationFilePath(citation: string): string {\r\n return `/content/${citation}`;\r\n}\r\n","export const enum Approaches {\r\n RetrieveThenRead = \"rtr\",\r\n ReadRetrieveRead = \"rrr\",\r\n ReadDecomposeAsk = \"rda\"\r\n}\r\n\r\nexport const enum CustomApproaches {\r\n BingSearch = \"bing\"\r\n}\r\n\r\nexport type AskRequestOverrides = {\r\n semanticRanker?: boolean;\r\n semanticCaptions?: boolean;\r\n excludeCategory?: string;\r\n top?: number;\r\n temperature?: number;\r\n promptTemplate?: string;\r\n promptTemplatePrefix?: string;\r\n promptTemplateSuffix?: string;\r\n suggestFollowupQuestions?: boolean;\r\n};\r\n\r\nexport type AskRequest = {\r\n question: string;\r\n approach: Approaches;\r\n overrides?: AskRequestOverrides;\r\n};\r\n\r\nexport type AskResponse = {\r\n answer: string;\r\n thoughts: string | null;\r\n data_points: string[];\r\n error?: string;\r\n};\r\n\r\nexport type AskBingRequest = {\r\n question: string;\r\n approach: CustomApproaches;\r\n overrides?: AskRequestOverrides;\r\n};\r\n\r\nexport type AskBingResponse = {\r\n answer: string;\r\n thoughts: string | null;\r\n data_points: string[];\r\n error?: string;\r\n};\r\n\r\n\r\nexport type ChatTurn = {\r\n user: string;\r\n bot?: string;\r\n};\r\n\r\nexport type ChatRequest = {\r\n history: ChatTurn[];\r\n approach: Approaches;\r\n overrides?: AskRequestOverrides;\r\n};\r\n\r\nexport type ReadRequest = {\r\n answer: string;\r\n}\r\n","import { renderToStaticMarkup } from \"react-dom/server\";\r\nimport { getCitationFilePath } from \"../../api\";\r\n\r\ntype HtmlParsedAnswer = {\r\n answerHtml: string;\r\n citations: Citation[];\r\n followupQuestions: string[];\r\n};\r\n\r\ntype Citation = {\r\n id: number;\r\n name: string;\r\n path: string;\r\n};\r\n\r\nexport function parseAnswerToHtml(answer: string, onCitationClicked: (citationFilePath: string) => void): HtmlParsedAnswer {\r\n const citations: Citation[] = [];\r\n const followupQuestions: string[] = [];\r\n\r\n // Extract any follow-up questions that might be in the answer\r\n let parsedAnswer = answer.replace(/<<([^>>]+)>>/g, (match, content) => {\r\n followupQuestions.push(content);\r\n return \"\";\r\n });\r\n\r\n // trim any whitespace from the end of the answer after removing follow-up questions\r\n parsedAnswer = parsedAnswer.trim();\r\n\r\n // find information in string like '[info1.txt](http://www.example.com/info1.txt): info1' and extract info1.txt and http://www.example.com/info1.txt to be used as a link\r\n // parsedAnswer = parsedAnswer.replace(/\\[([^\\]]+)\\]\\(([^\\)]+)\\)/g, (match, content, url) => {\r\n // const path = getCitationFilePath(content);\r\n // return renderToStaticMarkup(\r\n // onCitationClicked(path)}>\r\n // {content}\r\n // \r\n // );\r\n // });\r\n\r\n\r\n // const parts = parsedAnswer.split(/\\[([^\\]]+)\\]/g);\r\n const parts = parsedAnswer.split(/\\[([^\\]]+)\\]+\\(([^\\)]+)\\)/g);\r\n // const part_paths = parsedAnswer.split(/\\(([^\\)]+)\\)/g);\r\n\r\n console.log(parts);\r\n\r\n let citation_map = parsedAnswer.match(/\\[([^\\]]+)\\]+\\(([^\\)]+)\\)/g) ;\r\n console.log(citation_map);\r\n\r\n citation_map ? citation_map.map((citation, index) => {\r\n const name = citation.split(\"]\")[0].replace(\"[\", \"\");\r\n const path = citation.split(\"]\")[1].replace(\"(\", \"\").replace(\")\", \"\");\r\n console.log(name);\r\n console.log(path);\r\n citations.push({\r\n id: index,\r\n name: name,\r\n path: path\r\n });\r\n }) : [];\r\n\r\n const fragments: string[] = parts.map((part, index) => {\r\n if (index % 3 === 0) {\r\n return part;\r\n } else if(index % 3 == 1){\r\n // let citationIndex: number;\r\n let cite = citations.find((citation) => citation.name == part);\r\n\r\n let citationIndex = cite? cite.id : -1;\r\n\r\n if (citationIndex !== -1) {\r\n citationIndex = cite ? cite.id + 1 : -1;\r\n } else {\r\n // citations.push(part);\r\n citationIndex = citations.length;\r\n }\r\n\r\n // console.log(parts);\r\n\r\n const path = getCitationFilePath(part);\r\n\r\n return renderToStaticMarkup(\r\n onCitationClicked(path)}>\r\n {citationIndex}\r\n \r\n );\r\n } else{\r\n return \"\";\r\n }\r\n });\r\n\r\n return {\r\n answerHtml: fragments.join(\"\"),\r\n citations,\r\n followupQuestions\r\n };\r\n}\r\n","import { Sparkle28Filled } from \"@fluentui/react-icons\";\r\n\r\nexport const AnswerIcon = () => {\r\n return ;\r\n};\r\n","import { useMemo } from \"react\";\r\nimport { Stack, IconButton } from \"@fluentui/react\";\r\nimport DOMPurify from \"dompurify\";\r\n\r\nimport styles from \"./Answer.module.css\";\r\n\r\nimport { AskResponse, getCitationFilePath } from \"../../api\";\r\nimport { parseAnswerToHtml } from \"./AnswerParser\";\r\nimport { AnswerIcon } from \"./AnswerIcon\";\r\n\r\ninterface Props {\r\n answer: AskResponse;\r\n isSelected?: boolean;\r\n onCitationClicked: (filePath: string) => void;\r\n onThoughtProcessClicked: () => void;\r\n onSupportingContentClicked: () => void;\r\n onFollowupQuestionClicked?: (question: string) => void;\r\n onReadAnswerClicked: () => void;\r\n showFollowupQuestions?: boolean;\r\n}\r\n\r\nexport const Answer = ({\r\n answer,\r\n isSelected,\r\n onCitationClicked,\r\n onThoughtProcessClicked,\r\n onSupportingContentClicked,\r\n onFollowupQuestionClicked,\r\n onReadAnswerClicked,\r\n showFollowupQuestions\r\n}: Props) => {\r\n const parsedAnswer = useMemo(() => parseAnswerToHtml(answer.answer, onCitationClicked), [answer]);\r\n\r\n const sanitizedAnswerHtml = DOMPurify.sanitize(parsedAnswer.answerHtml);\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n
\r\n onThoughtProcessClicked()}\r\n disabled={!answer.thoughts}\r\n />\r\n onSupportingContentClicked()}\r\n disabled={!answer.data_points.length}\r\n />\r\n onReadAnswerClicked()}\r\n disabled= {!answer.answer}\r\n />\r\n
\r\n
\r\n
\r\n\r\n \r\n
\r\n
\r\n\r\n {!!parsedAnswer.citations.length && (\r\n \r\n \r\n 来源:\r\n {parsedAnswer.citations.map((x, i) => {\r\n // const path = getCitationFilePath(x);\r\n const path = x.path;\r\n return (\r\n onCitationClicked(path)}>\r\n {`${++i}. ${x.name}`}\r\n \r\n );\r\n })}\r\n \r\n \r\n )}\r\n\r\n {!!parsedAnswer.followupQuestions.length && showFollowupQuestions && onFollowupQuestionClicked && (\r\n \r\n \r\n 您可能还想问:\r\n {parsedAnswer.followupQuestions.map((x, i) => {\r\n return (\r\n onFollowupQuestionClicked(x)}>\r\n {`${x}`}\r\n \r\n );\r\n })}\r\n \r\n \r\n )}\r\n
\r\n );\r\n};\r\n","import { Stack } from \"@fluentui/react\";\r\nimport { animated, useSpring } from \"@react-spring/web\";\r\n\r\nimport styles from \"./Answer.module.css\";\r\nimport { AnswerIcon } from \"./AnswerIcon\";\r\n\r\nexport const AnswerLoading = () => {\r\n const animatedStyles = useSpring({\r\n from: { opacity: 0 },\r\n to: { opacity: 1 }\r\n });\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n

\r\n 正在生成回答\r\n \r\n

\r\n
\r\n
\r\n
\r\n );\r\n};\r\n","import { Stack, PrimaryButton } from \"@fluentui/react\";\r\nimport { ErrorCircle24Regular } from \"@fluentui/react-icons\";\r\n\r\nimport styles from \"./Answer.module.css\";\r\n\r\ninterface Props {\r\n error: string;\r\n onRetry: () => void;\r\n}\r\n\r\nexport const AnswerError = ({ error, onRetry }: Props) => {\r\n return (\r\n \r\n \r\n\r\n \r\n

{error}

\r\n
\r\n\r\n \r\n
\r\n );\r\n};\r\n","import { useState, useEffect } from \"react\";\r\nimport { Stack, TextField } from \"@fluentui/react\";\r\nimport { Send28Filled, BookOpenMicrophone28Regular } from \"@fluentui/react-icons\";\r\nimport {SpeechConfig, AudioConfig, CancellationDetails, ResultReason, SpeechRecognizer, CancellationReason} from \"microsoft-cognitiveservices-speech-sdk\"\r\nimport styles from \"./QuestionInput.module.css\";\r\n\r\ninterface Props {\r\n onSend: (question: string) => void;\r\n disabled: boolean;\r\n placeholder?: string;\r\n clearOnSend?: boolean;\r\n}\r\n\r\nexport const QuestionInput = ({ onSend, disabled, placeholder, clearOnSend }: Props) => {\r\n const [question, setQuestion] = useState(\"\");\r\n\r\n const sendQuestion = () => {\r\n if (disabled || !question.trim()) {\r\n console.log('send disabled');\r\n console.log('question: ' + question);\r\n return;\r\n }\r\n\r\n onSend(question);\r\n\r\n if (clearOnSend) {\r\n setQuestion(\"\");\r\n }\r\n };\r\n\r\n const speechToText = () => {\r\n var speechConfig = SpeechConfig.fromSubscription('','southeastasia');\r\n const audioConfig = AudioConfig.fromDefaultMicrophoneInput();\r\n speechConfig.speechRecognitionLanguage = \"zh-CN\";\r\n const speechRecognizer = new SpeechRecognizer(speechConfig, audioConfig);\r\n speechRecognizer.recognizeOnceAsync(result => {\r\n switch (result.reason) {\r\n case ResultReason.RecognizedSpeech:\r\n console.log(`RECOGNIZED: Text=${result.text}`);\r\n setQuestion(result.text);\r\n break;\r\n case ResultReason.NoMatch:\r\n console.log(\"NOMATCH: Speech could not be recognized.\");\r\n break;\r\n case ResultReason.Canceled:\r\n const cancellation = CancellationDetails.fromResult(result);\r\n console.log(`CANCELED: Reason=${cancellation.reason}`);\r\n \r\n if (cancellation.reason == CancellationReason.Error) {\r\n console.log(`CANCELED: ErrorCode=${cancellation.ErrorCode}`);\r\n console.log(`CANCELED: ErrorDetails=${cancellation.errorDetails}`);\r\n console.log(\"CANCELED: Did you set the speech resource key and region values?\");\r\n }\r\n break;\r\n }\r\n speechRecognizer.close();\r\n });\r\n }\r\n const onEnterPress = (ev: React.KeyboardEvent) => {\r\n if (ev.key === \"Enter\" && !ev.shiftKey) {\r\n ev.preventDefault();\r\n sendQuestion();\r\n }\r\n };\r\n\r\n const onQuestionChange = (_ev: React.FormEvent, newValue?: string) => {\r\n if (!newValue) {\r\n setQuestion(\"\");\r\n } else if (newValue.length <= 1000) {\r\n setQuestion(newValue);\r\n }\r\n };\r\n\r\n const sendQuestionDisabled = disabled || !question.trim();\r\n\r\n return (\r\n \r\n \r\n
\r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n
\r\n );\r\n};\r\n","import styles from \"./Example.module.css\";\r\n\r\ninterface Props {\r\n text: string;\r\n value: string;\r\n onClick: (value: string) => void;\r\n}\r\n\r\nexport const Example = ({ text, value, onClick }: Props) => {\r\n return (\r\n
onClick(value)}>\r\n

{text}

\r\n
\r\n );\r\n};\r\n","import { Example } from \"./Example\";\r\n\r\nimport styles from \"./Example.module.css\";\r\n\r\nexport type ExampleModel = {\r\n text: string;\r\n value: string;\r\n};\r\n\r\nconst EXAMPLES: ExampleModel[] = [\r\n {\r\n text: \"九节菖蒲与石菖蒲是同一植物吗?\",\r\n value: \"九节菖蒲与石菖蒲是同一植物吗?\"\r\n },\r\n { text: \"餐饮食品吃拉肚子想要做检测,有什么标准可依?\", value: \"餐饮食品吃拉肚子想要做检测,有什么标准可依?\" },\r\n { text: \"茶叶按9833.3测试冠突散囊菌,如何知道茶叶是否长毛?\", value: \"茶叶按9833.3测试冠突散囊菌,如何知道茶叶是否长毛?\" }\r\n];\r\n\r\ninterface Props {\r\n onExampleClicked: (value: string) => void;\r\n}\r\n\r\nexport const ExampleList = ({ onExampleClicked }: Props) => {\r\n return (\r\n
    \r\n {EXAMPLES.map((x, i) => (\r\n
  • \r\n \r\n
  • \r\n ))}\r\n
\r\n );\r\n};\r\n","type ParsedSupportingContentItem = {\r\n title: string;\r\n content: string;\r\n url: string;\r\n};\r\n\r\nexport function parseSupportingContentItem(item: string): ParsedSupportingContentItem {\r\n // Assumes the item starts with the file name followed by : and the content.\r\n // Example: \"sdp_corporate.pdf: this is the content that follows\".\r\n const parts = item.split(\": \");\r\n const title = parts[0];\r\n var content = parts.slice(1).join(\": \") ? parts.slice(1).join(\": \") : \"No content\";\r\n \r\n //Extrace string in '<>' in content, example: info1.txt: abc \r\n const url = content.match(/<([^>]+)>/);\r\n\r\n //Replace string in '<>' in content, example: info1.txt: abc \r\n content = content.replace(/<([^>]+)>/g, \"\");\r\n \r\n \r\n\r\n return {\r\n title,\r\n content,\r\n url: url ? url[1] : \"\"\r\n };\r\n}\r\n","import { parseSupportingContentItem } from \"./SupportingContentParser\";\r\n\r\nimport styles from \"./SupportingContent.module.css\";\r\n\r\ninterface Props {\r\n supportingContent: string[];\r\n}\r\n\r\nexport const SupportingContent = ({ supportingContent }: Props) => {\r\n return (\r\n
    \r\n {supportingContent.map((x, i) => {\r\n const parsed = parseSupportingContentItem(x);\r\n\r\n return (\r\n
  • \r\n

    {parsed.title}

    \r\n

    {parsed.content}

    \r\n {parsed.url}\r\n
  • \r\n );\r\n })}\r\n
\r\n );\r\n};\r\n","export enum AnalysisPanelTabs {\r\n ThoughtProcessTab = \"thoughtProcess\",\r\n SupportingContentTab = \"supportingContent\",\r\n CitationTab = \"citation\"\r\n}\r\n","import { Pivot, PivotItem } from \"@fluentui/react\";\r\nimport DOMPurify from \"dompurify\";\r\n\r\nimport styles from \"./AnalysisPanel.module.css\";\r\n\r\nimport { SupportingContent } from \"../SupportingContent\";\r\nimport { AskResponse } from \"../../api\";\r\nimport { AnalysisPanelTabs } from \"./AnalysisPanelTabs\";\r\n\r\ninterface Props {\r\n className: string;\r\n activeTab: AnalysisPanelTabs;\r\n onActiveTabChanged: (tab: AnalysisPanelTabs) => void;\r\n activeCitation: string | undefined;\r\n citationHeight: string;\r\n answer: AskResponse;\r\n}\r\n\r\nconst pivotItemDisabledStyle = { disabled: true, style: { color: \"grey\" } };\r\n\r\nexport const AnalysisPanel = ({ answer, activeTab, activeCitation, citationHeight, className, onActiveTabChanged }: Props) => {\r\n const isDisabledThoughtProcessTab: boolean = !answer.thoughts;\r\n const isDisabledSupportingContentTab: boolean = !answer.data_points.length;\r\n const isDisabledCitationTab: boolean = !activeCitation;\r\n\r\n const sanitizedThoughts = DOMPurify.sanitize(answer.thoughts!);\r\n\r\n return (\r\n pivotItem && onActiveTabChanged(pivotItem.props.itemKey! as AnalysisPanelTabs)}\r\n >\r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n