├── .env.template ├── .gitattributes ├── .github ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── README.md │ ├── app_backend-test.yml │ ├── app_frontend-vitest.yml │ ├── dockerfile-lint.yml │ ├── python-deps-install-test.yml │ ├── python-static-checks.yml │ ├── shellcheck.yml │ └── yaml-format.yml ├── .gitignore ├── .hadolint.yml ├── .shellcheckrc ├── .yamlfmt.yml ├── CHANGELOG.md ├── LICENSE.txt ├── Makefile ├── Pulumi.yaml ├── README.md ├── Set-Env.ps1 ├── app_backend ├── .gitignore ├── README.md ├── __init__.py ├── app │ ├── __init__.py │ └── main.py ├── metadata.yaml.jinja ├── pyproject.toml ├── requirements.txt ├── start-app.sh ├── static │ ├── assets │ │ ├── Chats-Dd9N05MP.css │ │ ├── Chats-M0pjWu7k.js │ │ ├── Data-Bpsku5AZ.js │ │ ├── DataRobot_white-C2JrcVRN.svg │ │ ├── ResponseMessage-CWOV94tO.js │ │ ├── dm-sans-latin-300-normal-CfSGLRSF.woff2 │ │ ├── dm-sans-latin-300-normal-Cjw7_AC8.woff │ │ ├── dm-sans-latin-400-normal-COF6noiJ.woff2 │ │ ├── dm-sans-latin-400-normal-DmRB7q_B.woff │ │ ├── dm-sans-latin-500-normal-DN3Amd4H.woff │ │ ├── dm-sans-latin-500-normal-kGSpR5A9.woff2 │ │ ├── dm-sans-latin-600-normal-DOZeTYVF.woff │ │ ├── dm-sans-latin-600-normal-DrBIvsIy.woff2 │ │ ├── dm-sans-latin-700-normal-1DREuLwQ.woff2 │ │ ├── dm-sans-latin-700-normal-ryGpXDOP.woff │ │ ├── dm-sans-latin-ext-300-normal-C06zYcNH.woff2 │ │ ├── dm-sans-latin-ext-300-normal-CJf67p0q.woff │ │ ├── dm-sans-latin-ext-400-normal-Cygz-XR6.woff2 │ │ ├── dm-sans-latin-ext-400-normal-NAt9AhwD.woff │ │ ├── dm-sans-latin-ext-500-normal-BBd_G3i-.woff2 │ │ ├── dm-sans-latin-ext-500-normal-hI9Kr37g.woff │ │ ├── dm-sans-latin-ext-600-normal-CFRgRepe.woff2 │ │ ├── dm-sans-latin-ext-600-normal-Czy-B68B.woff │ │ ├── dm-sans-latin-ext-700-normal-BS_Ohp14.woff │ │ ├── dm-sans-latin-ext-700-normal-CGQ_Vo0j.woff2 │ │ ├── index-CMsw26cy.css │ │ ├── index-FhmhbUKT.js │ │ ├── loading-CK9GbiUV.js │ │ ├── react-plotly-BPP4jxfQ.js │ │ └── tabs-3OT-8Yc1.js │ ├── datarobot_favicon.png │ └── index.html └── tests │ ├── __init__.py │ └── test_main.py ├── app_frontend ├── .npmrc ├── .prettierrc.json ├── README.md ├── Taskfile.yaml ├── components.json ├── eslint.config.js ├── index.html ├── package.json ├── postcss.config.mjs ├── public │ └── datarobot_favicon.png ├── src │ ├── App.css │ ├── App.tsx │ ├── api │ │ ├── apiClient.ts │ │ ├── chat-messages │ │ │ ├── api-requests.ts │ │ │ ├── hooks.ts │ │ │ ├── keys.ts │ │ │ ├── mocks.ts │ │ │ └── types.ts │ │ ├── cleansed-datasets │ │ │ ├── api-requests.ts │ │ │ ├── hooks.ts │ │ │ └── keys.ts │ │ ├── database │ │ │ ├── api-requests.ts │ │ │ ├── hooks.ts │ │ │ └── keys.ts │ │ ├── datasets │ │ │ ├── api-requests.ts │ │ │ ├── hooks.ts │ │ │ └── keys.ts │ │ ├── dictionaries │ │ │ ├── api-requests.ts │ │ │ ├── hooks.ts │ │ │ ├── keys.ts │ │ │ └── types.ts │ │ └── user │ │ │ ├── api-requests.ts │ │ │ ├── hooks.ts │ │ │ └── keys.ts │ ├── assets │ │ ├── DataRobotLogo_black.svg │ │ ├── DataRobot_black.svg │ │ ├── DataRobot_white.svg │ │ ├── chat-midnight.svg │ │ ├── loader.svg │ │ └── playground-midnight.svg │ ├── components │ │ ├── AddDataModal.tsx │ │ ├── DataSourceSelector.tsx │ │ ├── DataSourceToggle.tsx │ │ ├── NewChatModal.tsx │ │ ├── RenameChatModal.tsx │ │ ├── SettingsModal.tsx │ │ ├── Sidebar.tsx │ │ ├── WelcomeModal.tsx │ │ ├── chat │ │ │ ├── AnalystDatasetTable.tsx │ │ │ ├── Avatars.tsx │ │ │ ├── CodeTabContent.tsx │ │ │ ├── CollapsiblePanel.tsx │ │ │ ├── ErrorPanel.tsx │ │ │ ├── HeaderSection.tsx │ │ │ ├── InfoText.tsx │ │ │ ├── InitialPrompt.tsx │ │ │ ├── InsightsTabContent.tsx │ │ │ ├── Loading.tsx │ │ │ ├── LoadingIndicator.tsx │ │ │ ├── MarkdownContent.css │ │ │ ├── MarkdownContent.tsx │ │ │ ├── MessageContainer.tsx │ │ │ ├── MessageHeader.tsx │ │ │ ├── PlotPanel.css │ │ │ ├── PlotPanel.tsx │ │ │ ├── ResponseMessage.tsx │ │ │ ├── ResponseTabs.tsx │ │ │ ├── SuggestedPrompt.tsx │ │ │ ├── SuggestedQuestionsSection.tsx │ │ │ ├── SummaryTabContent.tsx │ │ │ ├── UserMessage.tsx │ │ │ ├── UserPrompt.tsx │ │ │ ├── constants.ts │ │ │ ├── index.ts │ │ │ └── utils.ts │ │ ├── data │ │ │ ├── CleansedDataTable.tsx │ │ │ ├── ClearDatasetsButton.tsx │ │ │ ├── DataViewTabs.tsx │ │ │ ├── DatasetCardDescriptionPanel.tsx │ │ │ ├── DictionaryTable.tsx │ │ │ ├── SearchControl.tsx │ │ │ └── index.ts │ │ ├── ui-custom │ │ │ ├── file-uploader.tsx │ │ │ ├── loading.tsx │ │ │ ├── multi-select.tsx │ │ │ ├── prompt-input.tsx │ │ │ ├── sidebar-menu.tsx │ │ │ └── truncated-text.tsx │ │ └── ui │ │ │ ├── alert.tsx │ │ │ ├── badge.tsx │ │ │ ├── button.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── command.tsx │ │ │ ├── dialog.tsx │ │ │ ├── input.tsx │ │ │ ├── label.tsx │ │ │ ├── popover.tsx │ │ │ ├── progress.tsx │ │ │ ├── radio-group.tsx │ │ │ ├── resizable.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── separator.tsx │ │ │ ├── switch.tsx │ │ │ ├── table.tsx │ │ │ ├── tabs.tsx │ │ │ ├── toggle-group.tsx │ │ │ └── toggle.tsx │ ├── constants │ │ ├── dataSources.ts │ │ └── dev.ts │ ├── global.d.ts │ ├── index.css │ ├── jest-dom.d.ts │ ├── lib │ │ └── utils.ts │ ├── main.tsx │ ├── pages │ │ ├── Chats.tsx │ │ ├── Data.tsx │ │ ├── index.tsx │ │ └── routes.ts │ ├── state │ │ ├── AppStateContext.ts │ │ ├── AppStateProvider.tsx │ │ ├── constants.ts │ │ ├── hooks.ts │ │ ├── index.ts │ │ ├── reducer.ts │ │ ├── storage.ts │ │ └── types.ts │ └── vite-env.d.ts ├── tailwind.config.js ├── tests │ ├── __mocks__ │ │ ├── handlers.ts │ │ ├── handlers │ │ │ └── app.ts │ │ └── node.ts │ ├── components │ │ ├── LoadingIndicator.test.tsx │ │ ├── MessageContainer.test.tsx │ │ ├── NewChatModal.test.tsx │ │ ├── button.test.tsx │ │ ├── input.test.tsx │ │ └── prompt-input.test.tsx │ ├── setupTests.ts │ ├── state │ │ └── storage.test.ts │ └── test-utils.tsx ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.node.json ├── tsconfig.test.json └── vite.config.ts ├── frontend ├── .streamlit │ └── config.toml ├── 01_connect_and_explore.py ├── 02_chat_with_data.py ├── DataRobot_black.svg ├── DataRobot_white.svg ├── Google_Cloud.svg ├── Snowflake.svg ├── __init__.py ├── app.py ├── app_settings.py ├── bot.jpg ├── csv_File_Logo.svg ├── datarobot_connect.py ├── datarobot_favicon.png ├── helpers.py ├── metadata.yaml.jinja ├── requirements.txt ├── sap.svg ├── start-app.sh ├── style.css └── you.jpg ├── infra ├── __init__.py ├── __main__.py ├── components │ ├── __init__.py │ └── dr_credential.py ├── feature_flag_requirements.yaml ├── settings_app_infra.py ├── settings_database.py ├── settings_generative.py ├── settings_main.py └── settings_proxy_llm.py ├── notebooks └── testing.ipynb ├── pyproject.toml ├── quickstart.py ├── requirements.txt ├── set_env.bat ├── set_env.sh ├── test_pydantic.py ├── trivy-ignore.rego └── utils ├── __init__.py ├── analyst_db.py ├── api.py ├── code_execution.py ├── credentials.py ├── data_cleansing_helpers.py ├── database_helpers.py ├── logging_helper.py ├── prompts.py ├── resources.py ├── rest_api.py ├── schema.py └── tools.py /.env.template: -------------------------------------------------------------------------------- 1 | # Refer to https://docs.datarobot.com/en/docs/api/api-quickstart/index.html#create-a-datarobot-api-key 2 | # and https://docs.datarobot.com/en/docs/api/api-quickstart/index.html#retrieve-the-api-endpoint 3 | # Can be deleted on a DataRobot codespace 4 | DATAROBOT_API_TOKEN= 5 | DATAROBOT_ENDPOINT= 6 | 7 | # Required, unless logged in to pulumi cloud. Choose your own alphanumeric passphrase to be used for encrypting pulumi config 8 | PULUMI_CONFIG_PASSPHRASE=123 9 | 10 | # Optional: Choose which frontend implementation to use (streamlit or react) 11 | # FRONTEND_TYPE=streamlit 12 | 13 | # To use an existing TextGen Model or Deployment: 14 | # 1. Provide either the registered model ID, or the deployment ID 15 | # 2. Set CHAT_MODEL_NAME to the model name expected by the TextGen model (e.g. gpt-4o-mini) 16 | # 3. Set LLM=DEPLOYED_LLM in infra/settings_generative.py 17 | 18 | # TEXTGEN_REGISTERED_MODEL_ID= 19 | # TEXTGEN_DEPLOYMENT_ID= 20 | # CHAT_MODEL_NAME=datarobot-deployed-llm # for NIM models, "datarobot-deployed-llm" will automatically be translated to the correct model name. 21 | 22 | # For Azure OpenAI: 23 | 24 | # Refer to (https://learn.microsoft.com/en-us/azure/ai-services/openai/chatgpt-quickstart?tabs=command-line%2Cjavascript-keyless%2Ctypescript-keyless%2Cpython-new&pivots=programming-language-python#retrieve-key-and-endpoint) 25 | 26 | # OPENAI_API_KEY= 27 | # OPENAI_API_BASE= 28 | # OPENAI_API_VERSION= 29 | # OPENAI_API_DEPLOYMENT_ID= 30 | 31 | # For Snowflake (Optional) 32 | # Either password authentication: 33 | # SNOWFLAKE_USER= 34 | # SNOWFLAKE_PASSWORD= 35 | # Or key file authentication: 36 | # SNOWFLAKE_KEY_PATH= 37 | 38 | # Common Snowflake settings (required if using Snowflake): 39 | # SNOWFLAKE_ACCOUNT= 40 | # SNOWFLAKE_WAREHOUSE= 41 | # SNOWFLAKE_DATABASE= 42 | # SNOWFLAKE_SCHEMA= 43 | # SNOWFLAKE_ROLE= 44 | 45 | # For Google VertexAI 46 | 47 | # You will need a service account JSON with aiplatform.endpoints.predict permission (https://cloud.google.com/iam/docs/keys-create-delete) 48 | # GOOGLE_DB_SCHEMA is required if using BigQuery as a database but can be omitted for Vertex LLMs 49 | # Add the JSON file content enclosed by '' here: 50 | 51 | # GOOGLE_SERVICE_ACCOUNT= 52 | # GOOGLE_REGION= 53 | # GOOGLE_DB_SCHEMA= 54 | 55 | # For AWS Bedrock: 56 | 57 | # Refer to https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html 58 | # AWS_SESSION_TOKEN is optional in case you are using a long term access key 59 | 60 | # AWS_ACCESS_KEY_ID= 61 | # AWS_SECRET_ACCESS_KEY= 62 | # AWS_SESSION_TOKEN= 63 | # AWS_REGION= 64 | 65 | # For SAP DataSphere 66 | # SAP_DATASPHERE_HOST= 67 | # SAP_DATASPHERE_PORT= 68 | # SAP_DATASPHERE_USER= 69 | # SAP_DATASPHERE_PASSWORD= 70 | # SAP_DATASPHERE_SCHEMA= 71 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh text eol=lf -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This file configures the Dependabot for the repository. 3 | version: 2 4 | updates: 5 | # Maintain dependencies for GitHub Actions. 6 | - package-ecosystem: "github-actions" 7 | directory: "/" 8 | schedule: 9 | interval: "weekly" 10 | open-pull-requests-limit: 5 11 | labels: 12 | - "dependencies" 13 | - "github-actions" 14 | 15 | # Maintain dependencies for Python packages. 16 | - package-ecosystem: "pip" 17 | insecure-external-code-execution: allow 18 | directory: "/" 19 | schedule: 20 | interval: "daily" 21 | pull-request-branch-name: 22 | separator: "/" 23 | open-pull-requests-limit: 1 24 | versioning-strategy: "increase-if-necessary" 25 | target-branch: "main" 26 | labels: 27 | - "dependencies" 28 | - "python" 29 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | 4 | # Rationale 5 | 6 | 7 | # Checklist 8 | - [ ] Implementation 9 | - [ ] Update Changelog -------------------------------------------------------------------------------- /.github/workflows/README.md: -------------------------------------------------------------------------------- 1 | ### **GitHub Workflows** 2 | 3 | #### 📌 **Overview** 4 | 5 | This directory (`.github/workflows/`) contains GitHub Actions workflow definitions that automate various tasks such as 6 | CI/CD, releases, and repository synchronization. 7 | 8 | #### ⚙️ **Workflows** 9 | 10 | Below is a list of the workflows included in this repository: 11 | 12 | | Workflow File | Purpose | 13 | |--------------------------------|-------------------------------------------------------------------| 14 | | `dockerfile-lint.yml` | Run Hadolint to check Dockerfiles for best practices. | 15 | | `license-check.yml` | Check and fix license headers and resolve dependencies' licenses. | 16 | | `python-static-checks.yml` | Run Ruff linter and formatter, and MyPy static type checks. | 17 | | `python-deps-install-test.yml` | Verify Python dependencies install for different Python versions. | 18 | | `shellcheck.yml` | Run [shellcheck](https://github.com/koalaman/shellcheck/). | 19 | | `yaml-format.yml` | Run YAML linter tool (yamlfmt). | 20 | 21 | --- 22 | 23 | Feel free to update this document as new workflows are added or modified! ✨ 24 | -------------------------------------------------------------------------------- /.github/workflows/app_backend-test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Test app_backend 3 | 4 | on: 5 | push: 6 | branches: ["main"] 7 | paths: 8 | - 'app_backend/**.py' 9 | 10 | pull_request: 11 | branches: ["main"] 12 | paths: 13 | - 'app_backend/**.py' 14 | 15 | jobs: 16 | tests: 17 | name: "FastAPI: app_backend ${{ matrix.python-version }}" 18 | runs-on: "ubuntu-latest" 19 | defaults: 20 | run: 21 | working-directory: app_backend 22 | 23 | strategy: 24 | matrix: 25 | python-version: ["3.10", "3.11", "3.12"] 26 | 27 | steps: 28 | - uses: "actions/checkout@v4" 29 | 30 | # Ref: https://docs.astral.sh/uv/guides/integration/github/#installation 31 | - name: Setup uv 32 | uses: astral-sh/setup-uv@v6 33 | with: 34 | working-directory: app_backend 35 | enable-cache: true 36 | cache-dependency-glob: "uv.lock" 37 | python-version: ${{ matrix.python-version }} 38 | 39 | - name: Install Dependencies 40 | working-directory: app_backend 41 | run: uv sync --all-extras --dev 42 | 43 | - name: Run Static Checks 44 | working-directory: app_backend 45 | run: | 46 | uv run ruff format --check . 47 | uv run ruff check . 48 | uv run mypy --pretty --explicit-package-bases . 49 | 50 | - name: Test 51 | working-directory: app_backend 52 | run: uv run pytest --cov --cov-report=html --cov-report=term --cov-report xml:.coverage.xml 53 | 54 | - name: Get Cover 55 | uses: orgoro/coverage@v3.2 56 | with: 57 | coverageFile: app_backend/.coverage.xml 58 | token: ${{ secrets.GITHUB_TOKEN }} 59 | -------------------------------------------------------------------------------- /.github/workflows/app_frontend-vitest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Test app_frontend 3 | 4 | on: 5 | push: 6 | branches: ["main"] 7 | paths: 8 | - 'app_frontend/**' 9 | 10 | pull_request: 11 | branches: ["main"] 12 | paths: 13 | - 'app_frontend/**' 14 | 15 | workflow_dispatch: 16 | 17 | jobs: 18 | tests: 19 | name: "React: app_frontend node: ${{ matrix.node-version }}" 20 | runs-on: ubuntu-latest 21 | defaults: 22 | run: 23 | working-directory: frontend_web 24 | 25 | strategy: 26 | matrix: 27 | node-version: ["18", "20", "22"] 28 | 29 | steps: 30 | - name: Checkout code 31 | uses: actions/checkout@v4 32 | 33 | - name: Set up Node.js ${{ matrix.node-version }} 34 | uses: actions/setup-node@v4 35 | with: 36 | node-version: ${{ matrix.node-version }} 37 | 38 | - name: Install dependencies 39 | run: npm ci 40 | working-directory: app_frontend 41 | 42 | - name: Run Vitest 43 | run: npm run test 44 | working-directory: app_frontend 45 | -------------------------------------------------------------------------------- /.github/workflows/dockerfile-lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Dockerfile Lint 3 | 4 | on: 5 | push: 6 | paths: 7 | - '**Dockerfile' 8 | - '**Dockerfile.*' 9 | branches: 10 | - main 11 | - 'release/*' 12 | pull_request: 13 | paths: 14 | - '**Dockerfile' 15 | - '**Dockerfile.*' 16 | workflow_dispatch: 17 | 18 | jobs: 19 | hadolint: 20 | name: lint-dockerfile 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Run Hadolint 25 | uses: hadolint/hadolint-action@v3.1.0 26 | with: 27 | recursive: true 28 | -------------------------------------------------------------------------------- /.github/workflows/python-deps-install-test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Dependency Install Test 3 | 4 | on: 5 | pull_request: 6 | 7 | jobs: 8 | python-deps-install-test: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | python-version: ["3.10", "3.11", "3.12"] 13 | 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v4 17 | 18 | - name: Set up Python ${{ matrix.python-version }} 19 | uses: actions/setup-python@v5 20 | with: 21 | python-version: ${{ matrix.python-version }} 22 | 23 | - name: Install dependencies 24 | run: | 25 | python3 -m pip install --upgrade pip 26 | python3 -m pip install -r requirements.txt 27 | -------------------------------------------------------------------------------- /.github/workflows/python-static-checks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Python Static Checks 3 | 4 | on: 5 | push: 6 | paths: 7 | - '**.py' 8 | 9 | jobs: 10 | python-static-checks: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up Python 15 | uses: actions/setup-python@v5 16 | with: 17 | python-version: '3.10' 18 | - name: Install dependencies 19 | run: | 20 | python3 -m pip install --upgrade pip 21 | python3 -m pip install -r requirements.txt 22 | - name: Run Static Checks 23 | run: | 24 | ruff format --check . 25 | ruff check . 26 | mypy --pretty . 27 | -------------------------------------------------------------------------------- /.github/workflows/shellcheck.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Shellcheck 3 | 4 | on: 5 | push: 6 | paths: 7 | - '**.sh' 8 | branches: 9 | - main 10 | - 'release/*' 11 | pull_request: 12 | paths: 13 | - '**.sh' 14 | workflow_dispatch: 15 | 16 | jobs: 17 | shellcheck: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Install dependencies 22 | run: | 23 | wget -qO- https://github.com/koalaman/shellcheck/releases/download/stable/shellcheck-stable.linux.x86_64.tar.xz | tar -xJv 24 | sudo install -o root -g root -m 0755 shellcheck-stable/shellcheck /usr/local/bin 25 | shellcheck --version 26 | - name: Run shellcheck 27 | run: | 28 | find . -type f -name "*.sh" -exec shellcheck {} + 29 | -------------------------------------------------------------------------------- /.github/workflows/yaml-format.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: YAML formatter 3 | on: 4 | push: 5 | paths: 6 | - '**.yaml' 7 | - '**.yml' 8 | branches: 9 | - main 10 | - 'release/*' 11 | pull_request: 12 | paths: 13 | - '**.yaml' 14 | - '**.yml' 15 | workflow_dispatch: 16 | 17 | jobs: 18 | yaml-formatter: 19 | name: yamlfmt 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | - name: Install go 25 | uses: actions/setup-go@v5 26 | - name: Install yamlfmt 27 | run: go install github.com/google/yamlfmt/cmd/yamlfmt@latest 28 | - name: Run yamlfmt 29 | run: yamlfmt -conf .yamlfmt.yml -lint . 30 | -------------------------------------------------------------------------------- /.hadolint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ignored: 3 | - DL3013 4 | - DL3018 5 | -------------------------------------------------------------------------------- /.shellcheckrc: -------------------------------------------------------------------------------- 1 | # ShellCheck configuration 2 | # 3 | # https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md#rc-files. 4 | 5 | disable=SC1091 # Not following 6 | -------------------------------------------------------------------------------- /.yamlfmt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://github.com/google/yamlfmt config file 3 | continue_on_error: true 4 | formatter: 5 | include_document_start: true 6 | retain_line_breaks: true 7 | max_line_length: 120 8 | exclude: 9 | - .datarobot/ 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: copyright-check apply-copyright fix-licenses check-licenses 2 | 3 | help: 4 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 5 | 6 | copyright-check: ## Copyright checks 7 | docker run -it --rm -v $(CURDIR):/github/workspace apache/skywalking-eyes -c .github/.licenserc.yaml header check 8 | 9 | apply-copyright: ## Add copyright notice to new files 10 | docker run -it --rm -v $(CURDIR):/github/workspace apache/skywalking-eyes -c .github/.licenserc.yaml header fix 11 | 12 | fix-licenses: apply-copyright 13 | 14 | check-licenses: copyright-check 15 | 16 | fix-lint: ## Fix linting issues 17 | ruff format . 18 | ruff check . --fix 19 | mypy --pretty . 20 | 21 | lint: ## Lint the code 22 | ruff format --check . 23 | ruff check . 24 | mypy --pretty . 25 | 26 | check-all: check-licenses lint ## Run all checks 27 | 28 | run-local-dev-backend: 29 | PYTHONPATH=app_backend SERVE_STATIC_FRONTEND=False DEV_MODE=True ./app_backend/start-app.sh 30 | 31 | run-local-static-backend: 32 | PYTHONPATH=app_backend DEV_MODE=True ./app_backend/start-app.sh 33 | -------------------------------------------------------------------------------- /Pulumi.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: dataanalyst 3 | runtime: 4 | name: python 5 | main: infra 6 | description: Data Analyst 7 | config: 8 | pulumi:tags: 9 | value: 10 | pulumi:template: python 11 | datarobot:tracecontext: dataanalyst 12 | -------------------------------------------------------------------------------- /Set-Env.ps1: -------------------------------------------------------------------------------- 1 | # Function to load .env file 2 | function Import-EnvFile { 3 | if (-not (Test-Path '.env')) { 4 | Write-Host "Error: .env file not found." 5 | Write-Host "Please create a .env file with VAR_NAME=value pairs." 6 | return $false 7 | } 8 | 9 | $envVarsJson = python -c "import json; from quickstart import load_dotenv; env_vars = load_dotenv(); print(json.dumps(env_vars))" 10 | 11 | $envVars = $envVarsJson | ConvertFrom-Json 12 | 13 | $envVars.PSObject.Properties | ForEach-Object { 14 | [System.Environment]::SetEnvironmentVariable($_.Name, $_.Value) 15 | } 16 | 17 | Write-Host "Environment variables from .env have been set." 18 | return $true 19 | } 20 | # Function to activate the virtual environment if it exists 21 | function Enable-VirtualEnvironment { 22 | if (Test-Path '.venv\Scripts\Activate.ps1') { 23 | Write-Host "Activated virtual environment found at .venv\Scripts\Activate.ps1" 24 | . '.venv\Scripts\Activate.ps1' 25 | } 26 | } 27 | 28 | # Main execution 29 | Enable-VirtualEnvironment 30 | Import-EnvFile -------------------------------------------------------------------------------- /app_backend/.gitignore: -------------------------------------------------------------------------------- 1 | /metadata.yaml -------------------------------------------------------------------------------- /app_backend/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 DataRobot, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /app_backend/app/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 DataRobot, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /app_backend/app/main.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 DataRobot, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | import logging 17 | import os 18 | 19 | from fastapi import APIRouter 20 | from fastapi.responses import FileResponse, Response 21 | from fastapi.staticfiles import StaticFiles 22 | from utils.rest_api import app 23 | 24 | # Configure logging to filter out the health check logs 25 | logging.getLogger("uvicorn.access").setLevel(logging.WARNING) 26 | 27 | 28 | class EndpointFilter(logging.Filter): 29 | def filter(self, record: logging.LogRecord) -> bool: 30 | # Filter out "GET /" health check logs 31 | return "GET / HTTP/1.1" not in record.getMessage() 32 | 33 | 34 | logging.getLogger("uvicorn.access").addFilter(EndpointFilter()) 35 | 36 | SCRIPT_NAME = os.environ.get("SCRIPT_NAME", "") 37 | SERVE_STATIC_FRONTEND = os.environ.get("SERVE_STATIC_FRONTEND", "True") 38 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 39 | STATIC_DIR = os.path.join(BASE_DIR, "static") 40 | base_router = APIRouter() 41 | 42 | 43 | @base_router.get("/_dr_env.js") 44 | async def get_env() -> Response: 45 | NOTEBOOK_ID = os.getenv("NOTEBOOK_ID", "") 46 | app_base_url = os.getenv("BASE_PATH", "") 47 | if not app_base_url and NOTEBOOK_ID: 48 | app_base_url = f"notebook-sessions/{NOTEBOOK_ID}" 49 | 50 | env_vars = { 51 | "APP_BASE_URL": app_base_url, 52 | "API_PORT": os.getenv("PORT"), 53 | "DATAROBOT_ENDPOINT": os.getenv("DATAROBOT_ENDPOINT", ""), 54 | "IS_STATIC_FRONTEND": SERVE_STATIC_FRONTEND, 55 | } 56 | js = f"window.ENV = {json.dumps(env_vars)};" 57 | return Response(content=js, media_type="application/javascript") 58 | 59 | 60 | if SERVE_STATIC_FRONTEND: 61 | 62 | @base_router.get(f"{SCRIPT_NAME}/data") 63 | @base_router.get(f"{SCRIPT_NAME}/chats") 64 | @base_router.get(f"{SCRIPT_NAME}/chats/{{chat_id}}") 65 | @base_router.get(f"{SCRIPT_NAME}/") 66 | async def serve_root() -> FileResponse: 67 | """Serve the React index.html for the root route.""" 68 | return FileResponse(os.path.join(STATIC_DIR, "index.html")) 69 | 70 | 71 | app.include_router(base_router) 72 | 73 | if SERVE_STATIC_FRONTEND: 74 | # Important to be last so that we fall back to the static files if the route is not found 75 | app.mount("/", StaticFiles(directory=STATIC_DIR, html=True), name="static") 76 | -------------------------------------------------------------------------------- /app_backend/metadata.yaml.jinja: -------------------------------------------------------------------------------- 1 | name: runtime-params 2 | 3 | runtimeParameterDefinitions: 4 | {{ additional_params }} 5 | -------------------------------------------------------------------------------- /app_backend/requirements.txt: -------------------------------------------------------------------------------- 1 | # python sandbox libraries 2 | pandas>=2.2.3,<3.0 3 | numpy>=2.1.3,<3.0 4 | scipy>=1.15.1,<2.0 5 | statsmodels>=0.14.4,<1.0 6 | scikit-learn>=1.6.1,<2.0 7 | lightgbm>=4.5.0,<5.0 8 | tslearn>=0.6.3,<1.0 9 | spacy>=3.8.3,<4.0 10 | pyarrow<19.0.0 11 | polars>=1.22.0,<2.0 12 | 13 | # plotting 14 | kaleido>=0.2.1,<1.0 15 | plotly>=5.24.1,<6.0 16 | textblob>=0.19.0,<1.0 17 | 18 | # data 19 | openpyxl>=3.1.5,<4.0 20 | snowflake-connector-python>=3.12.4,<4.0 21 | google-cloud-bigquery>=3.27.0,<4.0 22 | google-auth>=2.37.0,<3.0 23 | snowflake-sqlalchemy>=1.7.3,<2.0 24 | sqlalchemy>=2.0.37,<3.0 25 | cryptography>=44.0.0,<45.0 26 | hdbcli>=2.23.27,<3.0 27 | pillow 28 | # genai 29 | openai>=1.59.9,<2 30 | instructor>=1.3.4,<2.0 31 | boto3>=1.36.2,<2.0 32 | 33 | # backend 34 | datarobot-asgi-middleware>=0.1.0 35 | fastapi>=0.115.6,<1.0 36 | httpx>=0.28.1 37 | python-dotenv>=1.0.1 38 | datarobot>=3.6.0,<4.0 39 | python-multipart>=0.0.20,<1.0 40 | uvicorn==0.34.0,<1 41 | psutil>=6.1.1,<7.0 42 | pydantic==2.7.4,<3.0 43 | pydantic-settings==2.4.0,<3.0 44 | joblib>=1.4.2,<2.0 45 | duckdb>=1.2.0,<1.3 46 | fastexcel>=0.12.1,<1.0 47 | aiofiles==24.1.0 48 | types-aiofiles==24.1.0.20241221 49 | 50 | # dev & compatibility 51 | eval_type_backport>=0.2.2,<1.0 52 | db-dtypes>=1.3.1,<2.0 53 | typing-extensions>=4.12.2,<5.0 54 | numba>=0.61.0,<1.0 55 | -------------------------------------------------------------------------------- /app_backend/start-app.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export PORT=${PORT:-"8080"} 4 | DEV_MODE=${DEV_MODE:-false} 5 | LOG_LEVEL="info" 6 | EXTRA_OPTS="--proxy-headers" 7 | 8 | if [ "$DEV_MODE" = "true" ]; then 9 | EXTRA_OPTS="$EXTRA_OPTS --reload" 10 | fi 11 | 12 | python -m uvicorn app.main:app --host 0.0.0.0 --port "$PORT" --log-level $LOG_LEVEL "$EXTRA_OPTS" 13 | -------------------------------------------------------------------------------- /app_backend/static/assets/Chats-Dd9N05MP.css: -------------------------------------------------------------------------------- 1 | .markdown-content{line-height:1.5}.markdown-content ul,.markdown-content ol{margin-top:.5rem;margin-bottom:.5rem;padding-left:1.5rem}.markdown-content ul{list-style-type:disc}.markdown-content ol{list-style-type:decimal}.markdown-content li{margin-bottom:.25rem}.markdown-content p{margin-bottom:.75rem}.markdown-content h1,.markdown-content h2,.markdown-content h3,.markdown-content h4,.markdown-content h5,.markdown-content h6{font-weight:600;margin-top:1rem;margin-bottom:.5rem}.markdown-content code{padding:.2rem .4rem;border-radius:.25rem;font-family:monospace}.markdown-content pre{border-radius:.25rem;overflow-x:auto}.markdown-content blockquote{border-left:3px solid #ccc;padding-left:1rem;margin-left:0;margin-right:0;font-style:italic}.markdown-content hr{border:0;border-top:1px solid #ccc;margin:1rem 0}.plot-container{filter:invert(90%) hue-rotate(180deg)} 2 | -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-300-normal-CfSGLRSF.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-300-normal-CfSGLRSF.woff2 -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-300-normal-Cjw7_AC8.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-300-normal-Cjw7_AC8.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-400-normal-COF6noiJ.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-400-normal-COF6noiJ.woff2 -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-400-normal-DmRB7q_B.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-400-normal-DmRB7q_B.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-500-normal-DN3Amd4H.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-500-normal-DN3Amd4H.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-500-normal-kGSpR5A9.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-500-normal-kGSpR5A9.woff2 -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-600-normal-DOZeTYVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-600-normal-DOZeTYVF.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-600-normal-DrBIvsIy.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-600-normal-DrBIvsIy.woff2 -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-700-normal-1DREuLwQ.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-700-normal-1DREuLwQ.woff2 -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-700-normal-ryGpXDOP.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-700-normal-ryGpXDOP.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-300-normal-C06zYcNH.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-300-normal-C06zYcNH.woff2 -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-300-normal-CJf67p0q.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-300-normal-CJf67p0q.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-400-normal-Cygz-XR6.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-400-normal-Cygz-XR6.woff2 -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-400-normal-NAt9AhwD.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-400-normal-NAt9AhwD.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-500-normal-BBd_G3i-.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-500-normal-BBd_G3i-.woff2 -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-500-normal-hI9Kr37g.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-500-normal-hI9Kr37g.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-600-normal-CFRgRepe.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-600-normal-CFRgRepe.woff2 -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-600-normal-Czy-B68B.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-600-normal-Czy-B68B.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-700-normal-BS_Ohp14.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-700-normal-BS_Ohp14.woff -------------------------------------------------------------------------------- /app_backend/static/assets/dm-sans-latin-ext-700-normal-CGQ_Vo0j.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/assets/dm-sans-latin-ext-700-normal-CGQ_Vo0j.woff2 -------------------------------------------------------------------------------- /app_backend/static/datarobot_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datarobot-community/talk-to-my-data-agent/17301f5fad9192aeefa13315f179328b29135334/app_backend/static/datarobot_favicon.png -------------------------------------------------------------------------------- /app_backend/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |