├── .azdo └── pipelines │ └── azure-dev.yml ├── .coveragerc ├── .devcontainer ├── devcontainer.json └── setup_env.sh ├── .flake8 ├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── subtask.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── Scheduled-Dependabot-PRs-Auto-Merge.yml │ ├── azure-dev-validation.yml │ ├── bicep_deploy.yml │ ├── codeql.yml │ ├── create-release.yml │ ├── deploy-KMGeneric.yml │ ├── deploy.yml │ ├── docker-build.yml │ ├── pr-title-checker.yml │ ├── pylint.yml │ ├── stale-bot.yml │ └── test.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── TRANSPARENCY_FAQ.md ├── azure.yaml ├── docs └── workshop │ ├── README.md │ ├── docs │ ├── index.md │ └── workshop │ │ ├── .env.sample │ │ ├── 00-Use-Case-Scenerio.md │ │ ├── Challenge-0 │ │ ├── CU-Challenge.md │ │ └── index.md │ │ ├── Challenge-1 │ │ ├── Code_Walkthrough │ │ │ ├── 01_Data_Explore.md │ │ │ ├── 02_Frontend.md │ │ │ ├── 03_Backend.md │ │ │ └── 04_Api.md │ │ ├── Deployment.md │ │ └── Solution_Overview.md │ │ ├── Challenge-2 │ │ └── index.md │ │ ├── Challenge-3-and-4 │ │ ├── Challenge-3.md │ │ ├── Challenge-4.md │ │ ├── index.md │ │ └── knowledge_mining_api.ipynb │ │ ├── Challenge-5 │ │ ├── analyzer_templates │ │ │ ├── video_content_understanding.json │ │ │ └── video_tag.json │ │ ├── data │ │ │ └── FlightSimulator.mp4 │ │ ├── docs │ │ │ ├── create_azure_ai_service.md │ │ │ ├── create_srv_1.png │ │ │ ├── create_srv_2.png │ │ │ └── create_srv_3.png │ │ ├── index.md │ │ ├── notebooks │ │ │ ├── .env.sample │ │ │ ├── video_chapter_generation.ipynb │ │ │ └── video_tag_generation.ipynb │ │ ├── python │ │ │ ├── content_understanding_client.py │ │ │ └── utility.py │ │ └── requirements.txt │ │ ├── Challenge-6 │ │ ├── Content_safety_evaluation.ipynb │ │ ├── Sample_content_safety_output_scores.jsonl │ │ └── index.md │ │ ├── Challenge-data │ │ ├── Analyzer.md │ │ └── data.md │ │ ├── Tear-Down │ │ └── index.md │ │ ├── data │ │ ├── FlightSimulator.mp4 │ │ └── convo_2c703f97-6657-4a15-b8b2-db6b96630b2d_2024-12-06 06_00_00.wav │ │ ├── img │ │ ├── ReadMe │ │ │ ├── ckm-sol-arch.png │ │ │ ├── ckm-ui.png │ │ │ ├── customerTruth.png │ │ │ ├── quickDeploy.png │ │ │ ├── quotaImage.png │ │ │ ├── techkeyfeatures.png │ │ │ └── userStory.png │ │ ├── ai-services-landing-page.png │ │ ├── audio-folder.png │ │ ├── avg_time_handling.png │ │ ├── billing_summary.png │ │ ├── build-analyzer.png │ │ ├── call_transcripts.png │ │ ├── chart_screenshot.png │ │ ├── common_calls.png │ │ ├── create_project.png │ │ ├── cu-landing-page.png │ │ ├── cu-upload-document.png │ │ ├── data-folders.png │ │ ├── define-schema-template-selection.png │ │ ├── define-schema.png │ │ ├── numer_of_calls.png │ │ ├── portal-app-api-env.png │ │ ├── storage-blob.png │ │ ├── storage-container.png │ │ ├── test-analyzer-results.png │ │ ├── test-analyzer.png │ │ └── top_challenge.png │ │ ├── index.md │ │ ├── requirements.txt │ │ └── support-docs │ │ ├── AzureGPTQuotaSettings.md │ │ └── quota_check.md │ ├── mkdocs.yml │ └── overrides │ └── main.html ├── documents ├── AppAuthentication.md ├── AzureAccountSetUp.md ├── AzureGPTQuotaSettings.md ├── AzureSemanticSearchRegion.md ├── ConversationalDataFormat.md ├── CustomizeData.md ├── CustomizingAzdParameters.md ├── DeleteResourceGroup.md ├── DeploymentGuide.md ├── Fabric_deployment.md ├── Images │ ├── AddDetails.png │ ├── AddPlatform.png │ ├── AddRedirectURL.png │ ├── AppAuthIdentityProvider.png │ ├── AppAuthIdentityProviderAdd.png │ ├── AppAuthIdentityProviderAdded.png │ ├── AppAuthentication.png │ ├── AppAuthenticationIdentity.png │ ├── Appregistrations.png │ ├── DeleteRG.png │ ├── MicrosoftEntraID.png │ ├── NewRegistration.png │ ├── ReadMe │ │ ├── business-scenario.png │ │ ├── quick-deploy.png │ │ ├── quotaImage.png │ │ ├── solution-architecture.png │ │ ├── solution-overview.png │ │ ├── supporting-documentation.png │ │ └── ui.png │ ├── Web.png │ ├── WebAppURL.png │ ├── deleteservices.png │ ├── git_bash.png │ ├── quota-check-output.png │ ├── resource-groups.png │ └── resourcegroup.png ├── PowershellSetup.md ├── QuotaCheck.md ├── TechnicalArchitecture.md └── create_new_app_registration.md ├── infra ├── abbreviations.json ├── build_bicep.md ├── data │ ├── audio_data.zip │ ├── call_transcripts.zip │ ├── ckm-analyzer_config_audio.json │ ├── ckm-analyzer_config_text.json │ ├── sample_processed_data.json │ ├── sample_processed_data_key_phrases.json │ └── sample_search_index_data.json ├── deploy_ai_foundry.bicep ├── deploy_app_service.bicep ├── deploy_app_service_plan.bicep ├── deploy_appservice-appsettings.bicep ├── deploy_backend_docker.bicep ├── deploy_cosmos_db.bicep ├── deploy_frontend_docker.bicep ├── deploy_keyvault.bicep ├── deploy_managed_identity.bicep ├── deploy_post_deployment_scripts.bicep ├── deploy_sql_db.bicep ├── deploy_storage_account.bicep ├── main.bicep ├── main.bicepparam ├── main.json ├── modules │ └── fetch-container-image.bicep ├── process_data_scripts.bicep ├── resources.bicep └── scripts │ ├── add_user_scripts │ └── create-sql-user-and-role.ps1 │ ├── checkquota_ckmv2.sh │ ├── checkquota_km.sh │ ├── copy_kb_files.sh │ ├── fabric_scripts │ ├── ckm_cu_env.yml │ ├── ckm_environment.yml │ ├── create_fabric_items.py │ ├── notebooks │ │ ├── 00_process_json_files.ipynb │ │ ├── 01_process_audio_files.ipynb │ │ ├── 02_enrich_audio_data.ipynb │ │ ├── 03_post_processing.ipynb │ │ ├── 04_create_calendar_data.ipynb │ │ ├── cu │ │ │ ├── create_cu_template.ipynb │ │ │ ├── cu_pipeline_notebook.ipynb │ │ │ └── process_cu_data.ipynb │ │ ├── pipeline_notebook.ipynb │ │ └── speech_to_text │ │ │ ├── process_data_stt.ipynb │ │ │ └── topic_modeling_stt.ipynb │ ├── requirements.txt │ └── run_fabric_items_scripts.sh │ ├── index_scripts │ ├── 01_create_search_index.py │ ├── 02_create_cu_template_audio.py │ ├── 02_create_cu_template_text.py │ ├── 03_cu_process_data_text.py │ ├── 04_cu_process_data_new_data.py │ ├── content_understanding_client.py │ └── requirements.txt │ ├── process_data_scripts.sh │ ├── quota_check_params.sh │ ├── run_create_index_scripts.sh │ └── run_process_data_scripts.sh ├── next-steps.md ├── pytest.ini └── src ├── .flake8 ├── .gitignore ├── App ├── .dockerignore ├── .env ├── .gitignore ├── .npmrc ├── README.md ├── WebApp.Dockerfile ├── env.sh ├── package-lock.json ├── package.json ├── public │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── config │ │ └── config.json │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── index.html │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── Assets │ │ ├── ContosoImg.png │ │ ├── Reset-icon.svg │ │ ├── Sparkle.png │ │ ├── Sparkle.svg │ │ └── km_logo.png │ ├── api │ │ └── api.ts │ ├── chartComponents │ │ ├── Card.tsx │ │ ├── DonutChart.tsx │ │ ├── HorizontalBarChart.tsx │ │ ├── TopicTable.tsx │ │ └── WordCloudChart.tsx │ ├── components │ │ ├── Chart │ │ │ ├── Chart.css │ │ │ └── Chart.tsx │ │ ├── ChartFilter │ │ │ ├── ChartFilter.css │ │ │ └── ChartFilter.tsx │ │ ├── Chat │ │ │ ├── Chat.css │ │ │ └── Chat.tsx │ │ ├── ChatChart │ │ │ └── ChatChart.tsx │ │ ├── ChatHistory │ │ │ ├── ChatHistory.css │ │ │ └── ChatHistory.tsx │ │ ├── ChatHistoryListItemCell │ │ │ ├── ChatHistoryListItemCell.module.css │ │ │ └── ChatHistoryListItemCell.tsx │ │ ├── ChatHistoryListItemGroups │ │ │ ├── ChatHistoryListItemGroups.module.css │ │ │ └── ChatHistoryListItemGroups.tsx │ │ ├── ChatHistoryPanel │ │ │ ├── ChatHistoryPanel.module.css │ │ │ └── ChatHistoryPanel.tsx │ │ ├── CitationPanel │ │ │ ├── CitationPanel.css │ │ │ └── CitationPanel.tsx │ │ ├── Citations │ │ │ ├── AnswerParser.tsx │ │ │ ├── Citations.css │ │ │ └── Citations.tsx │ │ ├── CustomSpinner │ │ │ ├── CustomSpinner.module.css │ │ │ └── CustomSpinner.tsx │ │ ├── NoData │ │ │ └── NoData.tsx │ │ └── Svg │ │ │ └── Svg.tsx │ ├── configs │ │ ├── StaticData.tsx │ │ └── Utils.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── react-app-env.d.ts │ ├── reportWebVitals.ts │ ├── setupTests.ts │ ├── state │ │ ├── ActionConstants.tsx │ │ ├── AppProvider.tsx │ │ ├── AppReducer.tsx │ │ └── useAppContext.tsx │ └── types │ │ ├── AppTypes.ts │ │ └── d3-cloud.d.ts └── tsconfig.json ├── api ├── .dockerignore ├── .env.sample ├── .gitignore ├── ApiApp.Dockerfile ├── agents │ └── agent_factory.py ├── api │ ├── api_routes.py │ ├── history_routes.py │ └── models │ │ └── input_models.py ├── app.py ├── auth │ ├── auth_utils.py │ └── sample_user.py ├── common │ ├── config │ │ └── config.py │ ├── database │ │ ├── cosmosdb_service.py │ │ └── sqldb_service.py │ └── logging │ │ └── event_utils.py ├── helpers │ ├── chat_helper.py │ ├── streaming_helper.py │ └── utils.py ├── plugins │ └── chat_with_data_plugin.py ├── requirements.txt └── services │ ├── chart_service.py │ ├── chat_service.py │ └── history_service.py ├── asset-manifest.json ├── favicon-16x16.png ├── favicon-32x32.png ├── gunicorn.conf.py ├── manifest.json ├── start.cmd ├── start.sh └── tests ├── __init__.py ├── api ├── agents │ └── test_agent_factory.py ├── api │ ├── test_api_routes.py │ └── test_history_routes.py ├── auth │ └── test_auth_utils.py ├── common │ ├── config │ │ └── test_config.py │ ├── database │ │ ├── test_cosmosdb_service.py │ │ └── test_sqldb_service.py │ └── logging │ │ └── test_event_utils.py ├── helpers │ ├── test_chat_helper.py │ ├── test_streaming_helper.py │ └── test_utils.py ├── plugins │ └── test_chat_with_data_plugin.py └── services │ ├── test_chart_service.py │ ├── test_chat_service.py │ └── test_history_service.py └── test_app.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | */test_*.py 4 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "azd-template", 3 | "image": "mcr.microsoft.com/devcontainers/python:3.11-bullseye", 4 | "forwardPorts": [50505], 5 | "features": { 6 | "ghcr.io/azure/azure-dev/azd:latest": {}, 7 | "ghcr.io/devcontainers/features/azure-cli:1": {} 8 | }, 9 | "customizations": { 10 | "vscode": { 11 | "extensions": [ 12 | "ms-azuretools.azure-dev", 13 | "ms-azuretools.vscode-bicep", 14 | "ms-python.python", 15 | "ms-toolsai.jupyter", 16 | "GitHub.vscode-github-actions" 17 | ] 18 | } 19 | }, 20 | "postStartCommand": "bash ./.devcontainer/setup_env.sh", 21 | "remoteUser": "vscode", 22 | "hostRequirements": { 23 | "memory": "4gb" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.devcontainer/setup_env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git fetch 4 | git pull 5 | 6 | # provide execute permission to quotacheck script 7 | sudo chmod +x ./infra/scripts/checkquota_km.sh 8 | sudo chmod +x ./infra/scripts/quota_check_params.sh 9 | sudo chmod +x ./infra/scripts/run_process_data_scripts.sh -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | extend-ignore = E501 4 | exclude = .venv, frontend 5 | ignore = E203, W503, G004, G200 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in the repo. 5 | * @Avijit-Microsoft @Roopan-Microsoft @Prajwal-Microsoft @aniaroramsft @brittneek @Vinay-Microsoft 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Describe the bug 11 | A clear and concise description of what the bug is. 12 | 13 | # Expected behavior 14 | A clear and concise description of what you expected to happen. 15 | 16 | # How does this bug make you feel? 17 | _Share a gif from [giphy](https://giphy.com/) to tells us how you'd feel_ 18 | 19 | --- 20 | 21 | # Debugging information 22 | 23 | ## Steps to reproduce 24 | Steps to reproduce the behavior: 25 | 1. Go to '...' 26 | 2. Click on '....' 27 | 3. Scroll down to '....' 28 | 4. See error 29 | 30 | ## Screenshots 31 | If applicable, add screenshots to help explain your problem. 32 | 33 | ## Logs 34 | 35 | If applicable, add logs to help the engineer debug the problem. 36 | 37 | --- 38 | 39 | # Tasks 40 | 41 | _To be filled in by the engineer picking up the issue_ 42 | 43 | - [ ] Task 1 44 | - [ ] Task 2 45 | - [ ] ... 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Motivation 11 | 12 | A clear and concise description of why this feature would be useful and the value it would bring. 13 | Explain any alternatives considered and why they are not sufficient. 14 | 15 | # How would you feel if this feature request was implemented? 16 | 17 | _Share a gif from [giphy](https://giphy.com/) to tells us how you'd feel. Format: ![alt_text](https://media.giphy.com/media/xxx/giphy.gif)_ 18 | 19 | # Requirements 20 | 21 | A list of requirements to consider this feature delivered 22 | - Requirement 1 23 | - Requirement 2 24 | - ... 25 | 26 | # Tasks 27 | 28 | _To be filled in by the engineer picking up the issue_ 29 | 30 | - [ ] Task 1 31 | - [ ] Task 2 32 | - [ ] ... 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/subtask.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Sub task 3 | about: A sub task 4 | title: '' 5 | labels: subtask 6 | assignees: '' 7 | 8 | --- 9 | 10 | Required by 11 | 12 | # Description 13 | 14 | A clear and concise description of what this subtask is. 15 | 16 | # Tasks 17 | 18 | _To be filled in by the engineer picking up the subtask 19 | 20 | - [ ] Task 1 21 | - [ ] Task 2 22 | - [ ] ... 23 | -------------------------------------------------------------------------------- /.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 | 25 | 26 | ## Golden Path Validation 27 | - [ ] I have tested the primary workflows (the "golden path") to ensure they function correctly without errors. 28 | 29 | ## Deployment Validation 30 | - [ ] I have validated the deployment process successfully and all services are running as expected with this change. 31 | 32 | ## What to Check 33 | Verify that the following are valid 34 | * ... 35 | 36 | ## Other Information 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | # GitHub Actions - grouped 5 | - package-ecosystem: "github-actions" 6 | directory: "/" 7 | schedule: 8 | interval: "monthly" 9 | target-branch: "dependabotchanges" 10 | commit-message: 11 | prefix: "build" 12 | open-pull-requests-limit: 10 13 | groups: 14 | github-actions: 15 | patterns: 16 | - "*" 17 | 18 | # Python backend dependencies - grouped 19 | - package-ecosystem: "pip" 20 | directory: "/src/api" 21 | schedule: 22 | interval: "monthly" 23 | target-branch: "dependabotchanges" 24 | commit-message: 25 | prefix: "build" 26 | open-pull-requests-limit: 10 27 | groups: 28 | backend-deps: 29 | patterns: 30 | - "*" 31 | 32 | # Frontend npm dependencies - grouped 33 | - package-ecosystem: "npm" 34 | directory: "/src/App" 35 | schedule: 36 | interval: "monthly" 37 | target-branch: "dependabotchanges" 38 | commit-message: 39 | prefix: "build" 40 | open-pull-requests-limit: 10 41 | registries: 42 | - npm_public_registry 43 | groups: 44 | frontend-deps: 45 | patterns: 46 | - "*" 47 | 48 | registries: 49 | npm_public_registry: 50 | type: "npm-registry" 51 | url: "https://registry.npmjs.org/" 52 | token: ${{ secrets.TOKEN }} 53 | -------------------------------------------------------------------------------- /.github/workflows/azure-dev-validation.yml: -------------------------------------------------------------------------------- 1 | name: Azure Template Validation 2 | on: 3 | workflow_dispatch: 4 | 5 | permissions: 6 | contents: read 7 | id-token: write 8 | pull-requests: write 9 | 10 | jobs: 11 | template_validation_job: 12 | runs-on: ubuntu-latest 13 | name: Template validation 14 | 15 | steps: 16 | # Step 1: Checkout the code from your repository 17 | - name: Checkout code 18 | uses: actions/checkout@v4 19 | 20 | # Step 2: Validate the Azure template using microsoft/template-validation-action 21 | - name: Validate Azure Template 22 | uses: microsoft/template-validation-action@v0.3.5 23 | id: validation 24 | env: 25 | AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} 26 | AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} 27 | AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} 28 | AZURE_ENV_NAME: ${{ secrets.AZURE_ENV_NAME }} 29 | AZURE_LOCATION: ${{ secrets.AZURE_LOCATION }} 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | 32 | # Step 3: Print the result of the validation 33 | - name: Print result 34 | run: cat ${{ steps.validation.outputs.resultFile }} -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: "Create Release" 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | 7 | workflow_dispatch: 8 | 9 | permissions: 10 | contents: write 11 | pull-requests: write 12 | 13 | jobs: 14 | create-release: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v4 19 | with: 20 | ref: ${{ github.sha }} 21 | 22 | - uses: codfish/semantic-release-action@v3 23 | id: semantic 24 | with: 25 | tag-format: 'v${version}' 26 | additional-packages: | 27 | ['conventional-changelog-conventionalcommits@7'] 28 | plugins: | 29 | [ 30 | [ 31 | "@semantic-release/commit-analyzer", 32 | { 33 | "preset": "conventionalcommits" 34 | } 35 | ], 36 | [ 37 | "@semantic-release/release-notes-generator", 38 | { 39 | "preset": "conventionalcommits", 40 | "presetConfig": { 41 | "types": [ 42 | { type: 'feat', section: 'Features', hidden: false }, 43 | { type: 'fix', section: 'Bug Fixes', hidden: false }, 44 | { type: 'perf', section: 'Performance Improvements', hidden: false }, 45 | { type: 'revert', section: 'Reverts', hidden: false }, 46 | { type: 'docs', section: 'Other Updates', hidden: false }, 47 | { type: 'style', section: 'Other Updates', hidden: false }, 48 | { type: 'chore', section: 'Other Updates', hidden: false }, 49 | { type: 'refactor', section: 'Other Updates', hidden: false }, 50 | { type: 'test', section: 'Other Updates', hidden: false }, 51 | { type: 'build', section: 'Other Updates', hidden: false }, 52 | { type: 'ci', section: 'Other Updates', hidden: false } 53 | ] 54 | } 55 | } 56 | ], 57 | '@semantic-release/github' 58 | ] 59 | env: 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | 62 | - run: echo ${{ steps.semantic.outputs.release-version }} 63 | 64 | - run: echo "$OUTPUTS" 65 | env: 66 | OUTPUTS: ${{ toJson(steps.semantic.outputs) }} -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Deploy MkDocs site to GitHub Pages 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | 9 | permissions: 10 | contents: write 11 | pages: write 12 | id-token: write 13 | 14 | jobs: 15 | build-and-deploy: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout repo 20 | uses: actions/checkout@v3 21 | 22 | - name: Set up Python 23 | uses: actions/setup-python@v4 24 | with: 25 | python-version: '3.x' 26 | 27 | - name: Install MkDocs and dependencies 28 | run: | 29 | pip install mkdocs-material mkdocs-jupyter 30 | 31 | - name: Build MkDocs site 32 | working-directory: docs/workshop 33 | run: | 34 | mkdocs build 35 | touch site/.nojekyll # Disable Jekyll processing 36 | 37 | - name: Deploy to GitHub Pages 38 | uses: peaceiris/actions-gh-pages@v3 39 | with: 40 | github_token: ${{ secrets.GITHUB_TOKEN }} 41 | publish_dir: docs/workshop/site 42 | 43 | -------------------------------------------------------------------------------- /.github/workflows/pr-title-checker.yml: -------------------------------------------------------------------------------- 1 | name: "PR Title Checker" 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | merge_group: 10 | 11 | permissions: 12 | pull-requests: read 13 | 14 | jobs: 15 | main: 16 | name: Validate PR title 17 | runs-on: ubuntu-latest 18 | if: ${{ github.event_name != 'merge_group' }} 19 | steps: 20 | - uses: amannn/action-semantic-pull-request@v5 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.github/workflows/pylint.yml: -------------------------------------------------------------------------------- 1 | name: PyLint 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | python-version: ["3.11"] 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: Set up Python ${{ matrix.python-version }} 15 | uses: actions/setup-python@v3 16 | with: 17 | python-version: ${{ matrix.python-version }} 18 | 19 | - name: Install dependencies 20 | run: | 21 | python -m pip install --upgrade pip 22 | pip install -r src/api/requirements.txt 23 | pip install flake8 # Ensure flake8 is installed explicitly 24 | 25 | - name: Run flake8 and pylint 26 | run: | 27 | flake8 --config=.flake8 src/api # Specify the directory to lint 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | *.venv 5 | *.myenv 6 | *.vscode 7 | *.vs 8 | /LUISSchemaSerializationTool/.vs 9 | /LUISSchemaSerializationTool/LUISSchemaSerializationTool/bin 10 | /LUISSchemaSerializationTool/LUISSchemaSerializationTool/obj 11 | .fake 12 | .azure 13 | .idea 14 | /myenv 15 | scriptenv/ 16 | __pycache__/ 17 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This project welcomes contributions and suggestions. Most contributions require you to 4 | agree to a Contributor License Agreement (CLA) declaring that you have the right to, 5 | and actually do, grant us the rights to use your contribution. For details, visit 6 | https://cla.microsoft.com. 7 | 8 | When you submit a pull request, a CLA-bot will automatically determine whether you need 9 | to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the 10 | instructions provided by the bot. You will only need to do this once across all repositories using our CLA. 11 | 12 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 13 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 14 | or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /azure.yaml: -------------------------------------------------------------------------------- 1 | # # yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json 2 | # metadata: 3 | # template: azd-init@1.11.1 4 | environment: 5 | name: conversation-knowledge-mining 6 | location: eastus 7 | name: conversation-knowledge-mining 8 | metadata: 9 | template: conversation-knowledge-mining@1.0 10 | 11 | hooks: 12 | postprovision: 13 | windows: 14 | run: | 15 | Write-Host "Web app URL: " 16 | Write-Host "$env:WEB_APP_URL" -ForegroundColor Cyan 17 | shell: pwsh 18 | continueOnError: false 19 | interactive: true 20 | posix: 21 | run: | 22 | echo "Web app URL: " 23 | echo $WEB_APP_URL 24 | shell: sh 25 | continueOnError: false 26 | interactive: true -------------------------------------------------------------------------------- /docs/workshop/README.md: -------------------------------------------------------------------------------- 1 | # Conversation Knowledge Mining Solution Accelerator: Hands-on Workshop 2 | 3 | | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator) | [![Open in Dev Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator) | 4 | 5 | 6 | ### About the Conversation Knowledge Mining Solution Accelerator 7 | 8 | Gain actionable insights from large volumes of conversational data by identifying key themes, patterns, and relationships. Using Azure AI Foundry, Azure AI Content Understanding, Azure OpenAI Service, and Azure AI Search, this solution analyzes unstructured dialogue and maps it to meaningful, structured insights. 9 | 10 | Capabilities such as topic modeling, key phrase extraction, speech-to-text transcription, and interactive chat enable users to explore data naturally and make faster, more informed decisions. 11 | 12 | Analysts working with large volumes of conversational data can use this solution to extract insights through natural language interaction. It supports tasks like identifying customer support trends, improving contact center quality, and uncovering operational intelligence—enabling teams to spot patterns, act on feedback, and make informed decisions faster. 13 | 14 | ### Solution architecture 15 | ![High-level architecture diagram for the solution](./docs/workshop/img/ReadMe/techkeyfeatures.png) 16 | 17 | ### Workshop Guide 18 | 19 | The current repository is instrumented with a `workshop/docs` folder that contains the step-by-step lab guide for developers, covering the entire workflow from resource provisioning to ideation, evaluation, deployment, and usage. 20 | 21 | You can **preview and extend** the workshop directly from this source by running the [MKDocs](https://www.mkdocs.org/) pages locally: 22 | 23 | 1. Install the `mkdocs-material` package 24 | 25 | ```bash 26 | pip install mkdocs-material mkdocs-jupyter 27 | ``` 28 | 29 | 2. Run the `mkdocs serve` command from the `workshop` folder 30 | 31 | ```bash 32 | cd docs/workshopcd 33 | mkdocs serve -a localhost:5000 34 | ``` 35 | 36 | This should run the dev server with a preview of the workshop guide on the specified local address. Simply open a browser and navigate to `http://localhost:5000` to view the content. 37 | 38 | (Optional) If you want to deploy the workshop guide to a live site, you can use the `mkdocs gh-deploy` command to push the content to a GitHub Pages site. 39 | -------------------------------------------------------------------------------- /docs/workshop/docs/index.md: -------------------------------------------------------------------------------- 1 | # Microhack Challenges Hands-On Lab : Knowledge Mining 2 | 3 | The Micohack event is designed to engage technical roles through a condensed, half-day hands-on hack experience. Leveraging the latest Microsoft technologies, this event provides participants with the opportunity to work on real-world problems, collaborate with peers, and explore innovative solutions. 4 | 5 | The Microhack event is divided into several key challenges, each carefully crafted to test and expand the participants' proficiency with Microsoft's suite of tools. These challenges are not only technical in nature but also reflect real-world scenarios that businesses face, providing a comprehensive understanding of how to apply theoretical knowledge practically. 6 | 7 | 8 | 9 | ### Hack Duration: 2 hours 10 | 11 | 12 | 13 | The event kicks off with an initial overview of the customer scenario for the business problem the participants will solve by leveraging cutting-edge technology and services. 14 | 15 | Following this, the team will complete the setup phase, where participants ensure that their development environments are correctly configured, and all necessary tools are ready for use. 16 | 17 | Finally, they will tackle the first challenge, which involves identifying key ideas that underpin the implementation of Microsoft technologies in solving predefined problems. 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/.env.sample: -------------------------------------------------------------------------------- 1 | AZURE_AI_SEARCH_API_KEY="" 2 | AZURE_OPENAI_API_KEY="" 3 | 4 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-0/CU-Challenge.md: -------------------------------------------------------------------------------- 1 | # Create your first Content Understanding project in the AI Foundry 2 | 3 | ## Step 1: Create a Content Understanding Project 4 | 5 | - Navigate to the [AI Foundry homepage](https://ai.azure.com) and select Try Content Understanding. 6 | > **Note**: You will need to create a project in one of the following regions: westus, swedencentral, or australiaeast 7 | 8 | ![AI Foundry Homepage](../img/ai-services-landing-page.png) 9 | 10 | - Select + Create to create a new Content Understand project. 11 | 12 | ![CU Landing Page](../img/cu-landing-page.png) 13 | 14 | - Provide a name for your project (i.e. call_analyzer), select create a new hub, keep the default Azure AI service connection and select Next 15 | ![create project](../img/create_project.png) 16 | - Keep the default storage account, select next and select Create project. 17 | 18 | - Select Browse file to upload the sample audio file included in this [workshop](../data/convo_2c703f97-6657-4a15-b8b2-db6b96630b2d_2024-12-06%2006_00_00.wav). 19 | 20 | ![CU upload document](../img/cu-upload-document.png) 21 | 22 | - Select the Post call analytics template and select create. 23 | ![Template Suggestion](../img/define-schema-template-selection.png) 24 | 25 | - Save the default schema 26 | ![define schema](../img/define-schema.png) 27 | 28 | - Select Run analysis and review the fields on the left side 29 | ![Template Suggestion](../img/test-analyzer.png) 30 | 31 | - Select the Results to view the JSON output. 32 | ![test-analyzer-results](../img/test-analyzer-results.png) 33 | 34 | In this challenge we saw how to process one audio file through Azure AI Foundry. In a later challenge, we will see how to process multiple files for a full AI application and chat with data scenario through a pro-code approach. 35 | 36 | > For more detailed information and advanced configurations, refer to the official [Azure AI Content Understanding documentation](https://learn.microsoft.com/en-us/azure/ai-services/content-understanding/quickstart/use-ai-foundry). 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-0/index.md: -------------------------------------------------------------------------------- 1 | # Before you begin 2 | 3 | To get started, make sure you have the following resources and permissions: 4 | 5 | - An Azure subscription. If you don't have an Azure subscription, create a free account before you begin. 6 | - An Azure AI Foundry hub is required to manage the resources provisioned in your Content Understanding project, and it must be created in one of the following supported regions: westus, swedencentral, or australiaeast. If you're creating a hub for the first time, see [How to create and manage an Azure AI Foundry hub to learn more](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/create-azure-ai-resource?tabs=portal). It's important to note you need the proper permissions to create a hub, or your admin may create one for you. 7 | - If your role is Contributor or Owner, you can proceed with creating your own hub. 8 | - If your role is Azure AI Developer, the hub must already be created before you can complete this quickstart. Your user role must be Azure AI Developer, Contributor, or Owner on the hub. For more information, see [hubs](https://learn.microsoft.com/en-us/azure/ai-foundry/concepts/ai-resources) and [Azure AI roles](https://learn.microsoft.com/en-us/azure/ai-foundry/concepts/rbac-azure-ai-foundry). -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-1/Code_Walkthrough/02_Frontend.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | **Folder**: `src/App/Frontend` 5 | 6 | The frontend is a **React-based web interface** that allows users to explore insights from conversations, interact with an AI-powered chatbot, and view dynamic visualizations. 7 | 8 | 9 | ![image](../../img/ReadMe/ckm-ui.png) 10 | 11 | 12 | ### Features 13 | 14 | 1. **Dynamic Chart Rendering** 15 | 16 | - Renders charts like Donut, Bar, and Word Cloud using **Chart.js**. 17 | - Visualizes insights such as sentiment, topics, and keywords. 18 | 19 | 2. **Chatbot Interface** 20 | 21 | - Allows users to query via natural language. 22 | - Auto-generates insights and charts. 23 | 24 | 3. **Filter Management** 25 | 26 | - Filters such as **Date**, **Sentiment**, **Topic**. 27 | - Updates chart views dynamically. 28 | 29 | 30 | ### Workflow (Frontend) 31 | 32 | | Step | Description | Maps to Architecture | 33 | |------|-------------|----------------------| 34 | | 1. **Initial Load** | Fetch chart/filter data. | API Layer | 35 | | 2. **Chatbot Queries** | Send messages to backend. | Azure OpenAI + Semantic Kernel| 36 | | 3. **Chart Rendering** | Render chart components. | Web Front-end | 37 | | 4. **History Sync** | Display chat history. | Cosmos DB | 38 | 39 | ### Tools & Libraries 40 | 41 | - **React** 42 | - **Chart.js** 43 | - **Axios** 44 | 45 | --- 46 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-1/Code_Walkthrough/03_Backend.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | **Folder**: `src\App\backend` 5 | 6 | The backend is a **Python Quart app** that processes queries, generates insights, and communicates with databases and AI services. 7 | 8 | ### Features 9 | 10 | 1. **Azure OpenAI Integration** 11 | 12 | - Handles natural language queries from users. 13 | - Calls Azure OpenAI for understanding and response generation. 14 | 15 | 2. **Semantic Kernel Plugin**: 16 | 17 | - Powers natural language interactions via custom kernel functions 18 | 19 | 2. **Data Access** 20 | 21 | - SQL for structured data. 22 | - Azure Cognitive Search for transcripts. 23 | 24 | 3. **Chat History** 25 | 26 | - Cosmos DB for storing user conversations. 27 | 28 | 4. **Chart Processing** 29 | 30 | - Converts results to chart-ready JSON that is then used to diplay chart on the frontend. 31 | 32 | ### Semantic Kernel Plugin Breakdown 33 | 34 | Located in `ChatWithDataPlugin`: 35 | 36 | **greeting()** 37 | 38 | - Responds to simple greetings or general questions 39 | 40 | - Uses either Azure AI Project or direct OpenAI client 41 | 42 | **get_SQL_Response()** 43 | 44 | - Converts natural language questions into valid SQL queries 45 | 46 | 47 | **get_answers_from_calltranscripts()** 48 | 49 | - Performs Retrieval-Augmented Generation (RAG) 50 | 51 | - Uses semantic + vector hybrid search with Azure AI Search 52 | 53 | - Returns summarized or specific insights from indexed call data 54 | 55 | ### Tools & Libraries 56 | 57 | - **Quart** 58 | - **Azure OpenAI** 59 | - **CosmosDB SDK** 60 | - **SQLAlchemy** 61 | - **Semantic Kernel** 62 | - **Azure AI Search** 63 | 64 | --- -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-1/Code_Walkthrough/04_Api.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **Folder**: [`src/api`](https://github.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/tree/main/src/api) 4 | 5 | ### Key Endpoints 6 | 7 | #### Chart & Filters 8 | 9 | - `GET /api/fetchChartData` 10 | - Loads default chart data 11 | 12 | - `POST /api/fetchChartDataWithFilters` 13 | - Applies filters and regenerates chart based on user input 14 | 15 | - `GET /api/fetchFilterData` 16 | - Loads values for filter dropdowns (sentiment, topics, dates) 17 | 18 | #### Chatbot 19 | 20 | - `POST /api/chat` 21 | - Sends user’s question and filters to AI engine 22 | - Returns streamed natural language answer 23 | 24 | #### Conversation History 25 | 26 | - `POST /history/generate` 27 | - Starts a new conversation thread, returns conversation_id 28 | 29 | - `POST /history/update` 30 | - Updates chat history with question and answer 31 | 32 | - `GET /history/list` 33 | - Lists all conversation histories 34 | 35 | - `POST /history/read` 36 | - Loads full Q&A history for a specific thread 37 | 38 | - `DELETE /history/delete` 39 | - Deletes a conversation by ID 40 | 41 | 42 | 43 | --- 44 | 45 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-1/Solution_Overview.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | The Conversation Knowledge Mining Solution Accelerator is a robust application designed to extract actionable insights from conversational data. It leverages Azure AI services and provides an interactive user interface for querying and visualizing data. The solution is built with a modular architecture, combining a React-based frontend, a FastAPI backend, and Azure services for data processing and storage. 4 | 5 | 6 | ![image](../img/ReadMe/ckm-sol-arch.png) 7 | 8 | 9 | The solution extracts insights from call audio files or transcripts and enables users to interact with the data via a chatbot and dynamic charts: 10 | 11 | 1. **Ingest**: Audio/transcripts are stored. 12 | 13 | 2. **Understand**: Azure AI extracts conversation details. 14 | 15 | 3. **Index & Store**: Data is vectorized and stored in SQL + Azure AI Search. 16 | 17 | 4. **Orchestrate**: Chatbot + chart logic handled by APIs. 18 | 19 | 5. **Frontend**: Displays insights using charts and chat interface. 20 | 21 | ## Key Features 22 | 23 | ### Data Processing and Analysis: 24 | 25 | - Processes conversational data using Azure AI Foundry, Azure AI Content Understanding, and Azure OpenAI Service. 26 | - Extracts insights such as sentiment, key phrases, and topics from conversations. 27 | - Supports speech-to-text transcription for audio data. 28 | 29 | ### Dynamic Dashboard: 30 | 31 | - Visualizes insights through various chart types (e.g., Donut Chart, Bar Chart, Word Cloud). 32 | - Enables filtering and customization of data views. 33 | - Provides a responsive layout for seamless user experience. 34 | 35 | 36 | ### Interactive Chat Interface: 37 | 38 | - Allows users to query data in natural language and receive real-time responses. 39 | - Supports both text-based and chart-based responses. 40 | - Integrates with Azure OpenAI and Azure Cognitive Search for generating responses and retrieving relevant data. 41 | 42 | ### Backend API: 43 | 44 | - Built with FastAPI for handling requests and integrating with Azure services. 45 | - Includes modular routes for backend operations and conversation history management. 46 | - Provides a health check endpoint for monitoring service status. 47 | 48 | ### Scalable Deployment: 49 | 50 | - Supports deployment via GitHub Codespaces, VS Code Dev Containers, or local environments. 51 | - Includes configurable deployment settings for regions, models, and resource capacities. -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-2/index.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | The app allows you to interact with the dashboard using natural language queries. You can ask questions to gain insights from the data, and the system will respond with relevant charts, summaries, or structured data. 4 | 5 | --- 6 | 7 | ## **How It Works** 8 | 1. **Ask Questions**: Use natural language to ask about your data. 9 | 2. **Get Insights**: The app processes your query and provides answers, charts, or summaries. 10 | 3. **Explore**: Dive deeper into your data with follow-up questions. 11 | 12 | --- 13 | 14 | ## **Sample Questions to Get You Started** 15 | 16 | ### **Call Metrics** 17 | - What is the total number of calls by date for the last 7 days? 18 | 19 | ![image](../img/numer_of_calls.png) 20 | 21 | - Show me the average handling time by topics in minutes. 22 | 23 | ![image](../img/avg_time_handling.png) 24 | 25 | - You can also generate these call metrics question in a chart 26 | 27 | ![image](../img/chart_screenshot.png) 28 | 29 | ### **Customer Challenges** 30 | - What are the top 7 challenges users reported? 31 | 32 | ![image](../img/top_challenge.png) 33 | 34 | - Give me a summary of billing issues. 35 | 36 | ![image](../img/billing_summary.png) 37 | 38 | ### **Billing Insights** 39 | - When customers call about unexpected charges, what types of charges are they seeing? 40 | 41 | ![image](../img/common_calls.png) 42 | 43 | --- 44 | 45 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-3-and-4/Challenge-4.md: -------------------------------------------------------------------------------- 1 | # Workshop challenge: run each function in the notebooks to see how they work 2 | 3 | 1. Open the [knowledge_mining_api notebook](./knowledge_mining_api.ipynb) from the Challenge-3-and-4 folder 4 | 2. Run the first cell to import the requirements 5 | 3. The second cell defines a class that is used to define the plugin for the Azure AI Project Client. This contains the various functions that power different behaviors such as greeting, query Azure SQL database and query Azure AI Search. Run cell 2 to see the results when a user says Hello. The next result will show when a user asks a question and runs the Azure SQL query function. Finally we will see two more results when the user asks questions that runs the Azure AI Search function. 6 | 4. Finally, you could update the `user_inputs` in cell 2 to try out more questions. 7 | 8 | ```shell 9 | user_inputs = [ 10 | "Hello", 11 | "Give a summary of billing issues" 12 | "Total number of calls by date for the last 7 days", 13 | "Show average handling time by topics in minutes", 14 | "What are the top 7 challenges users reported?", 15 | "When customers call in about unexpected charges, what types of charges are they seeing?", 16 | ] 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/analyzer_templates/video_content_understanding.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Generating content understanding from video.", 3 | "scenario": "videoShot", 4 | "config": { 5 | "returnDetails": true, 6 | "locales": [ 7 | "en-US", 8 | "es-ES", 9 | "es-MX", 10 | "fr-FR", 11 | "hi-IN", 12 | "it-IT", 13 | "ja-JP", 14 | "ko-KR", 15 | "pt-BR", 16 | "zh-CN" 17 | ], 18 | "enableFace": false 19 | }, 20 | "fieldSchema": { 21 | "name": "Content Understanding", 22 | "descriptions": "Generate content understanding from video.", 23 | "fields": { 24 | "segmentDescription": { 25 | "type": "string", 26 | "description": "Detailed summary of the video segment, focusing on people, places, and actions taking place." 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/analyzer_templates/video_tag.json: -------------------------------------------------------------------------------- 1 | { 2 | "analyzerId": "video_tag_analyzer", 3 | "name": "Video Content Understanding", 4 | "description": "Generating content understanding from video.", 5 | "scenario": "videoShot", 6 | "config": { 7 | "returnDetails": true, 8 | "locales": [ 9 | "en-US", 10 | "es-ES", 11 | "es-MX", 12 | "fr-FR", 13 | "hi-IN", 14 | "it-IT", 15 | "ja-JP", 16 | "ko-KR", 17 | "pt-BR", 18 | "zh-CN" 19 | ], 20 | "enableFace": false 21 | }, 22 | "fieldSchema": { 23 | "name": "Content Understanding", 24 | "descriptions": "Generate content understanding from video.", 25 | "fields": { 26 | "segmentDescription": { 27 | "type": "string", 28 | "description": "Detailed summary of the video segment, focusing on people, places, and actions taking place." 29 | }, 30 | "transcript": { 31 | "type": "string", 32 | "kind": "generate", 33 | "description": "Include transcript in this segment." 34 | }, 35 | "tags": { 36 | "type": "string", 37 | "description": "generate tags from the video segment." 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/data/FlightSimulator.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/Challenge-5/data/FlightSimulator.mp4 -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/docs/create_azure_ai_service.md: -------------------------------------------------------------------------------- 1 | # How To Create Azure AI Service 2 | 1. Navigate to https://portal.azure.com/#create/Microsoft.CognitiveServicesAIServices . 3 | 2. Select your Azure subscription. 4 | 3. Select the available Resource group. 5 | 4. Choose the region which support Content Understanding service from below tables. 6 | | Geography | Region | Region Identifier| 7 | | --------- | -------------- | ---------------- | 8 | | US | West US | westus | 9 | | Europe | Sweden Central | swedencentral | 10 | | Australia | Australia East | australiaeast | 11 | 5. Enter a name for your resource. 12 | 6. Choose a price plan. 13 | 14 | 7. Configure other settings for your resource as needed, read, and accept the conditions (as applicable), and then select Review + create. 15 | 16 | 8. Azure will run a quick validation check, after a few seconds you should see a green banner that says Validation Passed. 17 | 9. Once the validation banner appears, select the Create button from the bottom-left corner. 18 | 10. After you select create, you'll be redirected to a new page that says Deployment in progress. After a few seconds, you'll see a message that says, Your deployment is complete. 19 | 11. Navigate to the resouce. In the left navigation menu, select "Keys and Endpoint", then get the **key** and **endpoint**. 20 | 21 | Now,you could start with these information to run the samples. -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/docs/create_srv_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/Challenge-5/docs/create_srv_1.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/docs/create_srv_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/Challenge-5/docs/create_srv_2.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/docs/create_srv_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/Challenge-5/docs/create_srv_3.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/index.md: -------------------------------------------------------------------------------- 1 | # Video Processing Using Azure AI Content Understanding and Azure OpenAI 2 | 3 | Content Understanding is an innovative solution designed to analyze and interpret diverse media types, including documents, images, audio, and video. It transforms this content into structured, organized, and searchable data. In this sample, we will demonstrate how to extract semantic information from you file, and send these information to Azure OpenAI to achive complex works. 4 | 5 | 6 | - The samples in this repository default to the latest preview API version: **(2024-12-01-preview)**. 7 | 8 | 9 | ## Samples 10 | 11 | | File | Description | 12 | | --- | --- | 13 | | [video_chapter_generation.ipynb](video_chapter_generation.ipynb) | Extract semantic descriptions using content understanding API, and then leverage OpenAI to group into video chapters. | 14 | | [video_tag_generation.ipynb](video_tag_generation.ipynb) | Generate video tags based on Azure Content Understanding and Azure OpenAI. | 15 | 16 | ## Getting started 17 | 18 | 1. Identify your [Azure AI Services resource](docs/create_azure_ai_service.md), suggest to use ***Sweden Central*** region for the availability of the content understanding API. 19 | 1. Go to `Access Control (IAM)` in resource, grant yourself role `Cognitive Services User` 20 | 1. Identify your [Azure OpenAI resource](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource?pivots=web-portal) 21 | 1. Go to `Access Control (IAM)` in resource, grant yourself role `Cognitive Services OpenAI User` 22 | 1. Copy `notebooks/.env.sample` to `notebooks/.env` 23 | ```shell 24 | cp notebooks/.env.example notebooks/.env 25 | ``` 26 | 1. Fill required information into .env from the resources that you alredy have created, remember that your model is ***gpt-4o-mini***, you should have something like this: 27 | ```shell 28 | AZURE_AI_SERVICE_ENDPOINT="https://-aiservices-cu.cognitiveservices.azure.com" 29 | AZURE_AI_SERVICE_API_VERSION=2024-12-01-preview 30 | AZURE_OPENAI_ENDPOINT="https://-aiservices.openai.azure.com" 31 | AZURE_OPENAI_API_VERSION=2024-08-01-preview 32 | AZURE_OPENAI_CHAT_DEPLOYMENT_NAME=gpt-4o-mini 33 | AUTHENTICATION_URL="https://cognitiveservices.azure.com/.default" 34 | ``` 35 | 1. Login Azure 36 | ```shell 37 | az login 38 | ``` 39 | 40 | ## Open a Jupyter notebook and follow the step-by-step guidance 41 | 42 | Navigate to the `notebooks` directory and select the sample notebook you are interested in. Since Codespaces is pre-configured with the necessary environment, you can directly execute each step in the notebook. 43 | 44 | ## More Samples using Azure Content Understanding 45 | [Azure Content Understanding Basic Usecase](https://github.com/Azure-Samples/azure-ai-content-understanding-python) 46 | 47 | [Azure Search with Content Understanding](https://github.com/Azure-Samples/azure-ai-search-with-content-understanding-python) -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/notebooks/.env.sample: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------- 2 | # -------------- Azure AI services configurations -------------- 3 | # -------------------------------------------------------------- 4 | # The end point of Azure AI services, should be in the format of "https://.cognitiveservices.azure.com" 5 | AZURE_AI_SERVICE_ENDPOINT="https://.cognitiveservices.azure.com" 6 | 7 | # The version of the Azure AI services 8 | AZURE_AI_SERVICE_API_VERSION=2024-12-01-preview 9 | 10 | # ----------------------------------------------------------------- 11 | # -------------- Azure OpenAI service configurations -------------- 12 | # ----------------------------------------------------------------- 13 | # The end point of Azure OpenAI service, should be in the format of "https://.openai.azure.com" 14 | AZURE_OPENAI_ENDPOINT="https://.openai.azure.com" 15 | 16 | # The version of the Azure OpenAI service 17 | AZURE_OPENAI_API_VERSION=2024-08-01-preview 18 | 19 | # The deployment name of your own Azure OpenAI service 20 | AZURE_OPENAI_CHAT_DEPLOYMENT_NAME= 21 | 22 | # Other URLs 23 | AUTHENTICATION_URL = "https://cognitiveservices.azure.com/.default" -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-5/requirements.txt: -------------------------------------------------------------------------------- 1 | openai>=1.46.1 2 | requests>=2.32.3 3 | azure-identity>=1.16.0 4 | python-dotenv>=1.0.1 5 | tiktoken>=0.8.0 6 | pydantic>=2.4.2 7 | tenacity>=8.2.3 8 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-6/index.md: -------------------------------------------------------------------------------- 1 | # Evaluation 2 | 3 | ## Content Safety Evaluation 4 | 5 | This notebook demonstrates how to evaluate content safety using Azure AI's evaluation tools. It includes steps to: 6 | 7 | * Simulate content safety and grounded scenarios. 8 | * Evaluate content for safety metrics such as violence, sexual content, hate/unfairness, and self-harm. 9 | * Generate evaluation reports in JSON format. 10 | 11 | ### Prerequisites 12 | - Azure AI project credentials. 13 | - [Python 3.9+](https://www.python.org/downloads/) 14 | - Python environment with required libraries installed (`azure-ai-evaluation`, `pandas`, etc.). 15 | - Access to the Azure API endpoint. 16 | - Completed [Challenge 3](../Challenge-3-and-4/Challenge-3.md) 17 | 18 | 19 | If you did not create a virtual environment during the Challenge 3, please follow the steps [here](../Challenge-3-and-4/Challenge-3.md) 20 | 1. Navigate to the `workshop/docs/workshop` folder in the terminal in your local repository and run the following commands 21 | 2. In the terminal run the following command 22 | 23 | * Install the requirements 24 | ```shell 25 | pip install -r requirements.txt 26 | ``` 27 | 3. Open the `.env` in the `workshop/docs/workshop` folder to validate the variables were updated with the details of your solution. 28 | 4. Open the [Content_safety_evaluation notebook](./Content_safety_evaluation.ipynb) 29 | 5. Run the first cell to create a folder for the output file of the evaluations. 30 | 6. Run cells 2-4 to initialize your Azure AI Project, the call streaming function and callback function. 31 | 7. Cell 5 run the Adversarial Scenario to generate questions, run the questions against your AI solution and write these results to a local file. Cell 6 will format the output of the results. 32 | - The Adversarial Scenario will run content safety evaluation tests on your AI solution 33 | 8. Cell 7 and 8 initialize the model configuration and the Groundedness Evaluator. The groundedness measure assesses the correspondence between claims in an AI-generated answer and the source context, making sure that these claims are substantiated by the context. 34 | - Learn more about the groundedness evaluator [here](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/develop/evaluate-sdk#performance-and-quality-evaluator-usage) 35 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Challenge-data/data.md: -------------------------------------------------------------------------------- 1 | # 🧠 Understanding the Data in the Conversation Knowledge Mining Solution Accelerator 2 | 3 | This document is a comprehensive walkthrough of the **data** used and generated in the [Conversation Knowledge Mining Solution Accelerator](https://github.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator) by Microsoft. This guide is designed to help you understand **how conversational data flows**, is **processed**, and is **transformed into insights** using Azure services. 4 | 5 | --- 6 | 7 | ## 1. Raw Data Input 8 | 9 | ### Audio Files 10 | - Format: `.wav` 11 | - Location: Uploaded to Azure Blob Storage (`-sa`) 12 | - file: `data/audio/sample-call.wav` 13 | 14 | **Purpose**: Represents real-world customer interactions (e.g., support calls). 15 | 16 | --- 17 | 18 | ## 📝 2. Transcription (Speech-to-Text) 19 | 20 | ### ✅ Service Used: Azure Cognitive Services – Speech 21 | 22 | - Converts `.wav` audio files into **text transcripts** 23 | - Output: JSON with text and metadata (timestamps, speaker info) 24 | - Example Output: 25 | ```json 26 | { 27 | "DisplayText": "Thank you for calling customer support...", 28 | "Offset": 12300000, 29 | "Duration": 5500000 30 | } 31 | Location: Saved in Blob Storage and later processed by the pipeline 32 | 33 | 34 | ## 📝 2. Transcription (Speech-to-Text) 35 | 36 | ### ✅ Service Used: Azure Cognitive Services – Speech 37 | 38 | ## 3. Text Processing and Insight Generation 39 | 40 | ### ✅ Service Used: Azure OpenAI (via Azure AI Foundry Pipelines) 41 | This step uses LLMs to process raw transcript and extract insights: 42 | - Key Phrase Extraction – Main themes or terms 43 | - Summarization – Condensed version of the conversation 44 | - Topic Modeling – High-level categorization 45 | 46 | Sentiment Analysis (optional) 47 | - Converts `.wav` audio files into **text transcripts** 48 | - Output: JSON with text and metadata (timestamps, speaker info) 49 | - Example Output: 50 | ```json 51 | { 52 | "conversation_id": "12345", 53 | "key_phrases": ["billing issue", "account cancellation"], 54 | "summary": "Customer called to cancel due to a billing issue.", 55 | "topics": ["Billing", "Account Management"] 56 | } 57 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/Tear-Down/index.md: -------------------------------------------------------------------------------- 1 | # Cleanup Resources 2 | 3 | ## Give us a ⭐️ on GitHub 4 | 5 | !!! question "FOUND THIS WORKSHOP AND SAMPLE USEFUL? MAKE SURE YOU GET UPDATES." 6 | 7 | The **[Conversation Knowledge Mining Solution Accelerator](https://github.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator)** sample is an actively updated project that will reflect the latest features and best practices for code-first development of RAG-based copilots on the Azure AI platform. **[Visit the repo](https://github.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator)** or click the button below, to give us a ⭐️. 8 | 9 | 10 | Give the Conversation Knowledge Mining Solution Accelerator a Star! 11 | 12 | ## Provide Feedback 13 | 14 | Have feedback that can help us make this lab better for others? [Open an issue](https://github.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/issues) and let us know. 15 | 16 | ## Clean-up 17 | 18 | Once you have completed this workshop, delete the Azure resources you created. You are charged for the configured capacity, not how much the resources are used. Follow these instructions to delete your resource group and all resources you created for this solution accelerator. 19 | 20 | 1. In VS Code, open a new integrated terminal prompt. 21 | 22 | 2. At the terminal prompt, execute the following command to delete the resources created by the deployment script: 23 | 24 | !!! danger "Execute the following Azure Developer CLI command to delete resources!" 25 | 26 | ```bash title="" 27 | azd down --purge 28 | ``` 29 | 30 | !!! tip "The `--purge` flag purges the resources that provide soft-delete functionality in Azure, including Azure KeyVault and Azure OpenAI. This flag is required to remove all resources completely." 31 | 32 | 3. In the terminal window, you will be shown a list of the resources that will be deleted and prompted about continuing. Enter "y" at the prompt to being the resource deletion. 33 | 34 | ## Persist changes to GitHub 35 | 36 | If you want to save any changes you have made to files, use the Source Control tool in VS Code to commit and push your changes to your fork of the GitHub repo. 37 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/data/FlightSimulator.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/data/FlightSimulator.mp4 -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/data/convo_2c703f97-6657-4a15-b8b2-db6b96630b2d_2024-12-06 06_00_00.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/data/convo_2c703f97-6657-4a15-b8b2-db6b96630b2d_2024-12-06 06_00_00.wav -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/ReadMe/ckm-sol-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/ReadMe/ckm-sol-arch.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/ReadMe/ckm-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/ReadMe/ckm-ui.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/ReadMe/customerTruth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/ReadMe/customerTruth.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/ReadMe/quickDeploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/ReadMe/quickDeploy.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/ReadMe/quotaImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/ReadMe/quotaImage.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/ReadMe/techkeyfeatures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/ReadMe/techkeyfeatures.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/ReadMe/userStory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/ReadMe/userStory.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/ai-services-landing-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/ai-services-landing-page.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/audio-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/audio-folder.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/avg_time_handling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/avg_time_handling.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/billing_summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/billing_summary.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/build-analyzer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/build-analyzer.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/call_transcripts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/call_transcripts.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/chart_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/chart_screenshot.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/common_calls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/common_calls.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/create_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/create_project.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/cu-landing-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/cu-landing-page.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/cu-upload-document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/cu-upload-document.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/data-folders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/data-folders.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/define-schema-template-selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/define-schema-template-selection.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/define-schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/define-schema.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/numer_of_calls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/numer_of_calls.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/portal-app-api-env.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/portal-app-api-env.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/storage-blob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/storage-blob.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/storage-container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/storage-container.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/test-analyzer-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/test-analyzer-results.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/test-analyzer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/test-analyzer.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/img/top_challenge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/docs/workshop/docs/workshop/img/top_challenge.png -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/index.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | This solution accelerator enables customers with large amounts of conversational data to improve decision-making by leveraging intelligence to uncover insights, relationships, and patterns from customer interactions. It empowers users to gain valuable knowledge and drive targeted business impact. 4 | 5 | It leverages Azure AI Foundry, Azure AI Content Understanding, Azure OpenAI Service, and Azure AI Search to transform large volumes of conversational data into actionable insights through topic modeling, key phrase extraction, speech-to-text transcription, and interactive chat experiences. 6 | 7 | ### Use case / scenario 8 | 9 | An analyst managing large volumes of conversational data needs a solution to visualize key insights and uncover patterns using natural language. An interactive dashboard enables them to explore rich, actionable insights for faster, and more informed decision-making. 10 | 11 | ### Technical key features 12 | 13 | ![image](../workshop/support-docs/Images/ReadMe/techkeyfeatures.png) 14 | 15 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/requirements.txt: -------------------------------------------------------------------------------- 1 | # Azure Services 2 | azure-identity==1.21.0 3 | azure-ai-evaluation==1.5.0 4 | # Additional utilities 5 | semantic-kernel[azure]==1.28.0 6 | azure-ai-projects==1.0.0b8 7 | openai==1.74.0 8 | pyodbc==5.2.0 9 | ipykernel==6.29.5 -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/support-docs/AzureGPTQuotaSettings.md: -------------------------------------------------------------------------------- 1 | ## How to Check & Update Quota 2 | 3 | 1. Go to the [Azure Portal](https://portal.azure.com). 4 | 2. In the **search bar**, type the name of the **Resource Group** you created during **Challenge 1**. 5 | 3. Within the resource group, look for the **Azure AI services** ending in -aiservices. 6 | 4. In the AI services, Click on **Go to Azure AI Foundry portal**. 7 | 4. **Navigate** to `Shared resources` in the bottom-left menu. 8 | 9 | --- 10 | 11 | ### 🔍 To Check Quota 12 | 13 | - Click on the `Quota` tab. 14 | - In the `GlobalStandard` dropdown: 15 | - Select the desired model (e.g., **GPT-4**, **GPT-4o**, **GPT-4o Mini**, or **text-embedding-ada-002**). 16 | - Choose the **region** where your deployment is hosted. 17 | - You can: 18 | **Request more quota**, or **Delete unused deployments** to free up capacity. 19 | 20 | --- 21 | 22 | ### ✏️ To Update Quota 23 | 24 | - Go to the `Deployments` tab. 25 | - Select the deployment of the desired model. 26 | - Click **Edit**, update the **Tokens per Minute (TPM) Rate Limit**, then **Submit Changes**. 27 | -------------------------------------------------------------------------------- /docs/workshop/docs/workshop/support-docs/quota_check.md: -------------------------------------------------------------------------------- 1 | ## Check Quota Availability Before Deployment 2 | 3 | Before deploying the accelerator, **ensure sufficient quota availability** for the required model. 4 | Use one of the following scripts based on your needs: 5 | 6 | - **`quota_check_params.sh`** → If you **know the model and capacity** required. 7 | --- 8 | ## **If using Azure Portal and Cloud Shell** 9 | 10 | 1. Navigate to the [Azure Portal](https://portal.azure.com). 11 | 2. Click on **Azure Cloud Shell** in the top right navigation menu. 12 | 3. Run the appropriate command based on your requirement: 13 | 14 | **To check quota for a specific model and capacity:** 15 | 16 | ```sh 17 | curl -L -o quota_check_params.sh "https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/main/infra/scripts/quota_check_params.sh" 18 | chmod +x quota_check_params.sh 19 | ./quota_check_params.sh [] (e.g., gpt-4o-mini:30,text-embedding-ada-002:20 eastus) 20 | ``` 21 | 22 | ## **If using VS Code or Codespaces** 23 | 24 | 1. Run the appropriate script based on your requirement: 25 | 26 | **To check quota for a specific model and capacity:** 27 | 28 | ```sh 29 | ./quota_check_params.sh [] (e.g., gpt-4o-mini:30,text-embedding-ada-002:20 eastus) 30 | ``` 31 | 32 | 2. If you see the error `_bash: az: command not found_`, install Azure CLI: 33 | 34 | ```sh 35 | curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash 36 | az login 37 | ``` 38 | 3. Rerun the script after installing Azure CLI. 39 | 40 | **Parameters** 41 | - ``: The name and required capacity for each model, in the format model_name:capacity (**e.g., gpt-4o-mini:30,text-embedding-ada-002:20**). 42 | - `[] (optional)`: The Azure region to check first. If not provided, all supported regions will be checked (**e.g., eastus**). 43 | -------------------------------------------------------------------------------- /docs/workshop/overrides/main.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block scripts %} 4 | 5 | {{ super() }} 6 | 7 | 8 | 9 | 10 | 11 | {% endblock %} -------------------------------------------------------------------------------- /documents/AppAuthentication.md: -------------------------------------------------------------------------------- 1 | # Set Up Authentication in Azure App Service 2 | 3 | This document provides step-by-step instructions to configure Azure App Registrations for a front-end application. 4 | 5 | ## Prerequisites 6 | 7 | - Access to **Microsoft Entra ID** 8 | - Necessary permissions to create and manage **App Registrations** 9 | 10 | ## Step 1: Add Authentication in Azure App Service configuration 11 | 12 | 1. Click on `Authentication` from left menu. 13 | 14 | ![Authentication](Images/AppAuthentication.png) 15 | 16 | 2. Click on `+ Add identity provider` to see a list of identity providers. 17 | 18 | ![Authentication Identity](Images/AppAuthenticationIdentity.png) 19 | 20 | 3. Click on `Identity Provider` dropdown to see a list of identity providers. 21 | 22 | ![Add Provider](Images/AppAuthIdentityProvider.png) 23 | 24 | 4. Select the first option `Microsoft Entra Id` from the drop-down list and select `client secret expiration` under App registration. 25 | > NOTE: If `Create new app registration` is disabled, then go to [Create new app registration](/documents/create_new_app_registration.md) and come back to this step to complete the app authentication. 26 | 27 | ![Add Provider](Images/AppAuthIdentityProviderAdd.png) 28 | 29 | 5. Accept the default values and click on `Add` button to go back to the previous page with the identity provider added. 30 | 31 | ![Add Provider](Images/AppAuthIdentityProviderAdded.png) 32 | 33 | 6. You have successfully added app authentication, and now required to log in to access the application. 34 | -------------------------------------------------------------------------------- /documents/AzureAccountSetUp.md: -------------------------------------------------------------------------------- 1 | ## Azure account setup 2 | 3 | 1. Sign up for a [free Azure account](https://azure.microsoft.com/free/) and create an Azure Subscription. 4 | 2. Check that you have the necessary permissions: 5 | * Your Azure account must have `Microsoft.Authorization/roleAssignments/write` permissions, such as [Role Based Access Control Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator-preview), [User Access Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#user-access-administrator), or [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner). 6 | * Your Azure account also needs `Microsoft.Resources/deployments/write` permissions on the subscription level. 7 | 8 | You can view the permissions for your account and subscription by following the steps below: 9 | - Navigate to the [Azure Portal](https://portal.azure.com/) and click on `Subscriptions` under 'Navigation' 10 | - Select the subscription you are using for this accelerator from the list. 11 | - If you try to search for your subscription and it does not come up, make sure no filters are selected. 12 | - Select `Access control (IAM)` and you can see the roles that are assigned to your account for this subscription. 13 | - If you want to see more information about the roles, you can go to the `Role assignments` 14 | tab and search by your account name and then click the role you want to view more information about. -------------------------------------------------------------------------------- /documents/AzureGPTQuotaSettings.md: -------------------------------------------------------------------------------- 1 | ## How to Check & Update Quota 2 | 3 | 1. **Navigate** to the [Azure AI Foundry portal](https://ai.azure.com/). 4 | 2. **Select** the AI Project associated with this accelerator. 5 | 3. **Go to** the `Management Center` from the bottom-left navigation menu. 6 | 4. Select `Quota` 7 | - Click on the `GlobalStandard` dropdown. 8 | - Select the required **GPT model** (`GPT-4, GPT-4o, GPT-4o Mini`) or **Embeddings model** (`text-embedding-ada-002`). 9 | - Choose the **region** where the deployment is hosted. 10 | 5. Request More Quota or delete any unused model deployments as needed. 11 | -------------------------------------------------------------------------------- /documents/AzureSemanticSearchRegion.md: -------------------------------------------------------------------------------- 1 | ## Select a region where Semantic Search Availability is available before proceeding with the deployment. 2 | 3 | Steps to Check Semantic Search Availability 4 | 1. Open the [Semantic Search Availability](https://learn.microsoft.com/en-us/azure/search/search-region-support) page. 5 | 2. Scroll down to the **"Availability by Region"** section. 6 | 3. Use the table to find supported regions for **Azure AI Search** and its **Semantic Search** feature. 7 | 4. If your target region is not listed, choose a supported region for deployment. -------------------------------------------------------------------------------- /documents/CustomizeData.md: -------------------------------------------------------------------------------- 1 | ## Customize the solution with your own data 2 | 3 | If you would like to update the solution to leverage your own data please follow the steps below. 4 | > Note: you will need to complete the deployment steps [here](./DeploymentGuide.md) before proceeding. 5 | 6 | ## Prerequisites: 7 | 1. Your data will need to be in JSON or wav format with the file name formated prefixed with "convo" then a GUID followed by a timestamp. For more examples of the data format, please review the sample transcripts and audio data included [here](/infra/data/) 8 | * Example: convo_32e38683-bbf7-407e-a541-09b37b77921d_2024-12-07 04%3A00%3A00 9 | 10 | 11 | 1. Navigate to the storage account in the resource group you are using for this solution. 12 | 2. Open the `data` container 13 | 3. If you have audio files, upload them to `custom_audiodata` folder. If you have call transcript files, upload them to `custom_transcripts` folder. 14 | 4. Navigate to the terminal and run the `run_process_data_scripts.sh` to process the new data into the solution with the following commands. 15 | ```shell 16 | cd infra/scripts 17 | 18 | az login 19 | 20 | bash run_process_data_scripts.sh resourcegroupname_param 21 | ``` 22 | a. resourcegroupname_param - the name of the resource group. 23 | 24 | -------------------------------------------------------------------------------- /documents/CustomizingAzdParameters.md: -------------------------------------------------------------------------------- 1 | ## [Optional]: Customizing resource names 2 | 3 | By default this template will use the environment name as the prefix to prevent naming collisions within Azure. The parameters below show the default values. You only need to run the statements below if you need to change the values. 4 | 5 | 6 | > To override any of the parameters, run `azd env set ` before running `azd up`. On the first azd command, it will prompt you for the environment name. Be sure to choose 3-20 characters alphanumeric unique name. 7 | 8 | Change the Content Understanding Location (allowed values: Sweden Central, Australia East) 9 | 10 | ```shell 11 | azd env set AZURE_CONTENT_UNDERSTANDING_LOCATION 'swedencentral' 12 | ``` 13 | 14 | Change the Secondary Location (example: eastus2, westus2, etc.) 15 | 16 | ```shell 17 | azd env set AZURE_SECONDARY_LOCATION eastus2 18 | ``` 19 | 20 | Change the Model Deployment Type (allowed values: Standard, GlobalStandard) 21 | 22 | ```shell 23 | azd env set AZURE_OPEN_AI_MODEL_DEPLOYMENT_TYPE GlobalStandard 24 | ``` 25 | 26 | Set the Model Name (allowed values: gpt-4o-mini, gpt-4o, gpt-4) 27 | 28 | ```shell 29 | azd env set AZURE_OPEN_AI_DEPLOYMENT_MODEL gpt-4o-mini 30 | ``` 31 | 32 | Change the Model Capacity (choose a number based on available GPT model capacity in your subscription) 33 | 34 | ```shell 35 | azd env set AZURE_OPEN_AI_DEPLOYMENT_MODEL_CAPACITY 30 36 | ``` 37 | 38 | Change the Embedding Model 39 | 40 | ```shell 41 | azd env set AZURE_OPENAI_EMBEDDING_MODEL text-embedding-ada-002 42 | ``` 43 | 44 | Change the Embedding Deployment Capacity (choose a number based on available embedding model capacity in your subscription) 45 | 46 | ```shell 47 | azd env set AZURE_OPENAI_EMBEDDING_MODEL_CAPACITY 80 48 | ``` 49 | 50 | Set the Log Analytics Workspace Id if you need to reuse the existing workspace which is already existing 51 | ```shell 52 | azd env set AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID '/subscriptions//resourceGroups//providers/Microsoft.OperationalInsights/workspaces/' 53 | ``` -------------------------------------------------------------------------------- /documents/DeleteResourceGroup.md: -------------------------------------------------------------------------------- 1 | # Deleting Resources After a Failed Deployment in Azure Portal 2 | 3 | If your deployment fails and you need to clean up the resources manually, follow these steps in the Azure Portal. 4 | 5 | --- 6 | 7 | ## **1. Navigate to the Azure Portal** 8 | 1. Open [Azure Portal](https://portal.azure.com/). 9 | 2. Sign in with your Azure account. 10 | 11 | --- 12 | 13 | ## **2. Find the Resource Group** 14 | 1. In the search bar at the top, type **"Resource groups"** and select it. 15 | 2. Locate the **resource group** associated with the failed deployment. 16 | 17 | ![Resource Groups](Images/resourcegroup.png) 18 | 19 | ![Resource Groups](Images/resource-groups.png) 20 | 21 | --- 22 | 23 | ## **3. Delete the Resource Group** 24 | 1. Click on the **resource group name** to open it. 25 | 2. Click the **Delete resource group** button at the top. 26 | 27 | ![Delete Resource Group](Images/DeleteRG.png) 28 | 29 | 3. Type the resource group name in the confirmation box and click **Delete**. 30 | 31 | 📌 **Note:** Deleting a resource group will remove all resources inside it. 32 | 33 | --- 34 | 35 | ## **4. Delete Individual Resources (If Needed)** 36 | If you don’t want to delete the entire resource group, follow these steps: 37 | 38 | 1. Open **Azure Portal** and go to the **Resource groups** section. 39 | 2. Click on the specific **resource group**. 40 | 3. Select the **resource** you want to delete (e.g., App Service, Storage Account). 41 | 4. Click **Delete** at the top. 42 | 43 | ![Delete Individual Resource](Images/deleteservices.png) 44 | 45 | --- 46 | 47 | ## **5. Verify Deletion** 48 | - After a few minutes, refresh the **Resource groups** page. 49 | - Ensure the deleted resource or group no longer appears. 50 | 51 | 📌 **Tip:** If a resource fails to delete, check if it's **locked** under the **Locks** section and remove the lock. 52 | 53 | 54 | -------------------------------------------------------------------------------- /documents/Images/AddDetails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/AddDetails.png -------------------------------------------------------------------------------- /documents/Images/AddPlatform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/AddPlatform.png -------------------------------------------------------------------------------- /documents/Images/AddRedirectURL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/AddRedirectURL.png -------------------------------------------------------------------------------- /documents/Images/AppAuthIdentityProvider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/AppAuthIdentityProvider.png -------------------------------------------------------------------------------- /documents/Images/AppAuthIdentityProviderAdd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/AppAuthIdentityProviderAdd.png -------------------------------------------------------------------------------- /documents/Images/AppAuthIdentityProviderAdded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/AppAuthIdentityProviderAdded.png -------------------------------------------------------------------------------- /documents/Images/AppAuthentication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/AppAuthentication.png -------------------------------------------------------------------------------- /documents/Images/AppAuthenticationIdentity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/AppAuthenticationIdentity.png -------------------------------------------------------------------------------- /documents/Images/Appregistrations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/Appregistrations.png -------------------------------------------------------------------------------- /documents/Images/DeleteRG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/DeleteRG.png -------------------------------------------------------------------------------- /documents/Images/MicrosoftEntraID.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/MicrosoftEntraID.png -------------------------------------------------------------------------------- /documents/Images/NewRegistration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/NewRegistration.png -------------------------------------------------------------------------------- /documents/Images/ReadMe/business-scenario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/ReadMe/business-scenario.png -------------------------------------------------------------------------------- /documents/Images/ReadMe/quick-deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/ReadMe/quick-deploy.png -------------------------------------------------------------------------------- /documents/Images/ReadMe/quotaImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/ReadMe/quotaImage.png -------------------------------------------------------------------------------- /documents/Images/ReadMe/solution-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/ReadMe/solution-architecture.png -------------------------------------------------------------------------------- /documents/Images/ReadMe/solution-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/ReadMe/solution-overview.png -------------------------------------------------------------------------------- /documents/Images/ReadMe/supporting-documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/ReadMe/supporting-documentation.png -------------------------------------------------------------------------------- /documents/Images/ReadMe/ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/ReadMe/ui.png -------------------------------------------------------------------------------- /documents/Images/Web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/Web.png -------------------------------------------------------------------------------- /documents/Images/WebAppURL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/WebAppURL.png -------------------------------------------------------------------------------- /documents/Images/deleteservices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/deleteservices.png -------------------------------------------------------------------------------- /documents/Images/git_bash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/git_bash.png -------------------------------------------------------------------------------- /documents/Images/quota-check-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/quota-check-output.png -------------------------------------------------------------------------------- /documents/Images/resource-groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/resource-groups.png -------------------------------------------------------------------------------- /documents/Images/resourcegroup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/documents/Images/resourcegroup.png -------------------------------------------------------------------------------- /documents/PowershellSetup.md: -------------------------------------------------------------------------------- 1 | # Add PowerShell 7 to PATH in Windows 2 | 3 | This guide will help you add **PowerShell 7** (PowerShell Core) to your system’s PATH variable on Windows, so you can easily run it from any Command Prompt or Run dialog. 4 | 5 | ## Prerequisites 6 | 7 | - You should have **PowerShell 7** installed on your machine. If you haven’t installed it yet, you can download it following the guide here: [Installing PowerShell on Windows | Microsoft Learn](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.5). 8 | - **Administrative privileges are not required** unless you're modifying system-wide environment variables. You can modify your **user-specific PATH** without admin rights. 9 | 10 | ## Steps to Add PowerShell 7 to PATH 11 | 12 | ### 1. Open **System Properties** 13 | - Press `Win + X` and choose **System**. 14 | - Click on **Advanced system settings** on the left sidebar. This will open the **System Properties** window. 15 | - In the **System Properties** window, click on the **Environment Variables** button at the bottom. 16 | 17 | ### 2. Edit User Environment Variables 18 | - In the **Environment Variables** window, under **User variables**, find the `Path` variable. 19 | - Select the `Path` variable and click **Edit**. (If the `Path` variable doesn’t exist, click **New** and name it `Path`.) 20 | 21 | ### 3. Check if PowerShell 7 Path is Already in PATH 22 | - Before adding the path, make sure the following path is not already present in the list: 23 | ``` 24 | C:\Program Files\PowerShell\7\ 25 | ``` 26 | - If the path is already there, you don't need to add it again. 27 | 28 | ### 4. Add PowerShell 7 Path 29 | - If the path is not already in the list, click **New** in the **Edit Environment Variable** window. 30 | - Add the following path to the list: 31 | 32 | ``` 33 | C:\Program Files\PowerShell\7\ 34 | ``` 35 | 36 | > **Note:** If you installed PowerShell 7 in a custom location, replace the above path with the correct one. 37 | 38 | ### 5. Save Changes 39 | - After adding the path, click **OK** to close the **Edit Environment Variable** window. 40 | - Click **OK** again to close the **Environment Variables** window. 41 | - Finally, click **OK** to exit the **System Properties** window. 42 | 43 | ### 6. Verify PowerShell 7 in PATH 44 | - Open **Command Prompt** or **Run** (press `Win + R`). 45 | - Type `pwsh` and press Enter. 46 | - If PowerShell 7 opens, you've successfully added it to your PATH! 47 | 48 | --- 49 | 50 | ## Troubleshooting 51 | 52 | - **PowerShell 7 not opening:** Ensure the path to PowerShell 7 is entered correctly. If you're using a custom installation folder, check that the correct path is added to the `Path` variable. 53 | 54 | - **Changes not taking effect:** Try restarting your computer or logging out and logging back in for the changes to apply. 55 | -------------------------------------------------------------------------------- /documents/TechnicalArchitecture.md: -------------------------------------------------------------------------------- 1 | ## Technical Architecture 2 | 3 | This section outlines the components and interactions that power the conversational insights platform. The architecture ingests call transcripts and audio files, applies AI services for enrichment and structuring, and surfaces insights via an interactive web experience. 4 | 5 | ![image](./Images/ReadMe/solution-architecture.png) 6 | 7 | ### Call Audio Files / Call Transcripts 8 | Raw audio and text-based transcripts are the primary input into the system. These files are uploaded and stored for downstream processing. 9 | 10 | ### Storage Account 11 | Stores uploaded call transcripts and audio files. Serves as the initial staging layer before processing begins. 12 | 13 | ### Azure AI Content Understanding 14 | Processes the audio and text files to extract conversation details, including speaker turns, timestamps, and semantic structure. 15 | 16 | ### Azure AI Search 17 | Indexes the vectorized transcripts for semantic search. Enables rapid retrieval of relevant conversation snippets and contextual fragments using vector search and keyword matching. 18 | 19 | ### SQL Database 20 | Stores structured output including extracted entities, mapped concepts, and additional metadata. 21 | 22 | ### Azure AI Services 23 | Performs topic modeling on enriched transcript data, uncovering themes and conversation patterns using pre-trained models. 24 | 25 | ### Azure OpenAI Service 26 | Provides large language model (LLM) capabilities to support summarization, natural language querying, and semantic enrichment. 27 | 28 | ### Semantic Kernel 29 | Handles orchestration and intelligent function calling for contextualized responses and multi-step reasoning over retrieved data. 30 | 31 | ### App Service 32 | Hosts the web application and API layer that interfaces with the AI services and storage layers. Manages user sessions and handles REST calls. 33 | 34 | ### Container Registry 35 | Stores containerized deployments for use in the hosting environment. 36 | 37 | ### Azure Cosmos DB 38 | Persists chat history and session context for the web interface. Enables retrieval of past interactions. 39 | 40 | ### Web Front-End 41 | An interactive UI where users can explore call insights, visualize trends, ask questions in natural language, and generate charts. Connects directly to Cosmos DB and App Services for real-time interaction. -------------------------------------------------------------------------------- /documents/create_new_app_registration.md: -------------------------------------------------------------------------------- 1 | # Creating a new App Registration 2 | 3 | 1. Click on `Home` and select `Microsoft Entra ID`. 4 | 5 | ![Microsoft Entra ID](Images/MicrosoftEntraID.png) 6 | 7 | 2. Click on `App registrations`. 8 | 9 | ![App registrations](Images/Appregistrations.png) 10 | 11 | 3. Click on `+ New registration`. 12 | 13 | ![New Registrations](Images/NewRegistration.png) 14 | 15 | 4. Provide the `Name`, select supported account types as `Accounts in this organizational directory only(Contoso only - Single tenant)`, select platform as `Web`, enter/select the `URL` and register. 16 | 17 | ![Add Details](Images/AddDetails.png) 18 | 19 | 5. After application is created successfully, then click on `Add a Redirect URL`. 20 | 21 | ![Redirect URL](Images/AddRedirectURL.png) 22 | 23 | 6. Click on `+ Add a platform`. 24 | 25 | ![+ Add platform](Images/AddPlatform.png) 26 | 27 | 7. Click on `Web`. 28 | 29 | ![Web](Images/Web.png) 30 | 31 | 8. Enter the `web app URL` (Provide the app service name in place of XXXX) and Save. Then go back to [Set Up Authentication in Azure App Service](/documents/AppAuthentication.md) Step 1 page and follow from _Point 4_ choose `Pick an existing app registration in this directory` from the Add an Identity Provider page and provide the newly registered App Name. 32 | 33 | E.g. <>.azurewebsites.net/.auth/login/aad/callback>> 34 | 35 | ![Add Details](Images/WebAppURL.png) 36 | -------------------------------------------------------------------------------- /infra/build_bicep.md: -------------------------------------------------------------------------------- 1 | **Run below code to build bicep.json after changes** 2 | 3 | az bicep build --file main.bicep 4 | 5 | **Creates Resource group** 6 | az group create --name --location 7 | 8 | **Deploys bicep template** 9 | az deployment group create --resource-group --template-file master.bicep -------------------------------------------------------------------------------- /infra/data/audio_data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/infra/data/audio_data.zip -------------------------------------------------------------------------------- /infra/data/call_transcripts.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/infra/data/call_transcripts.zip -------------------------------------------------------------------------------- /infra/data/ckm-analyzer_config_audio.json: -------------------------------------------------------------------------------- 1 | { 2 | "analyzerId": "ckm-analyzer", 3 | "name": "ckm-analyzer", 4 | "scenario": "conversation", 5 | "description": "Conversation process", 6 | "tags": { 7 | "projectId": "", 8 | "templateId": "postCallAnalytics-2024-12-01" 9 | }, 10 | "config": { 11 | "returnDetails": false, 12 | "locales": ["en-US"] 13 | }, 14 | "fieldSchema": { 15 | "name": "CallCenterConversationAnalysis", 16 | "descriptions": "Content, Summary, sentiment, and more analyses from a call center conversation", 17 | "fields": { 18 | "content": { 19 | "type": "string", 20 | "method": "generate", 21 | "description": "Full text of the conversation" 22 | }, 23 | "Duration": { 24 | "type": "string", 25 | "method": "generate", 26 | "description": "Find out how long the conversation lasted in seconds" 27 | }, 28 | "summary": { 29 | "type": "string", 30 | "method": "generate", 31 | "description": "Summarize the conversation" 32 | }, 33 | "satisfied": { 34 | "type": "string", 35 | "method": "classify", 36 | "description": "Is the customer satisfied with the agent interaction", 37 | "enum": [ 38 | "Yes", 39 | "No" 40 | ] 41 | }, 42 | "sentiment": { 43 | "type": "string", 44 | "method": "classify", 45 | "description": "Identify the sentiment of the conversation", 46 | "enum": [ 47 | "Positive", 48 | "Neutral", 49 | "Negative" 50 | ] 51 | }, 52 | "topic": { 53 | "type": "string", 54 | "method": "generate", 55 | "description": "Identify the single primary topic of the conversation in 6 words or less" 56 | }, 57 | "keyPhrases": { 58 | "type": "string", 59 | "method": "generate", 60 | "description": "Identify the top 10 key phrases as comma separated string excluding people names" 61 | }, 62 | "complaint": { 63 | "type": "string", 64 | "method": "generate", 65 | "description": "Identify the single primary complaint of the conversation in 3 words or less" 66 | } 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /infra/data/ckm-analyzer_config_text.json: -------------------------------------------------------------------------------- 1 | { 2 | "analyzerId": "ckm-analyzer-text", 3 | "name": "ckm-analyzer-text", 4 | "scenario": "text", 5 | "description": "Conversation analytics", 6 | "tags": { 7 | "projectId": "", 8 | "templateId": "postCallAnalytics-2024-12-01" 9 | }, 10 | "config": { 11 | "returnDetails": true 12 | }, 13 | "fieldSchema": { 14 | "name": "CallCenterConversationAnalysis", 15 | "descriptions": "Content, Summary, sentiment, and more analyses from a call center conversation", 16 | "fields": { 17 | "content": { 18 | "type": "string", 19 | "method": "generate", 20 | "description": "Full text of the conversation" 21 | }, 22 | "Duration": { 23 | "type": "string", 24 | "method": "generate", 25 | "description": "Find out how long the conversation lasted in seconds" 26 | }, 27 | "summary": { 28 | "type": "string", 29 | "method": "generate", 30 | "description": "Summarize the conversation" 31 | }, 32 | "satisfied": { 33 | "type": "string", 34 | "method": "classify", 35 | "description": "Is the customer satisfied with the agent interaction", 36 | "enum": [ 37 | "Yes", 38 | "No" 39 | ] 40 | }, 41 | "sentiment": { 42 | "type": "string", 43 | "method": "classify", 44 | "description": "Identify the sentiment of the conversation", 45 | "enum": [ 46 | "Positive", 47 | "Neutral", 48 | "Negative" 49 | ] 50 | }, 51 | "topic": { 52 | "type": "string", 53 | "method": "generate", 54 | "description": "Identify the single primary topic of the conversation in 6 words or less" 55 | }, 56 | "keyPhrases": { 57 | "type": "string", 58 | "method": "generate", 59 | "description": "Identify the top 10 key phrases as comma separated string excluding people names" 60 | }, 61 | "complaint": { 62 | "type": "string", 63 | "method": "generate", 64 | "description": "Identify the single primary complaint of the conversation in 3 words or less" 65 | } 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /infra/deploy_app_service.bicep: -------------------------------------------------------------------------------- 1 | // ========== Key Vault ========== // 2 | targetScope = 'resourceGroup' 3 | 4 | @description('Solution Name') 5 | param solutionName string 6 | 7 | @description('Solution Location') 8 | param solutionLocation string 9 | 10 | @secure() 11 | param appSettings object = {} 12 | param appServicePlanId string 13 | param appImageName string 14 | param userassignedIdentityId string = '' 15 | 16 | resource appService 'Microsoft.Web/sites@2020-06-01' = { 17 | name: solutionName 18 | location: solutionLocation 19 | identity: userassignedIdentityId == '' ? { 20 | type: 'SystemAssigned' 21 | } : { 22 | type: 'SystemAssigned, UserAssigned' 23 | userAssignedIdentities: { 24 | '${userassignedIdentityId}': {} 25 | } 26 | } 27 | properties: { 28 | serverFarmId: appServicePlanId 29 | siteConfig: { 30 | alwaysOn: true 31 | ftpsState: 'Disabled' 32 | linuxFxVersion: appImageName 33 | } 34 | } 35 | resource basicPublishingCredentialsPoliciesFtp 'basicPublishingCredentialsPolicies' = { 36 | name: 'ftp' 37 | properties: { 38 | allow: false 39 | } 40 | } 41 | resource basicPublishingCredentialsPoliciesScm 'basicPublishingCredentialsPolicies' = { 42 | name: 'scm' 43 | properties: { 44 | allow: false 45 | } 46 | } 47 | } 48 | 49 | module configAppSettings 'deploy_appservice-appsettings.bicep' = { 50 | name: '${appService.name}-appSettings' 51 | params: { 52 | name: appService.name 53 | appSettings: appSettings 54 | } 55 | } 56 | 57 | resource configLogs 'Microsoft.Web/sites/config@2022-03-01' = { 58 | name: 'logs' 59 | parent: appService 60 | properties: { 61 | applicationLogs: { fileSystem: { level: 'Verbose' } } 62 | detailedErrorMessages: { enabled: true } 63 | failedRequestsTracing: { enabled: true } 64 | httpLogs: { fileSystem: { enabled: true, retentionInDays: 1, retentionInMb: 35 } } 65 | } 66 | dependsOn: [configAppSettings] 67 | } 68 | 69 | output identityPrincipalId string = appService.identity.principalId 70 | output appUrl string = 'https://${solutionName}.azurewebsites.net' 71 | 72 | -------------------------------------------------------------------------------- /infra/deploy_app_service_plan.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure App Service plan.' 2 | 3 | @description('Solution Location') 4 | param solutionLocation string 5 | 6 | @description('Name of App Service plan') 7 | param HostingPlanName string 8 | 9 | @description('The pricing tier for the App Service plan') 10 | @allowed( 11 | ['F1', 'D1', 'B1', 'B2', 'B3', 'S1', 'S2', 'S3', 'P1', 'P2', 'P3', 'P4','P0v3'] 12 | ) 13 | param HostingPlanSku string = 'B2' 14 | 15 | resource HostingPlan 'Microsoft.Web/serverfarms@2020-06-01' = { 16 | name: HostingPlanName 17 | location: solutionLocation 18 | sku: { 19 | name: HostingPlanSku 20 | } 21 | properties: { 22 | reserved: true 23 | } 24 | kind: 'linux' 25 | } 26 | 27 | output id string = HostingPlan.id 28 | output name string = HostingPlan.name 29 | -------------------------------------------------------------------------------- /infra/deploy_appservice-appsettings.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Updates app settings for an Azure App Service.' 2 | @description('The name of the app service resource within the current resource group scope') 3 | param name string 4 | 5 | @description('The app settings to be applied to the app service') 6 | @secure() 7 | param appSettings object 8 | 9 | resource appService 'Microsoft.Web/sites@2022-03-01' existing = { 10 | name: name 11 | } 12 | 13 | resource settings 'Microsoft.Web/sites/config@2022-03-01' = { 14 | name: 'appsettings' 15 | parent: appService 16 | properties: appSettings 17 | } 18 | -------------------------------------------------------------------------------- /infra/deploy_frontend_docker.bicep: -------------------------------------------------------------------------------- 1 | param imageTag string 2 | param applicationInsightsId string 3 | 4 | @description('Solution Location') 5 | param solutionLocation string 6 | 7 | @secure() 8 | param appSettings object = {} 9 | param appServicePlanId string 10 | 11 | var imageName = 'DOCKER|kmcontainerreg.azurecr.io/km-app:${imageTag}' 12 | //var name = '${solutionName}-app' 13 | param name string 14 | module appService 'deploy_app_service.bicep' = { 15 | name: '${name}-app-module' 16 | params: { 17 | solutionLocation:solutionLocation 18 | solutionName: name 19 | appServicePlanId: appServicePlanId 20 | appImageName: imageName 21 | appSettings: union( 22 | appSettings, 23 | { 24 | APPINSIGHTS_INSTRUMENTATIONKEY: reference(applicationInsightsId, '2015-05-01').InstrumentationKey 25 | } 26 | ) 27 | } 28 | } 29 | 30 | output appUrl string = appService.outputs.appUrl 31 | -------------------------------------------------------------------------------- /infra/deploy_keyvault.bicep: -------------------------------------------------------------------------------- 1 | param solutionLocation string 2 | param managedIdentityObjectId string 3 | 4 | param keyvaultName string 5 | 6 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { 7 | name: keyvaultName 8 | location: solutionLocation 9 | properties: { 10 | createMode: 'default' 11 | accessPolicies: [ 12 | { 13 | objectId: managedIdentityObjectId 14 | permissions: { 15 | certificates: [ 16 | 'all' 17 | ] 18 | keys: [ 19 | 'all' 20 | ] 21 | secrets: [ 22 | 'all' 23 | ] 24 | storage: [ 25 | 'all' 26 | ] 27 | } 28 | tenantId: subscription().tenantId 29 | } 30 | ] 31 | enabledForDeployment: true 32 | enabledForDiskEncryption: true 33 | enabledForTemplateDeployment: true 34 | enableRbacAuthorization: true 35 | publicNetworkAccess: 'enabled' 36 | // networkAcls: { 37 | // bypass: 'AzureServices' 38 | // defaultAction: 'Deny' 39 | // } 40 | sku: { 41 | family: 'A' 42 | name: 'standard' 43 | } 44 | softDeleteRetentionInDays: 7 45 | tenantId: subscription().tenantId 46 | } 47 | } 48 | 49 | @description('This is the built-in Key Vault Administrator role.') 50 | resource kvAdminRole 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = { 51 | scope: resourceGroup() 52 | name: '00482a5a-887f-4fb3-b363-3b7fe8e74483' 53 | } 54 | 55 | resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 56 | name: guid(resourceGroup().id, managedIdentityObjectId, kvAdminRole.id) 57 | properties: { 58 | principalId: managedIdentityObjectId 59 | roleDefinitionId:kvAdminRole.id 60 | principalType: 'ServicePrincipal' 61 | } 62 | } 63 | 64 | output keyvaultName string = keyvaultName 65 | output keyvaultId string = keyVault.id 66 | output keyvaultUri string = keyVault.properties.vaultUri 67 | -------------------------------------------------------------------------------- /infra/deploy_managed_identity.bicep: -------------------------------------------------------------------------------- 1 | // ========== Managed Identity ========== // 2 | targetScope = 'resourceGroup' 3 | 4 | @minLength(3) 5 | @maxLength(15) 6 | @description('Solution Name') 7 | param solutionName string 8 | 9 | @description('Solution Location') 10 | param solutionLocation string 11 | 12 | @description('Name') 13 | param miName string 14 | 15 | resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { 16 | name: miName 17 | location: solutionLocation 18 | tags: { 19 | app: solutionName 20 | location: solutionLocation 21 | } 22 | } 23 | 24 | @description('This is the built-in owner role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#owner') 25 | resource ownerRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = { 26 | scope: resourceGroup() 27 | name: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' 28 | } 29 | 30 | resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 31 | name: guid(resourceGroup().id, managedIdentity.id, ownerRoleDefinition.id) 32 | properties: { 33 | principalId: managedIdentity.properties.principalId 34 | roleDefinitionId: ownerRoleDefinition.id 35 | principalType: 'ServicePrincipal' 36 | } 37 | } 38 | 39 | resource managedIdentityBackendApp 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { 40 | name: '${solutionName}-backend-app-mi' 41 | location: solutionLocation 42 | tags: { 43 | app: solutionName 44 | location: solutionLocation 45 | } 46 | } 47 | 48 | output managedIdentityOutput object = { 49 | id: managedIdentity.id 50 | objectId: managedIdentity.properties.principalId 51 | clientId: managedIdentity.properties.clientId 52 | name: miName 53 | } 54 | 55 | output managedIdentityBackendAppOutput object = { 56 | id: managedIdentityBackendApp.id 57 | objectId: managedIdentityBackendApp.properties.principalId 58 | clientId: managedIdentityBackendApp.properties.clientId 59 | name: managedIdentityBackendApp.name 60 | } 61 | -------------------------------------------------------------------------------- /infra/main.bicepparam: -------------------------------------------------------------------------------- 1 | using './main.bicep' 2 | 3 | param AZURE_LOCATION = readEnvironmentVariable('AZURE_LOCATION', '') 4 | param environmentName = readEnvironmentVariable('AZURE_ENV_NAME', 'env_name') 5 | param contentUnderstandingLocation = readEnvironmentVariable('AZURE_CONTENT_UNDERSTANDING_LOCATION', 'swedencentral') 6 | param secondaryLocation = readEnvironmentVariable('AZURE_SECONDARY_LOCATION', 'eastus2') 7 | param deploymentType = readEnvironmentVariable('AZURE_OPEN_AI_MODEL_DEPLOYMENT_TYPE', 'GlobalStandard') 8 | param gptModelName = readEnvironmentVariable('AZURE_OPEN_AI_DEPLOYMENT_MODEL', 'gpt-4o-mini') 9 | param gptModelVersion = readEnvironmentVariable('AZURE_ENV_MODEL_VERSION', '2024-07-18') 10 | param gptDeploymentCapacity = int(readEnvironmentVariable('AZURE_OPEN_AI_DEPLOYMENT_MODEL_CAPACITY', '30')) 11 | param embeddingModel = readEnvironmentVariable('AZURE_OPENAI_EMBEDDING_MODEL', 'text-embedding-ada-002') 12 | param embeddingDeploymentCapacity = int(readEnvironmentVariable('AZURE_OPENAI_EMBEDDING_MODEL_CAPACITY', '80')) 13 | param existingLogAnalyticsWorkspaceId = readEnvironmentVariable('AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID', '') 14 | -------------------------------------------------------------------------------- /infra/modules/fetch-container-image.bicep: -------------------------------------------------------------------------------- 1 | param exists bool 2 | param name string 3 | 4 | resource existingApp 'Microsoft.App/containerApps@2023-05-02-preview' existing = if (exists) { 5 | name: name 6 | } 7 | 8 | output containers array = exists ? existingApp.properties.template.containers : [] 9 | -------------------------------------------------------------------------------- /infra/process_data_scripts.bicep: -------------------------------------------------------------------------------- 1 | param solutionLocation string 2 | param keyVaultName string 3 | param identity string 4 | 5 | var baseUrl = 'https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/main/' 6 | 7 | resource process_data_scripts 'Microsoft.Resources/deploymentScripts@2020-10-01' = { 8 | kind:'AzureCLI' 9 | name: 'process_data_scripts' 10 | location: solutionLocation // Replace with your desired location 11 | identity: { 12 | type: 'UserAssigned' 13 | userAssignedIdentities: { 14 | '${identity}' : {} 15 | } 16 | } 17 | properties: { 18 | azCliVersion: '2.52.0' 19 | primaryScriptUri: '${baseUrl}infra/scripts/process_data_scripts.sh' 20 | arguments: '${baseUrl} ${keyVaultName}' // Specify any arguments for the script 21 | timeout: 'PT1H' // Specify the desired timeout duration 22 | retentionInterval: 'PT1H' // Specify the desired retention interval 23 | cleanupPreference:'OnSuccess' 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /infra/scripts/copy_kb_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | storageAccount="$1" 5 | fileSystem="$2" 6 | baseUrl="$3" 7 | managedIdentityClientId="$4" 8 | 9 | zipFileName1="call_transcripts.zip" 10 | extractedFolder1="call_transcripts" 11 | zipUrl1=${baseUrl}"infra/data/call_transcripts.zip" 12 | 13 | zipFileName2="audio_data.zip" 14 | extractedFolder2="audiodata" 15 | zipUrl2=${baseUrl}"infra/data/audio_data.zip" 16 | 17 | # Create folders if they do not exist 18 | mkdir -p "/mnt/azscripts/azscriptinput/$extractedFolder1" 19 | mkdir -p "/mnt/azscripts/azscriptinput/$extractedFolder2" 20 | 21 | # Download the zip file 22 | curl --output /mnt/azscripts/azscriptinput/"$zipFileName1" "$zipUrl1" 23 | curl --output /mnt/azscripts/azscriptinput/"$zipFileName2" "$zipUrl2" 24 | 25 | # Extract the zip file 26 | unzip /mnt/azscripts/azscriptinput/"$zipFileName1" -d /mnt/azscripts/azscriptinput/"$extractedFolder1" 27 | unzip /mnt/azscripts/azscriptinput/"$zipFileName2" -d /mnt/azscripts/azscriptinput/"$extractedFolder2" 28 | 29 | echo "Script Started" 30 | 31 | # Authenticate with Azure using managed identity 32 | az login --identity --client-id ${managedIdentityClientId} 33 | # Using az storage blob upload-batch to upload files with managed identity authentication, as the az storage fs directory upload command is not working with managed identity authentication. 34 | az storage blob upload-batch --account-name "$storageAccount" --destination data/"$extractedFolder1" --source /mnt/azscripts/azscriptinput/"$extractedFolder1" --auth-mode login --pattern '*' --overwrite 35 | az storage blob upload-batch --account-name "$storageAccount" --destination data/"$extractedFolder2" --source /mnt/azscripts/azscriptinput/"$extractedFolder2" --auth-mode login --pattern '*' --overwrite 36 | az storage fs directory create --account-name "$storageAccount" --file-system data --name custom_audiodata --auth-mode login 37 | az storage fs directory create --account-name "$storageAccount" --file-system data --name custom_transcripts --auth-mode login -------------------------------------------------------------------------------- /infra/scripts/fabric_scripts/ckm_cu_env.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - pip: 3 | - openai==0.28.0 4 | - pymssql==2.3.2 5 | - tiktoken==0.8.0 6 | -------------------------------------------------------------------------------- /infra/scripts/fabric_scripts/ckm_environment.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - pip: 3 | - azure-cognitiveservices-speech==1.37.0 4 | -------------------------------------------------------------------------------- /infra/scripts/fabric_scripts/notebooks/cu/cu_pipeline_notebook.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"cell_type":"code","source":["%run create_cu_template"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2024-07-01T03:36:40.0792374Z","execution_start_time":"2024-07-01T03:35:20.8329974Z","livy_statement_state":"available","normalized_state":"finished","parent_msg_id":"f77e37b8-b6af-4acb-aa11-9f6593ce92a8","queued_time":"2024-07-01T03:35:08.2258444Z","session_id":"a4fdd437-af0f-4a0d-b2bb-f89cc384e4ab","session_start_time":"2024-07-01T03:35:08.4670253Z","spark_pool":null,"state":"finished","statement_id":12,"statement_ids":[3,4,5,6,7,8,9,10,11,12]},"text/plain":"StatementMeta(, a4fdd437-af0f-4a0d-b2bb-f89cc384e4ab, 12, Finished, Available, Finished)"},"metadata":{}}],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"a9a2074c-59d9-48e8-8efe-54be6089ef7f"},{"cell_type":"code","source":["%run process_cu_data"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"execution_finish_time":"2024-07-01T03:40:46.4757932Z","execution_start_time":"2024-07-01T03:40:24.095566Z","livy_statement_state":"available","normalized_state":"finished","parent_msg_id":"c28e3862-7a4e-4495-aaa1-4c2ef6299d9e","queued_time":"2024-07-01T03:40:23.7437768Z","session_id":"a4fdd437-af0f-4a0d-b2bb-f89cc384e4ab","session_start_time":null,"spark_pool":null,"state":"finished","statement_id":15,"statement_ids":[13,14,15]},"text/plain":"StatementMeta(, a4fdd437-af0f-4a0d-b2bb-f89cc384e4ab, 15, Finished, Available, Finished)"},"metadata":{}}],"execution_count":null,"metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"microsoft":{"language":"python","language_group":"synapse_pyspark"},"nteract":{"transient":{"deleting":false}}},"id":"ad2c0570-7d1e-4867-b884-799f7cc311b6"}],"metadata":{"kernel_info":{"name":"synapse_pyspark"},"kernelspec":{"name":"synapse_pyspark","language":"Python","display_name":"Synapse PySpark"},"language_info":{"name":"python"},"microsoft":{"language":"python","language_group":"synapse_pyspark","ms_spell_check":{"ms_spell_check_language":"en"}},"nteract":{"version":"nteract-front-end@1.0.0"},"widgets":{},"spark_compute":{"compute_id":"/trident/default","session_options":{"conf":{"spark.synapse.nbs.session.timeout":"1200000"}}},"dependencies":{"lakehouse":{"default_lakehouse":"d93aef69-1e71-40fe-bf27-6c557ed5c959","default_lakehouse_name":"lakehouse_bk2","default_lakehouse_workspace_id":"f888d33a-4e28-4668-be3e-6a448040d2ee"},"environment":{"environmentId":"da011a17-6179-42a7-9886-d94769ece042","workspaceId":"f888d33a-4e28-4668-be3e-6a448040d2ee"}}},"nbformat":4,"nbformat_minor":5} -------------------------------------------------------------------------------- /infra/scripts/fabric_scripts/notebooks/pipeline_notebook.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"cell_type":"code","execution_count":null,"id":"301fa833-8b2e-438e-a1b8-24883dbba3bc","metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"outputs":[],"source":["# Welcome to your new notebook\n","# Type here in the cell editor to add code!\n"]},{"cell_type":"code","execution_count":null,"id":"7614ebb5-4149-43ec-99e6-b7e05df3a767","metadata":{"jupyter":{"outputs_hidden":false,"source_hidden":false},"microsoft":{"language":"python","language_group":"synapse_pyspark"},"nteract":{"transient":{"deleting":false}}},"outputs":[],"source":["%run 00_process_json_files"]},{"cell_type":"code","execution_count":null,"id":"2cc409ca","metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"outputs":[],"source":["# %run 01_process_audio_files"]},{"cell_type":"code","execution_count":null,"id":"a19223b3","metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"outputs":[],"source":["# %run 02_enrich_audio_data"]},{"cell_type":"code","execution_count":null,"id":"a9fd450a","metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"outputs":[],"source":["%run 03_post_processing"]},{"cell_type":"code","execution_count":null,"id":"f10629d2","metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"outputs":[],"source":["%run 04_create_calendar_data"]}],"metadata":{"dependencies":{"lakehouse":{"default_lakehouse":"e6ad9dad-e3da-4da5-bca6-6572c466b69a","default_lakehouse_name":"ckm_lakehouse","default_lakehouse_workspace_id":"0d98d480-171b-4b4d-a8e7-80fbd031d1a6"}},"kernel_info":{"name":"synapse_pyspark"},"language_info":{"name":"python"},"microsoft":{"language":"python","language_group":"synapse_pyspark","ms_spell_check":{"ms_spell_check_language":"en"}},"nteract":{"version":"nteract-front-end@1.0.0"},"spark_compute":{"compute_id":"/trident/default"},"widgets":{}},"nbformat":4,"nbformat_minor":5} 2 | -------------------------------------------------------------------------------- /infra/scripts/fabric_scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | msal==1.24.0b1 2 | azure-identity 3 | pandas 4 | azure-storage-file-datalake -------------------------------------------------------------------------------- /infra/scripts/fabric_scripts/run_fabric_items_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "starting script" 3 | 4 | # Variables 5 | keyvaultName="$1" 6 | fabricWorkspaceId="$2" 7 | solutionName="$3" 8 | 9 | # get signed user 10 | echo "Getting signed in user id" 11 | signed_user_id=$(az ad signed-in-user show --query id -o tsv) 12 | 13 | # Check if the user_id is empty 14 | if [ -z "$signed_user_id" ]; then 15 | echo "Error: User ID not found. Please check the user principal name or email address." 16 | exit 1 17 | fi 18 | 19 | # Define the scope for the Key Vault (replace with your Key Vault resource ID) 20 | echo "Getting key vault resource id" 21 | key_vault_resource_id=$(az keyvault show --name $keyvaultName --query id --output tsv) 22 | 23 | # Check if the key_vault_resource_id is empty 24 | if [ -z "$key_vault_resource_id" ]; then 25 | echo "Error: Key Vault not found. Please check the Key Vault name." 26 | exit 1 27 | fi 28 | 29 | # Assign the Key Vault Administrator role to the user 30 | echo "Assigning the Key Vault Administrator role to the user..." 31 | az role assignment create --assignee $signed_user_id --role "Key Vault Administrator" --scope $key_vault_resource_id 32 | 33 | 34 | # Check if the role assignment command was successful 35 | if [ $? -ne 0 ]; then 36 | echo "Error: Role assignment failed. Please check the provided details and your Azure permissions." 37 | exit 1 38 | fi 39 | echo "Role assignment completed successfully." 40 | 41 | #Replace key vault name and workspace id in the python files 42 | sed -i "s/kv_to-be-replaced/${keyvaultName}/g" "create_fabric_items.py" 43 | sed -i "s/solutionName_to-be-replaced/${solutionName}/g" "create_fabric_items.py" 44 | sed -i "s/workspaceId_to-be-replaced/${fabricWorkspaceId}/g" "create_fabric_items.py" 45 | 46 | # sed -i "s/kv_to-be-replaced/${keyvaultName}/g" "notebooks/01_process_data.ipynb" 47 | sed -i "s/kv_to-be-replaced/${keyvaultName}/g" "notebooks/cu/create_cu_template.ipynb" 48 | sed -i "s/kv_to-be-replaced/${keyvaultName}/g" "notebooks/cu/process_cu_data.ipynb" 49 | 50 | pip install -r requirements.txt --quiet 51 | 52 | python create_fabric_items.py -------------------------------------------------------------------------------- /infra/scripts/index_scripts/02_create_cu_template_audio.py: -------------------------------------------------------------------------------- 1 | # Import required modules 2 | 3 | 4 | from azure.keyvault.secrets import SecretClient 5 | from azure.identity import DefaultAzureCredential 6 | import sys 7 | from pathlib import Path 8 | from azure.identity import DefaultAzureCredential, get_bearer_token_provider 9 | 10 | key_vault_name = 'kv_to-be-replaced' 11 | managed_identity_client_id = 'mici_to-be-replaced' 12 | 13 | def get_secrets_from_kv(kv_name, secret_name): 14 | 15 | # Set the name of the Azure Key Vault 16 | key_vault_name = kv_name 17 | credential = DefaultAzureCredential(managed_identity_client_id=managed_identity_client_id) 18 | 19 | # Create a secret client object using the credential and Key Vault name 20 | secret_client = SecretClient(vault_url=f"https://{key_vault_name}.vault.azure.net/", credential=credential) 21 | 22 | # Retrieve the secret value 23 | return(secret_client.get_secret(secret_name).value) 24 | 25 | 26 | # Add the parent directory to the path to use shared modules 27 | parent_dir = Path(Path.cwd()).parent 28 | sys.path.append(str(parent_dir)) 29 | from content_understanding_client import AzureContentUnderstandingClient 30 | AZURE_AI_ENDPOINT = get_secrets_from_kv(key_vault_name,"AZURE-OPENAI-CU-ENDPOINT") 31 | AZURE_OPENAI_CU_KEY = get_secrets_from_kv(key_vault_name,"AZURE-OPENAI-CU-KEY") 32 | AZURE_AI_API_VERSION = "2024-12-01-preview" 33 | 34 | 35 | credential = DefaultAzureCredential(managed_identity_client_id=managed_identity_client_id) 36 | token_provider = get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default") 37 | client = AzureContentUnderstandingClient( 38 | endpoint=AZURE_AI_ENDPOINT, 39 | api_version=AZURE_AI_API_VERSION, 40 | subscription_key=AZURE_OPENAI_CU_KEY, 41 | token_provider=token_provider 42 | ) 43 | 44 | 45 | ANALYZER_ID = "ckm-audio" 46 | ANALYZER_TEMPLATE_FILE = 'ckm-analyzer_config_audio.json' 47 | 48 | 49 | # Create analyzer 50 | response = client.begin_create_analyzer(ANALYZER_ID, analyzer_template_path=ANALYZER_TEMPLATE_FILE) 51 | result = client.poll_result(response) -------------------------------------------------------------------------------- /infra/scripts/index_scripts/02_create_cu_template_text.py: -------------------------------------------------------------------------------- 1 | # Import required modules 2 | 3 | 4 | from azure.keyvault.secrets import SecretClient 5 | from azure.identity import DefaultAzureCredential 6 | import sys 7 | from pathlib import Path 8 | from azure.identity import DefaultAzureCredential, get_bearer_token_provider 9 | 10 | key_vault_name = 'kv_to-be-replaced' 11 | managed_identity_client_id = 'mici_to-be-replaced' 12 | 13 | def get_secrets_from_kv(kv_name, secret_name): 14 | 15 | # Set the name of the Azure Key Vault 16 | key_vault_name = kv_name 17 | credential = DefaultAzureCredential(managed_identity_client_id=managed_identity_client_id) 18 | 19 | # Create a secret client object using the credential and Key Vault name 20 | secret_client = SecretClient(vault_url=f"https://{key_vault_name}.vault.azure.net/", credential=credential) 21 | 22 | # Retrieve the secret value 23 | return(secret_client.get_secret(secret_name).value) 24 | 25 | 26 | # Add the parent directory to the path to use shared modules 27 | parent_dir = Path(Path.cwd()).parent 28 | sys.path.append(str(parent_dir)) 29 | from content_understanding_client import AzureContentUnderstandingClient 30 | AZURE_AI_ENDPOINT = get_secrets_from_kv(key_vault_name,"AZURE-OPENAI-CU-ENDPOINT") 31 | AZURE_OPENAI_CU_KEY = get_secrets_from_kv(key_vault_name,"AZURE-OPENAI-CU-KEY") 32 | AZURE_AI_API_VERSION = "2024-12-01-preview" 33 | 34 | 35 | credential = DefaultAzureCredential(managed_identity_client_id=managed_identity_client_id) 36 | token_provider = get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default") 37 | 38 | client = AzureContentUnderstandingClient( 39 | endpoint=AZURE_AI_ENDPOINT, 40 | api_version=AZURE_AI_API_VERSION, 41 | subscription_key=AZURE_OPENAI_CU_KEY, 42 | token_provider=token_provider 43 | ) 44 | 45 | 46 | ANALYZER_ID = "ckm-json" 47 | ANALYZER_TEMPLATE_FILE = 'ckm-analyzer_config_text.json' 48 | 49 | 50 | # Create analyzer 51 | response = client.begin_create_analyzer(ANALYZER_ID, analyzer_template_path=ANALYZER_TEMPLATE_FILE) 52 | result = client.poll_result(response) -------------------------------------------------------------------------------- /infra/scripts/index_scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | azure-storage-file-datalake 2 | # langchain 3 | openai 4 | pypdf 5 | # pyodbc 6 | tiktoken 7 | msal[broker]==1.31.1 8 | azure-identity 9 | azure-ai-textanalytics 10 | azure-search-documents==11.6.0b3 11 | azure-keyvault-secrets 12 | pandas 13 | pyodbc==5.2.0 14 | datetime 15 | # graphrag==0.3.6 -------------------------------------------------------------------------------- /infra/scripts/process_data_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "started the script" 3 | 4 | # Variables 5 | baseUrl="$1" 6 | keyvaultName="$2" 7 | requirementFile="requirements.txt" 8 | requirementFileUrl=${baseUrl}"infra/scripts/index_scripts/requirements.txt" 9 | 10 | echo "Script Started" 11 | 12 | curl --output "04_cu_process_data_new_data.py" ${baseUrl}"infra/scripts/index_scripts/04_cu_process_data_new_data.py" 13 | curl --output "content_understanding_client.py" ${baseUrl}"infra/scripts/index_scripts/content_understanding_client.py" 14 | curl --output "ckm-analyzer_config_text.json" ${baseUrl}"infra/data/ckm-analyzer_config_text.json" 15 | curl --output "ckm-analyzer_config_audio.json" ${baseUrl}"infra/data/ckm-analyzer_config_audio.json" 16 | 17 | ############################################ 18 | echo "Installing system packages..." 19 | apk add --no-cache --virtual .build-deps build-base unixodbc-dev 20 | #Download the desired package(s) 21 | curl -O https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/msodbcsql17_17.10.6.1-1_amd64.apk 22 | curl -O https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/mssql-tools_17.10.1.1-1_amd64.apk 23 | #Install the package(s) 24 | apk add --allow-untrusted msodbcsql17_17.10.6.1-1_amd64.apk 25 | apk add --allow-untrusted mssql-tools_17.10.1.1-1_amd64.apk 26 | ############################################ 27 | 28 | # Download the requirement file 29 | curl --output "$requirementFile" "$requirementFileUrl" 30 | 31 | echo "Download completed" 32 | 33 | sed -i "s/kv_to-be-replaced/${keyvaultName}/g" "04_cu_process_data_new_data.py" 34 | 35 | pip install -r requirements.txt 36 | 37 | python 04_cu_process_data_new_data.py -------------------------------------------------------------------------------- /infra/scripts/run_create_index_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "started the script" 3 | 4 | # Variables 5 | baseUrl="$1" 6 | keyvaultName="$2" 7 | managedIdentityClientId="$3" 8 | requirementFile="requirements.txt" 9 | requirementFileUrl=${baseUrl}"infra/scripts/index_scripts/requirements.txt" 10 | 11 | echo "Script Started" 12 | 13 | # Download the create_index and create table python files 14 | curl --output "01_create_search_index.py" ${baseUrl}"infra/scripts/index_scripts/01_create_search_index.py" 15 | curl --output "02_create_cu_template_text.py" ${baseUrl}"infra/scripts/index_scripts/02_create_cu_template_text.py" 16 | curl --output "02_create_cu_template_audio.py" ${baseUrl}"infra/scripts/index_scripts/02_create_cu_template_audio.py" 17 | curl --output "03_cu_process_data_text.py" ${baseUrl}"infra/scripts/index_scripts/03_cu_process_data_text.py" 18 | curl --output "content_understanding_client.py" ${baseUrl}"infra/scripts/index_scripts/content_understanding_client.py" 19 | curl --output "ckm-analyzer_config_text.json" ${baseUrl}"infra/data/ckm-analyzer_config_text.json" 20 | curl --output "ckm-analyzer_config_audio.json" ${baseUrl}"infra/data/ckm-analyzer_config_audio.json" 21 | 22 | curl --output "sample_processed_data.json" ${baseUrl}"infra/data/sample_processed_data.json" 23 | curl --output "sample_processed_data_key_phrases.json" ${baseUrl}"infra/data/sample_processed_data_key_phrases.json" 24 | curl --output "sample_search_index_data.json" ${baseUrl}"infra/data/sample_search_index_data.json" 25 | 26 | # RUN apt-get update 27 | # RUN apt-get install python3 python3-dev g++ unixodbc-dev unixodbc libpq-dev 28 | # apk add python3 python3-dev g++ unixodbc-dev unixodbc libpq-dev 29 | 30 | # # RUN apt-get install python3 python3-dev g++ unixodbc-dev unixodbc libpq-dev 31 | # pip install pyodbc 32 | 33 | # Download the requirement file 34 | curl --output "$requirementFile" "$requirementFileUrl" 35 | 36 | echo "Download completed" 37 | 38 | #Replace key vault name 39 | sed -i "s/kv_to-be-replaced/${keyvaultName}/g" "01_create_search_index.py" 40 | sed -i "s/mici_to-be-replaced/${managedIdentityClientId}/g" "01_create_search_index.py" 41 | sed -i "s/kv_to-be-replaced/${keyvaultName}/g" "02_create_cu_template_text.py" 42 | sed -i "s/mici_to-be-replaced/${managedIdentityClientId}/g" "02_create_cu_template_text.py" 43 | sed -i "s/kv_to-be-replaced/${keyvaultName}/g" "02_create_cu_template_audio.py" 44 | sed -i "s/mici_to-be-replaced/${managedIdentityClientId}/g" "02_create_cu_template_audio.py" 45 | sed -i "s/kv_to-be-replaced/${keyvaultName}/g" "03_cu_process_data_text.py" 46 | sed -i "s/mici_to-be-replaced/${managedIdentityClientId}/g" "03_cu_process_data_text.py" 47 | 48 | pip install -r requirements.txt 49 | 50 | python 01_create_search_index.py 51 | python 02_create_cu_template_text.py 52 | python 02_create_cu_template_audio.py 53 | python 03_cu_process_data_text.py -------------------------------------------------------------------------------- /infra/scripts/run_process_data_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # === Configuration === 4 | resourceGroupName="$1" 5 | bicepFile="./../process_data_scripts.bicep" 6 | 7 | # If resourcegroup not provided as an argument, get it from AZD environment 8 | if [ -z "$resourceGroupName" ]; then 9 | resourceGroupName=$(azd env get-value RESOURCE_GROUP_NAME 2>/dev/null) 10 | fi 11 | 12 | # Validate the value was eventually set 13 | if [ -z "$resourceGroupName" ]; then 14 | echo "Usage: $0 " 15 | echo "ERROR: resourceGroupName not provided and not found in AZD environment." 16 | exit 1 17 | fi 18 | 19 | # === Ensure user is logged in to Azure CLI === 20 | az account show > /dev/null 2>&1 || az login 21 | 22 | echo "Fetching Key Vault and Managed Identity from resource group: $resourceGroupName" 23 | 24 | # === Retrieve the first Key Vault name from the specified resource group === 25 | keyVaultName=$(az keyvault list --resource-group "$resourceGroupName" --query "[0].name" -o tsv) 26 | 27 | # === Retrieve the ID of the first user-assigned identity with name starting with 'id-' === 28 | identityId=$(az identity list --resource-group "$resourceGroupName" --query "[?starts_with(name, 'id-')].id | [0]" -o tsv) 29 | 30 | # === Normalize identityId (necessary for compatibility in Git Bash on Windows) === 31 | identityId=$(echo "$identityId" | sed -E 's|.*(/subscriptions/)|\1|') 32 | 33 | # === Get the location of the first SQL Server in the resource group === 34 | sqlServerLocation=$(az sql server list --resource-group "$resourceGroupName" --query "[0].location" -o tsv) 35 | 36 | # === Validate that all required resources were found === 37 | if [[ -z "$keyVaultName" || -z "$sqlServerLocation" || -z "$identityId" || ! "$identityId" =~ ^/subscriptions/ ]]; then 38 | echo "ERROR: Could not find required resources in resource group $resourceGroupName or identityId is invalid" 39 | exit 1 40 | fi 41 | 42 | echo "Using SQL Server Location: $sqlServerLocation" 43 | echo "Using Key Vault: $keyVaultName" 44 | echo "Using Managed Identity: $identityId" 45 | 46 | # === Deploy resources using the specified Bicep template === 47 | echo "Deploying Bicep template..." 48 | 49 | # MSYS_NO_PATHCONV disables path conversion in Git Bash for Windows 50 | MSYS_NO_PATHCONV=1 az deployment group create \ 51 | --resource-group "$resourceGroupName" \ 52 | --template-file "$bicepFile" \ 53 | --parameters solutionLocation="$sqlServerLocation" keyVaultName="$keyVaultName" identity="$identityId" 54 | 55 | echo "Deployment completed." 56 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | markers = 3 | unittest: Unit Tests (relatively fast) 4 | functional: Functional Tests (tests that require a running server, with stubbed downstreams) 5 | azure: marks tests as extended (run less frequently, relatively slow) 6 | pythonpath = ./src/api 7 | log_level=debug 8 | -------------------------------------------------------------------------------- /src/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | extend-ignore = E501, E203 4 | exclude = .venv, App, -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | # TeamsFx files 2 | env/.env.*.user 3 | env/.env.local 4 | .localConfigs 5 | appPackage/build 6 | 7 | # dependencies 8 | node_modules/ 9 | /node_modules 10 | App/frontend/node_modules 11 | App/.venv/ 12 | 13 | # misc 14 | .venv/ 15 | .deployment 16 | .DS_Store 17 | 18 | # build 19 | lib/ 20 | /lib 21 | /build 22 | 23 | .venv 24 | frontend/node_modules 25 | # static 26 | .azure/ 27 | __pycache__/ 28 | .ipynb_checkpoints/ 29 | 30 | .myenv 31 | /myenv 32 | myenv -------------------------------------------------------------------------------- /src/App/.dockerignore: -------------------------------------------------------------------------------- 1 | # Include any files or directories that you don't want to be copied to your 2 | # container here (e.g., local build artifacts, temporary files, etc.). 3 | # 4 | # For more help, visit the .dockerignore file reference guide at 5 | # https://docs.docker.com/engine/reference/builder/#dockerignore-file 6 | 7 | **/.DS_Store 8 | **/__pycache__ 9 | **/.venv 10 | **/.classpath 11 | **/.dockerignore 12 | **/.git 13 | **/.gitignore 14 | **/.project 15 | **/.settings 16 | **/.toolstarget 17 | **/.vs 18 | **/.vscode 19 | **/*.*proj.user 20 | **/*.dbmdl 21 | **/*.jfm 22 | **/bin 23 | **/charts 24 | **/docker-compose* 25 | **/compose* 26 | **/Dockerfile* 27 | **/*.Dockerfile 28 | **/node_modules 29 | **/npm-debug.log 30 | **/obj 31 | **/secrets.dev.yaml 32 | **/values.dev.yaml 33 | LICENSE 34 | README.md 35 | 36 | # Byte-compiled / optimized / DLL files 37 | __pycache__/ 38 | *.py[cod] 39 | *$py.class 40 | 41 | # C extensions 42 | *.so 43 | 44 | # Distribution / packaging 45 | .Python 46 | build/ 47 | develop-eggs/ 48 | dist/ 49 | downloads/ 50 | eggs/ 51 | lib/ 52 | lib64/ 53 | parts/ 54 | sdist/ 55 | var/ 56 | *.egg-info/ 57 | .installed.cfg 58 | *.egg 59 | 60 | # PyInstaller 61 | # Usually these files are written by a python script from a template 62 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 63 | *.manifest 64 | *.spec 65 | 66 | # Installer logs 67 | pip-log.txt 68 | pip-delete-this-directory.txt 69 | 70 | # Unit test / coverage reports 71 | htmlcov/ 72 | .tox/ 73 | .nox/ 74 | .coverage 75 | .coverage.* 76 | .cache 77 | nosetests.xml 78 | coverage.xml 79 | *.cover 80 | *.log 81 | 82 | # Translations 83 | *.mo 84 | *.pot 85 | 86 | # Django stuff: 87 | *.log 88 | local_settings.py 89 | db.sqlite3 90 | 91 | # Flask stuff: 92 | instance/ 93 | .webassets-cache 94 | 95 | # Scrapy stuff: 96 | .scrapy 97 | 98 | # Sphinx documentation 99 | docs/_build/ 100 | 101 | # PyBuilder 102 | target/ 103 | 104 | # Jupyter Notebook 105 | .ipynb_checkpoints 106 | 107 | # IPython 108 | profile_default/ 109 | ipython_config.py 110 | 111 | # pyenv 112 | .python-version 113 | 114 | # celery beat schedule file 115 | celerybeat-schedule 116 | 117 | # SageMath parsed files 118 | *.sage.py 119 | 120 | # Environments 121 | .venv 122 | env/ 123 | venv/ 124 | ENV/ 125 | env.bak/ 126 | venv.bak/ 127 | 128 | # Spyder project settings 129 | .spyderproject 130 | .spyproject 131 | 132 | # Rope project settings 133 | .ropeproject 134 | 135 | # mkdocs documentation 136 | /site 137 | 138 | # mypy 139 | .mypy_cache/ 140 | .dmypy.json 141 | dmypy.json 142 | 143 | # Pyre type checker 144 | .pyre/ 145 | 146 | # pytype static type analyzer 147 | .pytype/ 148 | 149 | # Cython debug symbols 150 | cython_debug/ 151 | 152 | # VS Code 153 | .vscode/ 154 | 155 | # Ignore other unnecessary files 156 | *.bak 157 | *.swp 158 | .DS_Store 159 | *.pdb 160 | *.sqlite3 161 | -------------------------------------------------------------------------------- /src/App/.env: -------------------------------------------------------------------------------- 1 | REACT_APP_API_BASE_URL=APP_API_BASE_URL -------------------------------------------------------------------------------- /src/App/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/App/.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://pkgs.dev.azure.com/CSACTOSOL/KnowledgeMining/_packaging/KnowledgeMining/_PublicPackages/npm/registry/ 2 | registry=https://registry.npmjs.org/ 3 | always-auth=true -------------------------------------------------------------------------------- /src/App/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | -------------------------------------------------------------------------------- /src/App/WebApp.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine AS build 2 | WORKDIR /home/node/app 3 | 4 | COPY ./package*.json ./ 5 | 6 | RUN npm ci --omit=dev 7 | 8 | COPY . . 9 | 10 | RUN npm run build 11 | 12 | FROM nginx:alpine 13 | 14 | COPY --from=build /home/node/app/build /usr/share/nginx/html 15 | 16 | COPY env.sh /docker-entrypoint.d/env.sh 17 | RUN chmod +x /docker-entrypoint.d/env.sh 18 | RUN sed -i 's/\r$//' /docker-entrypoint.d/env.sh 19 | 20 | # Expose the application port 21 | EXPOSE 3000 22 | 23 | # Start NGINX and run env.sh 24 | CMD ["/bin/sh", "-c", "/docker-entrypoint.d/env.sh && nginx -g 'daemon off;'"] -------------------------------------------------------------------------------- /src/App/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | for i in $(env | grep ^APP_) 3 | do 4 | key=$(echo $i | cut -d '=' -f 1) 5 | value=$(echo $i | cut -d '=' -f 2-) 6 | echo $key=$value 7 | # Use sed to replace only the exact matches of the key 8 | find /usr/share/nginx/html -type f -exec sed -i "s|\b${key}\b|${value}|g" '{}' + 9 | done 10 | echo 'done' -------------------------------------------------------------------------------- /src/App/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "km-chart-visualization", 3 | "version": "0.1.0", 4 | "private": true, 5 | "proxy": "http://localhost:5000", 6 | "dependencies": { 7 | "@fluentui/react": "^8.122.14", 8 | "@azure/msal-react": "^3.0.7", 9 | "@azure/msal-browser": "^4.8.0", 10 | "@testing-library/jest-dom": "^6.6.3", 11 | "@fluentui/react-icons": "^2.0.292", 12 | "@fluentui/react-components": "^9.61.6", 13 | "@testing-library/react": "^16.2.0", 14 | "@testing-library/user-event": "^13.5.0", 15 | "@types/d3": "^7.4.3", 16 | "@types/jest": "^29.5.14", 17 | "@types/node": "^22.13.16", 18 | "@types/react": "^18.3.11", 19 | "@types/react-dom": "^18.3.1", 20 | "axios": "^1.8.4", 21 | "chart.js": "^4.4.8", 22 | "d3": "^7.9.0", 23 | "d3-cloud": "^1.2.7", 24 | "react": "^18.3.1", 25 | "react-chartjs-2": "^5.3.0", 26 | "react-d3-cloud": "^1.0.6", 27 | "react-dom": "^18.3.1", 28 | "react-markdown": "^10.1.0", 29 | "rehype-raw": "^7.0.0", 30 | "lodash-es": "^4.17.21", 31 | "react-scripts": "5.0.1", 32 | "remark-gfm": "^4.0.1", 33 | "remark-supersub": "^1.0.0", 34 | "typescript": "^4.9.5", 35 | "web-vitals": "^2.1.4" 36 | }, 37 | "scripts": { 38 | "start": "react-scripts start", 39 | "build": "react-scripts build", 40 | "test": "react-scripts test", 41 | "eject": "react-scripts eject" 42 | }, 43 | "eslintConfig": { 44 | "extends": [ 45 | "react-app", 46 | "react-app/jest" 47 | ] 48 | }, 49 | "browserslist": { 50 | "production": [ 51 | ">0.2%", 52 | "not dead", 53 | "not op_mini all" 54 | ], 55 | "development": [ 56 | "last 1 chrome version", 57 | "last 1 firefox version", 58 | "last 1 safari version" 59 | ] 60 | }, 61 | "devDependencies": { 62 | "@types/chart.js": "^2.9.41", 63 | "@types/lodash-es": "^4.17.12" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/App/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/App/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /src/App/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/App/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /src/App/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/App/public/apple-touch-icon.png -------------------------------------------------------------------------------- /src/App/public/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appConfig": { 3 | "THREE_COLUMN": { 4 | "DASHBOARD": 50, 5 | "CHAT": 33, 6 | "CHATHISTORY": 17 7 | }, 8 | "TWO_COLUMN": { 9 | "DASHBOARD_CHAT": { 10 | "DASHBOARD": 65, 11 | "CHAT": 35 12 | }, 13 | "CHAT_CHATHISTORY": { 14 | "CHAT": 80, 15 | "CHATHISTORY": 20 16 | } 17 | } 18 | }, 19 | "charts": [ 20 | { 21 | "id": "SATISFIED", 22 | "chart_name": "Satisfied", 23 | "chart_type": "card", 24 | "layout": { "row": 1, "column": 1, "height": 11 } 25 | }, 26 | { 27 | "id": "TOTAL_CALLS", 28 | "chart_name": "Total Calls", 29 | "chart_type": "card", 30 | "layout": { "row": 1, "column": 2, "span": 1 } 31 | }, 32 | { 33 | "id": "AVG_HANDLING_TIME", 34 | "chart_name": "Average Handling Time", 35 | "chart_type": "card", 36 | "layout": { "row": 1, "column": 3, "span": 1 } 37 | }, 38 | { 39 | "id": "SENTIMENT", 40 | "chart_name": "Topics Overview", 41 | "chart_type": "donutchart", 42 | "layout": { "row": 2, "column": 1, "width": 40, "height": 44.5 } 43 | }, 44 | { 45 | "id": "AVG_HANDLING_TIME_BY_TOPIC", 46 | "chart_name": "Average Handling Time By Topic", 47 | "chart_type": "bar", 48 | "layout": { "row": 2, "column": 2, "row-span": 2, "width": 60 } 49 | }, 50 | { 51 | "id": "TOPICS", 52 | "chart_name": "Trending Topics", 53 | "chart_type": "table", 54 | "layout": { "row": 3, "column": 1, "span": 2 } 55 | }, 56 | { 57 | "id": "KEY_PHRASES", 58 | "chart_name": "Key Phrases", 59 | "chart_type": "wordcloud", 60 | "layout": { "row": 3, "column": 2, "height": 44.5 } 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /src/App/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/App/public/favicon-16x16.png -------------------------------------------------------------------------------- /src/App/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/App/public/favicon-32x32.png -------------------------------------------------------------------------------- /src/App/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/App/public/favicon.ico -------------------------------------------------------------------------------- /src/App/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 16 | 19 | 20 | 21 | 30 | KM-Generic 31 | 32 | 33 | 34 |
35 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/App/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "KM-Gen", 3 | "name": "Knowledge Mining Generic", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "/android-chrome-192x192.png", 12 | "sizes": "192x192", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "/android-chrome-512x512.png", 17 | "sizes": "512x512", 18 | "type": "image/png" 19 | }, 20 | { 21 | "src": "/favicon-16x16.png", 22 | "sizes": "16x16", 23 | "type": "image/png" 24 | }, 25 | { 26 | "src": "/favicon-32x32.png", 27 | "sizes": "32x32", 28 | "type": "image/png" 29 | } 30 | ], 31 | "start_url": ".", 32 | "display": "standalone", 33 | "theme_color": "#000000", 34 | "background_color": "#ffffff" 35 | } 36 | -------------------------------------------------------------------------------- /src/App/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/App/src/Assets/ContosoImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/App/src/Assets/ContosoImg.png -------------------------------------------------------------------------------- /src/App/src/Assets/Reset-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/App/src/Assets/Sparkle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/App/src/Assets/Sparkle.png -------------------------------------------------------------------------------- /src/App/src/Assets/km_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/App/src/Assets/km_logo.png -------------------------------------------------------------------------------- /src/App/src/chartComponents/Card.tsx: -------------------------------------------------------------------------------- 1 | import { Subtitle2 } from "@fluentui/react-components"; 2 | import React from "react"; 3 | 4 | interface CardProps { 5 | value: number | string; 6 | description: string; 7 | unit_of_measurement: string; 8 | containerHeight: number; 9 | } 10 | 11 | const Card: React.FC = ({ 12 | value, 13 | description, 14 | unit_of_measurement, 15 | containerHeight, 16 | }) => { 17 | if (unit_of_measurement === "") { 18 | value = value.toLocaleString("en-US"); 19 | } 20 | return ( 21 |
22 | {`${value}${unit_of_measurement}`} 23 |
24 | ); 25 | }; 26 | 27 | export default Card; 28 | -------------------------------------------------------------------------------- /src/App/src/components/ChatHistory/ChatHistory.css: -------------------------------------------------------------------------------- 1 | .chat-history-container { 2 | display: flex; 3 | flex-direction: column; 4 | height: calc(100% - 2px); 5 | width: calc(100% - 2px); 6 | margin: 0 auto; 7 | border: 1px solid #ccc; 8 | border-radius: 8px; 9 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 10 | background-color: #f5f5f5; 11 | overflow-y: auto; 12 | } 13 | 14 | .chat-history-list { 15 | flex: 1; 16 | overflow-y: auto; 17 | padding: 10px; 18 | background-color: #f9f9f9; 19 | position: relative; 20 | } 21 | 22 | .chat-history-header { 23 | font-size: 1rem; 24 | font-weight: 600; 25 | height: 6vh; 26 | display: flex; 27 | align-items: center; 28 | margin-left: 0.5rem; 29 | gap: 3%; 30 | } 31 | .initial-msg { 32 | display: flex; 33 | align-items: center; 34 | flex-direction: column; 35 | position: absolute; 36 | top: 50%; 37 | left: 50%; 38 | transform: translate(-50%, -50%); 39 | row-gap: 1rem; 40 | width: 73%; 41 | text-align: center; 42 | font-size: 1rem; 43 | } 44 | 45 | .initial-msg > span:first-of-type { 46 | color: #707070; 47 | font-weight: 500; 48 | } 49 | 50 | .initial-msg > span:nth-of-type(2) { 51 | color: #737373; 52 | font-weight: 400; 53 | font-size: 0.875em; 54 | } 55 | 56 | /* Large screens (≥992px) */ 57 | @media (min-width: 992px) { 58 | .chat-history-header, 59 | .initial-msg { 60 | font-size: 0.8rem; 61 | } 62 | } 63 | 64 | /* Extra Large screens (≥1200px) */ 65 | @media (min-width: 1200px) { 66 | .chat-history-header, 67 | .initial-msg { 68 | font-size: 0.9rem; 69 | } 70 | } 71 | 72 | /* Extra Extra Large screens (≥1400px) */ 73 | @media (min-width: 1400px) { 74 | .chat-history-header, 75 | .initial-msg { 76 | font-size: 1.1rem; 77 | } 78 | } 79 | 80 | /* Very Extra Large screens (≥1600px) */ 81 | @media (min-width: 1600px) { 82 | .chat-history-header, 83 | .initial-msg { 84 | font-size: 1.2rem; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/App/src/components/ChatHistory/ChatHistory.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./ChatHistory.css"; 3 | 4 | const ChatHistory: React.FC = () => { 5 | return ( 6 |
7 |
Chat History
8 |
9 |
10 | {/* Chat History */} 11 | Coming soon... 12 |
13 |
14 |
15 | ); 16 | }; 17 | 18 | export default ChatHistory; 19 | -------------------------------------------------------------------------------- /src/App/src/components/ChatHistoryListItemCell/ChatHistoryListItemCell.module.css: -------------------------------------------------------------------------------- 1 | .itemCell { 2 | min-height: 32px; 3 | cursor: pointer; 4 | padding-left: 12px; 5 | padding-right: 4px; 6 | padding-top: 5px; 7 | padding-bottom: 5px; 8 | box-sizing: border-box; 9 | border-radius: 5px; 10 | display: flex; 11 | } 12 | 13 | .itemCell:hover { 14 | background: #e6e6e6; 15 | } 16 | 17 | .cursorDefault { 18 | cursor: default; 19 | } 20 | 21 | .itemButton { 22 | display: flex; 23 | justify-content: center; 24 | align-items: center; 25 | width: 28px; 26 | height: 28px; 27 | border: 1px solid #d1d1d1; 28 | border-radius: 5px; 29 | background-color: white; 30 | margin: auto 2.5px; 31 | cursor: pointer; 32 | } 33 | 34 | .itemButton:hover { 35 | background-color: #e6e6e6; 36 | } 37 | 38 | .chatTitle { 39 | width: 70%; 40 | overflow: hidden; 41 | white-space: nowrap; 42 | text-overflow: ellipsis; 43 | } 44 | 45 | .chatHistoryItem { 46 | width: 100%; 47 | justify-content: space-between; 48 | position: relative 49 | } 50 | 51 | .chatHistoryItemsButtonsContainer { 52 | position: absolute; 53 | right: 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/App/src/components/ChatHistoryListItemGroups/ChatHistoryListItemGroups.module.css: -------------------------------------------------------------------------------- 1 | .listContainer { 2 | height: 100%; 3 | overflow: hidden auto; 4 | } 5 | 6 | .chatGroup { 7 | width: 100%; 8 | } 9 | 10 | .chatMonth { 11 | font-size: 14px; 12 | font-weight: 600; 13 | margin-bottom: 5px; 14 | padding-left: 15px; 15 | } 16 | 17 | .chatList { 18 | width: 100%; 19 | } 20 | 21 | .spinnerContainer { 22 | display: flex; 23 | justify-content: center; 24 | align-items: center; 25 | height: 22px; 26 | margin-top: -8px; 27 | } 28 | -------------------------------------------------------------------------------- /src/App/src/components/ChatHistoryPanel/ChatHistoryPanel.module.css: -------------------------------------------------------------------------------- 1 | .historyContainer { 2 | background: radial-gradient( 3 | 108.78% 108.78% at 50.02% 19.78%, 4 | #ffffff 57.29%, 5 | #eef6fe 100% 6 | ); 7 | border-radius: 8px; 8 | height: 100%; 9 | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.14), 0px 0px 2px rgba(0, 0, 0, 0.12); 10 | overflow-y: hidden; 11 | } 12 | 13 | .historyPanelTopRightButtons { 14 | height: 48px; 15 | } 16 | 17 | .chatHistoryListContainer { 18 | height: 100%; 19 | } 20 | 21 | .chatHistoryHeader { 22 | font-size: 1.1rem; 23 | font-weight: 600; 24 | height: 6vh; 25 | display: flex; 26 | align-items: center; 27 | margin-left: 0.5rem; 28 | gap: 3%; 29 | display: flex; 30 | justify-content: space-between; 31 | margin-inline: 3%; 32 | } 33 | -------------------------------------------------------------------------------- /src/App/src/components/CitationPanel/CitationPanel.css: -------------------------------------------------------------------------------- 1 | /* General styles for the parent container */ 2 | .citationPanel { 3 | display: flex; 4 | flex-direction: column; /* Stack children vertically */ 5 | border: 1px solid #ddd; /* Optional: Add a border for visibility */ 6 | border-radius: 8px; /* Optional: Rounded corners */ 7 | padding: 16px; /* Optional: Add padding */ 8 | background: radial-gradient(108.78% 108.78% at 50.02% 19.78%, #ffffff 57.29%, #eef6fe 100%); /* Optional: Background color */ 9 | height: 93%; /* Adjust height as needed */ 10 | overflow-y: auto; /* Enable vertical scrolling */ 11 | overflow-x: hidden; /* Prevent horizontal scrolling */ 12 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Optional: Add a shadow */ 13 | } 14 | 15 | /* Styling the header section */ 16 | .citationPanelInner { 17 | display: flex; 18 | align-items: center; 19 | justify-content: space-between; /* Space between title and icon */ 20 | padding-bottom: 10px; /* Add some spacing below the header */ 21 | border-bottom: 1px solid #ccc; /* Optional: Add a bottom border */ 22 | } 23 | 24 | /* Style the title */ 25 | .citationPanelInner span { 26 | font-weight: bold; 27 | font-size: 16px; 28 | color: #333; 29 | } 30 | 31 | /* Style the SVG button */ 32 | .citationPanelInner svg { 33 | cursor: pointer; 34 | transition: transform 0.3s; 35 | } 36 | 37 | .citationPanelInner svg:hover { 38 | transform: scale(1.1); /* Slightly enlarge on hover */ 39 | } 40 | 41 | /* Styling the file path link */ 42 | h5 { 43 | word-break: break-all; 44 | margin: 12px 0; 45 | font-size: 14px; 46 | color: #555; 47 | } 48 | 49 | h5 a { 50 | color: #0078d4; /* Microsoft blue */ 51 | text-decoration: none; 52 | } 53 | 54 | h5 a:hover { 55 | text-decoration: underline; 56 | } 57 | 58 | /* Styling the paragraphs */ 59 | p { 60 | margin: 10px 0; 61 | font-size: 14px; 62 | line-height: 1.6; 63 | color: #444; 64 | } 65 | 66 | p a { 67 | word-break: break-all; 68 | } 69 | /* Optional: Customize the scrollbar */ 70 | .citationPanel::-webkit-scrollbar { 71 | width: 8px; 72 | } 73 | 74 | .citationPanel::-webkit-scrollbar-thumb { 75 | background-color: #888; 76 | border-radius: 4px; 77 | } 78 | 79 | .citationPanel::-webkit-scrollbar-thumb:hover { 80 | background-color: #555; 81 | } -------------------------------------------------------------------------------- /src/App/src/components/CitationPanel/CitationPanel.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo, useState } from 'react'; 2 | import ReactMarkdown from 'react-markdown'; 3 | import { Stack } from '@fluentui/react'; 4 | import { DismissRegular } from '@fluentui/react-icons'; 5 | import remarkGfm from "remark-gfm"; 6 | import rehypeRaw from "rehype-raw"; 7 | import { useAppContext } from '../../state/useAppContext'; 8 | import { actionConstants } from '../../state/ActionConstants'; 9 | import "./CitationPanel.css"; 10 | interface Props { 11 | activeCitation: any 12 | } 13 | 14 | const CitationPanel = ({ activeCitation }: Props) => { 15 | const { dispatch } = useAppContext() 16 | 17 | const onCloseCitation = () => { 18 | dispatch({ type: actionConstants.UPDATE_CITATION,payload: { activeCitation: null, showCitation: false }}) 19 | } 20 | return ( 21 |
22 | 23 | 26 | 31 |
39 | 40 | Citations 41 |
42 | 45 | e.key === " " || e.key === "Enter" 46 | ? onCloseCitation() 47 | : () => { } 48 | } 49 | tabIndex={0} 50 | onClick={onCloseCitation} 51 | /> 52 |
53 |
56 | {activeCitation.title} 57 |
58 | 59 | 64 |
65 |
) 66 | }; 67 | 68 | 69 | export default CitationPanel; -------------------------------------------------------------------------------- /src/App/src/components/Citations/AnswerParser.tsx: -------------------------------------------------------------------------------- 1 | import { AskResponse, Citation } from "../../types/AppTypes"; 2 | 3 | 4 | type ParsedAnswer = { 5 | citations: Citation[]; 6 | markdownFormatText: string; 7 | }; 8 | 9 | let filteredCitations = [] as Citation[]; 10 | 11 | // Define a function to check if a citation with the same Chunk_Id already exists in filteredCitations 12 | const isDuplicate = (citation: Citation,citationIndex:string) => { 13 | return filteredCitations.some((c) => c.chunk_id === citation.chunk_id) ; 14 | }; 15 | 16 | export function parseAnswer(answer: AskResponse): ParsedAnswer { 17 | // let answerText = answer.answer; 18 | // const citationLinks = answerText.match(/\[(doc\d\d?\d?)]/g); 19 | 20 | // const lengthDocN = "[doc".length; 21 | 22 | // filteredCitations = [] as Citation[]; 23 | // let citationReindex = 0; 24 | // citationLinks?.forEach(link => { 25 | // // Replacing the links/citations with number 26 | // let citationIndex = link.slice(lengthDocN, link.length - 1); 27 | // let citation = cloneDeep(answer.citations[Number(citationIndex) - 1]) as Citation; 28 | 29 | // if (citation !== undefined && !isDuplicate(citation, citationIndex)) { 30 | // answerText = answerText.replaceAll(link, ` ^${++citationReindex}^ `); 31 | // citation.id = citationIndex; // original doc index to de-dupe 32 | // citation.reindex_id = citationReindex.toString(); // reindex from 1 for display 33 | // filteredCitations.push(citation); 34 | // }else{ 35 | // // Replacing duplicate citation with original index 36 | // let matchingCitation = filteredCitations.find((ct) => citation?.chunk_id == ct?.chunk_id); 37 | // if (matchingCitation) { 38 | // answerText= answerText.replaceAll(link, ` ^${matchingCitation.reindex_id}^ `) 39 | // } 40 | // } 41 | // }) 42 | 43 | 44 | return { 45 | citations: answer.citations, 46 | markdownFormatText: answer.answer 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /src/App/src/components/Citations/Citations.css: -------------------------------------------------------------------------------- 1 | .citationContainer { 2 | margin-left: 10px; 3 | font-family: "Segoe UI"; 4 | font-style: normal; 5 | font-weight: 600; 6 | font-size: 12px; 7 | line-height: 16px; 8 | max-width: 100%; 9 | color: #115EA3; 10 | display: flex; 11 | flex-direction: row; 12 | align-items: center; 13 | padding: 4px 6px; 14 | gap: 4px; 15 | border: 1px solid #D1D1D1; 16 | border-radius: 4px; 17 | } 18 | 19 | .citationContainer:hover { 20 | text-decoration: underline; 21 | cursor: pointer; 22 | } 23 | 24 | .citation { 25 | box-sizing: border-box; 26 | display: inline-flex; 27 | flex-direction: column; 28 | justify-content: center; 29 | align-items: center; 30 | padding: 0px; 31 | width: 14px; 32 | height: 14px; 33 | border: 1px solid #E0E0E0; 34 | border-radius: 4px; 35 | flex: none; 36 | flex-grow: 0; 37 | z-index: 2; 38 | font-family: "Segoe UI"; 39 | font-style: normal; 40 | font-weight: 600; 41 | font-size: 10px; 42 | line-height: 14px; 43 | text-align: center; 44 | color: #424242; 45 | cursor: pointer; 46 | } 47 | 48 | .citation:hover { 49 | text-decoration: underline; 50 | cursor: pointer; 51 | } 52 | 53 | @media (max-width: 500px) { 54 | .citationContainer { 55 | width: 100%; 56 | overflow-y: auto; 57 | } 58 | } -------------------------------------------------------------------------------- /src/App/src/components/Citations/Citations.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react'; 2 | import { parseAnswer } from './AnswerParser'; 3 | import { useAppContext } from '../../state/useAppContext'; 4 | import { actionConstants } from '../../state/ActionConstants'; 5 | import "./Citations.css"; 6 | import { AskResponse, Citation } from '../../types/AppTypes'; 7 | 8 | interface Props { 9 | answer: AskResponse; 10 | onSpeak?: any; 11 | isActive?: boolean; 12 | index: number; 13 | } 14 | 15 | const Citations = ({ answer, index }: Props) => { 16 | 17 | const { state, dispatch } = useAppContext(); 18 | const parsedAnswer = useMemo(() => parseAnswer(answer), [answer]); 19 | const filePathTruncationLimit = 50; 20 | const createCitationFilepath = ( 21 | citation: Citation, 22 | index: number, 23 | truncate: boolean = false 24 | ) => { 25 | let citationFilename = ""; 26 | citationFilename = citation.title ? (citation.title ?? `Citation ${index}`) : `Citation ${index}`; 27 | return citationFilename; 28 | }; 29 | 30 | const onCitationClicked = ( 31 | citation: Citation 32 | ) => { 33 | dispatch({ 34 | type: actionConstants.UPDATE_CITATION, 35 | payload: { showCitation: true, activeCitation: citation, currentConversationIdForCitation: state?.selectedConversationId}, 36 | }); 37 | }; 38 | 39 | 40 | return ( 41 |
51 | {parsedAnswer.citations.map((citation, idx) => { 52 | return ( 53 | 56 | e.key === " " || e.key === "Enter" 57 | ? onCitationClicked(citation) 58 | : () => { } 59 | } 60 | tabIndex={0} 61 | title={createCitationFilepath(citation, ++idx)} 62 | key={idx} 63 | onClick={() => onCitationClicked(citation)} 64 | className={"citationContainer"} 65 | > 66 |
69 | {idx} 70 |
71 | {createCitationFilepath(citation, idx, true)} 72 |
73 | ); 74 | })} 75 |
) 76 | }; 77 | 78 | 79 | export default Citations; -------------------------------------------------------------------------------- /src/App/src/components/CustomSpinner/CustomSpinner.module.css: -------------------------------------------------------------------------------- 1 | /* Full-screen overlay */ 2 | .overlay { 3 | position: fixed; 4 | top: 0; 5 | left: 0; 6 | width: 100%; 7 | height: 100%; 8 | background-color: rgba(0, 0, 0, 0.5); /* semi-transparent black background */ 9 | display: flex; 10 | align-items: center; 11 | justify-content: center; 12 | z-index: 999999999; /* Ensure it is above other content */ 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/App/src/components/CustomSpinner/CustomSpinner.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Spinner, SpinnerSize, ISpinnerStyles } from "@fluentui/react"; 3 | import styles from "./CustomSpinner.module.css"; 4 | 5 | interface CustomSpinnerProps { 6 | loading: boolean; 7 | label?: string; // Label is optional 8 | } 9 | 10 | const spinnerStyles: ISpinnerStyles = { 11 | label: { 12 | fontSize: "20px", 13 | color: "rgb(91 184 255)", 14 | fontWeight: 600, 15 | }, 16 | }; 17 | 18 | const CustomSpinner: React.FC = ({ loading, label }) => { 19 | if (!loading) return null; 20 | 21 | return ( 22 |
23 | 28 |
29 | ); 30 | }; 31 | 32 | export default CustomSpinner; 33 | -------------------------------------------------------------------------------- /src/App/src/components/NoData/NoData.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const NoData = () => { 4 | return ( 5 |
6 | No Data Available 7 |
8 | ); 9 | }; 10 | 11 | export default NoData; 12 | -------------------------------------------------------------------------------- /src/App/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/App/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | import { initializeIcons } from "@fluentui/react"; 7 | import AppProvider from './state/AppProvider'; 8 | initializeIcons(); 9 | 10 | const root = ReactDOM.createRoot( 11 | document.getElementById('root') as HTMLElement 12 | ); 13 | root.render( 14 | 15 | 16 | 17 | ); 18 | 19 | // If you want to start measuring performance in your app, pass a function 20 | // to log results (for example: reportWebVitals(console.log)) 21 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 22 | reportWebVitals(); 23 | -------------------------------------------------------------------------------- /src/App/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/App/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /src/App/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/App/src/state/ActionConstants.tsx: -------------------------------------------------------------------------------- 1 | export const actionConstants = { 2 | SET_FILTERS: "SET_FILTERS", 3 | UPDATE_FILTERS_FETCHED_FLAG: "UPDATE_FILTERS_FETCHED_FLAG", 4 | UPDATE_CHARTS_DATA: "UPDATE_CHARTS_DATA", 5 | UPDATE_INITIAL_CHARTS_FETCHED_FLAG: "UPDATE_INITIAL_CHARTS_FETCHED_FLAG", 6 | UPDATE_SELECTED_FILTERS: "UPDATE_SELECTED_FILTERS", 7 | UPDATE_USER_MESSAGE: "UPDATE_USER_MESSAGE", 8 | UPDATE_GENERATING_RESPONSE_FLAG: "UPDATE_GENERATING_RESPONSE_FLAG", 9 | UPDATE_MESSAGES: "UPDATE_MESSAGES", 10 | ADD_CONVERSATIONS_TO_LIST: "ADD_CONVERSATIONS_TO_LIST", 11 | SAVE_CONFIG: "SAVE_CONFIG", 12 | UPDATE_SELECTED_CONV_ID: "UPDATE_SELECTED_CONV_ID", 13 | UPDATE_GENERATED_CONV_ID: "UPDATE_GENERATED_CONV_ID", 14 | NEW_CONVERSATION_START: "NEW_CONVERSATION_START", 15 | UPDATE_CONVERSATIONS_FETCHING_FLAG: "UPDATE_CONVERSATIONS_FETCHING_FLAG", 16 | UPDATE_CONVERSATION_TITLE: "UPDATE_CONVERSATION_TITLE", 17 | UPDATE_ON_CLEAR_ALL_CONVERSATIONS: "UPDATE_ON_CLEAR_ALL_CONVERSATIONS", 18 | SHOW_CHATHISTORY_CONVERSATION: "SHOW_CHATHISTORY_CONVERSATION", 19 | UPDATE_CHATHISTORY_CONVERSATION_FLAG: "UPDATE_CHATHISTORY_CONVERSATION_FLAG", 20 | DELETE_CONVERSATION_FROM_LIST: "DELETE_CONVERSATION_FROM_LIST", 21 | STORE_COSMOS_INFO: "STORE_COSMOS_INFO", 22 | ADD_NEW_CONVERSATION_TO_CHAT_HISTORY: "ADD_NEW_CONVERSATION_TO_CHAT_HISTORY", 23 | UPDATE_APP_SPINNER_STATUS: "UPDATE_APP_SPINNER_STATUS", 24 | UPDATE_HISTORY_UPDATE_API_FLAG: "UPDATE_HISTORY_UPDATE_API_FLAG", 25 | SET_LAST_RAG_RESPONSE: "SET_LAST_RAG_RESPONSE", 26 | UPDATE_MESSAGE_BY_ID: "UPDATE_MESSAGE_BY_ID", 27 | UPDATE_STREAMING_FLAG: "UPDATE_STREAMING_FLAG", 28 | UPDATE_CHARTS_FETCHING_FLAG: "UPDATE_CHARTS_FETCHING_FLAG", 29 | UPDATE_FILTERS_FETCHING_FLAG: "UPDATE_FILTERS_FETCHING_FLAG", 30 | UPDATE_CITATION: "UPDATE_CITATION", 31 | } as const; 32 | -------------------------------------------------------------------------------- /src/App/src/state/useAppContext.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { AppContext } from "./AppProvider"; 3 | 4 | export const useAppContext = () => { 5 | return useContext(AppContext); 6 | }; 7 | -------------------------------------------------------------------------------- /src/App/src/types/d3-cloud.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'd3-cloud' { 2 | export interface Word { 3 | text: string; 4 | size: number; 5 | x?: number; 6 | y?: number; 7 | rotate?: number; 8 | } 9 | 10 | export interface Cloud { 11 | size: (size: [number, number]) => Cloud; 12 | words: (words: Word[]) => Cloud; 13 | padding: (padding: number) => Cloud; 14 | rotate: (rotate: () => number) => Cloud; 15 | font: (font: string) => Cloud; 16 | fontSize: (size: (word: Word) => number) => Cloud; 17 | on: (event: 'end', callback: (words: Word[]) => void) => Cloud; 18 | start: () => void; 19 | } 20 | 21 | export default function cloud(): Cloud; 22 | } 23 | -------------------------------------------------------------------------------- /src/App/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/api/.dockerignore: -------------------------------------------------------------------------------- 1 | # Include any files or directories that you don't want to be copied to your 2 | # container here (e.g., local build artifacts, temporary files, etc.). 3 | # 4 | # For more help, visit the .dockerignore file reference guide at 5 | # https://docs.docker.com/engine/reference/builder/#dockerignore-file 6 | 7 | **/.DS_Store 8 | **/__pycache__ 9 | **/.venv 10 | **/.classpath 11 | **/.dockerignore 12 | **/.env 13 | **/.git 14 | **/.gitignore 15 | **/.project 16 | **/.settings 17 | **/.toolstarget 18 | **/.vs 19 | **/.vscode 20 | **/*.*proj.user 21 | **/*.dbmdl 22 | **/*.jfm 23 | **/bin 24 | **/charts 25 | **/docker-compose* 26 | **/compose* 27 | **/Dockerfile* 28 | **/*.Dockerfile 29 | **/node_modules 30 | **/npm-debug.log 31 | **/obj 32 | **/secrets.dev.yaml 33 | **/values.dev.yaml 34 | LICENSE 35 | README.md 36 | 37 | # Byte-compiled / optimized / DLL files 38 | __pycache__/ 39 | *.py[cod] 40 | *$py.class 41 | 42 | # C extensions 43 | *.so 44 | 45 | # Distribution / packaging 46 | .Python 47 | build/ 48 | develop-eggs/ 49 | dist/ 50 | downloads/ 51 | eggs/ 52 | lib/ 53 | lib64/ 54 | parts/ 55 | sdist/ 56 | var/ 57 | *.egg-info/ 58 | .installed.cfg 59 | *.egg 60 | 61 | # PyInstaller 62 | # Usually these files are written by a python script from a template 63 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 64 | *.manifest 65 | *.spec 66 | 67 | # Installer logs 68 | pip-log.txt 69 | pip-delete-this-directory.txt 70 | 71 | # Unit test / coverage reports 72 | htmlcov/ 73 | .tox/ 74 | .nox/ 75 | .coverage 76 | .coverage.* 77 | .cache 78 | nosetests.xml 79 | coverage.xml 80 | *.cover 81 | *.log 82 | 83 | # Translations 84 | *.mo 85 | *.pot 86 | 87 | # Django stuff: 88 | *.log 89 | local_settings.py 90 | db.sqlite3 91 | 92 | # Flask stuff: 93 | instance/ 94 | .webassets-cache 95 | 96 | # Scrapy stuff: 97 | .scrapy 98 | 99 | # Sphinx documentation 100 | docs/_build/ 101 | 102 | # PyBuilder 103 | target/ 104 | 105 | # Jupyter Notebook 106 | .ipynb_checkpoints 107 | 108 | # IPython 109 | profile_default/ 110 | ipython_config.py 111 | 112 | # pyenv 113 | .python-version 114 | 115 | # celery beat schedule file 116 | celerybeat-schedule 117 | 118 | # SageMath parsed files 119 | *.sage.py 120 | 121 | # Environments 122 | .env 123 | .venv 124 | env/ 125 | venv/ 126 | ENV/ 127 | env.bak/ 128 | venv.bak/ 129 | 130 | # Spyder project settings 131 | .spyderproject 132 | .spyproject 133 | 134 | # Rope project settings 135 | .ropeproject 136 | 137 | # mkdocs documentation 138 | /site 139 | 140 | # mypy 141 | .mypy_cache/ 142 | .dmypy.json 143 | dmypy.json 144 | 145 | # Pyre type checker 146 | .pyre/ 147 | 148 | # pytype static type analyzer 149 | .pytype/ 150 | 151 | # Cython debug symbols 152 | cython_debug/ 153 | 154 | # VS Code 155 | .vscode/ 156 | 157 | # Ignore other unnecessary files 158 | *.bak 159 | *.swp 160 | .DS_Store 161 | *.pdb 162 | *.sqlite3 163 | -------------------------------------------------------------------------------- /src/api/.env.sample: -------------------------------------------------------------------------------- 1 | APPINSIGHTS_INSTRUMENTATIONKEY= 2 | AZURE_AI_PROJECT_CONN_STRING= 3 | AZURE_AI_SEARCH_API_KEY= 4 | AZURE_AI_SEARCH_ENDPOINT= 5 | AZURE_AI_SEARCH_INDEX="call_transcripts_index" 6 | AZURE_COSMOSDB_ACCOUNT= 7 | AZURE_COSMOSDB_CONVERSATIONS_CONTAINER="conversations" 8 | AZURE_COSMOSDB_DATABASE="db_conversation_history" 9 | AZURE_COSMOSDB_ENABLE_FEEDBACK="True" 10 | AZURE_OPEN_AI_DEPLOYMENT_MODEL="gpt-4o-mini" 11 | AZURE_OPEN_AI_ENDPOINT= 12 | AZURE_OPENAI_API_KEY= 13 | AZURE_OPENAI_API_VERSION= 14 | AZURE_OPENAI_RESOURCE= 15 | OPENAI_API_VERSION= 16 | SQLDB_DATABASE= 17 | SQLDB_SERVER= 18 | SQLDB_USER_MID= 19 | SQLDB_USERNAME= 20 | USE_AI_PROJECT_CLIENT="False" 21 | USE_CHAT_HISTORY_ENABLED="True" 22 | WEBSITE_HTTPLOGGING_RETENTION_DAYS= -------------------------------------------------------------------------------- /src/api/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | csx 4 | .vs 5 | edge 6 | Publish 7 | 8 | *.user 9 | *.suo 10 | *.cscfg 11 | *.Cache 12 | project.lock.json 13 | 14 | /packages 15 | /TestResults 16 | 17 | /tools/NuGet.exe 18 | /App_Data 19 | /secrets 20 | /data 21 | .secrets 22 | appsettings.json 23 | local.settings.json 24 | 25 | node_modules 26 | dist 27 | 28 | # Local python packages 29 | .python_packages/ 30 | 31 | # Python Environments 32 | .env 33 | .venv 34 | env/ 35 | venv/ 36 | ENV/ 37 | env.bak/ 38 | venv.bak/ 39 | 40 | # Byte-compiled / optimized / DLL files 41 | __pycache__/ 42 | *.py[cod] 43 | *$py.class 44 | 45 | # Azurite artifacts 46 | __blobstorage__ 47 | __queuestorage__ 48 | __azurite_db*__.json -------------------------------------------------------------------------------- /src/api/ApiApp.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.11-alpine 2 | 3 | # Install system dependencies required for building and running the application 4 | RUN apk add --no-cache --virtual .build-deps \ 5 | build-base \ 6 | libffi-dev \ 7 | openssl-dev \ 8 | curl \ 9 | unixodbc-dev \ 10 | libpq \ 11 | opus-dev \ 12 | libvpx-dev 13 | 14 | # Download and install Microsoft ODBC Driver and MSSQL tools 15 | RUN curl -O https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/msodbcsql17_17.10.6.1-1_amd64.apk \ 16 | && curl -O https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/mssql-tools_17.10.1.1-1_amd64.apk \ 17 | && apk add --allow-untrusted msodbcsql17_17.10.6.1-1_amd64.apk \ 18 | && apk add --allow-untrusted mssql-tools_17.10.1.1-1_amd64.apk \ 19 | && rm msodbcsql17_17.10.6.1-1_amd64.apk mssql-tools_17.10.1.1-1_amd64.apk 20 | 21 | # Set the working directory inside the container 22 | WORKDIR /app 23 | 24 | # Copy only the requirements file first to leverage Docker layer caching 25 | COPY ./requirements.txt . 26 | 27 | # Install Python dependencies 28 | RUN pip install --upgrade pip setuptools wheel \ 29 | && pip install --no-cache-dir -r requirements.txt && rm -rf /root/.cache 30 | 31 | # Copy the backend application code into the container 32 | COPY ./ . 33 | 34 | # Expose port 80 for incoming traffic 35 | EXPOSE 80 36 | 37 | # Start the application using Uvicorn 38 | CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "80"] -------------------------------------------------------------------------------- /src/api/api/models/input_models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import List 3 | 4 | 5 | class SelectedFilters(BaseModel): 6 | Topic: List[str] 7 | Sentiment: List[str] 8 | DateRange: List[str] 9 | 10 | 11 | class ChartFilters(BaseModel): 12 | selected_filters: SelectedFilters 13 | -------------------------------------------------------------------------------- /src/api/app.py: -------------------------------------------------------------------------------- 1 | """ 2 | FastAPI application entry point for the Conversation Knowledge Mining Solution Accelerator. 3 | 4 | This module sets up the FastAPI app, configures middleware, loads environment variables, 5 | registers API routers, and manages application lifespan events such as agent initialization 6 | and cleanup. 7 | """ 8 | 9 | 10 | from contextlib import asynccontextmanager 11 | from fastapi import FastAPI 12 | from fastapi.middleware.cors import CORSMiddleware 13 | 14 | from dotenv import load_dotenv 15 | import uvicorn 16 | 17 | from common.config.config import Config 18 | from agents.agent_factory import AgentFactory 19 | from api.api_routes import router as backend_router 20 | from api.history_routes import router as history_router 21 | 22 | load_dotenv() 23 | 24 | 25 | @asynccontextmanager 26 | async def lifespan(fastapi_app: FastAPI): 27 | """ 28 | Manages the application lifespan events for the FastAPI app. 29 | 30 | On startup, initializes the Azure AI agent using the configuration and attaches it to the app state. 31 | On shutdown, deletes the agent instance and performs any necessary cleanup. 32 | """ 33 | config = Config() 34 | fastapi_app.state.agent = await AgentFactory.get_instance(config=config) 35 | yield 36 | await AgentFactory.delete_instance() 37 | fastapi_app.state.agent = None 38 | 39 | 40 | def build_app() -> FastAPI: 41 | """ 42 | Creates and configures the FastAPI application instance. 43 | """ 44 | fastapi_app = FastAPI( 45 | title="Conversation Knowledge Mining Solution Accelerator", 46 | version="1.0.0", 47 | lifespan=lifespan 48 | ) 49 | 50 | fastapi_app.add_middleware( 51 | CORSMiddleware, 52 | allow_origins=["*"], 53 | allow_credentials=True, 54 | allow_methods=["*"], 55 | allow_headers=["*"], 56 | ) 57 | 58 | # Include routers 59 | fastapi_app.include_router(backend_router, prefix="/api", tags=["backend"]) 60 | fastapi_app.include_router(history_router, prefix="/history", tags=["history"]) 61 | 62 | @fastapi_app.get("/health") 63 | async def health_check(): 64 | """Health check endpoint""" 65 | return {"status": "healthy"} 66 | 67 | return fastapi_app 68 | 69 | 70 | app = build_app() 71 | 72 | 73 | if __name__ == "__main__": 74 | uvicorn.run("app:app", host="127.0.0.1", port=8000, reload=True) 75 | -------------------------------------------------------------------------------- /src/api/auth/auth_utils.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import json 3 | import logging 4 | 5 | 6 | def get_authenticated_user_details(request_headers): 7 | user_object = {} 8 | 9 | normalized_headers = {k.lower(): v for k, v in request_headers.items()} 10 | 11 | if "x-ms-client-principal-id" not in normalized_headers: 12 | # if it's not, assume we're in development mode and return a default user 13 | from . import sample_user 14 | 15 | raw_user_object = sample_user.sample_user 16 | else: 17 | # if it is, get the user details from the EasyAuth headers 18 | raw_user_object = {k: v for k, v in request_headers.items()} 19 | 20 | user_object["user_principal_id"] = raw_user_object.get("x-ms-client-principal-id") 21 | user_object["user_name"] = raw_user_object.get("x-ms-client-principal-name") 22 | user_object["auth_provider"] = raw_user_object.get("x-ms-client-principal-idp") 23 | user_object["auth_token"] = raw_user_object.get("x-ms-token-aad-id-token") 24 | user_object["client_principal_b64"] = raw_user_object.get("x-ms-client-principal") 25 | user_object["aad_id_token"] = raw_user_object.get("x-ms-token-aad-id-token") 26 | 27 | return user_object 28 | 29 | 30 | def get_tenantid(client_principal_b64): 31 | tenant_id = "" 32 | if client_principal_b64: 33 | try: 34 | # Decode the base64 header to get the JSON string 35 | decoded_bytes = base64.b64decode(client_principal_b64) 36 | decoded_string = decoded_bytes.decode("utf-8") 37 | # Convert the JSON string1into a Python dictionary 38 | user_info = json.loads(decoded_string) 39 | # Extract the tenant ID 40 | tenant_id = user_info.get("tid") # 'tid' typically holds the tenant ID 41 | except Exception as ex: 42 | logging.exception(ex) 43 | return tenant_id 44 | -------------------------------------------------------------------------------- /src/api/common/config/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dotenv import load_dotenv 3 | 4 | load_dotenv() 5 | 6 | 7 | class Config: 8 | def __init__(self): 9 | # SQL Database configuration 10 | self.sqldb_database = os.getenv("SQLDB_DATABASE") 11 | self.sqldb_server = os.getenv("SQLDB_SERVER") 12 | self.sqldb_username = os.getenv("SQLDB_USERNAME") 13 | self.driver = "{ODBC Driver 17 for SQL Server}" 14 | self.mid_id = os.getenv("SQLDB_USER_MID") 15 | 16 | # Azure OpenAI configuration 17 | self.azure_openai_endpoint = os.getenv("AZURE_OPEN_AI_ENDPOINT") 18 | self.azure_openai_deployment_model = os.getenv("AZURE_OPEN_AI_DEPLOYMENT_MODEL") 19 | self.azure_openai_api_key = os.getenv("AZURE_OPENAI_API_KEY") 20 | self.azure_openai_api_version = os.getenv("AZURE_OPENAI_API_VERSION") 21 | self.azure_openai_resource = os.getenv("AZURE_OPENAI_RESOURCE") 22 | 23 | # Azure AI Search configuration 24 | self.azure_ai_search_endpoint = os.getenv("AZURE_AI_SEARCH_ENDPOINT") 25 | self.azure_ai_search_api_key = os.getenv("AZURE_AI_SEARCH_API_KEY") 26 | self.azure_ai_search_index = os.getenv("AZURE_AI_SEARCH_INDEX") 27 | 28 | # AI Project Client configuration 29 | self.use_ai_project_client = os.getenv("USE_AI_PROJECT_CLIENT", "False").lower() == "true" 30 | self.azure_ai_project_conn_string = os.getenv("AZURE_AI_PROJECT_CONN_STRING") 31 | 32 | # Chat history configuration 33 | self.use_chat_history_enabled = os.getenv("USE_CHAT_HISTORY_ENABLED", "false").strip().lower() == "true" 34 | self.azure_cosmosdb_database = os.getenv("AZURE_COSMOSDB_DATABASE") 35 | self.azure_cosmosdb_account = os.getenv("AZURE_COSMOSDB_ACCOUNT") 36 | self.azure_cosmosdb_conversations_container = os.getenv("AZURE_COSMOSDB_CONVERSATIONS_CONTAINER") 37 | self.azure_cosmosdb_enable_feedback = os.getenv("AZURE_COSMOSDB_ENABLE_FEEDBACK", "false").lower() == "true" 38 | -------------------------------------------------------------------------------- /src/api/common/logging/event_utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from azure.monitor.events.extension import track_event 4 | from dotenv import load_dotenv 5 | 6 | load_dotenv() 7 | 8 | 9 | def track_event_if_configured(event_name: str, event_data: dict): 10 | instrumentation_key = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") 11 | print(f"Instrumentation Key: {instrumentation_key}") 12 | if instrumentation_key: 13 | track_event(event_name, event_data) 14 | else: 15 | logging.warning(f"Skipping track_event for {event_name} as Application Insights is not configured") 16 | -------------------------------------------------------------------------------- /src/api/helpers/streaming_helper.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | async def stream_processor(response): 5 | try: 6 | async for message in response: 7 | if message.content: 8 | yield message.content 9 | except Exception as e: 10 | logging.error(f"Error processing streaming response: {e}", exc_info=True) 11 | raise 12 | -------------------------------------------------------------------------------- /src/api/requirements.txt: -------------------------------------------------------------------------------- 1 | # Base packages 2 | cachetools 3 | python-dotenv 4 | fastapi 5 | uvicorn[standard] 6 | pydantic[email] 7 | 8 | # Azure SDK Core 9 | azure-core 10 | requests 11 | aiohttp 12 | 13 | # Azure Services 14 | azure-identity==1.21.0 15 | azure-search-documents==11.6.0b11 16 | azure-ai-projects==1.0.0b8 17 | azure-ai-inference==1.0.0b9 18 | azure-cosmos==4.9.0 19 | 20 | # Additional utilities 21 | semantic-kernel[azure]==1.28.0 22 | openai==1.74.0 23 | pyodbc==5.2.0 24 | pandas==2.2.3 25 | 26 | opentelemetry-exporter-otlp-proto-grpc 27 | opentelemetry-exporter-otlp-proto-http 28 | opentelemetry-exporter-otlp-proto-grpc 29 | azure-monitor-events-extension 30 | opentelemetry-sdk==1.31.1 31 | opentelemetry-api==1.31.1 32 | opentelemetry-semantic-conventions==0.52b1 33 | opentelemetry-instrumentation==0.52b1 34 | azure-monitor-opentelemetry==1.6.8 35 | 36 | # Development tools 37 | pytest==8.3.5 38 | pytest-cov==6.1.1 39 | pytest-asyncio==0.26.0 -------------------------------------------------------------------------------- /src/api/services/chart_service.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from fastapi import HTTPException, status 3 | 4 | from api.models.input_models import ChartFilters 5 | from common.database.sqldb_service import adjust_processed_data_dates, fetch_chart_data, fetch_filters_data 6 | 7 | # Configure logging 8 | logging.basicConfig(level=logging.INFO) 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | class ChartService: 13 | """ 14 | Service class for handling chart-related data retrieval. 15 | """ 16 | 17 | async def fetch_filter_data(self): 18 | """ 19 | Fetch filter data for charts. 20 | """ 21 | try: 22 | await adjust_processed_data_dates() 23 | return await fetch_filters_data() 24 | except Exception as e: 25 | logger.error("Error in fetch_filter_data: %s", e, exc_info=True) 26 | raise HTTPException( 27 | status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, 28 | detail="An error occurred while fetching filter data." 29 | ) 30 | 31 | async def fetch_chart_data(self): 32 | """ 33 | Fetch chart data. 34 | """ 35 | try: 36 | return await fetch_chart_data() 37 | except Exception as e: 38 | logger.error("Error in fetch_chart_data: %s", e, exc_info=True) 39 | raise HTTPException( 40 | status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, 41 | detail="An error occurred while fetching chart data." 42 | ) 43 | 44 | async def fetch_chart_data_with_filters(self, chart_filters: ChartFilters): 45 | """ 46 | Fetch chart data based on applied filters. 47 | """ 48 | try: 49 | return await fetch_chart_data(chart_filters) 50 | except Exception as e: 51 | logger.error("Error in fetch_chart_data_with_filters: %s", e, exc_info=True) 52 | raise HTTPException( 53 | status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, 54 | detail="An error occurred while fetching filtered chart data." 55 | ) 56 | -------------------------------------------------------------------------------- /src/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | "main.css": "/static/css/main.c964de29.css", 4 | "main.js": "/static/js/main.2b932b97.js", 5 | "static/js/453.0a93e070.chunk.js": "/static/js/453.0a93e070.chunk.js", 6 | "index.html": "/index.html", 7 | "main.c964de29.css.map": "/static/css/main.c964de29.css.map", 8 | "main.2b932b97.js.map": "/static/js/main.2b932b97.js.map", 9 | "453.0a93e070.chunk.js.map": "/static/js/453.0a93e070.chunk.js.map" 10 | }, 11 | "entrypoints": [ 12 | "static/css/main.c964de29.css", 13 | "static/js/main.2b932b97.js" 14 | ] 15 | } -------------------------------------------------------------------------------- /src/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/favicon-16x16.png -------------------------------------------------------------------------------- /src/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/favicon-32x32.png -------------------------------------------------------------------------------- /src/gunicorn.conf.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | 3 | max_requests = 1000 4 | max_requests_jitter = 50 5 | log_file = "-" 6 | bind = "0.0.0.0" 7 | 8 | timeout = 230 9 | # https://learn.microsoft.com/en-us/troubleshoot/azure/app-service/web-apps-performance-faqs#why-does-my-request-time-out-after-230-seconds 10 | 11 | num_cpus = multiprocessing.cpu_count() 12 | workers = (num_cpus * 2) + 1 13 | worker_class = "uvicorn.workers.UvicornWorker" 14 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "KM-Gen", 3 | "name": "Knowledge Mining Generic", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "/android-chrome-192x192.png", 12 | "sizes": "192x192", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "/android-chrome-512x512.png", 17 | "sizes": "512x512", 18 | "type": "image/png" 19 | }, 20 | { 21 | "src": "/favicon-16x16.png", 22 | "sizes": "16x16", 23 | "type": "image/png" 24 | }, 25 | { 26 | "src": "/favicon-32x32.png", 27 | "sizes": "32x32", 28 | "type": "image/png" 29 | } 30 | ], 31 | "start_url": ".", 32 | "display": "standalone", 33 | "theme_color": "#000000", 34 | "background_color": "#ffffff" 35 | } 36 | -------------------------------------------------------------------------------- /src/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo Starting the application setup... 4 | 5 | # Set root and config paths 6 | ROOT_DIR=$(cd .. && pwd) 7 | AZURE_FOLDER="$ROOT_DIR/.azure" 8 | CONFIG_FILE="$AZURE_FOLDER/config.json" 9 | 10 | # Validate config.json 11 | if [ ! -f "$CONFIG_FILE" ]; then 12 | echo "config.json not found at $CONFIG_FILE" 13 | exit 1 14 | fi 15 | 16 | # Debug: Print the content of config.json 17 | echo "Content of config.json:" 18 | cat "$CONFIG_FILE" 19 | 20 | # Extract default environment name 21 | DEFAULT_ENV=$(grep -o '"defaultEnvironment"\s*:\s*"[^\"]*"' "$CONFIG_FILE" | sed -E 's/.*"defaultEnvironment"\s*:\s*"([^"]*)".*/\1/') 22 | 23 | # Check if DEFAULT_ENV is empty 24 | if [ -z "$DEFAULT_ENV" ]; then 25 | echo "Failed to extract defaultEnvironment from config.json" 26 | exit 1 27 | fi 28 | 29 | echo "Default environment: $DEFAULT_ENV" 30 | 31 | # Set path to source .env file 32 | ENV_FILE="$AZURE_FOLDER/$DEFAULT_ENV/.env" 33 | 34 | if [ ! -f "$ENV_FILE" ]; then 35 | echo ".env file not found at $ENV_FILE" 36 | exit 1 37 | fi 38 | 39 | # 1. Copy full .env to src/api 40 | API_ENV_FILE="$ROOT_DIR/src/api/.env" 41 | cp "$ENV_FILE" "$API_ENV_FILE" 42 | if [ $? -ne 0 ]; then 43 | echo "Failed to copy .env to src/api" 44 | exit 1 45 | fi 46 | echo "Copied .env to src/api" 47 | 48 | # Directly set APP_API_BASE_URL in src/App/.env 49 | APP_ENV_FILE="$ROOT_DIR/src/App/.env" 50 | echo "REACT_APP_API_BASE_URL=http://127.0.0.1:8000" > "$APP_ENV_FILE" 51 | 52 | if [ -f "$APP_ENV_FILE" ]; then 53 | echo "Updated src/App/.env with APP_API_BASE_URL" 54 | else 55 | echo "Failed to update src/App/.env" 56 | exit 1 57 | fi 58 | 59 | echo "Successfully updated REACT_APP_API_BASE_URL in $ENV_FILE" 60 | 61 | # Restoring backend Python packages 62 | echo "Restoring backend Python packages..." 63 | cd api 64 | python -m pip install -r requirements.txt || { echo "Failed to restore backend Python packages"; exit 1; } 65 | cd .. 66 | 67 | # Restoring frontend npm packages 68 | echo "Restoring frontend npm packages..." 69 | cd App 70 | npm install --force || { echo "Failed to restore frontend npm packages"; exit 1; } 71 | cd .. 72 | 73 | # Starting backend in the background 74 | echo "Starting backend..." 75 | (cd api && python app.py --port=8000 &) || { echo "Failed to start backend"; exit 1; } 76 | 77 | # Wait for 10 seconds to ensure the backend starts properly 78 | sleep 10 79 | 80 | # Starting frontend in the background 81 | echo "Starting frontend..." 82 | (cd App && npm start &) || { echo "Failed to start frontend"; exit 1; } 83 | 84 | # Display running services 85 | echo "Backend running at http://127.0.0.1:8000" 86 | echo "Frontend running at http://localhost:3000" -------------------------------------------------------------------------------- /src/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Conversation-Knowledge-Mining-Solution-Accelerator/0bf8223f93bf4ddb25f04d0da9fdf9c24a4bee1d/src/tests/__init__.py -------------------------------------------------------------------------------- /src/tests/api/auth/test_auth_utils.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch, MagicMock 3 | import base64 4 | import json 5 | 6 | from auth import auth_utils,sample_user 7 | 8 | 9 | class TestAuthUtils(unittest.TestCase): 10 | 11 | @patch("auth.sample_user") 12 | def test_get_authenticated_user_details_dev_mode(self, mock_sample_user): 13 | mock_sample_user.sample_user = { 14 | "x-ms-client-principal-id": "123", 15 | "x-ms-client-principal-name": "testuser", 16 | "x-ms-client-principal-idp": "aad", 17 | "x-ms-token-aad-id-token": "token123", 18 | "x-ms-client-principal": "encodedstring" 19 | } 20 | 21 | request_headers = {} 22 | result = auth_utils.get_authenticated_user_details(request_headers) 23 | 24 | self.assertEqual(result["user_principal_id"], "123") 25 | self.assertEqual(result["user_name"], "testuser") 26 | self.assertEqual(result["auth_provider"], "aad") 27 | self.assertEqual(result["auth_token"], "token123") 28 | self.assertEqual(result["client_principal_b64"], "encodedstring") 29 | self.assertEqual(result["aad_id_token"], "token123") 30 | 31 | def test_get_authenticated_user_details_prod_mode(self): 32 | request_headers = { 33 | "x-ms-client-principal-id": "123", 34 | "x-ms-client-principal-name": "testuser", 35 | "x-ms-client-principal-idp": "aad", 36 | "x-ms-token-aad-id-token": "token123", 37 | "x-ms-client-principal": "encodedstring" 38 | } 39 | 40 | result = auth_utils.get_authenticated_user_details(request_headers) 41 | 42 | self.assertEqual(result["user_principal_id"], "123") 43 | self.assertEqual(result["user_name"], "testuser") 44 | self.assertEqual(result["auth_provider"], "aad") 45 | self.assertEqual(result["auth_token"], "token123") 46 | self.assertEqual(result["client_principal_b64"], "encodedstring") 47 | self.assertEqual(result["aad_id_token"], "token123") 48 | 49 | def test_get_tenantid_valid_b64(self): 50 | payload = {"tid": "tenant123"} 51 | b64_encoded = base64.b64encode(json.dumps(payload).encode()).decode() 52 | 53 | result = auth_utils.get_tenantid(b64_encoded) 54 | self.assertEqual(result, "tenant123") 55 | 56 | def test_get_tenantid_invalid_b64(self): 57 | with self.assertLogs(level='ERROR'): 58 | result = auth_utils.get_tenantid("notbase64!!!") 59 | self.assertEqual(result, "") 60 | 61 | def test_get_tenantid_none(self): 62 | result = auth_utils.get_tenantid(None) 63 | self.assertEqual(result, "") 64 | 65 | 66 | if __name__ == '__main__': 67 | unittest.main() 68 | -------------------------------------------------------------------------------- /src/tests/api/common/config/test_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | from unittest.mock import patch 4 | from common.config.config import Config 5 | 6 | 7 | @pytest.fixture 8 | def mock_env_vars(): 9 | return { 10 | "SQLDB_DATABASE": "test_db", 11 | "SQLDB_SERVER": "test_server", 12 | "SQLDB_USERNAME": "test_user", 13 | "SQLDB_USER_MID": "test_mid", 14 | "AZURE_OPEN_AI_ENDPOINT": "https://openai.test", 15 | "AZURE_OPEN_AI_DEPLOYMENT_MODEL": "gpt-4", 16 | "AZURE_OPENAI_API_KEY": "test_key", 17 | "AZURE_OPENAI_API_VERSION": "2023-03-15-preview", 18 | "AZURE_OPENAI_RESOURCE": "test_resource", 19 | "AZURE_AI_SEARCH_ENDPOINT": "https://search.test", 20 | "AZURE_AI_SEARCH_API_KEY": "search_key", 21 | "AZURE_AI_SEARCH_INDEX": "test_index", 22 | "USE_AI_PROJECT_CLIENT": "true", 23 | "AZURE_AI_PROJECT_CONN_STRING": "Endpoint=sb://test/", 24 | "USE_CHAT_HISTORY_ENABLED": "TRUE", 25 | "AZURE_COSMOSDB_DATABASE": "cosmos_db", 26 | "AZURE_COSMOSDB_ACCOUNT": "cosmos_account", 27 | "AZURE_COSMOSDB_CONVERSATIONS_CONTAINER": "convo_container", 28 | "AZURE_COSMOSDB_ENABLE_FEEDBACK": "True" 29 | } 30 | 31 | 32 | def test_config_initialization(mock_env_vars): 33 | with patch.dict(os.environ, mock_env_vars, clear=True): 34 | config = Config() 35 | 36 | # SQL DB config 37 | assert config.sqldb_database == "test_db" 38 | assert config.sqldb_server == "test_server" 39 | assert config.sqldb_username == "test_user" 40 | assert config.driver == "{ODBC Driver 17 for SQL Server}" 41 | assert config.mid_id == "test_mid" 42 | 43 | # Azure OpenAI config 44 | assert config.azure_openai_endpoint == "https://openai.test" 45 | assert config.azure_openai_deployment_model == "gpt-4" 46 | assert config.azure_openai_api_key == "test_key" 47 | assert config.azure_openai_api_version == "2023-03-15-preview" 48 | assert config.azure_openai_resource == "test_resource" 49 | 50 | # Azure AI Search config 51 | assert config.azure_ai_search_endpoint == "https://search.test" 52 | assert config.azure_ai_search_api_key == "search_key" 53 | assert config.azure_ai_search_index == "test_index" 54 | 55 | # AI Project Client 56 | assert config.use_ai_project_client is True 57 | assert config.azure_ai_project_conn_string == "Endpoint=sb://test/" 58 | 59 | # Chat history config 60 | assert config.use_chat_history_enabled is True 61 | assert config.azure_cosmosdb_database == "cosmos_db" 62 | assert config.azure_cosmosdb_account == "cosmos_account" 63 | assert config.azure_cosmosdb_conversations_container == "convo_container" 64 | assert config.azure_cosmosdb_enable_feedback is True 65 | -------------------------------------------------------------------------------- /src/tests/api/common/logging/test_event_utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from unittest.mock import patch, MagicMock 3 | import pytest 4 | 5 | from common.logging.event_utils import track_event_if_configured 6 | 7 | @pytest.fixture 8 | def event_data(): 9 | return {"user": "test_user", "action": "test_action"} 10 | 11 | 12 | def test_track_event_with_instrumentation_key(monkeypatch, event_data): 13 | monkeypatch.setenv("APPLICATIONINSIGHTS_CONNECTION_STRING", "some-key") 14 | 15 | with patch("common.logging.event_utils.track_event") as mock_track_event: 16 | track_event_if_configured("TestEvent", event_data) 17 | mock_track_event.assert_called_once_with("TestEvent", event_data) 18 | 19 | 20 | def test_track_event_without_instrumentation_key(monkeypatch, event_data, caplog): 21 | monkeypatch.delenv("APPLICATIONINSIGHTS_CONNECTION_STRING", raising=False) 22 | 23 | with patch("common.logging.event_utils.track_event") as mock_track_event: 24 | with caplog.at_level(logging.WARNING): 25 | track_event_if_configured("TestEvent", event_data) 26 | mock_track_event.assert_not_called() 27 | assert "Skipping track_event for TestEvent as Application Insights is not configured" in caplog.text 28 | -------------------------------------------------------------------------------- /src/tests/api/helpers/test_streaming_helper.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from unittest.mock import AsyncMock, MagicMock, patch 3 | from helpers.streaming_helper import stream_processor 4 | 5 | 6 | @pytest.mark.asyncio 7 | async def test_stream_processor_yields_content(): 8 | # Mock message with content 9 | message1 = MagicMock() 10 | message1.content = "message 1" 11 | message2 = MagicMock() 12 | message2.content = "message 2" 13 | 14 | # Mock async generator 15 | response = AsyncMock() 16 | response.__aiter__.return_value = [message1, message2] 17 | 18 | # Collect results 19 | result = [msg async for msg in stream_processor(response)] 20 | 21 | assert result == ["message 1", "message 2"] 22 | 23 | 24 | @pytest.mark.asyncio 25 | async def test_stream_processor_skips_empty_content(): 26 | # Mock message with empty content 27 | message1 = MagicMock() 28 | message1.content = "" 29 | message2 = MagicMock() 30 | message2.content = "message 2" 31 | 32 | response = AsyncMock() 33 | response.__aiter__.return_value = [message1, message2] 34 | 35 | result = [msg async for msg in stream_processor(response)] 36 | 37 | assert result == ["message 2"] 38 | 39 | 40 | @pytest.mark.asyncio 41 | async def test_stream_processor_logs_and_raises_on_exception(): 42 | response = AsyncMock() 43 | 44 | # Simulate error during iteration 45 | async def mock_iter(): 46 | raise RuntimeError("stream error") 47 | yield # This is unreachable, but needed to define async generator 48 | 49 | response.__aiter__.side_effect = mock_iter 50 | 51 | with patch("helpers.streaming_helper.logging.error") as mock_log: 52 | with pytest.raises(RuntimeError, match="stream error"): 53 | async for _ in stream_processor(response): 54 | pass 55 | 56 | mock_log.assert_called_once() 57 | args, kwargs = mock_log.call_args 58 | assert "Error processing streaming response" in args[0] 59 | assert kwargs["exc_info"] is True 60 | -------------------------------------------------------------------------------- /src/tests/test_app.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import pytest_asyncio 3 | from fastapi import FastAPI 4 | from httpx import AsyncClient, ASGITransport 5 | from unittest.mock import AsyncMock, patch 6 | 7 | import app as app_module 8 | 9 | 10 | @pytest.fixture 11 | def mock_agent(): 12 | return AsyncMock() 13 | 14 | 15 | @pytest_asyncio.fixture 16 | async def test_app(mock_agent): 17 | with patch("app.AgentFactory.get_instance", return_value=mock_agent), \ 18 | patch("app.AgentFactory.delete_instance", new_callable=AsyncMock): 19 | app = app_module.build_app() 20 | transport = ASGITransport(app=app) 21 | async with AsyncClient(transport=transport, base_url="http://testserver") as ac: 22 | yield app, ac 23 | 24 | 25 | @pytest.mark.asyncio 26 | async def test_health_check(test_app): 27 | app, client = test_app 28 | response = await client.get("/health") 29 | assert response.status_code == 200 30 | assert response.json() == {"status": "healthy"} 31 | 32 | 33 | @pytest.mark.asyncio 34 | async def test_lifespan_startup_and_shutdown(mock_agent): 35 | with patch("app.AgentFactory.get_instance", return_value=mock_agent) as mock_get_instance, \ 36 | patch("app.AgentFactory.delete_instance", new_callable=AsyncMock) as mock_delete_instance: 37 | 38 | app = app_module.build_app() 39 | 40 | # Manually trigger lifespan events 41 | async with app_module.lifespan(app): 42 | mock_get_instance.assert_called_once() 43 | assert hasattr(app.state, "agent") 44 | assert app.state.agent == mock_agent 45 | 46 | mock_delete_instance.assert_awaited_once() 47 | assert app.state.agent is None 48 | 49 | 50 | def test_build_app_sets_metadata(): 51 | app = app_module.build_app() 52 | assert isinstance(app, FastAPI) 53 | assert app.title == "Conversation Knowledge Mining Solution Accelerator" 54 | assert app.version == "1.0.0" 55 | 56 | 57 | def test_routes_registered(): 58 | app = app_module.build_app() 59 | route_paths = [route.path for route in app.routes] 60 | 61 | assert "/health" in route_paths 62 | assert any(route.path.startswith("/api") for route in app.routes) 63 | assert any(route.path.startswith("/history") for route in app.routes) 64 | --------------------------------------------------------------------------------