MH0386 commited on
Commit
66760eb
·
verified ·
1 Parent(s): e6b7c67

Merge pull request #800 from AlphaSphereDotAI/hf

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .deepsource.toml +22 -0
  2. .dockerignore +9 -0
  3. .envrc +6 -0
  4. .gitattributes +4 -35
  5. .github/lint/.hadolint.yaml +6 -0
  6. .github/lint/.ls-lint.yaml +8 -0
  7. .github/lint/.markdownlint.yaml +3 -0
  8. .github/lint/.ruff.toml +24 -0
  9. .github/lint/.taplo.toml +7 -0
  10. .github/lint/.trivy.yaml +1 -0
  11. .github/lint/.trivyignore.yaml +2 -0
  12. .github/lint/.yamlfix.toml +3 -0
  13. .github/lint/.yamllint.yaml +28 -0
  14. .github/mergify.yml +127 -0
  15. .github/renovate.json +25 -0
  16. .github/workflows/.docker.yaml +306 -0
  17. .github/workflows/.lint.yaml +363 -0
  18. .github/workflows/build.yaml +86 -0
  19. .github/workflows/ci_tools.yaml +106 -0
  20. .github/workflows/release.yaml +70 -0
  21. .github/workflows/test.yaml +76 -0
  22. .github/workflows/version.yaml +45 -0
  23. .gitignore +12 -0
  24. .idea/.gitignore +12 -0
  25. .idea/chattr.iml +15 -0
  26. .idea/inspectionProfiles/Project_Default.xml +237 -0
  27. .idea/inspectionProfiles/profiles_settings.xml +6 -0
  28. .idea/misc.xml +13 -0
  29. .idea/modules.xml +8 -0
  30. .idea/vcs.xml +6 -0
  31. .pre-commit-config.yaml +118 -0
  32. .sonarlint/connectedMode.json +5 -0
  33. .vscode/launch.json +19 -0
  34. .vscode/tasks.json +15 -0
  35. .zed/tasks.json +24 -0
  36. AGENTS.md +133 -0
  37. Dockerfile +32 -0
  38. README.md +34 -8
  39. assets/image/Einstein.jpg +3 -0
  40. assets/image/Napoleon.jpg +0 -0
  41. assets/prompts/template.poml +30 -0
  42. docker-compose-dev.yaml +97 -0
  43. docker-compose.yaml +126 -0
  44. mcp.json +40 -0
  45. pyproject.toml +41 -0
  46. src/chattr/__init__.py +8 -0
  47. src/chattr/__main__.py +22 -0
  48. src/chattr/app/__init__.py +3 -0
  49. src/chattr/app/builder.py +323 -0
  50. src/chattr/app/logger.py +19 -0
.deepsource.toml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version = 1
2
+
3
+ [[analyzers]]
4
+ name = "shell"
5
+
6
+ [[analyzers]]
7
+ dependency_file_paths = ["pyproject.toml"]
8
+ name = "python"
9
+
10
+ [analyzers.meta]
11
+ additional_builtins = ["_", "pretty_output"]
12
+ runtime_version = "3.x.x"
13
+ type_checker = "mypy"
14
+
15
+ [[analyzers]]
16
+ name = "docker"
17
+
18
+ [[analyzers]]
19
+ name = "secrets"
20
+
21
+ [[transformers]]
22
+ name = "ruff"
.dockerignore ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ **/__pycache__/
2
+ .deepsource.toml
3
+ .env
4
+ .github/
5
+ .idea/
6
+ .mypy_cache/
7
+ .ruff_cache/
8
+ .venv/
9
+ .vscode/
.envrc ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export MODEL__URL=${MODEL__URL:-https://generativelanguage.googleapis.com/v1beta/openai}
2
+ export MODEL__NAME=${MODEL__NAME:-gemini-2.5-flash}
3
+ export MODEL__API_KEY=${GOOGLE_API_KEY}
4
+ export VECTOR_DATABASE__URL=http://localhost:6333
5
+ export VECTOR_DATABASE__NAME=main
6
+ export CHARACTER__NAME=Napoleon
.gitattributes CHANGED
@@ -1,35 +1,4 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ * text=auto eol=lf
2
+ *.jpg filter=lfs diff=lfs merge=lfs -text
3
+ *.png filter=lfs diff=lfs merge=lfs -text
4
+ *.jpeg filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.github/lint/.hadolint.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ trustedRegistries:
2
+ - docker.io
3
+ - ghcr.io
4
+ - cgr.dev
5
+ ignored:
6
+ - DL3018
.github/lint/.ls-lint.yaml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ ls:
2
+ .py: snake_case
3
+ .yaml: snake_case | kebab-case
4
+ .yml: snake_case | kebab-case
5
+ .toml: snake_case
6
+ .md: SCREAMING_SNAKE_CASE
7
+ ignore:
8
+ - .git
.github/lint/.markdownlint.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ $schema: https://raw.githubusercontent.com/DavidAnson/markdownlint/main/schema/markdownlint-config-schema-strict.json
2
+ line-length:
3
+ tables: false
.github/lint/.ruff.toml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ indent-width = 4
2
+ line-length = 88
3
+ target-version = "py313"
4
+
5
+ [lint]
6
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
7
+ fixable = ["ALL"]
8
+ ignore = ["D100", "D105", "D107", "D212", "D413", "SIM117"]
9
+ select = ["ALL"]
10
+ unfixable = []
11
+
12
+ [lint.isort]
13
+ combine-as-imports = true
14
+
15
+ [lint.per-file-ignores]
16
+ "test_app.py" = ["INP001", "S101"]
17
+
18
+ [format]
19
+ docstring-code-format = false
20
+ docstring-code-line-length = "dynamic"
21
+ indent-style = "space"
22
+ line-ending = "lf"
23
+ quote-style = "double"
24
+ skip-magic-trailing-comma = false
.github/lint/.taplo.toml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ exclude = [".venv/**"]
2
+ [formatting]
3
+ indent_entries = true
4
+ indent_tables = true
5
+ reorder_arrays = true
6
+ reorder_inline_tables = true
7
+ reorder_keys = true
.github/lint/.trivy.yaml ADDED
@@ -0,0 +1 @@
 
 
1
+ ignorefile: .github/lint/.trivyignore.yaml
.github/lint/.trivyignore.yaml ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ misconfigurations:
2
+ - id: AVD-DS-0026
.github/lint/.yamlfix.toml ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ comments_min_spaces_from_content = 1
2
+ explicit_start = false
3
+ sequence_style = 'block_style'
.github/lint/.yamllint.yaml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ extends: default
2
+ rules:
3
+ braces:
4
+ level: warning
5
+ max-spaces-inside: 1
6
+ brackets:
7
+ level: warning
8
+ max-spaces-inside: 1
9
+ colons:
10
+ level: warning
11
+ commas:
12
+ level: warning
13
+ comments: disable
14
+ comments-indentation: disable
15
+ document-start: disable
16
+ empty-lines:
17
+ level: warning
18
+ hyphens:
19
+ level: warning
20
+ indentation:
21
+ level: warning
22
+ indent-sequences: consistent
23
+ line-length:
24
+ level: warning
25
+ allow-non-breakable-inline-mappings: true
26
+ max: 140
27
+ truthy: disable
28
+ key-duplicates: enable
.github/mergify.yml ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pull_request_rules:
2
+ - name: Automatically queue pre-commit Updates
3
+ conditions:
4
+ - files ~= .pre-commit-config.yaml
5
+ - author = renovate[bot]
6
+ actions:
7
+ queue:
8
+ label:
9
+ add:
10
+ - pre-commit
11
+ - name: Automatically queue Dockerfile Updates
12
+ conditions:
13
+ - files ~= Dockerfile
14
+ - author = renovate[bot]
15
+ - check-success = Test Image / API Test
16
+ actions:
17
+ queue:
18
+ - name: Automatically label Dockerfile Updates
19
+ conditions:
20
+ - files ~= Dockerfile
21
+ - author = renovate[bot]
22
+ actions:
23
+ label:
24
+ add:
25
+ - docker
26
+ - name: Automatically queue Github Actions Updates
27
+ conditions:
28
+ - files ~= ^.github/workflows
29
+ - author = renovate[bot]
30
+ actions:
31
+ queue:
32
+ label:
33
+ add:
34
+ - github-actions
35
+ - name: Automatically queue valid Python Dependency Updates
36
+ conditions:
37
+ - files ~= ^(uv.lock|pyproject.toml)$
38
+ - author = renovate[bot]
39
+ - and:
40
+ - check-success = Check Dependency Compatibility
41
+ - check-success = Test Image / API Test
42
+ actions:
43
+ queue:
44
+ - name: Automatically label Python Dependency Updates
45
+ conditions:
46
+ - files ~= ^(uv.lock|pyproject.toml)$
47
+ - author = renovate[bot]
48
+ actions:
49
+ label:
50
+ add:
51
+ - uv
52
+ - python
53
+ - dependencies
54
+ - name: Automatically queue Docker Compose Updates
55
+ conditions:
56
+ - files ~= ^(docker-compose-dev.yaml|docker-compose.yaml)$
57
+ - author = renovate[bot]
58
+ actions:
59
+ queue:
60
+ label:
61
+ add:
62
+ - docker-compose
63
+ - name: Merge pull request when the configuration of Mergify is valid
64
+ conditions:
65
+ - author = MH0386
66
+ - 'title = ci(Mergify): configuration update'
67
+ - head = mergify/MH0386/config-update
68
+ actions:
69
+ merge:
70
+ - name: Comment when a pull request is merged
71
+ conditions:
72
+ - merged
73
+ actions:
74
+ delete_head_branch:
75
+ comment:
76
+ message: >-
77
+ Thank you for your contribution @{{author}}! Your pull request has been
78
+ merged.
79
+ - name: Comment if there is a conflict
80
+ conditions:
81
+ - conflict
82
+ actions:
83
+ comment:
84
+ message: Hi @{{author}}, Your PR is in conflict and cannot be merged.
85
+ label:
86
+ add:
87
+ - conflict
88
+ - name: Automatic update of the pull requests
89
+ conditions:
90
+ - -merged
91
+ actions:
92
+ update:
93
+ - name: Add a queue label when PR is queued
94
+ conditions:
95
+ - queue-position > 0
96
+ actions:
97
+ label:
98
+ toggle:
99
+ - merge-queued
100
+ - name: Notify when a PR is removed from the queue
101
+ conditions:
102
+ - queue-dequeue-reason != none
103
+ - queue-dequeue-reason != pr-merged
104
+ actions:
105
+ comment:
106
+ message: >-
107
+ Hey @{{author}}, your pull request has been dequeued due to the following
108
+ reason: {{queue_dequeue_reason}}.
109
+ Sorry about that, but you can requeue the PR by using `@mergifyio requeue`
110
+ if you think this was a mistake.
111
+ queue_rules:
112
+ - name: default
113
+ update_method: merge
114
+ allow_queue_branch_edit: true
115
+ queue_branch_merge_method: fast-forward
116
+ queue_conditions:
117
+ - and:
118
+ - 'check-success = DeepSource: Secrets'
119
+ - 'check-success = DeepSource: Python'
120
+ - 'check-success = DeepSource: pyproject.toml'
121
+ - 'check-success = DeepSource: Docker'
122
+ - check-success = CodeFactor
123
+ - check-success = GitGuardian Security Checks
124
+ - check-success = SonarCloud
125
+ - check-success = CodeQL
126
+ - check-success = Lint / UV Lock Check
127
+ - check-success = Lint / TruffleHog
.github/renovate.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "dependencyDashboardOSVVulnerabilitySummary": "all",
4
+ "extends": [
5
+ "config:best-practices"
6
+ ],
7
+ "lockFileMaintenance": {
8
+ "enabled": true
9
+ },
10
+ "osvVulnerabilityAlerts": true,
11
+ "packageRules": [
12
+ {
13
+ "matchManagers": [
14
+ "pep621"
15
+ ],
16
+ "matchPackageNames": [
17
+ "*"
18
+ ],
19
+ "rangeStrategy": "bump"
20
+ }
21
+ ],
22
+ "pre-commit": {
23
+ "enabled": true
24
+ }
25
+ }
.github/workflows/.docker.yaml ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Docker Image
2
+ on:
3
+ workflow_call:
4
+ inputs:
5
+ is_test:
6
+ type: boolean
7
+ required: true
8
+ description: Test Mode
9
+ registry:
10
+ type: string
11
+ required: true
12
+ description: Registry
13
+ install_source:
14
+ type: string
15
+ required: true
16
+ description: Source to install from (e.g., PyPI Package or Git source)
17
+ permissions:
18
+ contents: read
19
+ packages: write
20
+ attestations: write
21
+ id-token: write
22
+ actions: read
23
+ security-events: write
24
+ jobs:
25
+ check_dockerfile:
26
+ name: Check Dockerfile
27
+ runs-on: ubuntu-latest
28
+ if: ${{ inputs.is_test }}
29
+ environment:
30
+ name: code_quality
31
+ steps:
32
+ - name: Checkout repository
33
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
34
+ - name: Check Dockerfile
35
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
36
+ id: dockerfile_lint
37
+ with:
38
+ call: check
39
+ - name: Job Summary
40
+ uses: jazanne/job-summary-action@690eb386a0b86fe4da7c6f0e543e61330ff09f06 # v1.0.0
41
+ if: success() || failure()
42
+ with:
43
+ summary: |
44
+ ## Dockerfile Check
45
+ - **Status**: ${{ steps.dockerfile_lint.outcome == 'success' && ':white_check_mark:' || ':x:' }}
46
+ build_image:
47
+ name: Build and push Docker image to ${{ inputs.registry }}
48
+ needs: check_dockerfile
49
+ if: ${{ always() && !cancelled() && !failure() }}
50
+ runs-on: ubuntu-latest
51
+ outputs:
52
+ image_tag: ${{ steps.tag.outputs.TAG }}
53
+ environment:
54
+ name: docker_image
55
+ url: ${{inputs.registry}}/${{github.repository}}
56
+ steps:
57
+ - name: Free Disk Space
58
+ uses: endersonmenezes/free-disk-space@e6ed9b02e683a3b55ed0252f1ee469ce3b39a885 # v3.1.0
59
+ with:
60
+ remove_android: true
61
+ remove_dotnet: true
62
+ remove_haskell: true
63
+ remove_tool_cache: true
64
+ remove_swap: true
65
+ remove_packages_one_command: true
66
+ rm_cmd: rmz
67
+ remove_folders: >-
68
+ /usr/share /usr/local/lib /usr/local/share
69
+ /usr/local
70
+ - name: Checkout repository
71
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
72
+ - name: Get Python version from pyproject.toml
73
+ id: get_python_version
74
+ uses: mikefarah/yq@065b200af9851db0d5132f50bc10b1406ea5c0a8 # v4.50.1
75
+ with:
76
+ cmd: yq -roy '.project.requires-python' pyproject.toml
77
+ - name: Log in to ${{ inputs.registry }} Registry
78
+ uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
79
+ with:
80
+ registry: ${{ inputs.registry }}
81
+ username: mh0386
82
+ password: ${{ inputs.registry == 'ghcr.io' && secrets.GH_TOKEN || inputs.registry == 'docker.io' && secrets.TOKEN_KEY_DOCKER }}
83
+ - name: Set up QEMU
84
+ uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
85
+ - name: Set up Docker Buildx
86
+ uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
87
+ - name: Docker meta
88
+ id: meta
89
+ uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
90
+ with:
91
+ images: ${{ inputs.registry }}/${{ github.repository }}
92
+ tags: |
93
+ type=raw,value=latest,enable=${{ github.event_name == 'push' && contains(github.ref, 'refs/tags/') }}
94
+ type=ref,event=pr,prefix={{sha}}-pr-
95
+ type=ref,event=tag
96
+ type=ref,event=branch
97
+ - name: Build and Push to ${{ inputs.registry }}
98
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
99
+ id: push
100
+ with:
101
+ push: true
102
+ sbom: true
103
+ tags: ${{ steps.meta.outputs.tags }}
104
+ labels: ${{ steps.meta.outputs.labels }}
105
+ annotations: ${{ steps.meta.outputs.annotations }}
106
+ build-args: |
107
+ INSTALL_SOURCE=${{ inputs.install_source }}
108
+ PYTHON_VERSION=${{ steps.get_python_version.outputs.result }}
109
+ env:
110
+ DOCKER_CONTENT_TRUST: '1'
111
+ - name: Generate artifact attestation
112
+ uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0
113
+ if: ${{ inputs.is_test == false }}
114
+ with:
115
+ subject-name: ${{ inputs.registry == 'docker.io' && 'index.docker.io' || inputs.registry }}/${{github.repository}}
116
+ subject-digest: ${{ steps.push.outputs.digest }}
117
+ push-to-registry: true
118
+ - name: Update Docker Hub Description
119
+ if: ${{ inputs.registry == 'docker.io' }}
120
+ uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0
121
+ with:
122
+ username: mh0386
123
+ password: ${{ secrets.TOKEN_KEY_DOCKER }}
124
+ repository: ${{ github.repository }}
125
+ short-description: ${{ github.event.repository.description }}
126
+ enable-url-completion: true
127
+ - name: Export tag for Testing and Scanning
128
+ id: tag
129
+ run: echo "TAG=$(echo "${{ steps.meta.outputs.tags }}" | tail -n 1)" >> $GITHUB_OUTPUT
130
+ docker_scout:
131
+ name: Docker Scout CVEs
132
+ needs: build_image
133
+ runs-on: ubuntu-latest
134
+ environment:
135
+ name: container_health
136
+ steps:
137
+ - name: Docker Scout
138
+ uses: docker/scout-action@f8c776824083494ab0d56b8105ba2ca85c86e4de # v1.18.2
139
+ with:
140
+ command: cves
141
+ dockerhub-user: mh0386
142
+ dockerhub-password: ${{ secrets.TOKEN_KEY_DOCKER }}
143
+ image: ${{ needs.build_image.outputs.image_tag }}
144
+ github-token: ${{ secrets.GH_TOKEN }}
145
+ trufflehog:
146
+ name: TruffleHog
147
+ runs-on: ubuntu-latest
148
+ needs: build_image
149
+ environment:
150
+ name: container_health
151
+ steps:
152
+ - name: Install trufflehog
153
+ uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0
154
+ with:
155
+ repo: trufflesecurity/trufflehog
156
+ cache: enable
157
+ - name: Docker Secret Scanning
158
+ run: >-
159
+ trufflehog docker --image ${{needs.build_image.outputs.image_tag}}
160
+ --fail --github-actions --results=verified --log-level=4 --no-update
161
+ syft:
162
+ name: Syft
163
+ runs-on: ubuntu-latest
164
+ needs: build_image
165
+ environment:
166
+ name: container_health
167
+ permissions:
168
+ contents: write
169
+ steps:
170
+ - name: SBOM Generation
171
+ uses: anchore/sbom-action@deef08a0db64bfad603422135db61477b16cef56 # v0.22.1
172
+ with:
173
+ image: ${{ needs.build_image.outputs.image_tag }}
174
+ dependency-snapshot: true
175
+ output-file: ${{ github.event.repository.name }}-sbom.json
176
+ format: syft-json
177
+ grype:
178
+ name: Grype
179
+ needs: build_image
180
+ runs-on: ubuntu-latest
181
+ environment:
182
+ name: container_health
183
+ steps:
184
+ - name: Scan image
185
+ uses: anchore/scan-action@8d2fce09422cd6037e577f4130e9b925e9a37175 # v7.3.1
186
+ id: scan
187
+ with:
188
+ image: ${{ needs.build_image.outputs.image_tag }}
189
+ cache-db: true
190
+ - name: upload Anchore scan SARIF report
191
+ if: success() || failure()
192
+ uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
193
+ with:
194
+ sarif_file: ${{ steps.scan.outputs.sarif }}
195
+ trivy:
196
+ name: Trivy
197
+ needs: build_image
198
+ runs-on: ubuntu-latest
199
+ environment:
200
+ name: container_health
201
+ steps:
202
+ - name: Checkout repository
203
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
204
+ - name: Run Trivy vulnerability scanner
205
+ uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
206
+ with:
207
+ image-ref: ${{ needs.build_image.outputs.image_tag }}
208
+ trivy-config: .github/lint/.trivy.yaml
209
+ format: sarif
210
+ output: trivy-results-image.sarif
211
+ exit-code: '1'
212
+ scanners: vuln,secret,misconfig,license
213
+ - name: Upload Trivy scan results to GitHub Security tab
214
+ if: success() || failure()
215
+ uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
216
+ with:
217
+ sarif_file: trivy-results-image.sarif
218
+ dockle:
219
+ name: Dockle
220
+ needs: build_image
221
+ runs-on: ubuntu-latest
222
+ environment:
223
+ name: container_health
224
+ steps:
225
+ - name: Lint the Container Image
226
+ uses: goodwithtech/dockle-action@e30e6af832aad6ea7dca2a248d31a85eab6dbd68 # v0.4.15
227
+ with:
228
+ image: ${{ needs.build_image.outputs.image_tag }}
229
+ format: sarif
230
+ output: dockle.sarif
231
+ accept-file: settings.py
232
+ accept-key: --chmod,--chown,GRADIO_SERVER_PORT,GRADIO_SERVER_NAME,FASTEMBED_CACHE_PATH,PATH
233
+ ignore: CIS-DI-0006
234
+ - name: upload Dockle scan SARIF report
235
+ if: success() || failure()
236
+ uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
237
+ with:
238
+ sarif_file: dockle.sarif
239
+ api_test:
240
+ name: API Test
241
+ needs: build_image
242
+ runs-on: ubuntu-latest
243
+ if: ${{ inputs.is_test }}
244
+ environment:
245
+ name: container_health
246
+ services:
247
+ vector_database:
248
+ image: qdrant/qdrant:latest@sha256:0425e3e03e7fd9b3dc95c4214546afe19de2eb2e28ca621441a56663ac6e1f46
249
+ ports:
250
+ - 6333:6333
251
+ app:
252
+ image: ${{ needs.build_image.outputs.image_tag }}
253
+ ports:
254
+ - 7860:7860
255
+ env:
256
+ MODEL__URL: https://api.groq.com/openai/v1
257
+ MODEL__API_KEY: ${{ secrets.GROQ_API_KEY }}
258
+ MODEL__NAME: llama3-70b-8192
259
+ VECTOR_DATABASE__URL: http://vector_database:6333
260
+ VECTOR_DATABASE__NAME: test
261
+ options: >-
262
+ --health-cmd "curl -o /dev/null -f -s -w 'Status: %{http_code}, Time: %{time_total}s'
263
+ http://localhost:7860/" --health-interval 10s --health-timeout
264
+ 10s --health-start-period 20s --health-retries 15
265
+ steps:
266
+ - name: Echo URL
267
+ run: echo "${{ github.event.repository.name }} available on localhost:${{ job.services.app.ports['7860'] }}"
268
+ - name: Checkout repository
269
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
270
+ - name: Install uv
271
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
272
+ with:
273
+ enable-cache: true
274
+ activate-environment: true
275
+ - name: Install deps
276
+ run: uv sync --only-dev
277
+ - name: Test
278
+ uses: pavelzw/pytest-action@510c5e90c360a185039bea56ce8b3e7e51a16507 # v2.2.0
279
+ with:
280
+ click-to-expand: false
281
+ custom-arguments: tests/test_app.py::test_app -p no:warnings
282
+ env:
283
+ MERGIFY_TOKEN: ${{ secrets.MERGIFY_TOKEN }}
284
+ clean:
285
+ name: Cleaning GHCR
286
+ needs:
287
+ - api_test
288
+ - docker_scout
289
+ - dockle
290
+ - trivy
291
+ - grype
292
+ - syft
293
+ - trufflehog
294
+ if: ${{ inputs.registry == 'ghcr.io' && ( success() || failure() ) && !contains(github.event.head_commit.message, '[skip ghcr clean]') }}
295
+ runs-on: ubuntu-latest
296
+ environment:
297
+ name: docker_image
298
+ steps:
299
+ - name: GHCR Cleaning
300
+ uses: snok/container-retention-policy@3b0972b2276b171b212f8c4efbca59ebba26eceb # v3.0.1
301
+ with:
302
+ account: ${{ github.repository_owner }}
303
+ token: ${{ secrets.GH_TOKEN }}
304
+ image-names: ${{ github.event.repository.name }}
305
+ image-tags: '!latest !*.*.*'
306
+ cut-off: 1s
.github/workflows/.lint.yaml ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Lint
2
+ on:
3
+ workflow_call:
4
+ permissions:
5
+ contents: write
6
+ pull-requests: write
7
+ checks: write
8
+ security-events: write
9
+ actions: read
10
+ jobs:
11
+ taplo:
12
+ name: Taplo ${{ matrix.command }}
13
+ runs-on: ubuntu-latest
14
+ environment:
15
+ name: code_quality
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ command:
20
+ - format
21
+ - lint
22
+ steps:
23
+ - name: Checkout repository
24
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
25
+ - name: Install taplo
26
+ uses: baptiste0928/cargo-install@b687c656bda5733207e629b50a22bf68974a0305 # v3.3.2
27
+ with:
28
+ crate: taplo-cli
29
+ locked: true
30
+ - name: ${{ matrix.command }}
31
+ run: >-
32
+ taplo ${{matrix.command}}
33
+ --config .github/lint/.taplo.toml
34
+ ${{matrix.command == 'lint' && '--default-schema-catalogs' || ''}}
35
+ - name: Commit and push applied formatter fixes
36
+ if: matrix.command == 'format'
37
+ uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
38
+ with:
39
+ commit_message: '[Taplo] Apply formatter fixes'
40
+ commit_options: --no-verify
41
+ trufflehog:
42
+ name: TruffleHog
43
+ runs-on: ubuntu-latest
44
+ environment:
45
+ name: code_quality
46
+ steps:
47
+ - name: Install trufflehog
48
+ uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0
49
+ with:
50
+ repo: trufflesecurity/trufflehog
51
+ cache: enable
52
+ - name: Git Secret Scanning
53
+ run: >-
54
+ trufflehog git ${{github.event.repository.html_url}} --branch=${{github.head_ref || github.ref_name}}
55
+ --fail --github-actions --results=verified,unknown --log-level=4 --no-update
56
+ pre-commit:
57
+ name: pre-commit
58
+ runs-on: ubuntu-latest
59
+ environment:
60
+ name: code_quality
61
+ steps:
62
+ - name: Checkout repository
63
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
64
+ - name: Install uv
65
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
66
+ with:
67
+ enable-cache: true
68
+ activate-environment: true
69
+ - name: Restore pre-commit cache
70
+ uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
71
+ id: cache-restore
72
+ with:
73
+ path: ~/.cache/pre-commit
74
+ key: pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }}
75
+ restore-keys: pre-commit-
76
+ - name: Run pre-commit hooks
77
+ run: uvx pre-commit run --show-diff-on-failure --color=always --all-files
78
+ - name: Save pre-commit cache
79
+ uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
80
+ if: always() && steps.cache-restore.outputs.cache-hit != 'true'
81
+ with:
82
+ path: ~/.cache/pre-commit
83
+ key: ${{ steps.cache-restore.outputs.cache-primary-key }}
84
+ - name: Run pre-commit-ci-lite
85
+ uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
86
+ if: always()
87
+ uv_lock:
88
+ name: UV Lock Check
89
+ runs-on: ubuntu-latest
90
+ environment:
91
+ name: code_quality
92
+ steps:
93
+ - name: Checkout repository
94
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
95
+ - name: Install uv
96
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
97
+ with:
98
+ enable-cache: true
99
+ activate-environment: true
100
+ - name: Check if the lockfile is up-to-date
101
+ id: uv_lock_check
102
+ run: uv lock --check
103
+ - name: Job Summary
104
+ uses: jazanne/job-summary-action@690eb386a0b86fe4da7c6f0e543e61330ff09f06 # v1.0.0
105
+ if: success() || failure()
106
+ with:
107
+ summary: |
108
+ ## UV Lock Check
109
+ - **Status**: ${{ steps.uv_lock_check.outcome == 'success' && ':white_check_mark:' || ':x:' }}
110
+ ls_lint:
111
+ name: ls-lint
112
+ runs-on: ubuntu-latest
113
+ environment:
114
+ name: code_quality
115
+ steps:
116
+ - name: Checkout repository
117
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
118
+ - name: Lint file names
119
+ uses: ls-lint/action@02e380fe8733d499cbfc9e22276de5085508a5bd # v2.3.1
120
+ with:
121
+ config: .github/lint/.ls-lint.yaml
122
+ ruff:
123
+ name: Ruff ${{ matrix.command }}
124
+ runs-on: ubuntu-latest
125
+ environment:
126
+ name: code_quality
127
+ strategy:
128
+ fail-fast: false
129
+ matrix:
130
+ command:
131
+ - check
132
+ - format
133
+ include:
134
+ - command: check
135
+ output: sarif
136
+ - command: format
137
+ output: github
138
+ steps:
139
+ - name: Checkout repository
140
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
141
+ with:
142
+ token: ${{ secrets.GH_TOKEN }}
143
+ - name: ${{ matrix.command }}
144
+ uses: astral-sh/ruff-action@57714a7c8a2e59f32539362ba31877a1957dded1 # v3.5.1
145
+ with:
146
+ args: >-
147
+ ${{ matrix.command }} --config .github/lint/.ruff.toml
148
+ --output-format ${{matrix.output}}
149
+ ${{matrix.output == 'sarif' && '--output-file ruff.sarif' || ''}}
150
+ - name: upload Ruff scan SARIF report
151
+ if: matrix.output == 'sarif' && ( success() || failure() )
152
+ uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
153
+ with:
154
+ sarif_file: ruff.sarif
155
+ - name: Commit and push applied Ruff fixes
156
+ if: matrix.output == 'github'
157
+ uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
158
+ with:
159
+ commit_message: '[Ruff] Apply format fixes'
160
+ commit_options: --no-verify
161
+ yamlfix:
162
+ name: YamlFix
163
+ runs-on: ubuntu-latest
164
+ environment:
165
+ name: code_quality
166
+ steps:
167
+ - name: Checkout repository
168
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
169
+ with:
170
+ token: ${{ secrets.GH_TOKEN }}
171
+ - name: Install uv
172
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
173
+ with:
174
+ enable-cache: true
175
+ activate-environment: true
176
+ - name: Format
177
+ run: uvx yamlfix . --config-file .github/lint/.yamlfix.toml
178
+ - name: Commit and push applied linter fixes
179
+ uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
180
+ with:
181
+ commit_message: '[YamlFix] Apply linters fixes'
182
+ commit_options: --no-verify
183
+ yamllint:
184
+ name: YamlLint
185
+ runs-on: ubuntu-latest
186
+ environment:
187
+ name: code_quality
188
+ steps:
189
+ - name: Checkout repository
190
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
191
+ - name: Install uv
192
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
193
+ with:
194
+ enable-cache: true
195
+ activate-environment: true
196
+ - name: Check
197
+ run: uvx yamllint . --strict -c=.github/lint/.yamllint.yaml --format github
198
+ syft:
199
+ name: Syft
200
+ runs-on: ubuntu-latest
201
+ environment:
202
+ name: code_quality
203
+ steps:
204
+ - name: Checkout repository
205
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
206
+ - name: SBOM Generation
207
+ uses: anchore/sbom-action@deef08a0db64bfad603422135db61477b16cef56 # v0.22.1
208
+ with:
209
+ path: .
210
+ dependency-snapshot: true
211
+ output-file: ${{ github.event.repository.name }}-sbom.json
212
+ format: syft-json
213
+ grype:
214
+ name: Grype
215
+ runs-on: ubuntu-latest
216
+ environment:
217
+ name: code_quality
218
+ steps:
219
+ - name: Checkout repository
220
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
221
+ - name: Scan current project
222
+ uses: anchore/scan-action@8d2fce09422cd6037e577f4130e9b925e9a37175 # v7.3.1
223
+ id: scan
224
+ with:
225
+ path: .
226
+ cache-db: true
227
+ - name: upload Anchore scan SARIF report
228
+ if: success() || failure()
229
+ uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
230
+ with:
231
+ sarif_file: ${{ steps.scan.outputs.sarif }}
232
+ trivy:
233
+ name: Trivy ${{ matrix.name }}
234
+ runs-on: ubuntu-latest
235
+ environment:
236
+ name: code_quality
237
+ strategy:
238
+ fail-fast: false
239
+ matrix:
240
+ scan-type:
241
+ - repo
242
+ - config
243
+ - fs
244
+ include:
245
+ - scan-type: repo
246
+ format: sarif
247
+ output: trivy-results-repo.sarif
248
+ name: Repo
249
+ - scan-type: config
250
+ format: sarif
251
+ output: trivy-results-config.sarif
252
+ name: IaC
253
+ - scan-type: fs
254
+ format: github
255
+ output: dependency-results.sbom.json
256
+ name: SBOM
257
+ steps:
258
+ - name: Checkout repository
259
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
260
+ - name: Run Trivy vulnerability scanner in repo mode
261
+ uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
262
+ with:
263
+ scan-type: ${{ matrix.scan-type }}
264
+ trivy-config: .github/lint/.trivy.yaml
265
+ format: ${{ matrix.format }}
266
+ output: ${{ matrix.output }}
267
+ github-pat: ${{ secrets.GH_TOKEN }}
268
+ exit-code: '1'
269
+ scanners: vuln,secret,misconfig
270
+ - name: Upload Trivy scan results to GitHub Security tab
271
+ if: matrix.scan-type != 'fs' && ( success() || failure() )
272
+ uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
273
+ with:
274
+ sarif_file: ${{ matrix.output }}
275
+ category: ${{ matrix.scan-type }}
276
+ - name: Upload trivy report as a Github artifact
277
+ if: matrix.scan-type == 'fs' && ( success() || failure() )
278
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
279
+ with:
280
+ name: trivy-sbom-report
281
+ path: ${{ matrix.output }}
282
+ dclint:
283
+ name: DCLint
284
+ runs-on: ubuntu-latest
285
+ environment:
286
+ name: code_quality
287
+ steps:
288
+ - name: Checkout repository
289
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
290
+ - name: Lint Docker Compose file
291
+ uses: docker-compose-linter/dclint-github-action@18659f6a7956706cb67cf9c1ad5e55f4352cbc17 # v1.6.0
292
+ with:
293
+ fix: true
294
+ recursive: true
295
+ ty:
296
+ name: Ty
297
+ runs-on: ubuntu-latest
298
+ environment:
299
+ name: code_quality
300
+ steps:
301
+ - name: Checkout repository
302
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
303
+ - name: Install uv
304
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
305
+ with:
306
+ enable-cache: true
307
+ activate-environment: true
308
+ - name: Check
309
+ run: uvx ty check --output-format github
310
+ markdownlint:
311
+ name: MarkdownLint
312
+ runs-on: ubuntu-latest
313
+ environment:
314
+ name: code_quality
315
+ steps:
316
+ - name: Checkout repository
317
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
318
+ - name: Lint Markdown files
319
+ uses: DavidAnson/markdownlint-cli2-action@07035fd053f7be764496c0f8d8f9f41f98305101 # v22.0.0
320
+ with:
321
+ globs: '**/*.md'
322
+ config: .github/lint/.markdownlint.yaml
323
+ fix: true
324
+ hadolint:
325
+ name: Hadolint
326
+ runs-on: ubuntu-latest
327
+ environment:
328
+ name: code_quality
329
+ steps:
330
+ - name: Checkout repository
331
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
332
+ - name: Lint Dockerfile
333
+ uses: hadolint/hadolint-action@2332a7b74a6de0dda2e2221d575162eba76ba5e5 # v3.3.0
334
+ with:
335
+ config: .github/lint/.hadolint.yaml
336
+ format: sarif
337
+ output-file: hadolint.sarif
338
+ - name: upload Hadolint scan SARIF report
339
+ if: success() || failure()
340
+ uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
341
+ with:
342
+ sarif_file: hadolint.sarif
343
+ actionlint:
344
+ name: ActionLint
345
+ runs-on: ubuntu-latest
346
+ environment:
347
+ name: code_quality
348
+ steps:
349
+ - name: Checkout repository
350
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
351
+ - name: Install actionlint
352
+ uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0
353
+ with:
354
+ repo: rhysd/actionlint
355
+ cache: enable
356
+ - name: Download actionlint-matcher.json
357
+ run: >-
358
+ curl -fsSL https://raw.githubusercontent.com/rhysd/actionlint/main/.github/actionlint-matcher.json
359
+ -o .github/actionlint-matcher.json
360
+ - name: Run actionlint
361
+ run: |-
362
+ echo "::add-matcher::.github/actionlint-matcher.json"
363
+ actionlint -color
.github/workflows/build.yaml ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Build
2
+ on:
3
+ push:
4
+ tags:
5
+ - '[0-9]+.[0-9]+.[0-9]+'
6
+ - '[0-9]+.[0-9]+.[0-9]+a[0-9]+'
7
+ - '[0-9]+.[0-9]+.[0-9]+b[0-9]+'
8
+ permissions: read-all
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref_name }}
11
+ cancel-in-progress: true
12
+ jobs:
13
+ setup_and_build:
14
+ name: Setup and Build
15
+ environment:
16
+ name: uv
17
+ url: ${{github.event.repository.html_url}}/commits/${{github.ref_name}}
18
+ env:
19
+ UV_COMPILE_BYTECODE: '1'
20
+ UV_LINK_MODE: copy
21
+ permissions:
22
+ contents: write
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Checkout repository
26
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
27
+ with:
28
+ token: ${{ secrets.GH_TOKEN }}
29
+ - name: Get Package version from pyproject.toml
30
+ id: get_package_version
31
+ uses: mikefarah/yq@065b200af9851db0d5132f50bc10b1406ea5c0a8 # v4.50.1
32
+ with:
33
+ cmd: yq -roy '.project.version' pyproject.toml
34
+ - name: Install uv
35
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
36
+ with:
37
+ enable-cache: true
38
+ activate-environment: true
39
+ - name: Install the project
40
+ run: uv sync --no-dev --frozen --no-editable
41
+ - name: Update Project Version
42
+ if: ${{ github.ref_name != steps.get_package_version.outputs.result }}
43
+ run: uv version ${{ github.ref_name }}
44
+ - name: Build source and wheel distribution
45
+ run: uv build
46
+ - name: Upload artifacts
47
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
48
+ with:
49
+ name: dist
50
+ path: dist/
51
+ - name: Update the main branch to the updated version
52
+ if: ${{ github.ref_name != steps.get_package_version.outputs.result }}
53
+ uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
54
+ with:
55
+ commit_message: 'Version: ${{ github.ref_name }}'
56
+ branch: main
57
+ commit_options: --no-verify
58
+ - name: Update the tag to the updated version
59
+ if: ${{ github.ref_name != steps.get_package_version.outputs.result }}
60
+ run: |
61
+ git tag --force ${{ github.ref_name }}
62
+ git push origin --force HEAD:refs/tags/${{ github.ref_name }}
63
+ github_release:
64
+ name: Create GitHub Release
65
+ needs: setup_and_build
66
+ runs-on: ubuntu-latest
67
+ environment:
68
+ name: github
69
+ url: ${{github.event.repository.html_url}}/releases/tag/${{github.ref_name}}
70
+ permissions:
71
+ contents: write
72
+ steps:
73
+ - name: Checkout repository
74
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
75
+ - name: Download artifacts
76
+ uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
77
+ with:
78
+ name: dist
79
+ path: dist/
80
+ - name: Create GitHub Release
81
+ uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
82
+ with:
83
+ files: dist/*
84
+ generate_release_notes: true
85
+ make_latest: true
86
+ fail_on_unmatched_files: true
.github/workflows/ci_tools.yaml ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: CI Tools
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ issue_comment:
7
+ types:
8
+ - created
9
+ - edited
10
+ workflow_dispatch:
11
+ permissions:
12
+ id-token: write
13
+ contents: write
14
+ pull-requests: read
15
+ issues: read
16
+ jobs:
17
+ opencode:
18
+ if: |
19
+ github.event_name == 'issue_comment' &&
20
+ (
21
+ contains(github.event.comment.body, ' /oc') ||
22
+ startsWith(github.event.comment.body, '/oc') ||
23
+ contains(github.event.comment.body, ' /opencode') ||
24
+ startsWith(github.event.comment.body, '/opencode')
25
+ )
26
+ name: Opencode
27
+ runs-on: ubuntu-latest
28
+ environment:
29
+ name: ai_agent
30
+ steps:
31
+ - name: Checkout repository
32
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
33
+ - name: Run opencode
34
+ uses: sst/opencode/github@8f537940178772deedf3317c5c669950f1f6c5a6 # v1.1.45
35
+ env:
36
+ OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
37
+ with:
38
+ model: opencode/grok-code
39
+ uv_lock_sync:
40
+ if: |
41
+ github.event_name == 'workflow_dispatch' ||
42
+ (
43
+ github.event_name == 'issue_comment' &&
44
+ (
45
+ contains(github.event.comment.body, ' /uv-lock-sync') ||
46
+ startsWith(github.event.comment.body, '/uv-lock-sync')
47
+ )
48
+ )
49
+ name: UV Lock Sync
50
+ runs-on: ubuntu-latest
51
+ environment:
52
+ name: lockfile
53
+ steps:
54
+ - name: Checkout repository
55
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
56
+ with:
57
+ token: ${{ secrets.GH_TOKEN }}
58
+ - name: Install uv
59
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
60
+ with:
61
+ enable-cache: true
62
+ activate-environment: true
63
+ - name: Sync dependencies and uv.lock
64
+ run: uv lock
65
+ - name: Commit and push changes
66
+ uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
67
+ with:
68
+ commit_message: Sync uv.lock
69
+ commit_options: --no-verify
70
+ huggingface:
71
+ name: Sync HuggingFace Space
72
+ runs-on: ubuntu-latest
73
+ if: |
74
+ github.event_name == 'push' ||
75
+ github.event_name == 'workflow_dispatch' ||
76
+ (
77
+ github.event_name == 'issue_comment' &&
78
+ (
79
+ contains(github.event.comment.body, ' /hf-sync') ||
80
+ startsWith(github.event.comment.body, '/hf-sync')
81
+ )
82
+ )
83
+ permissions:
84
+ contents: read
85
+ id-token: write
86
+ environment:
87
+ name: huggingface
88
+ url: https://huggingface.co/spaces/${{github.repository}}
89
+ steps:
90
+ - name: Checkout repository
91
+ uses: actions/checkout@v4.0.0
92
+ with:
93
+ fetch-depth: 0
94
+ lfs: true
95
+ - name: Install uv
96
+ uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
97
+ with:
98
+ enable-cache: true
99
+ activate-environment: true
100
+ - name: Push to HF
101
+ env:
102
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
103
+ COMMIT_MESSAGE: ${{ github.event.head_commit.message || 'Sync from GitHub' }}
104
+ run: >-
105
+ uvx hf upload ${{github.repository}} . . --repo-type space
106
+ --delete '*' --exclude '.github' --commit-message "$COMMIT_MESSAGE"
.github/workflows/release.yaml ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Release
2
+ on:
3
+ release:
4
+ types:
5
+ - published
6
+ permissions: read-all
7
+ concurrency:
8
+ group: ${{ github.workflow }}-${{ github.ref_name }}
9
+ cancel-in-progress: true
10
+ jobs:
11
+ pypi:
12
+ name: Upload Python Package
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ contents: read
16
+ id-token: write
17
+ environment:
18
+ name: pypi
19
+ url: https://pypi.org/project/${{github.event.repository.name}}/${{github.event.release.tag_name}}
20
+ steps:
21
+ - name: Retrieve release distributions
22
+ uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 # v1.12
23
+ with:
24
+ tag: ${{ github.event.release.tag_name }}
25
+ out-file-path: dist/
26
+ fileName: '*'
27
+ - name: Publish release distributions to PyPI
28
+ uses: pypa/gh-action-pypi-publish@release/v1
29
+ with:
30
+ packages-dir: dist/
31
+ huggingface:
32
+ name: Tag HuggingFace Space
33
+ runs-on: ubuntu-latest
34
+ permissions:
35
+ contents: read
36
+ id-token: write
37
+ environment:
38
+ name: huggingface
39
+ url: https://huggingface.co/spaces/${{github.repository}}/tree/${{github.event.release.tag_name}}
40
+ steps:
41
+ - name: Install uv
42
+ uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
43
+ with:
44
+ enable-cache: true
45
+ activate-environment: true
46
+ - name: Push to HF
47
+ env:
48
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
49
+ run: >-
50
+ uvx hf repo tag create ${{github.repository}} ${{github.event.release.tag_name}}
51
+ --repo-type space
52
+ image:
53
+ name: Release Image
54
+ needs: pypi
55
+ permissions:
56
+ contents: read
57
+ packages: write
58
+ attestations: write
59
+ id-token: write
60
+ strategy:
61
+ matrix:
62
+ registry:
63
+ - ghcr.io
64
+ - docker.io
65
+ uses: ./.github/workflows/.docker.yaml
66
+ with:
67
+ is_test: false
68
+ registry: ${{ matrix.registry }}
69
+ install_source: ${{github.event.repository.name}}==${{github.event.release.tag_name}}
70
+ secrets: inherit
.github/workflows/test.yaml ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Test
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ pull_request:
7
+ workflow_dispatch:
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref_name }}
10
+ cancel-in-progress: true
11
+ permissions: read-all
12
+ jobs:
13
+ compatibility:
14
+ name: Check Dependency Compatibility
15
+ runs-on: ubuntu-latest
16
+ environment:
17
+ name: code_quality
18
+ permissions:
19
+ checks: write
20
+ contents: read
21
+ steps:
22
+ - name: Checkout repository
23
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
26
+ with:
27
+ enable-cache: true
28
+ activate-environment: true
29
+ - name: Install the project
30
+ id: dependency_check
31
+ run: uv sync --frozen --no-install-project
32
+ - name: Job Summary
33
+ uses: jazanne/job-summary-action@690eb386a0b86fe4da7c6f0e543e61330ff09f06 # v1.0.0
34
+ if: success() || failure()
35
+ with:
36
+ summary: |-
37
+ ## Dependency Compatibility Check
38
+ - **Status**: ${{ steps.dependency_check.outcome == 'success' && ':white_check_mark:' || ':x:' }}
39
+ - name: Show Dependency Tree
40
+ if: steps.dependency_check.outcome == 'success'
41
+ run: |
42
+ echo "## Dependency Tree" >> $GITHUB_STEP_SUMMARY
43
+ echo "<details>" >> $GITHUB_STEP_SUMMARY
44
+ echo "<summary> Dependency Tree </summary>" >> $GITHUB_STEP_SUMMARY
45
+ echo "" >> $GITHUB_STEP_SUMMARY
46
+ echo '```' >> $GITHUB_STEP_SUMMARY
47
+ echo "$(uv tree --show-sizes)" >> $GITHUB_STEP_SUMMARY
48
+ echo '```' >> $GITHUB_STEP_SUMMARY
49
+ echo "</details>" >> $GITHUB_STEP_SUMMARY
50
+ lint:
51
+ name: Lint
52
+ permissions:
53
+ contents: write
54
+ pull-requests: write
55
+ checks: write
56
+ security-events: write
57
+ actions: read
58
+ needs: compatibility
59
+ uses: ./.github/workflows/.lint.yaml
60
+ secrets: inherit
61
+ image:
62
+ name: Test Image
63
+ permissions:
64
+ contents: write
65
+ packages: write
66
+ attestations: write
67
+ id-token: write
68
+ security-events: write
69
+ actions: read
70
+ needs: compatibility
71
+ uses: ./.github/workflows/.docker.yaml
72
+ with:
73
+ is_test: true
74
+ registry: ghcr.io
75
+ install_source: git+${{ github.event.repository.html_url }}@${{ github.sha }}
76
+ secrets: inherit
.github/workflows/version.yaml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Version
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ paths:
7
+ - pyproject.toml
8
+ - uv.lock
9
+ - Dockerfile
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.ref_name }}
12
+ cancel-in-progress: false
13
+ permissions: read-all
14
+ jobs:
15
+ version:
16
+ name: Versioning
17
+ runs-on: ubuntu-latest
18
+ if: github.actor == 'renovate[bot]' || github.actor == 'mergify[bot]'
19
+ permissions:
20
+ contents: write
21
+ environment:
22
+ name: versioning
23
+ steps:
24
+ - name: Checkout repository
25
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26
+ with:
27
+ token: ${{ secrets.GH_TOKEN }}
28
+ fetch-depth: 0
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
31
+ with:
32
+ enable-cache: true
33
+ activate-environment: true
34
+ - name: Increase the patch version
35
+ run: uv version --bump patch
36
+ - name: Get Package version from pyproject.toml
37
+ id: get_package_version
38
+ uses: mikefarah/yq@065b200af9851db0d5132f50bc10b1406ea5c0a8 # v4.50.1
39
+ with:
40
+ cmd: yq -roy '.project.version' pyproject.toml
41
+ - name: Commit updated count
42
+ uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
43
+ with:
44
+ commit_message: 'Tag: ${{ steps.get_package_version.outputs.result }}'
45
+ tagging_message: ${{ steps.get_package_version.outputs.result }}
.gitignore ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ **/__pycache__/
2
+ .env
3
+ .mypy_cache/
4
+ .ruff_cache/
5
+ .venv/
6
+ logs/
7
+ results/
8
+ qdrant_storage/
9
+ assets/audio/
10
+ assets/video/
11
+ agno/
12
+ .vscode/settings.json
.idea/.gitignore ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Ignored default folder with query files
5
+ /queries/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
9
+ # Editor-based HTTP Client requests
10
+ /httpRequests/
11
+
12
+ copilot.*.xml
.idea/chattr.iml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
6
+ <excludeFolder url="file://$MODULE_DIR$/.venv" />
7
+ </content>
8
+ <orderEntry type="jdk" jdkName="uv (chattr)" jdkType="Python SDK" />
9
+ <orderEntry type="sourceFolder" forTests="false" />
10
+ </component>
11
+ <component name="PyDocumentationSettings">
12
+ <option name="format" value="GOOGLE" />
13
+ <option name="myDocStringFormat" value="Google" />
14
+ </component>
15
+ </module>
.idea/inspectionProfiles/Project_Default.xml ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <component name="InspectionProjectProfileManager">
2
+ <profile version="1.0">
3
+ <option name="myName" value="Project Default" />
4
+ <inspection_tool class="AlphaUnsortedPropertiesFile" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
5
+ <inspection_tool class="AngularAmbiguousComponentTag" enabled="false" level="ERROR" enabled_by_default="false" />
6
+ <inspection_tool class="AngularBindingTypeMismatch" enabled="false" level="ERROR" enabled_by_default="false" />
7
+ <inspection_tool class="AngularCliAddDependency" enabled="false" level="WARNING" enabled_by_default="false" />
8
+ <inspection_tool class="AngularDeferBlockOnTrigger" enabled="false" level="ERROR" enabled_by_default="false" />
9
+ <inspection_tool class="AngularForBlockNonIterableVar" enabled="false" level="ERROR" enabled_by_default="false" />
10
+ <inspection_tool class="AngularIllegalForLoopTrackAccess" enabled="false" level="ERROR" enabled_by_default="false" />
11
+ <inspection_tool class="AngularInaccessibleSymbol" enabled="false" level="ERROR" enabled_by_default="false" />
12
+ <inspection_tool class="AngularIncorrectBlockUsage" enabled="false" level="ERROR" enabled_by_default="false" />
13
+ <inspection_tool class="AngularIncorrectLetUsage" enabled="false" level="ERROR" enabled_by_default="false" />
14
+ <inspection_tool class="AngularIncorrectTemplateDefinition" enabled="false" level="ERROR" enabled_by_default="false" />
15
+ <inspection_tool class="AngularInsecureBindingToEvent" enabled="false" level="WARNING" enabled_by_default="false" />
16
+ <inspection_tool class="AngularInvalidAnimationTriggerAssignment" enabled="false" level="ERROR" enabled_by_default="false" />
17
+ <inspection_tool class="AngularInvalidEntryComponent" enabled="false" level="ERROR" enabled_by_default="false" />
18
+ <inspection_tool class="AngularInvalidI18nAttribute" enabled="false" level="WARNING" enabled_by_default="false" />
19
+ <inspection_tool class="AngularInvalidImportedOrDeclaredSymbol" enabled="false" level="ERROR" enabled_by_default="false" />
20
+ <inspection_tool class="AngularInvalidSelector" enabled="false" level="ERROR" enabled_by_default="false" />
21
+ <inspection_tool class="AngularInvalidTemplateReferenceVariable" enabled="false" level="ERROR" enabled_by_default="false" />
22
+ <inspection_tool class="AngularMissingEventHandler" enabled="false" level="ERROR" enabled_by_default="false" />
23
+ <inspection_tool class="AngularMissingOrInvalidDeclarationInModule" enabled="false" level="ERROR" enabled_by_default="false" />
24
+ <inspection_tool class="AngularMissingRequiredDirectiveInputBinding" enabled="false" level="ERROR" enabled_by_default="false" />
25
+ <inspection_tool class="AngularMultipleStructuralDirectives" enabled="false" level="ERROR" enabled_by_default="false" />
26
+ <inspection_tool class="AngularNgOptimizedImage" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
27
+ <inspection_tool class="AngularNonEmptyNgContent" enabled="false" level="ERROR" enabled_by_default="false" />
28
+ <inspection_tool class="AngularNonStandaloneComponentImports" enabled="false" level="ERROR" enabled_by_default="false" />
29
+ <inspection_tool class="AngularRecursiveModuleImportExport" enabled="false" level="ERROR" enabled_by_default="false" />
30
+ <inspection_tool class="AngularUndefinedBinding" enabled="false" level="ERROR" enabled_by_default="false" />
31
+ <inspection_tool class="AngularUndefinedModuleExport" enabled="false" level="ERROR" enabled_by_default="false" />
32
+ <inspection_tool class="AngularUndefinedTag" enabled="false" level="ERROR" enabled_by_default="false" />
33
+ <inspection_tool class="AngularUnresolvedPipe" enabled="false" level="ERROR" enabled_by_default="false" />
34
+ <inspection_tool class="AngularUnsupportedSyntax" enabled="false" level="ERROR" enabled_by_default="false" />
35
+ <inspection_tool class="AngularUnusedComponentImport" enabled="false" level="ERROR" enabled_by_default="false" />
36
+ <inspection_tool class="BadExpressionStatementJS" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
37
+ <inspection_tool class="CallerJS" enabled="false" level="WARNING" enabled_by_default="false" />
38
+ <inspection_tool class="CommaExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
39
+ <inspection_tool class="ConstantConditionalExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
40
+ <inspection_tool class="ContinueOrBreakFromFinallyBlockJS" enabled="false" level="WARNING" enabled_by_default="false" />
41
+ <inspection_tool class="CssBrowserCompatibilityForProperties" enabled="true" level="WARNING" enabled_by_default="true" />
42
+ <inspection_tool class="CssConvertColorToHexInspection" enabled="true" level="WARNING" enabled_by_default="true" />
43
+ <inspection_tool class="CssConvertColorToRgbInspection" enabled="true" level="WARNING" enabled_by_default="true" />
44
+ <inspection_tool class="CssInvalidNestedSelector" enabled="true" level="WARNING" enabled_by_default="true" />
45
+ <inspection_tool class="CssMissingSemicolon" enabled="true" level="WARNING" enabled_by_default="true" />
46
+ <inspection_tool class="CyclomaticComplexityInspection" enabled="true" level="WARNING" enabled_by_default="true" />
47
+ <inspection_tool class="DjangoUnresolvedUrlInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
48
+ <inspection_tool class="DuplicatePropertyInspection" enabled="true" level="WARNING" enabled_by_default="true" />
49
+ <inspection_tool class="ES6BindWithArrowFunction" enabled="false" level="WARNING" enabled_by_default="false" />
50
+ <inspection_tool class="ES6ClassMemberInitializationOrder" enabled="false" level="WARNING" enabled_by_default="false" />
51
+ <inspection_tool class="ES6ConvertIndexedForToForOf" enabled="false" level="INFORMATION" enabled_by_default="false" />
52
+ <inspection_tool class="ES6ConvertLetToConst" enabled="false" level="INFORMATION" enabled_by_default="false" />
53
+ <inspection_tool class="ES6ConvertModuleExportToExport" enabled="false" level="INFORMATION" enabled_by_default="false" />
54
+ <inspection_tool class="ES6ConvertRequireIntoImport" enabled="false" level="INFORMATION" enabled_by_default="false" />
55
+ <inspection_tool class="ES6ConvertToForOf" enabled="false" level="INFORMATION" enabled_by_default="false" />
56
+ <inspection_tool class="ES6ConvertVarToLetConst" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
57
+ <inspection_tool class="ES6DestructuringVariablesMerge" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
58
+ <inspection_tool class="ES6MissingAwait" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
59
+ <inspection_tool class="ES6PossiblyAsyncFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
60
+ <inspection_tool class="ES6PreferShortImport" enabled="false" level="WARNING" enabled_by_default="false" />
61
+ <inspection_tool class="ES6RedundantAwait" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
62
+ <inspection_tool class="ES6RedundantNestingInTemplateLiteral" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
63
+ <inspection_tool class="ES6ShorthandObjectProperty" enabled="false" level="INFORMATION" enabled_by_default="false" />
64
+ <inspection_tool class="ES6UnusedImports" enabled="false" level="WARNING" enabled_by_default="false" />
65
+ <inspection_tool class="EmptyDirectory" enabled="true" level="WARNING" enabled_by_default="true" />
66
+ <inspection_tool class="EmptyStatementBodyJS" enabled="false" level="WARNING" enabled_by_default="false" />
67
+ <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
68
+ <inspection_tool class="ExceptionCaughtLocallyJS" enabled="false" level="WARNING" enabled_by_default="false" />
69
+ <inspection_tool class="FallThroughInSwitchStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
70
+ <inspection_tool class="FlowJSConfig" enabled="false" level="WARNING" enabled_by_default="false" />
71
+ <inspection_tool class="FlowJSFlagCommentPlacement" enabled="false" level="WARNING" enabled_by_default="false" />
72
+ <inspection_tool class="HtmlNonExistentInternetResource" enabled="true" level="WARNING" enabled_by_default="true" />
73
+ <inspection_tool class="HtmlPresentationalElement" enabled="true" level="INFORMATION" enabled_by_default="true" />
74
+ <inspection_tool class="HtmlRequiredSummaryAttribute" enabled="true" level="INFORMATION" enabled_by_default="true" />
75
+ <inspection_tool class="HtmlRequiredTitleAttribute" enabled="true" level="INFORMATION" enabled_by_default="true" />
76
+ <inspection_tool class="IncompatibleMaskJS" enabled="false" level="WARNING" enabled_by_default="false" />
77
+ <inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
78
+ <inspection_tool class="IncorrectFormatting" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
79
+ <inspection_tool class="InfiniteLoopJS" enabled="false" level="WARNING" enabled_by_default="false" />
80
+ <inspection_tool class="InfiniteRecursionJS" enabled="false" level="WARNING" enabled_by_default="false" />
81
+ <inspection_tool class="JSAccessibilityCheck" enabled="false" level="WARNING" enabled_by_default="false" />
82
+ <inspection_tool class="JSAnnotator" enabled="false" level="ERROR" enabled_by_default="false" />
83
+ <inspection_tool class="JSArrowFunctionBracesCanBeRemoved" enabled="false" level="INFORMATION" enabled_by_default="false" />
84
+ <inspection_tool class="JSAssignmentUsedAsCondition" enabled="false" level="WARNING" enabled_by_default="false" />
85
+ <inspection_tool class="JSBitwiseOperatorUsage" enabled="false" level="WARNING" enabled_by_default="false" />
86
+ <inspection_tool class="JSCheckFunctionSignatures" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
87
+ <inspection_tool class="JSClosureCompilerSyntax" enabled="false" level="WARNING" enabled_by_default="false" />
88
+ <inspection_tool class="JSCommentMatchesSignature" enabled="false" level="WARNING" enabled_by_default="false" />
89
+ <inspection_tool class="JSComparisonWithNaN" enabled="false" level="WARNING" enabled_by_default="false" />
90
+ <inspection_tool class="JSConsecutiveCommasInArrayLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
91
+ <inspection_tool class="JSConstantReassignment" enabled="false" level="ERROR" enabled_by_default="false" />
92
+ <inspection_tool class="JSDeprecatedSymbols" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
93
+ <inspection_tool class="JSDuplicateCaseLabel" enabled="false" level="WARNING" enabled_by_default="false" />
94
+ <inspection_tool class="JSDuplicatedDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
95
+ <inspection_tool class="JSEqualityComparisonWithCoercion" enabled="false" level="WARNING" enabled_by_default="false" />
96
+ <inspection_tool class="JSFileReferences" enabled="false" level="WARNING" enabled_by_default="false" />
97
+ <inspection_tool class="JSFunctionExpressionToArrowFunction" enabled="false" level="INFORMATION" enabled_by_default="false" />
98
+ <inspection_tool class="JSIgnoredPromiseFromCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
99
+ <inspection_tool class="JSIncompatibleTypesComparison" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
100
+ <inspection_tool class="JSJQueryEfficiency" enabled="false" level="WARNING" enabled_by_default="false" />
101
+ <inspection_tool class="JSJoinVariableDeclarationAndAssignment" enabled="false" level="INFORMATION" enabled_by_default="false" />
102
+ <inspection_tool class="JSLastCommaInArrayLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
103
+ <inspection_tool class="JSLastCommaInObjectLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
104
+ <inspection_tool class="JSMethodCanBeStatic" enabled="false" level="INFORMATION" enabled_by_default="false" />
105
+ <inspection_tool class="JSMismatchedCollectionQueryUpdate" enabled="false" level="WARNING" enabled_by_default="false" />
106
+ <inspection_tool class="JSMissingSwitchBranches" enabled="false" level="INFORMATION" enabled_by_default="false" />
107
+ <inspection_tool class="JSMissingSwitchDefault" enabled="false" level="INFORMATION" enabled_by_default="false" />
108
+ <inspection_tool class="JSNonASCIINames" enabled="false" level="WARNING" enabled_by_default="false" />
109
+ <inspection_tool class="JSObjectNullOrUndefined" enabled="false" level="WARNING" enabled_by_default="false" />
110
+ <inspection_tool class="JSOctalInteger" enabled="false" level="ERROR" enabled_by_default="false" />
111
+ <inspection_tool class="JSPotentiallyInvalidConstructorUsage" enabled="false" level="WARNING" enabled_by_default="false" />
112
+ <inspection_tool class="JSPotentiallyInvalidTargetOfIndexedPropertyAccess" enabled="false" level="WARNING" enabled_by_default="false" />
113
+ <inspection_tool class="JSPotentiallyInvalidUsageOfClassThis" enabled="false" level="WARNING" enabled_by_default="false" />
114
+ <inspection_tool class="JSPotentiallyInvalidUsageOfThis" enabled="false" level="WARNING" enabled_by_default="false" />
115
+ <inspection_tool class="JSPrimitiveTypeWrapperUsage" enabled="false" level="WARNING" enabled_by_default="false" />
116
+ <inspection_tool class="JSRedundantSwitchStatement" enabled="false" level="INFORMATION" enabled_by_default="false" />
117
+ <inspection_tool class="JSReferencingMutableVariableFromClosure" enabled="false" level="WARNING" enabled_by_default="false" />
118
+ <inspection_tool class="JSRemoveUnnecessaryParentheses" enabled="false" level="INFORMATION" enabled_by_default="false" />
119
+ <inspection_tool class="JSStringConcatenationToES6Template" enabled="false" level="INFORMATION" enabled_by_default="false" />
120
+ <inspection_tool class="JSSuspiciousEqPlus" enabled="false" level="WARNING" enabled_by_default="false" />
121
+ <inspection_tool class="JSSuspiciousNameCombination" enabled="false" level="WARNING" enabled_by_default="false" />
122
+ <inspection_tool class="JSSwitchVariableDeclarationIssue" enabled="false" level="WARNING" enabled_by_default="false" />
123
+ <inspection_tool class="JSTestFailedLine" enabled="false" level="WARNING" enabled_by_default="false" />
124
+ <inspection_tool class="JSTypeOfValues" enabled="false" level="WARNING" enabled_by_default="false" />
125
+ <inspection_tool class="JSUndeclaredVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
126
+ <inspection_tool class="JSUndefinedPropertyAssignment" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
127
+ <inspection_tool class="JSUnnecessarySemicolon" enabled="false" level="WARNING" enabled_by_default="false" />
128
+ <inspection_tool class="JSUnreachableSwitchBranches" enabled="false" level="WARNING" enabled_by_default="false" />
129
+ <inspection_tool class="JSUnresolvedExtXType" enabled="false" level="WARNING" enabled_by_default="false" />
130
+ <inspection_tool class="JSUnresolvedLibraryURL" enabled="false" level="WARNING" enabled_by_default="false" />
131
+ <inspection_tool class="JSUnresolvedReference" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
132
+ <inspection_tool class="JSUnusedAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
133
+ <inspection_tool class="JSUnusedGlobalSymbols" enabled="false" level="WARNING" enabled_by_default="false" />
134
+ <inspection_tool class="JSUnusedLocalSymbols" enabled="false" level="WARNING" enabled_by_default="false" />
135
+ <inspection_tool class="JSUrlImportUsage" enabled="false" level="INFORMATION" enabled_by_default="false" />
136
+ <inspection_tool class="JSValidateJSDoc" enabled="false" level="WARNING" enabled_by_default="false" />
137
+ <inspection_tool class="JSValidateTypes" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
138
+ <inspection_tool class="JSVoidFunctionReturnValueUsed" enabled="false" level="WARNING" enabled_by_default="false" />
139
+ <inspection_tool class="JSXDomNesting" enabled="false" level="WARNING" enabled_by_default="false" />
140
+ <inspection_tool class="JSXNamespaceValidation" enabled="false" level="INFORMATION" enabled_by_default="false" />
141
+ <inspection_tool class="JSXUnresolvedComponent" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
142
+ <inspection_tool class="KarmaConfigFile" enabled="false" level="WARNING" enabled_by_default="false" />
143
+ <inspection_tool class="LongLine" enabled="true" level="WARNING" enabled_by_default="true" />
144
+ <inspection_tool class="LoopStatementThatDoesntLoopJS" enabled="false" level="WARNING" enabled_by_default="false" />
145
+ <inspection_tool class="NodeCoreCodingAssistance" enabled="false" level="WARNING" enabled_by_default="false" />
146
+ <inspection_tool class="NpmUsedModulesInstalled" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
147
+ <inspection_tool class="NpmVulnerableApiCode" enabled="false" level="WARNING" enabled_by_default="false" />
148
+ <inspection_tool class="PackageJsonMismatchedDependency" enabled="false" level="WARNING" enabled_by_default="false" />
149
+ <inspection_tool class="PointlessArithmeticExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
150
+ <inspection_tool class="PointlessBooleanExpressionJS" enabled="false" level="WARNING" enabled_by_default="false" />
151
+ <inspection_tool class="PostCssCustomMedia" enabled="false" level="ERROR" enabled_by_default="false" />
152
+ <inspection_tool class="PostCssCustomSelector" enabled="false" level="ERROR" enabled_by_default="false" />
153
+ <inspection_tool class="PostCssMediaRange" enabled="false" level="ERROR" enabled_by_default="false" />
154
+ <inspection_tool class="PostCssUnresolvedModuleValueReference" enabled="false" level="ERROR" enabled_by_default="false" />
155
+ <inspection_tool class="ProblematicWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
156
+ <inspection_tool class="PyArgumentEqualDefaultInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
157
+ <inspection_tool class="PyAugmentAssignmentInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
158
+ <inspection_tool class="PyClassicStyleClassInspection" enabled="true" level="WARNING" enabled_by_default="true" />
159
+ <inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
160
+ <option name="ourVersions">
161
+ <value>
162
+ <list size="5">
163
+ <item index="0" class="java.lang.String" itemvalue="3.14" />
164
+ <item index="1" class="java.lang.String" itemvalue="3.10" />
165
+ <item index="2" class="java.lang.String" itemvalue="3.11" />
166
+ <item index="3" class="java.lang.String" itemvalue="3.12" />
167
+ <item index="4" class="java.lang.String" itemvalue="3.13" />
168
+ </list>
169
+ </value>
170
+ </option>
171
+ </inspection_tool>
172
+ <inspection_tool class="PyMandatoryEncodingInspection" enabled="true" level="WARNING" enabled_by_default="true" />
173
+ <inspection_tool class="PyMissingOrEmptyDocstringInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
174
+ <inspection_tool class="PyMissingTypeHintsInspection" enabled="true" level="WARNING" enabled_by_default="true" editorAttributes="WARNING_ATTRIBUTES" />
175
+ <inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
176
+ <option name="ignoredErrors">
177
+ <list>
178
+ <option value="N812" />
179
+ </list>
180
+ </option>
181
+ </inspection_tool>
182
+ <inspection_tool class="PyTypeCheckerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
183
+ <inspection_tool class="PydanticTypeCheckerInspection" enabled="true" level="WARNING" enabled_by_default="true" />
184
+ <inspection_tool class="RegExpAnonymousGroup" enabled="true" level="WARNING" enabled_by_default="true" />
185
+ <inspection_tool class="ReservedWordUsedAsNameJS" enabled="false" level="WARNING" enabled_by_default="false" />
186
+ <inspection_tool class="RestRoleInspection" enabled="true" level="WARNING" enabled_by_default="true">
187
+ <option name="ignoredRoles">
188
+ <value>
189
+ <list size="0" />
190
+ </value>
191
+ </option>
192
+ </inspection_tool>
193
+ <inspection_tool class="ReturnFromFinallyBlockJS" enabled="false" level="WARNING" enabled_by_default="false" />
194
+ <inspection_tool class="ShiftOutOfRangeJS" enabled="false" level="WARNING" enabled_by_default="false" />
195
+ <inspection_tool class="SillyAssignmentJS" enabled="false" level="WARNING" enabled_by_default="false" />
196
+ <inspection_tool class="SqlGotoInspection" enabled="true" level="WARNING" enabled_by_default="true" />
197
+ <inspection_tool class="SqlJoinCountInspection" enabled="true" level="WARNING" enabled_by_default="true" />
198
+ <inspection_tool class="SqlMissingColumnAliasesInspection" enabled="true" level="WARNING" enabled_by_default="true" />
199
+ <inspection_tool class="SqlNamedArgumentsInspection" enabled="true" level="WARNING" enabled_by_default="true" />
200
+ <inspection_tool class="Stylelint" enabled="true" level="ERROR" enabled_by_default="true" />
201
+ <inspection_tool class="SuspiciousTypeOfGuard" enabled="false" level="WARNING" enabled_by_default="false" />
202
+ <inspection_tool class="ThisExpressionReferencesGlobalObjectJS" enabled="false" level="WARNING" enabled_by_default="false" />
203
+ <inspection_tool class="ThrowFromFinallyBlockJS" enabled="false" level="WARNING" enabled_by_default="false" />
204
+ <inspection_tool class="TodoComment" enabled="true" level="WARNING" enabled_by_default="true" />
205
+ <inspection_tool class="TrivialConditionalJS" enabled="false" level="WARNING" enabled_by_default="false" />
206
+ <inspection_tool class="TrivialIfJS" enabled="false" level="WARNING" enabled_by_default="false" />
207
+ <inspection_tool class="TypeScriptAbstractClassConstructorCanBeMadeProtected" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
208
+ <inspection_tool class="TypeScriptCheckImport" enabled="false" level="ERROR" enabled_by_default="false" />
209
+ <inspection_tool class="TypeScriptConfig" enabled="false" level="WARNING" enabled_by_default="false" />
210
+ <inspection_tool class="TypeScriptDuplicateUnionOrIntersectionType" enabled="false" level="WARNING" enabled_by_default="false" />
211
+ <inspection_tool class="TypeScriptExplicitMemberType" enabled="false" level="INFORMATION" enabled_by_default="false" />
212
+ <inspection_tool class="TypeScriptFieldCanBeMadeReadonly" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
213
+ <inspection_tool class="TypeScriptJSXUnresolvedComponent" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
214
+ <inspection_tool class="TypeScriptLibrary" enabled="false" level="ERROR" enabled_by_default="false" />
215
+ <inspection_tool class="TypeScriptMissingAugmentationImport" enabled="false" level="INFORMATION" enabled_by_default="false" />
216
+ <inspection_tool class="TypeScriptMissingConfigOption" enabled="false" level="WARNING" enabled_by_default="false" />
217
+ <inspection_tool class="TypeScriptRedundantGenericType" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
218
+ <inspection_tool class="TypeScriptSmartCast" enabled="false" level="WARNING" enabled_by_default="false" />
219
+ <inspection_tool class="TypeScriptSuspiciousConstructorParameterAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
220
+ <inspection_tool class="TypeScriptUMDGlobal" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
221
+ <inspection_tool class="TypeScriptUnresolvedReference" enabled="false" level="ERROR" enabled_by_default="false" />
222
+ <inspection_tool class="TypeScriptValidateGenericTypes" enabled="false" level="ERROR" enabled_by_default="false" />
223
+ <inspection_tool class="TypeScriptValidateTypes" enabled="false" level="ERROR" enabled_by_default="false" />
224
+ <inspection_tool class="UnnecessaryContinueJS" enabled="false" level="WARNING" enabled_by_default="false" />
225
+ <inspection_tool class="UnnecessaryLabelJS" enabled="false" level="WARNING" enabled_by_default="false" />
226
+ <inspection_tool class="UnnecessaryLabelOnBreakStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
227
+ <inspection_tool class="UnnecessaryLabelOnContinueStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
228
+ <inspection_tool class="UnnecessaryLocalVariableJS" enabled="false" level="WARNING" enabled_by_default="false" />
229
+ <inspection_tool class="UnnecessaryReturnJS" enabled="false" level="WARNING" enabled_by_default="false" />
230
+ <inspection_tool class="UnreachableCodeJS" enabled="false" level="WARNING" enabled_by_default="false" />
231
+ <inspection_tool class="UnusedDefine" enabled="true" level="WARNING" enabled_by_default="true" />
232
+ <inspection_tool class="UpdateDependencyToLatestVersion" enabled="false" level="INFORMATION" enabled_by_default="false" />
233
+ <inspection_tool class="UseEllipsisInPropertyInspection" enabled="true" level="WARNING" enabled_by_default="true" />
234
+ <inspection_tool class="WebpackConfigHighlighting" enabled="false" level="WARNING" enabled_by_default="false" />
235
+ <inspection_tool class="WithStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
236
+ </profile>
237
+ </component>
.idea/inspectionProfiles/profiles_settings.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
.idea/misc.xml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Black">
4
+ <option name="sdkName" value="uv (chattr)" />
5
+ </component>
6
+ <component name="ProjectRootManager" version="2" project-jdk-name="uv (chattr)" project-jdk-type="Python SDK" />
7
+ <component name="RuffConfiguration">
8
+ <option name="enabled" value="true" />
9
+ </component>
10
+ <component name="TyConfiguration">
11
+ <option name="enabled" value="true" />
12
+ </component>
13
+ </project>
.idea/modules.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/chattr.iml" filepath="$PROJECT_DIR$/.idea/chattr.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </project>
.pre-commit-config.yaml ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ repos:
2
+ - repo: https://github.com/Mergifyio/mergify-pre-commit
3
+ rev: 1.1.0
4
+ hooks:
5
+ - id: validate-mergify-config-location
6
+ - id: validate-mergify-config
7
+ - repo: https://github.com/ComPWA/taplo-pre-commit
8
+ rev: v0.9.3
9
+ hooks:
10
+ - id: taplo-format
11
+ args:
12
+ - --config
13
+ - .github/lint/.taplo.toml
14
+ - id: taplo-lint
15
+ args:
16
+ - --config
17
+ - .github/lint/.taplo.toml
18
+ - --default-schema-catalogs
19
+ - repo: https://github.com/igorshubovych/markdownlint-cli
20
+ rev: v0.47.0
21
+ hooks:
22
+ - id: markdownlint
23
+ args:
24
+ - --config
25
+ - .github/lint/.markdownlint.yaml
26
+ - id: markdownlint-fix
27
+ args:
28
+ - --config
29
+ - .github/lint/.markdownlint.yaml
30
+ - repo: https://github.com/adrienverge/yamllint
31
+ rev: v1.38.0
32
+ hooks:
33
+ - id: yamllint
34
+ args:
35
+ - --strict
36
+ - -c
37
+ - .github/lint/.yamllint.yaml
38
+ - repo: https://github.com/docker-compose-linter/pre-commit-dclint
39
+ rev: v3.1.0
40
+ hooks:
41
+ - id: dclint
42
+ args:
43
+ - --fix
44
+ - repo: https://github.com/pre-commit/pre-commit-hooks
45
+ rev: v6.0.0
46
+ hooks:
47
+ - id: check-yaml
48
+ - id: end-of-file-fixer
49
+ - id: trailing-whitespace
50
+ - id: check-added-large-files
51
+ - id: check-ast
52
+ - id: check-illegal-windows-names
53
+ - id: check-json
54
+ - id: check-merge-conflict
55
+ args:
56
+ - --assume-in-merge
57
+ - id: check-symlinks
58
+ - id: check-toml
59
+ - id: check-vcs-permalinks
60
+ - id: check-xml
61
+ - id: debug-statements
62
+ - id: destroyed-symlinks
63
+ - id: detect-private-key
64
+ - id: mixed-line-ending
65
+ args:
66
+ - --fix=lf
67
+ - id: pretty-format-json
68
+ args:
69
+ - --autofix
70
+ - repo: https://github.com/renovatebot/pre-commit-hooks
71
+ rev: 43.0.5
72
+ hooks:
73
+ - id: renovate-config-validator
74
+ args:
75
+ - --strict
76
+ - repo: https://github.com/astral-sh/uv-pre-commit
77
+ rev: 0.9.28
78
+ hooks:
79
+ - id: uv-lock
80
+ - id: uv-sync
81
+ - repo: https://github.com/astral-sh/ruff-pre-commit
82
+ rev: v0.14.14
83
+ hooks:
84
+ - id: ruff-check
85
+ args:
86
+ - --fix
87
+ - --config
88
+ - .github/lint/.ruff.toml
89
+ - id: ruff-format
90
+ args:
91
+ - --config
92
+ - .github/lint/.ruff.toml
93
+ - repo: https://github.com/facebook/pyrefly-pre-commit
94
+ rev: 0.50.1
95
+ hooks:
96
+ - id: pyrefly-check
97
+ - repo: https://github.com/lyz-code/yamlfix
98
+ rev: 1.19.1
99
+ hooks:
100
+ - id: yamlfix
101
+ args:
102
+ - -c
103
+ - .github/lint/.yamlfix.toml
104
+ - repo: https://github.com/rhysd/actionlint
105
+ rev: v1.7.10
106
+ hooks:
107
+ - id: actionlint-docker
108
+ - repo: https://github.com/trufflesecurity/trufflehog
109
+ rev: v3.92.5
110
+ hooks:
111
+ - id: trufflehog
112
+ - repo: https://github.com/hadolint/hadolint
113
+ rev: v2.14.0
114
+ hooks:
115
+ - id: hadolint-docker
116
+ args:
117
+ - -c
118
+ - .github/lint/.hadolint.yaml
.sonarlint/connectedMode.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "projectKey": "AlphaSphereDotAI_chatacter_backend_app",
3
+ "region": "EU",
4
+ "sonarCloudOrganization": "alphaspheredotai"
5
+ }
.vscode/launch.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "run: server",
9
+ "type": "debugpy",
10
+ "request": "launch",
11
+ "module": "${workspaceFolderBasename}",
12
+ "preLaunchTask": "uv sync",
13
+ "logToFile": true,
14
+ "env": {
15
+ "DOPPLER_ENV": "1"
16
+ }
17
+ }
18
+ ]
19
+ }
.vscode/tasks.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
3
+ // for the documentation about the tasks.json format
4
+ "version": "2.0.0",
5
+ "tasks": [
6
+ {
7
+ "label": "uv sync",
8
+ "type": "shell",
9
+ "command": "uv",
10
+ "args": [
11
+ "sync"
12
+ ]
13
+ }
14
+ ]
15
+ }
.zed/tasks.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "args": [
4
+ "run",
5
+ "chattr"
6
+ ],
7
+ "command": "uv",
8
+ "label": "Run Chattr",
9
+ "reveal_target": "center",
10
+ "shell": "system"
11
+ },
12
+ {
13
+ "args": [
14
+ "compose",
15
+ "-f",
16
+ "compose-dev.yaml",
17
+ "up"
18
+ ],
19
+ "command": "docker",
20
+ "label": "Run Docker Compose",
21
+ "reveal_target": "center",
22
+ "shell": "system"
23
+ }
24
+ ]
AGENTS.md ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Agent Guidelines for Chattr
2
+
3
+ [byterover-mcp]
4
+
5
+ ## Byterover MCP Server Tools Reference
6
+
7
+ There are two main workflows with Byterover tools and recommended tool call strategies that you **MUST** follow precisely.
8
+
9
+ ### Onboarding workflow
10
+
11
+ If users particularly ask you to start the onboarding process, you **MUST STRICTLY** follow these steps.
12
+
13
+ 1. **ALWAYS USE** **byterover-check-handbook-existence** first to check if the byterover handbook already exists. If not, You **MUST** call **byterover-create-handbook** to create the byterover handbook.
14
+ 2. If the byterover handbook already exists, first you **MUST** USE **byterover-check-handbook-sync** to analyze the gap between the current codebase and the existing byterover handbook.
15
+ 3. Then **IMMEDIATELY USE** **byterover-update-handbook** to update these changes to the byterover handbook.
16
+ 4. During the onboarding, you **MUST** use **byterover-list-modules** **FIRST** to get the available modules, and then **byterover-store-modules** and **byterover-update-modules** if there are new modules or changes to existing modules in the project.
17
+
18
+ ### Planning workflow
19
+
20
+ Based on user request, you **MUST** follow these sequences of tool calls
21
+
22
+ 1. If asked to continue an unfinished implementation, **CALL** **byterover-retrieve-active-plans** to find the most relevant active plan.
23
+ 2. **CRITICAL PLAN PERSISTENCE RULE**: Once a user approves a plan, you **MUST IMMEDIATELY CALL** **byterover-save-implementation-plan** to save it.
24
+ 3. Throughout the plan, you **MUST** run **byterover-retrieve-knowledge** several times to retrieve sufficient knowledge and context for the plan's tasks.
25
+ 4. In addition, you might need to run **byterover-search-modules** and **byterover-update-modules** if the tasks require or update knowledge about certain modules. However, **byterover-retrieve-knowledge** should **ALWAYS** be considered **FIRST**.
26
+ 5. **MUST** use **byterover-update-plan-progress** to mark tasks (and then the whole plan) as completed.
27
+ Example:
28
+
29
+ - Task: `byterover-update-plan-progress(plan_name="Feature X", task_name="Task 1", is_completed=true)`
30
+ - All done: `byterover-update-plan-progress(plan_name="Feature X", is_completed=true)`
31
+
32
+ 1. Then, you might call **byterover-store-knowledge** to save knowledge and experience implemented throughout the plan or in important tasks.
33
+ 2. During the plan's implementation, you **MUST** frequently call **byterover-think-about-collected-information** and **byterover-assess-context-completeness** to make sure you're on the right track and gather sufficient context for the tasks.
34
+
35
+ ### Recommended Workflow Sequence
36
+
37
+ 1. **MOST IMPORTANT**: **ALWAYS USE** **byterover-retrieve-knowledge** once or several times for **EACH TASK** of the plan to gather necessary context to complete that task.
38
+ 2. **MOST IMPORTANT**: **ALWAYS USE** **byterover-store-knowledge** once or several times to store critical knowledge and context for future implementations
39
+ 3. Over 15 provided tools, **byterover-retrieve-knowledge** and **byterover-store-knowledge** ARE the two main tools, which **MUST** be used regularly. You can use these two main tools outside the two main workflows for retrieval and storage purposes.
40
+ 4. You **MUST** include phrases like **"According to Byterover memory layer"**, **"Based on memory extracted from Byterover"**, **"From Byterover memory tools"**, ... to explicitly showcase that these sources are from **Byterover**.
41
+ 5. **Implementation & Progress Tracking** → Execute implementation following saved plan → Mark tasks complete as you go → Mark entire plan done when all tasks finished.
42
+ 6. You **MUST** use **byterover-update-module** **IMMEDIATELY** on changes to the module's purposes, technical details, or critical insights that essential for future implementations.
43
+
44
+ ## Build/Lint/Test Commands
45
+
46
+ ### Installation
47
+
48
+ ```bash
49
+ uv sync # Install dependencies
50
+ ```
51
+
52
+ ### Building
53
+
54
+ ```bash
55
+ uv build # Build source and wheel distributions
56
+ ```
57
+
58
+ ### Linting & Formatting
59
+
60
+ ```bash
61
+ trunk fmt --all --no-progress # Auto-format code
62
+ trunk check # Run all linters and checks
63
+ ```
64
+
65
+ ### Testing
66
+
67
+ ```bash
68
+ pytest # Run all tests
69
+ pytest tests/test_app.py::test_app # Run single test
70
+ ```
71
+
72
+ ## Code Style Guidelines
73
+
74
+ ### General
75
+
76
+ - **Line length**: 88 characters
77
+ - **Indentation**: 4 spaces
78
+ - **Quote style**: Double quotes (`"`)
79
+ - **File encoding**: UTF-8
80
+
81
+ ### Imports
82
+
83
+ - Use `from __future__ import annotations` when needed
84
+ - Group imports: standard library, third-party, local
85
+ - Use `TYPE_CHECKING` for conditional imports
86
+ - Combine as imports: `from typing import Dict, List` → `from typing import Dict, List`
87
+
88
+ ### Type Hints
89
+
90
+ - Use type hints for all function parameters and return values
91
+ - Use `Self` for methods returning the same class instance
92
+ - Use `Sequence`, `list`, `dict` instead of bare generics
93
+ - Use `Path` from `pathlib` for file paths
94
+
95
+ ### Naming Conventions
96
+
97
+ - **Functions/Methods**: `snake_case`
98
+ - **Variables**: `snake_case`
99
+ - **Classes**: `PascalCase`
100
+ - **Constants**: `UPPER_CASE`
101
+ - **Private attributes**: `_leading_underscore`
102
+
103
+ ### Error Handling
104
+
105
+ - Use specific exception types (e.g., `OSError`, `ValueError`, `ValidationError`)
106
+ - Log errors with appropriate levels (`logger.error`, `logger.warning`)
107
+ - Raise `Error` from gradio for user-facing errors
108
+ - Use try/except blocks with meaningful error messages
109
+
110
+ ### Async/Await
111
+
112
+ - Use `async def` for coroutines
113
+ - Use `await` for async operations
114
+ - Return `AsyncGenerator` for streaming responses
115
+
116
+ ### Documentation
117
+
118
+ - Use docstrings for all public functions, classes, and modules
119
+ - Follow Google-style docstring format
120
+ - Document parameters, return values, and exceptions
121
+
122
+ ### Logging
123
+
124
+ - Import logger from module settings
125
+ - Use appropriate log levels: `debug`, `info`, `warning`, `error`
126
+ - Include relevant context in log messages
127
+
128
+ ### Testing Guidelines
129
+
130
+ - Use `pytest` framework
131
+ - Test functions named `test_*`
132
+ - Use descriptive assertions
133
+ - Mock external dependencies when needed
Dockerfile ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM cgr.dev/chainguard/wolfi-base:latest@sha256:17ab0709456ce1a2aedd85e95f72e58d73133bb70c33ae945a4d4b2424e984f1 AS builder
2
+
3
+ ARG INSTALL_SOURCE
4
+ ARG PYTHON_VERSION
5
+
6
+ # skipcq: DOK-DL3018
7
+ RUN apk add --no-cache build-base git uv
8
+
9
+ USER nonroot
10
+
11
+ RUN --mount=type=cache,target=/root/.cache/uv \
12
+ uv tool install ${INSTALL_SOURCE} --python ${PYTHON_VERSION}
13
+
14
+ FROM cgr.dev/chainguard/wolfi-base:latest@sha256:17ab0709456ce1a2aedd85e95f72e58d73133bb70c33ae945a4d4b2424e984f1 AS production
15
+
16
+ ENV GRADIO_SERVER_PORT=7860 \
17
+ GRADIO_SERVER_NAME=0.0.0.0 \
18
+ FASTEMBED_CACHE_PATH=/home/nonroot/fastembed \
19
+ PATH=/home/nonroot/.local/bin:$PATH
20
+
21
+ # skipcq: DOK-DL3018
22
+ RUN apk add --no-cache curl libstdc++
23
+
24
+ USER nonroot
25
+
26
+ WORKDIR /home/nonroot
27
+
28
+ COPY --from=builder --chown=nonroot:nonroot --chmod=555 /home/nonroot/.local/ /home/nonroot/.local/
29
+
30
+ EXPOSE ${GRADIO_SERVER_PORT}
31
+
32
+ CMD ["chattr"]
README.md CHANGED
@@ -1,12 +1,38 @@
1
  ---
2
  title: Chattr
3
- emoji: 🐠
4
- colorFrom: blue
5
- colorTo: indigo
6
- sdk: gradio
7
- sdk_version: 6.5.1
8
- app_file: app.py
9
- pinned: false
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: Chattr
3
+ emoji: 💬
4
+ colorFrom: gray
5
+ colorTo: blue
6
+ sdk: docker
7
+ app_port: 7860
8
+ short_description: Chat with Characters
 
9
  ---
10
 
11
+ ## **Chattr**: App part of the Chatacter Backend
12
+
13
+ [![Build](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/build.yaml/badge.svg)](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/build.yaml)
14
+ [![CI Tools](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/ci_tools.yaml/badge.svg)](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/ci_tools.yaml)
15
+ [![CodeQL](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/github-code-scanning/codeql)
16
+ [![Dependabot Updates](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/dependabot/dependabot-updates/badge.svg)](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/dependabot/dependabot-updates)
17
+ [![Release](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/release.yaml/badge.svg)](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/release.yaml)
18
+ [![Test](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/test.yaml/badge.svg)](https://github.com/AlphaSphereDotAI/chattr/actions/workflows/test.yaml)
19
+
20
+ ### Environment Variables
21
+
22
+ The configuration of the server is done using environment variables:
23
+
24
+ | Name | Description | Required | Default Value |
25
+ |:---------------------------|:---------------------------------|:--------:|:-------------------------------------------|
26
+ | `MODEL__URL` | OpenAI-compatible endpoint | ✘ | `https://api.groq.com/openai/v1` |
27
+ | `MODEL__NAME` | Model name to use for chat | ✘ | `llama3-70b-8192` |
28
+ | `MODEL__API_KEY` | API key for model access | ✔ | `None` |
29
+ | `MODEL__TEMPERATURE` | Model temperature (0.0-1.0) | ✘ | `0.0` |
30
+ | `SHORT_TERM_MEMORY__URL` | Redis URL for memory store | ✘ | `redis://localhost:6379` |
31
+ | `VECTOR_DATABASE__NAME` | Vector database collection name | ✘ | `chattr` |
32
+ | `VOICE_GENERATOR_MCP__URL` | MCP service for audio generation | ✘ | `http://localhost:8001/gradio_api/mcp/sse` |
33
+ | `VIDEO_GENERATOR_MCP__URL` | MCP service for video generation | ✘ | `http://localhost:8002/gradio_api/mcp/sse` |
34
+ | `DIRECTORY__ASSETS` | Base assets directory | ✘ | `./assets` |
35
+ | `DIRECTORY__LOG` | Log files directory | ✘ | `./logs` |
36
+ | `DIRECTORY__IMAGE` | Image assets directory | ✘ | `./assets/image` |
37
+ | `DIRECTORY__AUDIO` | Audio assets directory | ✘ | `./assets/audio` |
38
+ | `DIRECTORY__VIDEO` | Video assets directory | ✘ | `./assets/video` |
assets/image/Einstein.jpg ADDED

Git LFS Details

  • SHA256: 4c97e39f0682557315535871d13878aef8b89cd16edfd657c9c528a30ba25eb4
  • Pointer size: 131 Bytes
  • Size of remote file: 161 kB
assets/image/Napoleon.jpg ADDED
assets/prompts/template.poml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <poml syntax="markdown">
2
+ <role speaker="system">
3
+ You are a helpful assistant who can act and mimic {{character}}'s character and answer questions about the era.
4
+ </role>
5
+ <task speaker="system">
6
+ Always respond to the user's query by first generating your text answer, then using an MCP to generate audio from that text, and finally using an MCP to create a video from that audio.
7
+ <br />
8
+ <b>Crucially, your final output MUST include the generated text response, followed by the tool call for the video creation.</b>
9
+ <list>
10
+ <item><b>Personality:</b> Adopt the voice, tone, and perspective of {{character}}.</item>
11
+ <item><b>Knowledge:</b> Answer questions about the {{character}} era, military campaigns, and French history relevant to his life.</item>
12
+ </list>
13
+ <stepwise-instructions>
14
+ <list>
15
+ <item>Understand the user's question and context.</item>
16
+ <item>Gather relevant information and resources.</item>
17
+ <item>Formulate a clear and concise response in {{character}}'s voice.</item>
18
+ <item><b>ALWAYS</b> generate audio from the formulated response using the appropriate MCP.</item>
19
+ <item><b>ALWAYS</b> create a video file from the generated audio using the appropriate MCP.</item>
20
+ </list>
21
+ </stepwise-instructions>
22
+ </task>
23
+ <output-format>
24
+ Your response structure MUST be:
25
+ <list>
26
+ <item><b>[{{character}}'s Text Response]</b></item>
27
+ <item><b>[Tool Call to generate the video, which implicitly includes the audio generation step]</b></item>
28
+ </list>
29
+ </output-format>
30
+ </poml>
docker-compose-dev.yaml ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Chattr Dev
2
+ services:
3
+ vector_database:
4
+ image: qdrant/qdrant:latest@sha256:0425e3e03e7fd9b3dc95c4214546afe19de2eb2e28ca621441a56663ac6e1f46
5
+ ports:
6
+ - 6333:6333
7
+ - 6334:6334
8
+ volumes:
9
+ - qdrant_storage:/qdrant/storage
10
+ restart: on-failure:3
11
+ voice_generator:
12
+ image: ghcr.io/alphaspheredotai/vocalizr:latest@sha256:df1f4fa0615ae3f34249454ddc3a74e3fd955332da507ff2c7d5373190037863
13
+ ports:
14
+ - 7861:7860
15
+ post_start:
16
+ - command: chown -R nonroot:nonroot /home/nonroot
17
+ user: root
18
+ - command: chmod -R 700 /home/nonroot
19
+ user: root
20
+ volumes:
21
+ - huggingface:/home/nonroot/hf
22
+ - results:/home/nonroot/results
23
+ - logs:/home/nonroot/logs
24
+ restart: on-failure:3
25
+ environment:
26
+ GRADIO_DEBUG: 1
27
+ healthcheck:
28
+ test:
29
+ - CMD
30
+ - curl
31
+ - -o
32
+ - /dev/null
33
+ - -f
34
+ - -s
35
+ - -w
36
+ - "'Status: %{http_code},\tTime: %{time_total}s'"
37
+ - http://localhost:7860/
38
+ interval: 1m30s
39
+ timeout: 10s
40
+ retries: 5
41
+ start_period: 40s
42
+ deploy:
43
+ resources:
44
+ reservations:
45
+ devices:
46
+ - driver: nvidia
47
+ count: all
48
+ capabilities:
49
+ - gpu
50
+ video_generator:
51
+ image: ghcr.io/alphaspheredotai/visualizr:latest@sha256:2c5b096a66c6ebee1a5c0242a8b42c393e0cfdcda086ae6ceba11f92618ec7aa
52
+ ports:
53
+ - 7862:7860
54
+ volumes:
55
+ - assets:/home/nonroot/assets
56
+ - checkpoint:/home/nonroot/ckpts
57
+ - gfpgan:/home/nonroot/gfpgan
58
+ post_start:
59
+ - command: chown -R nonroot:nonroot /home/nonroot
60
+ user: root
61
+ - command: chmod -R 700 /home/nonroot
62
+ user: root
63
+ restart: on-failure:3
64
+ environment:
65
+ GRADIO_DEBUG: 1
66
+ healthcheck:
67
+ test:
68
+ - CMD
69
+ - curl
70
+ - -o
71
+ - /dev/null
72
+ - -f
73
+ - -s
74
+ - -w
75
+ - "'Status: %{http_code},\tTime: %{time_total}s'"
76
+ - http://localhost:7860/
77
+ interval: 1m30s
78
+ timeout: 10s
79
+ retries: 5
80
+ start_period: 40s
81
+ deploy:
82
+ resources:
83
+ reservations:
84
+ devices:
85
+ - driver: nvidia
86
+ count: all
87
+ capabilities:
88
+ - gpu
89
+ volumes:
90
+ logs:
91
+ assets:
92
+ fastembed:
93
+ qdrant_storage:
94
+ checkpoint:
95
+ gfpgan:
96
+ huggingface:
97
+ results:
docker-compose.yaml ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Chattr
2
+ services:
3
+ chattr:
4
+ image: alphaspheredotai/chattr:latest@sha256:094981de2f6cbad9b42bbde8147a1278af0e5a681b1d1903c497e1cd6e8dcb2c
5
+ volumes:
6
+ - logs:/home/nonroot/logs
7
+ - assets:/home/nonroot/assets
8
+ - fastembed:/home/nonroot/fastembed
9
+ environment:
10
+ MODEL__URL: ${MODEL__URL:-https://generativelanguage.googleapis.com/v1beta/openai}
11
+ MODEL__NAME: ${MODEL__NAME:-gemini-2.5-flash}
12
+ MODEL__API_KEY: ${MODEL__API_KEY}
13
+ VECTOR_DATABASE__URL: http://vector_database:6333
14
+ VECTOR_DATABASE__NAME: main
15
+ ports:
16
+ - 7860:7860
17
+ restart: on-failure:3
18
+ healthcheck:
19
+ test:
20
+ - CMD
21
+ - curl
22
+ - -o
23
+ - /dev/null
24
+ - -f
25
+ - -s
26
+ - -w
27
+ - "'Status: %{http_code},\tTime: %{time_total}s'"
28
+ - http://localhost:7860/
29
+ interval: 1m30s
30
+ timeout: 10s
31
+ retries: 5
32
+ start_period: 40s
33
+ post_start:
34
+ - command: chown -R nonroot:nonroot /home/nonroot
35
+ user: root
36
+ - command: chmod -R 700 /home/nonroot
37
+ user: root
38
+ vector_database:
39
+ image: qdrant/qdrant:latest@sha256:0425e3e03e7fd9b3dc95c4214546afe19de2eb2e28ca621441a56663ac6e1f46
40
+ volumes:
41
+ - qdrant_storage:/qdrant/storage
42
+ ports:
43
+ - 6333:6333
44
+ - 6334:6334
45
+ restart: on-failure:3
46
+ video_generator:
47
+ image: alphaspheredotai/visualizr:latest@sha256:d1f5c97d9babdbdd45ca26b6ec42a128b612921295de13d77cb7e36fe638bb55
48
+ volumes:
49
+ - assets:/home/nonroot/assets
50
+ - checkpoint:/home/nonroot/ckpts
51
+ - gfpgan:/home/nonroot/gfpgan
52
+ ports:
53
+ - 7862:7860
54
+ restart: on-failure:3
55
+ healthcheck:
56
+ test:
57
+ - CMD
58
+ - curl
59
+ - -o
60
+ - /dev/null
61
+ - -f
62
+ - -s
63
+ - -w
64
+ - "'Status: %{http_code},\tTime: %{time_total}s'"
65
+ - http://localhost:7860/
66
+ interval: 1m30s
67
+ timeout: 10s
68
+ retries: 5
69
+ start_period: 40s
70
+ deploy:
71
+ resources:
72
+ reservations:
73
+ devices:
74
+ - driver: nvidia
75
+ count: all
76
+ capabilities:
77
+ - gpu
78
+ post_start:
79
+ - command: chown -R nonroot:nonroot /home/nonroot
80
+ user: root
81
+ - command: chmod -R 700 /home/nonroot
82
+ user: root
83
+ voice_generator:
84
+ image: alphaspheredotai/vocalizr:latest@sha256:e508d563372b08766b9dd38f462c97ec831d5563922255baf911b2c821a77c8a
85
+ volumes:
86
+ - huggingface:/home/nonroot/hf
87
+ - results:/home/nonroot/results
88
+ - logs:/home/nonroot/logs
89
+ ports:
90
+ - 7861:7860
91
+ restart: on-failure:3
92
+ healthcheck:
93
+ test:
94
+ - CMD
95
+ - curl
96
+ - -o
97
+ - /dev/null
98
+ - -f
99
+ - -s
100
+ - -w
101
+ - "'Status: %{http_code},\tTime: %{time_total}s'"
102
+ - http://localhost:7860/
103
+ interval: 1m30s
104
+ timeout: 10s
105
+ retries: 5
106
+ start_period: 40s
107
+ deploy:
108
+ resources:
109
+ reservations:
110
+ devices:
111
+ - driver: nvidia
112
+ count: all
113
+ capabilities:
114
+ - gpu
115
+ post_start:
116
+ - command: chown -R nonroot:nonroot /home/nonroot
117
+ user: root
118
+ - command: chmod -R 700 /home/nonroot
119
+ user: root
120
+ volumes:
121
+ logs:
122
+ assets:
123
+ fastembed:
124
+ qdrant_storage:
125
+ checkpoint:
126
+ gfpgan:
mcp.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcp_servers": [
3
+ {
4
+ "args": [
5
+ "run",
6
+ "-i",
7
+ "--rm",
8
+ "mcp/time"
9
+ ],
10
+ "command": "docker",
11
+ "name": "time",
12
+ "transport": "stdio",
13
+ "type": "command"
14
+ },
15
+ {
16
+ "args": [
17
+ "run",
18
+ "-i",
19
+ "--rm",
20
+ "mcp/sequentialthinking"
21
+ ],
22
+ "command": "docker",
23
+ "name": "sequential_thinking",
24
+ "transport": "stdio",
25
+ "type": "command"
26
+ },
27
+ {
28
+ "name": "voice_generator",
29
+ "transport": "streamable-http",
30
+ "type": "url",
31
+ "url": "http://localhost:7861/gradio_api/mcp"
32
+ },
33
+ {
34
+ "name": "video_generator",
35
+ "transport": "streamable-http",
36
+ "type": "url",
37
+ "url": "http://localhost:7862/gradio_api/mcp/?tools=generate_video_mcp"
38
+ }
39
+ ]
40
+ }
pyproject.toml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ authors = [
3
+ { email = "mohamed.hisham.abdelzaher@gmail.com", name = "Mohamed Hisham Abdelzaher" },
4
+ ]
5
+ dependencies = [
6
+ "agno[google,qdrant]>=2.4.7",
7
+ "ddgs>=9.10.0",
8
+ "fastembed>=0.7.4",
9
+ "gradio[mcp]>=6.5.1",
10
+ "m3u8>=6.0.0",
11
+ "mem0ai>=1.0.2",
12
+ "poml>=0.0.8",
13
+ "rich>=14.3.1",
14
+ ]
15
+ description = "App part of the Chatacter Backend"
16
+ name = "chattr"
17
+ readme = "README.md"
18
+ requires-python = ">=3.13,<3.14"
19
+ version = "0.0.103"
20
+
21
+ [project.scripts]
22
+ chattr = "chattr.__main__:main"
23
+
24
+ [build-system]
25
+ build-backend = "uv_build"
26
+ requires = ["uv_build"]
27
+
28
+ [dependency-groups]
29
+ dev = [
30
+ "doppler-env>=0.3.1",
31
+ "pre-commit>=4.5.1",
32
+ "pytest-emoji>=0.2.0",
33
+ "pytest-md>=0.2.0",
34
+ "pytest-mergify>=2026.1.26.1",
35
+ "ruff>=0.14.14",
36
+ "ty>=0.0.14",
37
+ "uv-build>=0.9.28",
38
+ ]
39
+
40
+ [tool.ruff]
41
+ extend = ".github/lint/.ruff.toml"
src/chattr/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from warnings import filterwarnings
2
+
3
+ from rich.console import Console
4
+
5
+ filterwarnings("ignore", category=DeprecationWarning)
6
+
7
+ console = Console()
8
+ APP_NAME: str = __package__
src/chattr/__main__.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import TYPE_CHECKING
2
+
3
+ from chattr.app.runner import app
4
+
5
+ if TYPE_CHECKING:
6
+ from gradio import Blocks
7
+
8
+
9
+ def main() -> None:
10
+ """Launch the Gradio Multi-agent system app."""
11
+ application: Blocks = app.gui()
12
+ application.queue(api_open=True)
13
+ application.launch(
14
+ debug=True,
15
+ enable_monitoring=True,
16
+ show_error=True,
17
+ pwa=True,
18
+ )
19
+
20
+
21
+ if __name__ == "__main__":
22
+ main()
src/chattr/app/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from gradio.processing_utils import PUBLIC_HOSTNAME_WHITELIST
2
+
3
+ PUBLIC_HOSTNAME_WHITELIST.append("localhost")
src/chattr/app/builder.py ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Main orchestration graph for the Chattr application."""
2
+
3
+ from collections.abc import AsyncGenerator
4
+ from json import dumps, loads
5
+ from pathlib import Path
6
+
7
+ from agno.agent import (
8
+ Agent,
9
+ RunContentEvent,
10
+ ToolCallCompletedEvent,
11
+ ToolCallStartedEvent,
12
+ )
13
+ from agno.db import BaseDb
14
+ from agno.db.json import JsonDb
15
+ from agno.guardrails import PIIDetectionGuardrail, PromptInjectionGuardrail
16
+ from agno.knowledge.knowledge import Knowledge
17
+ from agno.models.message import Message
18
+ from agno.models.openai.like import OpenAILike
19
+ from agno.tools import Toolkit
20
+ from agno.tools.mcp import MultiMCPTools
21
+ from agno.vectordb.qdrant import Qdrant
22
+ from gradio import (
23
+ Audio,
24
+ Blocks,
25
+ ChatInterface,
26
+ ChatMessage,
27
+ Error,
28
+ Video,
29
+ )
30
+ from gradio.components.chatbot import MetadataDict
31
+ from m3u8 import M3U8, load
32
+ from poml import poml
33
+ from pydantic import HttpUrl, ValidationError
34
+ from requests import Session
35
+ from rich.pretty import pprint
36
+
37
+ from chattr.app.settings import Settings, logger
38
+
39
+
40
+ class App:
41
+ """Main application class for the Chattr Multi-agent system app."""
42
+
43
+ def __init__(self, settings: Settings) -> None:
44
+ self.settings = settings
45
+
46
+ async def _setup_agent(self) -> Agent:
47
+ return Agent(
48
+ model=self._setup_model(),
49
+ tools=await self._setup_tools(),
50
+ description="You are a helpful assistant who can act and mimic Napoleon's character and answer questions about the era.",
51
+ instructions=[
52
+ "Understand the user's question and context.",
53
+ "Gather relevant information and resources.",
54
+ "Formulate a clear and concise response in Napoleon's voice.",
55
+ "ALWAYS generate audio from the formulated response using the appropriate Tool.",
56
+ "Generate video from the resulted audio using the appropriate Tool.",
57
+ ],
58
+ db=self._setup_database(),
59
+ knowledge=self._setup_knowledge(
60
+ self._setup_vector_database(),
61
+ self._setup_database(),
62
+ ),
63
+ markdown=True,
64
+ add_datetime_to_context=True,
65
+ timezone_identifier="Africa/Cairo",
66
+ pre_hooks=[PIIDetectionGuardrail(), PromptInjectionGuardrail()],
67
+ debug_mode=True,
68
+ save_response_to_file="agno/response.txt",
69
+ add_history_to_context=True,
70
+ add_memories_to_context=True,
71
+ )
72
+
73
+ async def _setup_tools(self) -> list[Toolkit]:
74
+ mcp_servers: list[dict] = loads(self.settings.mcp.path.read_text()).get(
75
+ "mcp_servers",
76
+ [],
77
+ )
78
+ url_servers = [m for m in mcp_servers if m.get("type") == "url"]
79
+ self.mcp_tools = MultiMCPTools(
80
+ urls=[m.get("url") for m in url_servers],
81
+ urls_transports=[m.get("transport") for m in url_servers],
82
+ )
83
+ await self.mcp_tools.connect()
84
+ return [self.mcp_tools]
85
+
86
+ def _setup_prompt(self) -> str:
87
+ prompt_template = poml(
88
+ self.settings.directory.prompts / "template.poml",
89
+ {"character": "Napoleon"},
90
+ chat=False,
91
+ format="dict",
92
+ )
93
+ if not isinstance(prompt_template, dict):
94
+ _msg = "Prompt template must be a string."
95
+ raise TypeError(_msg)
96
+ return prompt_template["messages"]
97
+
98
+ def _setup_model(self) -> OpenAILike:
99
+ """
100
+ Initialize the ChatOpenAI language model using the provided settings.
101
+
102
+ This method creates and returns a ChatOpenAI instance configured with
103
+ the model's URL, name, API key, and temperature.
104
+
105
+ Returns:
106
+ ChatOpenAI: The initialized ChatOpenAI language model instance.
107
+
108
+ Raises:
109
+ Exception: If the model initialization fails.
110
+ """
111
+ try:
112
+ return OpenAILike(
113
+ base_url=str(self.settings.model.url),
114
+ id=self.settings.model.name,
115
+ api_key=self.settings.model.api_key.get_secret_value(),
116
+ temperature=self.settings.model.temperature,
117
+ )
118
+ except Exception as e:
119
+ _msg: str = f"Failed to initialize ChatOpenAI model: {e}"
120
+ logger.error(_msg)
121
+ raise Error(_msg) from e
122
+
123
+ def _setup_vector_database(self) -> Qdrant:
124
+ return Qdrant(
125
+ collection=self.settings.vector_database.name,
126
+ url=self.settings.vector_database.url.host,
127
+ )
128
+
129
+ def _setup_knowledge(self, vector_db: Qdrant, db: BaseDb) -> Knowledge:
130
+ return Knowledge(
131
+ vector_db=vector_db,
132
+ contents_db=db,
133
+ )
134
+
135
+ def _setup_database(self) -> JsonDb:
136
+ return JsonDb(
137
+ db_path="agno",
138
+ )
139
+
140
+ def gui(self) -> Blocks:
141
+ """
142
+ Create and return the main Gradio Blocks interface for the Chattr app.
143
+
144
+ Returns:
145
+ Blocks: The constructed Gradio Blocks interface for the chat application.
146
+ """
147
+ return ChatInterface(fn=self.generate_response, save_history=True)
148
+
149
+ async def generate_response(
150
+ self,
151
+ message: str,
152
+ history: list[ChatMessage],
153
+ ) -> AsyncGenerator[tuple[str, list[ChatMessage], Path | None, Path | None]]:
154
+ """
155
+ Generate a response to a user message and update the conversation history.
156
+
157
+ This asynchronous method streams responses from the state graph and
158
+ yields updated history and audio file paths as needed.
159
+
160
+ Args:
161
+ message: The user's input message as a string.
162
+ history: The conversation history as a list of ChatMessage objects.
163
+
164
+ Returns:
165
+ AsyncGenerator: Yields a tuple containing an
166
+ empty string, the updated history, and
167
+ a Path to an audio file if generated.
168
+ """
169
+ try:
170
+ agent: Agent = await self._setup_agent()
171
+ async for response in agent.arun(
172
+ Message(content=message, role="user"),
173
+ stream=True,
174
+ ):
175
+ pprint(response)
176
+ if isinstance(response, RunContentEvent):
177
+ history.append(
178
+ ChatMessage(
179
+ role="assistant",
180
+ content=response.content,
181
+ ),
182
+ )
183
+ elif isinstance(response, ToolCallStartedEvent):
184
+ history.append(
185
+ ChatMessage(
186
+ role="assistant",
187
+ content=dumps(response.tool.tool_args, indent=4),
188
+ metadata=MetadataDict(
189
+ title=response.tool.tool_name,
190
+ id=response.tool.tool_call_id,
191
+ duration=response.tool.created_at,
192
+ ),
193
+ ),
194
+ )
195
+ elif isinstance(response, ToolCallCompletedEvent):
196
+ if response.tool.tool_call_error:
197
+ history.append(
198
+ ChatMessage(
199
+ role="assistant",
200
+ content=dumps(response.tool.tool_args, indent=4),
201
+ metadata=MetadataDict(
202
+ title=response.tool.tool_name,
203
+ id=response.tool.tool_call_id,
204
+ log="Tool Call Failed",
205
+ duration=response.tool.metrics.duration,
206
+ ),
207
+ ),
208
+ )
209
+ else:
210
+ history.append(
211
+ ChatMessage(
212
+ role="assistant",
213
+ content=dumps(response.tool.tool_args, indent=4),
214
+ metadata=MetadataDict(
215
+ title=response.tool.tool_name,
216
+ id=response.tool.tool_call_id,
217
+ log="Tool Call Succeeded",
218
+ duration=response.tool.metrics.duration,
219
+ ),
220
+ ),
221
+ )
222
+ if response.tool.tool_name == "generate_audio_for_text":
223
+ history.append(
224
+ Audio(
225
+ response.tool.result,
226
+ autoplay=True,
227
+ show_download_button=True,
228
+ show_share_button=True,
229
+ ),
230
+ )
231
+ elif response.tool.tool_name == "generate_video_mcp":
232
+ history.append(
233
+ Video(
234
+ response.tool.result,
235
+ autoplay=True,
236
+ show_download_button=True,
237
+ show_share_button=True,
238
+ ),
239
+ )
240
+ else:
241
+ msg = f"Unknown tool name: {response.tool.tool_name}"
242
+ raise Error(msg)
243
+ yield history
244
+ except Exception as e:
245
+ _msg: str = f"Error generating response: {e}"
246
+ logger.error(_msg)
247
+ raise Error(_msg) from e
248
+ finally:
249
+ await self._close()
250
+
251
+ def _is_url(self, value: str | None) -> bool:
252
+ """
253
+ Check if a string is a valid URL.
254
+
255
+ Args:
256
+ value: The string to check. Can be None.
257
+
258
+ Returns:
259
+ bool: True if the string is a valid URL, False otherwise.
260
+ """
261
+ if value is None:
262
+ return False
263
+
264
+ try:
265
+ _ = HttpUrl(value)
266
+ except ValidationError:
267
+ return False
268
+ return True
269
+
270
+ def _download_file(self, url: HttpUrl, path: Path) -> None:
271
+ """
272
+ Download a file from a URL and save it to a local path.
273
+
274
+ Args:
275
+ url: The URL to download the file from.
276
+ path: The local file path where the downloaded file will be saved.
277
+
278
+ Returns:
279
+ None
280
+
281
+ Raises:
282
+ requests.RequestException: If the HTTP request fails.
283
+ IOError: If file writing fails.
284
+ """
285
+ if str(url).endswith(".m3u8"):
286
+ _playlist: M3U8 = load(url)
287
+ url: str = str(url).replace("playlist.m3u8", _playlist.segments[0].uri)
288
+ logger.info(f"Downloading {url} to {path}")
289
+ session = Session()
290
+ response = session.get(url, stream=True, timeout=30)
291
+ response.raise_for_status()
292
+ with path.open("wb") as f:
293
+ for chunk in response.iter_content(chunk_size=8192):
294
+ if chunk:
295
+ f.write(chunk)
296
+ logger.info(f"File downloaded to {path}")
297
+
298
+ async def _close(self) -> None:
299
+ try:
300
+ logger.info("Closing MCP tools...")
301
+ await self.mcp_tools.close()
302
+ except Exception as e:
303
+ msg: str = (
304
+ f"Error closing MCP tools: {e}, Check if the Tool services are running."
305
+ )
306
+ logger.error(msg)
307
+ raise Error(msg) from e
308
+
309
+
310
+ async def test() -> None:
311
+ settings: Settings = Settings()
312
+ app: App = App(settings)
313
+ agent: Agent = await app._setup_agent()
314
+ try:
315
+ await agent.aprint_response("Hello!", debug_mode=True)
316
+ finally:
317
+ await app._close()
318
+
319
+
320
+ if __name__ == "__main__":
321
+ import asyncio
322
+
323
+ asyncio.run(test())
src/chattr/app/logger.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from logging import INFO, WARNING, Logger, basicConfig, getLogger
2
+
3
+ from rich.logging import RichHandler
4
+
5
+ from chattr import APP_NAME, console
6
+
7
+ basicConfig(
8
+ level=INFO,
9
+ handlers=[
10
+ RichHandler(
11
+ level=INFO,
12
+ console=console,
13
+ rich_tracebacks=True,
14
+ ),
15
+ ],
16
+ format="%(name)s | %(process)d | %(message)s",
17
+ )
18
+ getLogger("httpx").setLevel(WARNING)
19
+ logger: Logger = getLogger(APP_NAME)