├── .azdo └── pipelines │ └── azure-dev.yaml ├── .devcontainer └── devcontainer.json ├── .gitattributes ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── azure-dev.yaml │ ├── infra-ci.yaml │ ├── nightly-jobs.yaml │ └── stale-bot.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE.md ├── README.md ├── SECURITY.md ├── app ├── backend │ ├── .mvn │ │ ├── jvm.config │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── Dockerfile │ ├── applicationinsights.json │ ├── manifest.yml │ ├── manifests │ │ ├── backend-deployment.tmpl.yml │ │ ├── backend-service.yml │ │ └── ingress.yml │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── microsoft │ │ │ │ └── openai │ │ │ │ └── samples │ │ │ │ └── rag │ │ │ │ ├── Application.java │ │ │ │ ├── approaches │ │ │ │ ├── ContentSource.java │ │ │ │ ├── PromptTemplate.java │ │ │ │ ├── RAGApproach.java │ │ │ │ ├── RAGApproachFactory.java │ │ │ │ ├── RAGApproachFactorySpringBootImpl.java │ │ │ │ ├── RAGOptions.java │ │ │ │ ├── RAGResponse.java │ │ │ │ ├── RAGType.java │ │ │ │ ├── RetrievalMode.java │ │ │ │ └── SemanticKernelMode.java │ │ │ │ ├── ask │ │ │ │ ├── approaches │ │ │ │ │ ├── AnswerQuestionPromptTemplate.java │ │ │ │ │ ├── PlainJavaAskApproach.java │ │ │ │ │ └── semantickernel │ │ │ │ │ │ ├── JavaSemanticKernelChainsApproach.java │ │ │ │ │ │ ├── JavaSemanticKernelPlannerApproach.java.ignore │ │ │ │ │ │ └── JavaSemanticKernelWithVectorStoreApproach.java │ │ │ │ └── controller │ │ │ │ │ └── AskController.java │ │ │ │ ├── chat │ │ │ │ ├── approaches │ │ │ │ │ ├── AnswerQuestionChatPromptTemplate.java │ │ │ │ │ ├── PlainJavaChatApproach.java │ │ │ │ │ └── semantickernel │ │ │ │ │ │ ├── JavaSemanticKernelChainsChatApproach.java │ │ │ │ │ │ └── JavaSemanticKernelWithVectorStoreChatApproach.java │ │ │ │ └── controller │ │ │ │ │ └── ChatController.java │ │ │ │ ├── common │ │ │ │ ├── ChatGPTConversation.java │ │ │ │ ├── ChatGPTMessage.java │ │ │ │ └── ChatGPTUtils.java │ │ │ │ ├── config │ │ │ │ ├── AzureAISearchConfiguration.java │ │ │ │ ├── AzureAuthenticationConfiguration.java │ │ │ │ └── OpenAIConfiguration.java │ │ │ │ ├── content │ │ │ │ └── controller │ │ │ │ │ └── ContentController.java │ │ │ │ ├── controller │ │ │ │ ├── ChatAppRequest.java │ │ │ │ ├── ChatAppRequestContext.java │ │ │ │ ├── ChatAppRequestOverrides.java │ │ │ │ ├── ChatResponse.java │ │ │ │ ├── ResponseChoice.java │ │ │ │ ├── ResponseContext.java │ │ │ │ ├── ResponseMessage.java │ │ │ │ └── auth │ │ │ │ │ └── AuthSetup.java │ │ │ │ ├── proxy │ │ │ │ ├── AzureAISearchProxy.java │ │ │ │ ├── BlobStorageProxy.java │ │ │ │ └── OpenAIProxy.java │ │ │ │ └── retrieval │ │ │ │ ├── AzureAISearchRetriever.java │ │ │ │ ├── ExtractKeywordsChatTemplate.java │ │ │ │ ├── FactsRetrieverProvider.java │ │ │ │ ├── Retriever.java │ │ │ │ └── semantickernel │ │ │ │ ├── AzureAISearchPlugin.java │ │ │ │ └── AzureAISearchVectorStoreUtils.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── semantickernel │ │ │ └── Plugins │ │ │ └── RAG │ │ │ ├── AnswerConversation │ │ │ ├── answerConversation.prompt.yaml │ │ │ └── answerConversationNoFS.prompt.yaml │ │ │ ├── AnswerQuestion │ │ │ └── answerQuestion.prompt.yaml │ │ │ └── ExtractKeywords │ │ │ └── extractKeywords.prompt.yaml │ │ └── test │ │ └── java │ │ └── com │ │ └── microsoft │ │ └── openai │ │ └── samples │ │ └── rag │ │ ├── AskAPITest.java │ │ ├── ChatAPITest.java │ │ ├── approaches │ │ └── RAGApproachFactorySpringBootImplTest.java │ │ └── test │ │ ├── config │ │ └── ProxyMockConfiguration.java │ │ └── utils │ │ ├── CognitiveSearchUnitTestUtils.java │ │ └── OpenAIUnitTestUtils.java ├── frontend │ ├── .dockerignore │ ├── .env.dev │ ├── .env.local │ ├── .env.production │ ├── .npmrc │ ├── .prettierignore │ ├── .prettierrc.json │ ├── Dockerfile │ ├── Dockerfile-aks │ ├── index.html │ ├── manifests │ │ ├── frontend-deployment.tmpl.yml │ │ └── frontend-service.yml │ ├── nginx │ │ └── nginx.conf.template │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── api │ │ │ ├── api.ts │ │ │ ├── index.ts │ │ │ └── models.ts │ │ ├── assets │ │ │ ├── github.svg │ │ │ └── search.svg │ │ ├── authConfig.ts │ │ ├── components │ │ │ ├── AnalysisPanel │ │ │ │ ├── AnalysisPanel.module.css │ │ │ │ ├── AnalysisPanel.tsx │ │ │ │ ├── AnalysisPanelTabs.tsx │ │ │ │ └── index.tsx │ │ │ ├── Answer │ │ │ │ ├── Answer.module.css │ │ │ │ ├── Answer.tsx │ │ │ │ ├── AnswerError.tsx │ │ │ │ ├── AnswerIcon.tsx │ │ │ │ ├── AnswerLoading.tsx │ │ │ │ ├── AnswerParser.tsx │ │ │ │ └── index.ts │ │ │ ├── ClearChatButton │ │ │ │ ├── ClearChatButton.module.css │ │ │ │ ├── ClearChatButton.tsx │ │ │ │ └── index.tsx │ │ │ ├── Example │ │ │ │ ├── Example.module.css │ │ │ │ ├── Example.tsx │ │ │ │ ├── ExampleList.tsx │ │ │ │ └── index.tsx │ │ │ ├── LoginButton │ │ │ │ ├── LoginButton.module.css │ │ │ │ ├── LoginButton.tsx │ │ │ │ └── index.tsx │ │ │ ├── QuestionInput │ │ │ │ ├── QuestionInput.module.css │ │ │ │ ├── QuestionInput.tsx │ │ │ │ └── index.ts │ │ │ ├── SettingsButton │ │ │ │ ├── SettingsButton.module.css │ │ │ │ ├── SettingsButton.tsx │ │ │ │ └── index.tsx │ │ │ ├── SupportingContent │ │ │ │ ├── SupportingContent.module.css │ │ │ │ ├── SupportingContent.tsx │ │ │ │ ├── SupportingContentParser.ts │ │ │ │ └── index.ts │ │ │ ├── TokenClaimsDisplay │ │ │ │ ├── TokenClaimsDisplay.tsx │ │ │ │ └── index.tsx │ │ │ └── UserChatMessage │ │ │ │ ├── UserChatMessage.module.css │ │ │ │ ├── UserChatMessage.tsx │ │ │ │ └── index.ts │ │ ├── index.css │ │ ├── index.tsx │ │ ├── pages │ │ │ ├── NoPage.tsx │ │ │ ├── chat │ │ │ │ ├── Chat.module.css │ │ │ │ └── Chat.tsx │ │ │ ├── layout │ │ │ │ ├── Layout.module.css │ │ │ │ └── Layout.tsx │ │ │ └── oneshot │ │ │ │ ├── OneShot.module.css │ │ │ │ └── OneShot.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.ts ├── indexer │ ├── .mvn │ │ ├── jvm.config │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── cli │ │ ├── dependency-reduced-pom.xml │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── microsoft │ │ │ │ └── openai │ │ │ │ └── samples │ │ │ │ └── indexer │ │ │ │ ├── AddCommand.java │ │ │ │ ├── CLI.java │ │ │ │ └── UploadCommand.java │ │ │ └── resources │ │ │ └── logback.xml │ ├── core │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── microsoft │ │ │ │ └── openai │ │ │ │ └── samples │ │ │ │ └── indexer │ │ │ │ ├── DocumentProcessor.java │ │ │ │ ├── Section.java │ │ │ │ ├── SplitPage.java │ │ │ │ ├── embeddings │ │ │ │ ├── AbstractTextEmbeddingsService.java │ │ │ │ ├── AzureOpenAIEmbeddingService.java │ │ │ │ ├── EmbeddingBatch.java │ │ │ │ ├── EmbeddingData.java │ │ │ │ ├── EmbeddingResponse.java │ │ │ │ └── TextEmbeddingsService.java │ │ │ │ ├── index │ │ │ │ ├── AzureSearchClientFactory.java │ │ │ │ └── SearchIndexManager.java │ │ │ │ ├── parser │ │ │ │ ├── DocumentIntelligencePDFParser.java │ │ │ │ ├── ItextPDFParser.java │ │ │ │ ├── PDFParser.java │ │ │ │ ├── Page.java │ │ │ │ └── TextSplitter.java │ │ │ │ └── storage │ │ │ │ └── BlobManager.java │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── microsoft │ │ │ └── openai │ │ │ └── samples │ │ │ └── indexer │ │ │ └── parser │ │ │ └── TextSplitterTest.java │ ├── functions │ │ ├── .gitignore │ │ ├── host.json │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── microsoft │ │ │ │ └── openai │ │ │ │ └── samples │ │ │ │ └── indexer │ │ │ │ └── functions │ │ │ │ └── BlobProcessorFunction.java │ │ │ └── resources │ │ │ └── logback.xml │ ├── manifests │ │ ├── indexer-deployment.tmpl.yml │ │ └── indexer-service.yml │ ├── microservice │ │ ├── Dockerfile │ │ ├── applicationinsights.json │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ ├── microsoft.openai.samples.indexer.service │ │ │ │ ├── Application.java │ │ │ │ ├── BlobMessageConsumer.java │ │ │ │ └── IndexerService.java │ │ │ │ └── microsoft │ │ │ │ └── openai │ │ │ │ └── samples │ │ │ │ └── indexer │ │ │ │ └── service │ │ │ │ ├── config │ │ │ │ ├── AzureAuthenticationConfiguration.java │ │ │ │ ├── BlobManagerConfiguration.java │ │ │ │ ├── DocumentIntelligencePDFParserConfiguration.java │ │ │ │ ├── SearchIndexManagerConfiguration.java │ │ │ │ ├── ServiceBusConfig.java │ │ │ │ └── ServiceBusProcessorClientConfiguration.java │ │ │ │ └── events │ │ │ │ ├── BlobEventGridData.java │ │ │ │ ├── BlobMessageListener.java │ │ │ │ └── BlobUpsertEventGridEvent.java │ │ │ └── resources │ │ │ ├── application.properties │ │ │ └── local-dev.properties │ ├── mvnw │ ├── mvnw.cmd │ └── pom.xml └── package-lock.json ├── data ├── Benefit_Options.pdf ├── Northwind_Health_Plus_Benefits_Details.pdf ├── Northwind_Standard_Benefits_Details.pdf ├── PerksPlus.pdf ├── employee_handbook.pdf └── role_library.pdf ├── deploy ├── aca │ ├── azure.yaml │ ├── compose.yaml │ ├── infra │ │ ├── app │ │ │ ├── api.bicep │ │ │ ├── indexer.bicep │ │ │ └── web.bicep │ │ ├── main.bicep │ │ └── main.parameters.json │ ├── scripts │ │ ├── prepdocs.ps1 │ │ ├── prepdocs.sh │ │ ├── roles.ps1 │ │ ├── roles.sh │ │ ├── set-env.ps1 │ │ └── set-env.sh │ ├── start-compose.ps1 │ └── start-compose.sh ├── aks │ ├── azure.yaml │ ├── compose.yaml │ ├── easyauth │ │ ├── cluster-issuer.yaml │ │ ├── easyauth-proxy │ │ │ ├── .helmignore │ │ │ ├── Chart.yaml │ │ │ ├── templates │ │ │ │ ├── NOTES.txt │ │ │ │ ├── _helpers.tpl │ │ │ │ ├── hpa.yaml │ │ │ │ ├── ingress.yaml │ │ │ │ ├── pvc.yaml │ │ │ │ ├── secret.yaml │ │ │ │ ├── service.yaml │ │ │ │ ├── serviceaccount.yaml │ │ │ │ ├── statefulset.yaml │ │ │ │ └── tests │ │ │ │ │ └── test-connection.yaml │ │ │ └── values.yaml │ │ └── manifest.json │ ├── infra │ │ ├── main.bicep │ │ └── main.parameters.json │ ├── scripts │ │ ├── easyauth-down.ps1 │ │ ├── easyauth-down.sh │ │ ├── easyauth.ps1 │ │ ├── easyauth.sh │ │ ├── predeploy.ps1 │ │ ├── predeploy.sh │ │ ├── prepdocs.ps1 │ │ └── prepdocs.sh │ ├── start-compose.ps1 │ └── start-compose.sh ├── app-service │ ├── azure.yaml │ ├── infra │ │ ├── main.bicep │ │ ├── main.parameters.json │ │ └── main.test.bicep │ ├── package-lock.json │ ├── scripts │ │ ├── prepdocs.ps1 │ │ ├── prepdocs.sh │ │ ├── roles.ps1 │ │ ├── roles.sh │ │ ├── set-env.ps1 │ │ └── set-env.sh │ ├── start.ps1 │ └── start.sh └── shared │ ├── abbreviations.json │ ├── ai │ └── cognitiveservices.bicep │ ├── backend-dashboard.bicep │ ├── event │ └── eventgrid.bicep │ ├── host │ ├── aks-agent-pool.bicep │ ├── aks-managed-cluster.bicep │ ├── aks.bicep │ ├── appservice-appsettings.bicep │ ├── appservice.bicep │ ├── appserviceplan.bicep │ ├── container-app-upsert.bicep │ ├── container-app.bicep │ ├── container-apps-environment.bicep │ ├── container-apps.bicep │ ├── container-registry.bicep │ └── functions.bicep │ ├── monitor │ ├── applicationinsights-dashboard.bicep │ ├── applicationinsights.bicep │ ├── loganalytics.bicep │ └── monitoring.bicep │ ├── search │ └── search-services.bicep │ ├── security │ ├── aks-managed-cluster-access.bicep │ ├── keyvault-access.bicep │ ├── keyvault-secret.bicep │ ├── keyvault.bicep │ ├── registry-access.bicep │ └── role.bicep │ ├── servicebus │ └── servicebus-queue.bicep │ └── storage │ └── storage-account.bicep ├── docs ├── aca │ ├── README-ACA.md │ ├── aca-endpoint.png │ ├── aca-hla.png │ ├── aca-internal-java-ai.png │ └── transaction-tracing.png ├── aks │ ├── README-AKS.md │ ├── aks-deploy-success.png │ ├── aks-hla.png │ └── aks-transaction-tracing.png ├── app-service │ ├── README-App-Service.md │ ├── app-service-hla.png │ ├── azDo-pipeline-success.png │ ├── endpoint.png │ ├── github-actions-pipeline-success.png │ ├── pipeline-azure-service-connection1.png │ ├── pipeline-azure-service-connection2.png │ ├── prepdocs-success.png │ └── transaction-tracing.png ├── appcomponents.png ├── chatscreen.png └── endpoint.png └── ps-rule.yaml /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Java 17 and maven 3.8.8 DevContainer to build Java RAG example with Azure AI", 3 | "image": "mcr.microsoft.com/devcontainers/java:1-17-bullseye", 4 | "features": { 5 | "azure-cli": "latest", 6 | "ghcr.io/azure/azure-dev/azd:latest": { 7 | "version": "1.9.5" 8 | }, 9 | "ghcr.io/devcontainers/features/java:1": { 10 | "version": "none", 11 | "installMaven": true, 12 | "mavenVersion": "3.8.8" 13 | }, 14 | "ghcr.io/devcontainers/features/node:1": { 15 | "version": "20.5.0" 16 | }, 17 | 18 | "ghcr.io/devcontainers/features/git:1": { 19 | "version": "2.39.1" 20 | }, 21 | "ghcr.io/devcontainers-contrib/features/typescript:2": {}, 22 | "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {}, 23 | "docker-in-docker": { 24 | "version": "latest", 25 | "moby": true, 26 | "dockerDashComposeVersion": "v1" 27 | } 28 | }, 29 | "customizations": { 30 | "vscode": { 31 | "extensions": [ 32 | "GitHub.vscode-github-actions", 33 | "ms-azuretools.azure-dev", 34 | "ms-azuretools.vscode-bicep", 35 | "vscjava.vscode-java-pack", 36 | "amodio.tsl-problem-matcher" 37 | ] 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh text eol=lf -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | > Please provide us with the following information: 5 | > --------------------------------------------------------------- 6 | 7 | ### This issue is for a: (mark with an `x`) 8 | ``` 9 | - [ ] bug report -> please search issues before submitting 10 | - [ ] feature request 11 | - [ ] documentation issue or request 12 | - [ ] regression (a behavior that used to work and stopped in a new release) 13 | ``` 14 | 15 | ### Minimal steps to reproduce 16 | > 17 | 18 | ### Any log messages given by the failure 19 | > 20 | 21 | ### Expected/desired behavior 22 | > 23 | 24 | ### OS and Version? 25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) 26 | 27 | ### azd version? 28 | > run `azd version` and copy paste here. 29 | 30 | ### Versions 31 | > 32 | 33 | ### Mention any other details that might be useful 34 | 35 | > --------------------------------------------------------------- 36 | > Thanks! We'll be in touch soon. 37 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | * ... 4 | 5 | ## Does this introduce a breaking change? 6 | 7 | ``` 8 | [ ] Yes 9 | [ ] No 10 | ``` 11 | 12 | ## Pull Request Type 13 | What kind of change does this Pull Request introduce? 14 | 15 | 16 | ``` 17 | [ ] Bugfix 18 | [ ] Feature 19 | [ ] Code style update (formatting, local variables) 20 | [ ] Refactoring (no functional changes, no api changes) 21 | [ ] Documentation content changes 22 | [ ] Other... Please describe: 23 | ``` 24 | 25 | ## How to Test 26 | * Get the code 27 | 28 | ``` 29 | git clone [repo-address] 30 | cd [repo-name] 31 | git checkout [branch-name] 32 | npm install 33 | ``` 34 | 35 | * Test the code 36 | 37 | ``` 38 | ``` 39 | 40 | ## What to Check 41 | Verify that the following are valid 42 | * ... 43 | 44 | ## Other Information 45 | -------------------------------------------------------------------------------- /.github/workflows/stale-bot.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: '30 1 * * *' 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v8 11 | with: 12 | stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this issue will be closed.' 13 | stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed.' 14 | close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' 15 | close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.' 16 | days-before-issue-stale: 60 17 | days-before-pr-stale: 60 18 | days-before-issue-close: -1 19 | days-before-pr-close: -1 20 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "vscjava.vscode-java-debug" 5 | ] 6 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to Java Functions", 6 | "type": "java", 7 | "request": "attach", 8 | "hostName": "127.0.0.1", 9 | "port": 5005, 10 | "preLaunchTask": "func: host start" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.javaBuildTool": "maven", 3 | "azureFunctions.deploySubpath": "app/indexer/functions/target/azure-functions/indexer-blob-processor", 4 | "azureFunctions.projectLanguage": "Java", 5 | "azureFunctions.projectRuntime": "~4", 6 | "debug.internalConsoleOptions": "neverOpen", 7 | "azureFunctions.projectSubpath": "app/indexer/functions", 8 | "azureFunctions.preDeployTask": "package (functions)", 9 | "java.configuration.updateBuildConfiguration": "interactive" 10 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Start App ", 6 | "type": "shell", 7 | "command": "${workspaceFolder}/deploy/app-service/start.sh", 8 | "windows": { 9 | "command": "pwsh ${workspaceFolder}/deploy/app-service/start.ps1" 10 | }, 11 | "presentation": { 12 | "reveal": "always" 13 | }, 14 | "options": { 15 | "cwd": "${workspaceFolder}/app" 16 | }, 17 | "problemMatcher": [] 18 | }, 19 | { 20 | "type": "func", 21 | "label": "func: host start", 22 | "command": "host start", 23 | "problemMatcher": "$func-java-watch", 24 | "isBackground": true, 25 | "options": { 26 | "cwd": "${workspaceFolder}/app/indexer/functions/target/azure-functions/indexer-blob-processor" 27 | }, 28 | "dependsOn": "package (functions)" 29 | }, 30 | { 31 | "label": "package (functions)", 32 | "command": "mvn clean package", 33 | "type": "shell", 34 | "group": { 35 | "kind": "build", 36 | "isDefault": true 37 | }, 38 | "options": { 39 | "cwd": "${workspaceFolder}/app/indexer/functions" 40 | } 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [project-title] Changelog 2 | 3 | 4 | # x.y.z (yyyy-mm-dd) 5 | 6 | *Features* 7 | * ... 8 | 9 | *Bug Fixes* 10 | * ... 11 | 12 | *Breaking Changes* 13 | * ... 14 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # this repo. Unless a later match takes precedence, 3 | # @global-owner1 and @global-owner2 will be requested for 4 | # review when someone opens a pull request. 5 | * @dantelmomsft 6 | * @johnoliver 7 | * @brunoborges 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Azure Samples 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /app/backend/.mvn/jvm.config: -------------------------------------------------------------------------------- 1 | --add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED 2 | --add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED 3 | --add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED 4 | --add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED 5 | -------------------------------------------------------------------------------- /app/backend/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/azure-search-openai-demo-java/e9b5f67d6d98c22aaa3a778fb9a10c46d304e7b8/app/backend/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /app/backend/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.tar.gz 3 | -------------------------------------------------------------------------------- /app/backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/openjdk/jdk:17-mariner AS build 2 | 3 | WORKDIR /workspace/app 4 | EXPOSE 3100 5 | 6 | COPY mvnw . 7 | COPY .mvn .mvn 8 | COPY pom.xml . 9 | COPY src src 10 | 11 | RUN chmod +x ./mvnw 12 | # Convert CRLF to LF 13 | RUN sed -i 's/\r$//' ./mvnw 14 | RUN ./mvnw package -DskipTests 15 | RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) 16 | 17 | FROM mcr.microsoft.com/openjdk/jdk:17-mariner 18 | 19 | ARG DEPENDENCY=/workspace/app/target/dependency 20 | COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib 21 | COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF 22 | COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app 23 | 24 | 25 | RUN curl -LJ -o /app/applicationinsights-agent-3.4.19.jar https://github.com/microsoft/ApplicationInsights-Java/releases/download/3.4.19/applicationinsights-agent-3.4.19.jar 26 | COPY applicationinsights.json /app 27 | 28 | EXPOSE 8080 29 | 30 | ENTRYPOINT ["java","-javaagent:/app/applicationinsights-agent-3.4.19.jar","-noverify", "-XX:MaxRAMPercentage=70", "-XX:+UseParallelGC", "-XX:ActiveProcessorCount=2", "-cp","app:app/lib/*","com.microsoft.openai.samples.rag.Application"] -------------------------------------------------------------------------------- /app/backend/applicationinsights.json: -------------------------------------------------------------------------------- 1 | { 2 | "role": { 3 | "name": "api" 4 | } 5 | } -------------------------------------------------------------------------------- /app/backend/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: rest-service-guides 4 | memory: 256M 5 | instances: 1 6 | random-route: true 7 | domain: cfapps.io 8 | timeout: 180 9 | buildpack: java_buildpack 10 | # For Maven target/gs-rest-service-cors-0.1.0.jar 11 | path: build/libs/gs-rest-service-cors-0.1.0.jar 12 | -------------------------------------------------------------------------------- /app/backend/manifests/backend-deployment.tmpl.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: backend-deployment 5 | namespace: azure-open-ai 6 | labels: 7 | app: backend 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: backend 13 | template: 14 | metadata: 15 | labels: 16 | app: backend 17 | spec: 18 | containers: 19 | - name: backend 20 | image: {{.Env.SERVICE_API_IMAGE_NAME}} 21 | imagePullPolicy: IfNotPresent 22 | ports: 23 | - containerPort: 8080 24 | envFrom: 25 | - configMapRef: 26 | name: azd-env-configmap 27 | resources: 28 | requests: 29 | memory: "2Gi" 30 | -------------------------------------------------------------------------------- /app/backend/manifests/backend-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: backend-service 5 | namespace: azure-open-ai 6 | spec: 7 | type: ClusterIP 8 | ports: 9 | - protocol: TCP 10 | port: 80 11 | targetPort: 8080 12 | selector: 13 | app: backend 14 | -------------------------------------------------------------------------------- /app/backend/manifests/ingress.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: ingress-api 5 | namespace: azure-open-ai 6 | # annotations: 7 | # nginx.ingress.kubernetes.io/use-regex: "true" 8 | # nginx.ingress.kubernetes.io/rewrite-target: /$2 9 | spec: 10 | ingressClassName: webapprouting.kubernetes.azure.com 11 | rules: 12 | - http: 13 | paths: 14 | - path: /api 15 | pathType: Prefix 16 | backend: 17 | service: 18 | name: backend-service 19 | port: 20 | number: 80 21 | - path: / 22 | pathType: Prefix 23 | backend: 24 | service: 25 | name: frontend-service 26 | port: 27 | number: 80 -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/Application.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag; 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | 9 | @SpringBootApplication 10 | public class Application { 11 | 12 | private static final Logger LOG = LoggerFactory.getLogger(Application.class); 13 | 14 | public static void main(String[] args) { 15 | LOG.info( 16 | "Application profile from system property is [{}]", 17 | System.getProperty("spring.profiles.active")); 18 | new SpringApplication(Application.class).run(args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/ContentSource.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.approaches; 3 | 4 | public class ContentSource { 5 | 6 | private String sourceName; 7 | private String sourceContent; 8 | private final boolean noNewLine; 9 | 10 | public ContentSource(String sourceName, String sourceContent, Boolean noNewLine) { 11 | this.noNewLine = noNewLine; 12 | this.sourceName = sourceName; 13 | buildContent(sourceContent); 14 | } 15 | 16 | public ContentSource(String sourceName, String sourceContent) { 17 | this(sourceName, sourceContent, true); 18 | } 19 | 20 | public String getSourceName() { 21 | return sourceName; 22 | } 23 | 24 | public void setSourceName(String sourceName) { 25 | this.sourceName = sourceName; 26 | } 27 | 28 | public String getSourceContent() { 29 | return sourceContent; 30 | } 31 | 32 | public void setSourceContent(String sourceContent) { 33 | this.sourceContent = sourceContent; 34 | } 35 | 36 | public boolean isNoNewLine() { 37 | return noNewLine; 38 | } 39 | 40 | private void buildContent(String sourceContent) { 41 | if (this.noNewLine) { 42 | this.sourceContent = sourceContent.replace("\n", ""); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/PromptTemplate.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.approaches; 3 | 4 | public interface PromptTemplate { 5 | 6 | String getPrompt(); 7 | 8 | void setVariables(); 9 | } 10 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/RAGApproach.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.approaches; 3 | 4 | import java.io.OutputStream; 5 | 6 | public interface RAGApproach { 7 | 8 | O run(I questionOrConversation, RAGOptions options); 9 | 10 | void runStreaming(I questionOrConversation, RAGOptions options, OutputStream outputStream); 11 | } 12 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/RAGApproachFactory.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.approaches; 3 | 4 | public interface RAGApproachFactory { 5 | 6 | RAGApproach createApproach(String approachName, RAGType ragType, RAGOptions options); 7 | } 8 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/RAGResponse.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.approaches; 3 | 4 | import java.util.List; 5 | 6 | public class RAGResponse { 7 | 8 | private final String question; 9 | private final List sources; 10 | private final String sourcesAsText; 11 | private final String answer; 12 | private final String prompt; 13 | 14 | private RAGResponse(Builder builder) { 15 | this.question = builder.question; 16 | this.sources = builder.sources; 17 | this.answer = builder.answer; 18 | this.prompt = builder.prompt; 19 | this.sourcesAsText = builder.sourcesAsText; 20 | } 21 | 22 | public String getQuestion() { 23 | return question; 24 | } 25 | 26 | public List getSources() { 27 | return sources; 28 | } 29 | 30 | public String getSourcesAsText() { 31 | return sourcesAsText; 32 | } 33 | 34 | public String getAnswer() { 35 | return answer; 36 | } 37 | 38 | public String getPrompt() { 39 | return prompt; 40 | } 41 | 42 | public static class Builder { 43 | private String question; 44 | private List sources; 45 | private String sourcesAsText; 46 | private String answer; 47 | private String prompt; 48 | 49 | public Builder question(String question) { 50 | this.question = question; 51 | return this; 52 | } 53 | 54 | public Builder sources(List sources) { 55 | this.sources = sources; 56 | return this; 57 | } 58 | 59 | public Builder sourcesAsText(String sourcesAsText) { 60 | this.sourcesAsText = sourcesAsText; 61 | return this; 62 | } 63 | 64 | public Builder answer(String answer) { 65 | this.answer = answer; 66 | return this; 67 | } 68 | 69 | public Builder prompt(String prompt) { 70 | this.prompt = prompt; 71 | return this; 72 | } 73 | 74 | public RAGResponse build() { 75 | return new RAGResponse(this); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/RAGType.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.approaches; 3 | 4 | public enum RAGType { 5 | CHAT, 6 | ASK 7 | } 8 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/RetrievalMode.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.approaches; 3 | 4 | public enum RetrievalMode { 5 | hybrid, 6 | vectors, 7 | text; 8 | } 9 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/SemanticKernelMode.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.approaches; 3 | 4 | public enum SemanticKernelMode { 5 | chains, 6 | planner; 7 | } 8 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/common/ChatGPTMessage.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.common; 3 | 4 | import com.azure.core.util.ExpandableStringEnum; 5 | import java.util.Collection; 6 | 7 | public record ChatGPTMessage(ChatGPTMessage.ChatRole role, String content) { 8 | 9 | public static final class ChatRole extends ExpandableStringEnum { 10 | public static final ChatGPTMessage.ChatRole SYSTEM = fromString("system"); 11 | 12 | public static final ChatGPTMessage.ChatRole ASSISTANT = fromString("assistant"); 13 | 14 | public static final ChatGPTMessage.ChatRole USER = fromString("user"); 15 | 16 | public static ChatGPTMessage.ChatRole fromString(String name) { 17 | return fromString(name, ChatGPTMessage.ChatRole.class); 18 | } 19 | 20 | public static Collection values() { 21 | return values(ChatGPTMessage.ChatRole.class); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/config/AzureAuthenticationConfiguration.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.config; 3 | 4 | import com.azure.core.credential.TokenCredential; 5 | import com.azure.identity.AzureCliCredentialBuilder; 6 | import com.azure.identity.EnvironmentCredentialBuilder; 7 | import com.azure.identity.ManagedIdentityCredentialBuilder; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.context.annotation.Profile; 12 | 13 | /** 14 | * The following Azure authentication providers are used in the application: 15 | * - Local development: Azure CLI 16 | * - Local Docker: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT SECRET env variables are used with Environment credential builder. 17 | * - Azure: Managed Identity 18 | */ 19 | @Configuration 20 | public class AzureAuthenticationConfiguration { 21 | 22 | @Value("${azure.identity.client-id}") 23 | String clientId; 24 | 25 | @Profile("dev") 26 | @Bean 27 | public TokenCredential localTokenCredential() { 28 | return new AzureCliCredentialBuilder().build(); 29 | } 30 | 31 | @Profile("docker") 32 | @Bean 33 | public TokenCredential servicePrincipalTokenCredential() { 34 | return new EnvironmentCredentialBuilder().build(); 35 | } 36 | 37 | @Bean 38 | @Profile("default") 39 | public TokenCredential managedIdentityTokenCredential() { 40 | if (this.clientId.equals("system-managed-identity")) 41 | return new ManagedIdentityCredentialBuilder().build(); 42 | else 43 | return new ManagedIdentityCredentialBuilder().clientId(this.clientId).build(); 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/controller/ChatAppRequest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.controller; 3 | 4 | import java.util.List; 5 | 6 | public record ChatAppRequest( 7 | List messages, 8 | ChatAppRequestContext context, 9 | boolean stream, 10 | String approach) {} 11 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/controller/ChatAppRequestContext.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.controller; 3 | 4 | public record ChatAppRequestContext(ChatAppRequestOverrides overrides) {} 5 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/controller/ChatAppRequestOverrides.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.controller; 3 | 4 | import com.microsoft.openai.samples.rag.approaches.RetrievalMode; 5 | 6 | public record ChatAppRequestOverrides( 7 | RetrievalMode retrieval_mode, 8 | boolean semantic_ranker, 9 | boolean semantic_captions, 10 | String exclude_category, 11 | int top, 12 | float temperature, 13 | String prompt_template, 14 | String prompt_template_prefix, 15 | String prompt_template_suffix, 16 | boolean suggest_followup_questions, 17 | boolean use_oid_security_filter, 18 | boolean use_groups_security_filter, 19 | String semantic_kernel_mode) {} 20 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/controller/ChatResponse.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.controller; 3 | 4 | import com.microsoft.openai.samples.rag.approaches.RAGResponse; 5 | import com.microsoft.openai.samples.rag.common.ChatGPTMessage; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | public record ChatResponse(List choices) { 10 | 11 | public static ChatResponse buildChatResponse(RAGResponse ragResponse) { 12 | List dataPoints = Collections.emptyList(); 13 | 14 | if (ragResponse.getSources() != null) { 15 | dataPoints = 16 | ragResponse.getSources().stream() 17 | .map( 18 | source -> 19 | source.getSourceName() 20 | + ": " 21 | + source.getSourceContent()) 22 | .toList(); 23 | } 24 | 25 | String thoughts = 26 | "Question:
" 27 | + ragResponse.getQuestion() 28 | + "

Prompt:
" 29 | + ragResponse.getPrompt().replace("\n", "
"); 30 | 31 | return new ChatResponse( 32 | List.of( 33 | new ResponseChoice( 34 | 0, 35 | new ResponseMessage( 36 | ragResponse.getAnswer(), 37 | ChatGPTMessage.ChatRole.ASSISTANT.toString()), 38 | new ResponseContext(thoughts, dataPoints), 39 | new ResponseMessage( 40 | ragResponse.getAnswer(), 41 | ChatGPTMessage.ChatRole.ASSISTANT.toString())))); 42 | } 43 | 44 | public static ChatResponse buildChatDeltaResponse(Integer index, RAGResponse ragResponse) { 45 | return new ChatResponse( 46 | List.of( 47 | new ResponseChoice( 48 | index, 49 | new ResponseMessage(ragResponse.getAnswer(), "ASSISTANT"), 50 | null, 51 | new ResponseMessage(ragResponse.getAnswer(), "ASSISTANT")))); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/controller/ResponseChoice.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.controller; 3 | 4 | public record ResponseChoice( 5 | int index, ResponseMessage message, ResponseContext context, ResponseMessage delta) {} 6 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/controller/ResponseContext.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.controller; 3 | 4 | import java.util.List; 5 | 6 | public record ResponseContext(String thoughts, List data_points) {} 7 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/controller/ResponseMessage.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.controller; 3 | 4 | public record ResponseMessage(String content, String role) {} 5 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/controller/auth/AuthSetup.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.controller.auth; 3 | 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | /** 8 | * This api is call on frontend startup to check if login custom openid javascript provider is enabled. 9 | * However for this sample the default value is false. Authentication is provided instead by easyauth managed service on Azure compute platform. 10 | * See 'Enabling Authentication' section on README.md for more details. 11 | */ 12 | @RestController 13 | public class AuthSetup { 14 | 15 | @GetMapping("/api/auth_setup") 16 | public String authSetup() { 17 | return """ 18 | { 19 | "useLogin": false 20 | } 21 | """ 22 | .stripIndent(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/proxy/AzureAISearchProxy.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.proxy; 3 | 4 | import com.azure.core.util.Context; 5 | import com.azure.search.documents.SearchClient; 6 | import com.azure.search.documents.models.SearchOptions; 7 | import com.azure.search.documents.util.SearchPagedIterable; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * This class is a proxy to the Azure AI Search API. It is responsible for: 12 | * - calling the OpenAI API 13 | * - handling errors and retry strategy 14 | * - add monitoring points 15 | * - add circuit breaker with exponential backoff 16 | */ 17 | @Component 18 | public class AzureAISearchProxy { 19 | 20 | private final SearchClient client; 21 | 22 | public AzureAISearchProxy(SearchClient searchClient) { 23 | this.client = searchClient; 24 | } 25 | 26 | public SearchPagedIterable search( 27 | String searchText, SearchOptions searchOptions, Context context) { 28 | return client.search(searchText, searchOptions, context); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/proxy/BlobStorageProxy.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.proxy; 3 | 4 | import com.azure.core.credential.TokenCredential; 5 | import com.azure.storage.blob.BlobContainerClient; 6 | import com.azure.storage.blob.BlobContainerClientBuilder; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.IOException; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * This class is a proxy to the Blob storage client. It is responsible for: 14 | * - calling the API 15 | * - handling errors and retry strategy 16 | * - add monitoring points 17 | * - add circuit breaker with exponential backoff 18 | */ 19 | @Component 20 | public class BlobStorageProxy { 21 | 22 | private final BlobContainerClient client; 23 | 24 | public BlobStorageProxy( 25 | @Value("${storage-account.service}") String storageAccountServiceName, 26 | @Value("${blob.container.name}") String containerName, 27 | TokenCredential tokenCredential) { 28 | 29 | String endpoint = "https://%s.blob.core.windows.net".formatted(storageAccountServiceName); 30 | this.client = 31 | new BlobContainerClientBuilder() 32 | .endpoint(endpoint) 33 | .credential(tokenCredential) 34 | .containerName(containerName) 35 | .buildClient(); 36 | } 37 | 38 | public byte[] getFileAsBytes(String fileName) throws IOException { 39 | var blobClient = client.getBlobClient(fileName); 40 | int dataSize = (int) blobClient.getProperties().getBlobSize(); 41 | 42 | // There is no need to close ByteArrayOutputStream. 43 | // https://docs.oracle.com/javase/8/docs/api/java/io/ByteArrayOutputStream.html 44 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(dataSize); 45 | blobClient.downloadStream(outputStream); 46 | 47 | return outputStream.toByteArray(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/retrieval/FactsRetrieverProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.retrieval; 3 | 4 | import com.microsoft.openai.samples.rag.approaches.RAGOptions; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.context.ApplicationContextAware; 7 | import org.springframework.stereotype.Component; 8 | 9 | 10 | /** 11 | * RAG retriever provider that provides the appropriate retriever based on the options. 12 | * Currently only supports Azure AI Search. More useful in the future to support multiple retrieval systems (RedisSearch.Pinecone, etc). 13 | * This class is used with RAG implemented with plain openai java client. It's not needed when using semantic kernel memory or vector store 14 | * abstractions implementations 15 | */ 16 | @Component 17 | public class FactsRetrieverProvider implements ApplicationContextAware { 18 | private ApplicationContext applicationContext; 19 | 20 | /** 21 | * @param options rag options containing search types(Cognitive Semantic Search, Cognitive 22 | * Vector Search, Cognitive Hybrid Search) Default is now cognitive search. 23 | * @return retriever implementation 24 | */ 25 | public Retriever getFactsRetriever(RAGOptions options) { 26 | // default to Azure AI search Semantic Search for MVP. More useful in the future to support 27 | // multiple retrieval systems (RedisSearch.Pinecone, etc) 28 | switch (options.getRetrievalMode()) { 29 | case vectors, hybrid, text: 30 | return this.applicationContext.getBean(AzureAISearchRetriever.class); 31 | default: 32 | return this.applicationContext.getBean(AzureAISearchRetriever.class); 33 | } 34 | } 35 | 36 | public void setApplicationContext(ApplicationContext applicationContext) { 37 | this.applicationContext = applicationContext; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/backend/src/main/java/com/microsoft/openai/samples/rag/retrieval/Retriever.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.retrieval; 3 | 4 | import com.microsoft.openai.samples.rag.approaches.ContentSource; 5 | import com.microsoft.openai.samples.rag.approaches.RAGOptions; 6 | import com.microsoft.openai.samples.rag.common.ChatGPTConversation; 7 | import java.util.List; 8 | 9 | /** 10 | * Interface for RAG facts retrievers that can retrieve content from a one shot question or a chat conversation. 11 | * RAGOptions can be used to specify the retrieval strategy. 12 | */ 13 | public interface Retriever { 14 | 15 | List retrieveFromQuestion(String question, RAGOptions ragOptions); 16 | 17 | List retrieveFromConversation( 18 | ChatGPTConversation conversation, RAGOptions ragOptions); 19 | } 20 | -------------------------------------------------------------------------------- /app/backend/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #Used to enable mocked class to take precedence over real class in unit tests 2 | spring.main.lazy-initialization=true 3 | 4 | openai.service=${AZURE_OPENAI_SERVICE} 5 | openai.chatgpt.deployment=${AZURE_OPENAI_CHATGPT_DEPLOYMENT:chat} 6 | openai.embedding.deployment=${AZURE_OPENAI_EMB_DEPLOYMENT:embedding} 7 | openai.tracing.enabled=${AZURE_OPENAI_TRACING_ENABLED:true} 8 | 9 | cognitive.search.service=${AZURE_SEARCH_SERVICE:example} 10 | cognitive.search.index=${AZURE_SEARCH_INDEX:gptkbindex} 11 | cognitive.tracing.enabled=${AZURE_SEARCH_TRACING_ENABLED:true} 12 | 13 | 14 | storage-account.service=${AZURE_STORAGE_ACCOUNT} 15 | blob.container.name=${AZURE_STORAGE_CONTAINER:content} 16 | 17 | logging.level.com.microsoft.openai.samples.rag.ask.approaches.semantickernel=DEBUG 18 | server.error.include-message=always 19 | 20 | # Support for User Assigned Managed identity 21 | azure.identity.client-id=${AZURE_CLIENT_ID:system-managed-identity} -------------------------------------------------------------------------------- /app/backend/src/main/resources/semantickernel/Plugins/RAG/ExtractKeywords/extractKeywords.prompt.yaml: -------------------------------------------------------------------------------- 1 | name: ExtractKeywords 2 | description: Extract keywords from a conversation to form a search query. 3 | template: | 4 | 5 | Generate a search query for the below conversation. 6 | Do not include cited source filenames and document names e.g info.txt or doc.pdf in the search query terms. 7 | Do not include any text inside [] or <<>> in the search query terms. 8 | Do not enclose the search query in quotes or double quotes. 9 | conversation: 10 | 11 | 12 | {{#each conversation}} 13 | {{content}} 14 | {{/each}} 15 | template_format: handlebars 16 | input_variables: 17 | - name: conversation 18 | description: Chat conversation 19 | is_required: true 20 | execution_settings: 21 | default: 22 | max_tokens: 1024 23 | temperature: 0.2 24 | top_p: 1 25 | presence_penalty: 0.0 26 | frequency_penalty: 0.0 27 | -------------------------------------------------------------------------------- /app/backend/src/test/java/com/microsoft/openai/samples/rag/ChatAPITest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag; 3 | 4 | import java.net.URI; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.boot.test.web.client.TestRestTemplate; 9 | import org.springframework.test.context.ActiveProfiles; 10 | 11 | @ActiveProfiles("test") 12 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 13 | class ChatAPITest { 14 | 15 | @Autowired private TestRestTemplate restTemplate; 16 | 17 | @Test 18 | void testExample() throws Exception { 19 | // TODO This test is failing due to external services dependencies. 20 | // Explore springmockserver to mock the external services response based on specific 21 | // requests. Sevices to mock are: Azure token, Cognitive Search, OpenAI chat apis 22 | /** 23 | * ChatTurn chatTurn = new ChatTurn(); chatTurn.setUserText("What does a Product Manager 24 | * do?"); List chatTurns = new ArrayList<>(); chatTurns.add(chatTurn); 25 | * 26 | *

ChatRequest chatRequest = new ChatRequest(); chatRequest.setChatHistory(chatTurns); 27 | * chatRequest.setApproach("rrr"); HttpEntity request = new 28 | * HttpEntity<>(chatRequest); 29 | * 30 | *

ResponseEntity result = 31 | * this.restTemplate.postForEntity(uri("/api/chat"), chatRequest, ChatResponse.class); 32 | * 33 | *

assertEquals(HttpStatus.OK, result.getStatusCode()); 34 | */ 35 | } 36 | 37 | private URI uri(String path) { 38 | return restTemplate.getRestTemplate().getUriTemplateHandler().expand(path); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/backend/src/test/java/com/microsoft/openai/samples/rag/test/config/ProxyMockConfiguration.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.rag.test.config; 3 | 4 | import com.azure.ai.openai.OpenAIAsyncClient; 5 | import com.microsoft.openai.samples.rag.proxy.AzureAISearchProxy; 6 | import com.microsoft.openai.samples.rag.proxy.BlobStorageProxy; 7 | import com.microsoft.openai.samples.rag.proxy.OpenAIProxy; 8 | import org.mockito.Mockito; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.context.annotation.Primary; 12 | import org.springframework.context.annotation.Profile; 13 | 14 | @Profile("test") 15 | @Configuration 16 | public class ProxyMockConfiguration { 17 | 18 | @Bean 19 | @Primary 20 | public AzureAISearchProxy mockedCognitiveSearchProxy() { 21 | return Mockito.mock(AzureAISearchProxy.class); 22 | } 23 | 24 | @Bean 25 | @Primary 26 | public OpenAIProxy mockedOpenAISearchProxy() { 27 | return Mockito.mock(OpenAIProxy.class); 28 | } 29 | 30 | @Bean 31 | @Primary 32 | public BlobStorageProxy mockedBlobStorageProxy() { 33 | return Mockito.mock(BlobStorageProxy.class); 34 | } 35 | 36 | @Bean 37 | @Primary 38 | public OpenAIAsyncClient mockedOpenAIAsynchClient() { 39 | return Mockito.mock(OpenAIAsyncClient.class); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | manifests 2 | node_modules -------------------------------------------------------------------------------- /app/frontend/.env.dev: -------------------------------------------------------------------------------- 1 | VITE_BACKEND_URI=http://localhost:8081/api 2 | -------------------------------------------------------------------------------- /app/frontend/.env.local: -------------------------------------------------------------------------------- 1 | VITE_BACKEND_URI=http://localhost:8081/api 2 | -------------------------------------------------------------------------------- /app/frontend/.env.production: -------------------------------------------------------------------------------- 1 | VITE_BACKEND_URI=/api 2 | 3 | -------------------------------------------------------------------------------- /app/frontend/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /app/frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore JSON 2 | **/*.json 3 | -------------------------------------------------------------------------------- /app/frontend/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "printWidth": 160, 4 | "arrowParens": "avoid", 5 | "trailingComma": "none" 6 | } 7 | -------------------------------------------------------------------------------- /app/frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine AS build 2 | 3 | # make the 'app' folder the current working directory 4 | WORKDIR /app 5 | 6 | COPY . . 7 | 8 | 9 | # install project dependencies 10 | RUN npm install 11 | RUN npm run build 12 | 13 | FROM nginx:alpine 14 | 15 | WORKDIR /usr/share/nginx/html 16 | COPY --from=build /app/build . 17 | COPY --from=build /app/nginx/nginx.conf.template /etc/nginx/conf.d 18 | 19 | EXPOSE 80 20 | 21 | CMD ["/bin/sh", "-c", "envsubst < /etc/nginx/conf.d/nginx.conf.template > /etc/nginx/conf.d/default.conf && nginx -g \"daemon off;\""] 22 | -------------------------------------------------------------------------------- /app/frontend/Dockerfile-aks: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine AS build 2 | 3 | # make the 'app' folder the current working directory 4 | WORKDIR /app 5 | 6 | COPY . . 7 | 8 | 9 | # install project dependencies 10 | RUN npm install 11 | RUN npm run build 12 | 13 | FROM nginx:alpine 14 | 15 | WORKDIR /usr/share/nginx/html 16 | COPY --from=build /app/build . 17 | 18 | EXPOSE 80 19 | 20 | CMD ["/bin/sh", "-c", "nginx -g \"daemon off;\""] -------------------------------------------------------------------------------- /app/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPT + Enterprise data | Java Sample 8 | 9 | 10 |

11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/frontend/manifests/frontend-deployment.tmpl.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: frontend-deployment 5 | namespace: azure-open-ai 6 | labels: 7 | app: frontend 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: frontend 13 | template: 14 | metadata: 15 | labels: 16 | app: frontend 17 | spec: 18 | containers: 19 | - name: frontend 20 | image: {{.Env.SERVICE_FRONTEND_IMAGE_NAME}} 21 | imagePullPolicy: IfNotPresent 22 | ports: 23 | - containerPort: 80 24 | envFrom: 25 | - configMapRef: 26 | name: azd-env-configmap 27 | -------------------------------------------------------------------------------- /app/frontend/manifests/frontend-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: frontend-service 5 | namespace: azure-open-ai 6 | spec: 7 | type: ClusterIP 8 | ports: 9 | - protocol: TCP 10 | port: 80 11 | targetPort: 80 12 | selector: 13 | app: frontend 14 | -------------------------------------------------------------------------------- /app/frontend/nginx/nginx.conf.template: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | location / { 4 | root /usr/share/nginx/html; 5 | index index.html index.htm; 6 | } 7 | 8 | location /api { 9 | proxy_ssl_server_name on; 10 | proxy_http_version 1.1; 11 | proxy_pass $REACT_APP_API_BASE_URL; 12 | } 13 | } -------------------------------------------------------------------------------- /app/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "1.4.0-alpha", 5 | "type": "module", 6 | "engines": { 7 | "node": ">=14.0.0" 8 | }, 9 | "scripts": { 10 | "dev": "vite --port=8081", 11 | "build": "tsc && vite build", 12 | "preview": "vite preview" 13 | }, 14 | "dependencies": { 15 | "@azure/msal-browser": "^3.1.0", 16 | "@azure/msal-react": "^2.0.4", 17 | "@fluentui/react": "^8.112.5", 18 | "@fluentui/react-components": "^9.37.3", 19 | "@fluentui/react-icons": "^2.0.221", 20 | "@react-spring/web": "^9.7.3", 21 | "dompurify": "^3.1.3", 22 | "frontend": "file:", 23 | "ndjson-readablestream": "^1.0.7", 24 | "react": "^18.2.0", 25 | "react-dom": "^18.2.0", 26 | "react-router-dom": "^6.18.0", 27 | "scheduler": "^0.20.2" 28 | }, 29 | "devDependencies": { 30 | "@types/dompurify": "^3.0.3", 31 | "@types/react": "^18.2.34", 32 | "@types/react-dom": "^18.2.14", 33 | "@vitejs/plugin-react": "^4.1.1", 34 | "prettier": "^3.0.3", 35 | "typescript": "^5.2.2", 36 | "vite": "^4.5.5" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/azure-search-openai-demo-java/e9b5f67d6d98c22aaa3a778fb9a10c46d304e7b8/app/frontend/public/favicon.ico -------------------------------------------------------------------------------- /app/frontend/src/api/api.ts: -------------------------------------------------------------------------------- 1 | import { ChatAppResponse, ChatAppResponseOrError, ChatAppRequest } from "./models"; 2 | import { useLogin } from "../authConfig"; 3 | 4 | const BACKEND_URI = import.meta.env.VITE_BACKEND_URI ? import.meta.env.VITE_BACKEND_URI : ""; 5 | 6 | function getHeaders(idToken: string | undefined, stream:boolean): Record { 7 | var headers: Record = { 8 | "Content-Type": "application/json" 9 | }; 10 | // If using login, add the id token of the logged in account as the authorization 11 | if (useLogin) { 12 | if (idToken) { 13 | headers["Authorization"] = `Bearer ${idToken}` 14 | } 15 | } 16 | 17 | if (stream) { 18 | headers["Accept"] = "application/x-ndjson"; 19 | } else { 20 | headers["Accept"] = "application/json"; 21 | } 22 | 23 | return headers; 24 | } 25 | 26 | export async function askApi(request: ChatAppRequest, idToken: string | undefined): Promise { 27 | const response = await fetch(`${BACKEND_URI}/ask`, { 28 | method: "POST", 29 | headers: getHeaders(idToken, request.stream || false), 30 | body: JSON.stringify(request) 31 | }); 32 | 33 | const parsedResponse: ChatAppResponseOrError = await response.json(); 34 | if (response.status > 299 || !response.ok) { 35 | throw Error(parsedResponse.error || "Unknown error"); 36 | } 37 | 38 | return parsedResponse as ChatAppResponse; 39 | } 40 | 41 | export async function chatApi(request: ChatAppRequest, idToken: string | undefined): Promise { 42 | return await fetch(`${BACKEND_URI}/chat`, { 43 | method: "POST", 44 | headers: getHeaders(idToken, request.stream || false), 45 | body: JSON.stringify(request) 46 | }); 47 | } 48 | 49 | export function getCitationFilePath(citation: string): string { 50 | return `${BACKEND_URI}/content/${citation}`; 51 | } 52 | -------------------------------------------------------------------------------- /app/frontend/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./api"; 2 | export * from "./models"; 3 | -------------------------------------------------------------------------------- /app/frontend/src/api/models.ts: -------------------------------------------------------------------------------- 1 | export const enum Approaches { 2 | JAVA_OPENAI_SDK = "jos", 3 | JAVA_SEMANTIC_KERNEL = "jsk", 4 | JAVA_SEMANTIC_KERNEL_PLANNER = "jskp" 5 | } 6 | 7 | export const enum RetrievalMode { 8 | Hybrid = "hybrid", 9 | Vectors = "vectors", 10 | Text = "text" 11 | } 12 | 13 | export const enum SKMode { 14 | Chains = "chains", 15 | Planner = "planner" 16 | } 17 | 18 | export type ChatAppRequestOverrides = { 19 | retrieval_mode?: RetrievalMode; 20 | semantic_ranker?: boolean; 21 | semantic_captions?: boolean; 22 | exclude_category?: string; 23 | top?: number; 24 | temperature?: number; 25 | prompt_template?: string; 26 | prompt_template_prefix?: string; 27 | prompt_template_suffix?: string; 28 | suggest_followup_questions?: boolean; 29 | use_oid_security_filter?: boolean; 30 | use_groups_security_filter?: boolean; 31 | semantic_kernel_mode?: SKMode; 32 | }; 33 | 34 | export type ResponseMessage = { 35 | content: string; 36 | role: string; 37 | }; 38 | 39 | export type ResponseContext = { 40 | thoughts: string | null; 41 | data_points: string[]; 42 | }; 43 | 44 | export type ResponseChoice = { 45 | index: number; 46 | message: ResponseMessage; 47 | context: ResponseContext; 48 | session_state: any; 49 | }; 50 | 51 | export type ChatAppResponseOrError = { 52 | choices?: ResponseChoice[]; 53 | error?: string; 54 | }; 55 | 56 | export type ChatAppResponse = { 57 | choices: ResponseChoice[]; 58 | }; 59 | 60 | export type ChatAppRequestContext = { 61 | overrides?: ChatAppRequestOverrides; 62 | }; 63 | 64 | export type ChatAppRequest = { 65 | messages: ResponseMessage[]; 66 | approach: Approaches; 67 | context?: ChatAppRequestContext; 68 | stream?: boolean; 69 | session_state: any; 70 | }; 71 | -------------------------------------------------------------------------------- /app/frontend/src/assets/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/frontend/src/assets/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/frontend/src/components/AnalysisPanel/AnalysisPanel.module.css: -------------------------------------------------------------------------------- 1 | .thoughtProcess { 2 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; 3 | word-wrap: break-word; 4 | padding-top: 12px; 5 | padding-bottom: 12px; 6 | } 7 | -------------------------------------------------------------------------------- /app/frontend/src/components/AnalysisPanel/AnalysisPanelTabs.tsx: -------------------------------------------------------------------------------- 1 | export enum AnalysisPanelTabs { 2 | ThoughtProcessTab = "thoughtProcess", 3 | SupportingContentTab = "supportingContent", 4 | CitationTab = "citation" 5 | } 6 | -------------------------------------------------------------------------------- /app/frontend/src/components/AnalysisPanel/index.tsx: -------------------------------------------------------------------------------- 1 | export * from "./AnalysisPanel"; 2 | export * from "./AnalysisPanelTabs"; 3 | -------------------------------------------------------------------------------- /app/frontend/src/components/Answer/AnswerError.tsx: -------------------------------------------------------------------------------- 1 | import { Stack, PrimaryButton } from "@fluentui/react"; 2 | import { ErrorCircle24Regular } from "@fluentui/react-icons"; 3 | 4 | import styles from "./Answer.module.css"; 5 | 6 | interface Props { 7 | error: string; 8 | onRetry: () => void; 9 | } 10 | 11 | export const AnswerError = ({ error, onRetry }: Props) => { 12 | return ( 13 | 14 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /app/frontend/src/components/Answer/AnswerIcon.tsx: -------------------------------------------------------------------------------- 1 | import { Sparkle28Filled } from "@fluentui/react-icons"; 2 | 3 | export const AnswerIcon = () => { 4 | return