Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e51c0eb3aa | ||
|
|
8f788eeff0 | ||
|
|
1af2fa4333 | ||
|
|
305b787dd6 | ||
|
|
e14844a113 | ||
|
|
9ed97cd8f4 | ||
|
|
e8042ee19d | ||
|
|
802908cb8f | ||
|
|
3b18ce23b1 | ||
|
|
c37b482b87 | ||
|
|
486ff4bb53 |
No files matched your search
@@ -0,0 +1,39 @@
|
|||||||
|
# Linux Voice Assistant - AI Policy
|
||||||
|
|
||||||
|
We support using AI (i.e., LLMs) as tools when contributing to Linux Voice Assistant. However, you are responsible for any contributions you submit, and we are responsible for any contributions we merge and release. We hold a high bar for all contributions to our projects.
|
||||||
|
|
||||||
|
Our maintainers dedicate their time and expertise to reviewing contributions. Submitting AI-generated content that you have not personally reviewed and understood wastes that time and will not be accepted.
|
||||||
|
|
||||||
|
## Autonomous agents
|
||||||
|
|
||||||
|
We do not allow autonomous agents to be used for contributing to our projects. We will close any pull requests or issues that we believe were created autonomously, and may mark automated comments as spam. This includes contributions that bypass the provided issue or pull request templates.
|
||||||
|
|
||||||
|
## Communication on issues, pull requests, and code reviews
|
||||||
|
|
||||||
|
We don't mind if you use AI tools to help you write. However, do not have tools post unreviewed content on your behalf. Keep responses to the minimum needed to communicate your intent. We may hide any comments that we believe are unreviewed AI output.
|
||||||
|
|
||||||
|
If you are opening a pull request, we expect you to be able to explain the proposed changes in your own words. This includes the pull request description and responses to questions. If you use AI to help generate the pull request summary, you must review it for technical accuracy.
|
||||||
|
|
||||||
|
**Do not use AI to generate answers to questions from maintainers.** You should understand and be able to explain your own work. Using AI to improve grammar or clarity is fine, but the substance of your responses must be your own.
|
||||||
|
|
||||||
|
If you wish to include context from an interaction with AI in your comments, it must be in a quote block (e.g., using `>`) and disclosed as such. It must be accompanied by your own commentary explaining the relevance and implications of the context. Do not share long snippets.
|
||||||
|
|
||||||
|
## Non-native English speakers
|
||||||
|
|
||||||
|
We understand that AI is useful when communicating as a non-native English speaker. If you are using AI to translate your comments, please ensure the translation accurately reflects your intent. Including your original text in a details block shows the effort behind your contribution, helps maintainers verify the translation if needed, and keeps the conversation readable.
|
||||||
|
|
||||||
|
## Code and documentation contributions
|
||||||
|
|
||||||
|
AI can be a helpful tool for writing code and documentation. However, due to the foundational open source nature of our projects, we require a human in the loop who understands the work produced by AI.
|
||||||
|
|
||||||
|
All contributions must be reviewed and understood by the contributor before submission. You should be able to explain every change in a pull request you submit. Pull requests that appear to be unreviewed AI output will be closed without review.
|
||||||
|
|
||||||
|
## Our use of AI
|
||||||
|
|
||||||
|
Some of our projects use AI tools to assist with code reviews, issue triaging, reporting, and other project management tasks. These tools may leave comments on pull requests or issues. As with any automated tooling, these comments are not always correct.
|
||||||
|
|
||||||
|
If an AI tool leaves a comment on your contribution, treat it as you would any other review comment. If you believe it is incorrect, say so; a brief explanation is sufficient. Maintainers always have the final say. If in doubt, ask a maintainer.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Contributions that do not follow this policy will be closed. Repeated violations may result in being blocked from contributing to LVA projects.
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Contributing to Linux Voice Assistant
|
||||||
|
|
||||||
|
Everybody is invited and welcome to contribute to Linux Voice Assistant. Even if you are not a developer, perhaps you would like to help with the documentation? If you are a developer and have a feature that isn't supported by LVA yet, why not spend some time and help to integrate it?
|
||||||
|
|
||||||
|
The process is straight-forward.
|
||||||
|
|
||||||
|
- Fork the LVA repository.
|
||||||
|
- Write the code for your feature or fix.
|
||||||
|
- Ensure tests pass and linting succeeds (`./script/lint` and `./script/tests`).
|
||||||
|
- Create a Pull Request against the `main` branch.
|
||||||
|
|
||||||
|
## Feature suggestions
|
||||||
|
|
||||||
|
If you want to suggest a new feature for LVA, please open a discussion on GitHub.
|
||||||
|
|
||||||
|
## Issue Tracker
|
||||||
|
|
||||||
|
If you want to report an issue, please create an issue on the repository.
|
||||||
|
|
||||||
|
## AI Policy
|
||||||
|
|
||||||
|
Linux Voice Assistant is an [Open Home Foundation](https://www.openhomefoundation.org/) project and follows the [OHF AI Policy](https://github.com/music-assistant/.github/blob/main/AI_POLICY.md). Please read it before submitting AI-assisted contributions. The TLDR: AI tools are allowed, but a human is responsible and must review and understand every change. Autonomous agents and unreviewed AI output will be rejected.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
custom: https://www.openhomefoundation.org
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: "🐛 Report a bug"
|
||||||
|
url: https://github.com/OHF-Voice/linux-voice-assistant/issues/new?template=bug_report.md
|
||||||
|
about: Report bugs in the Linux Voice Assistant.
|
||||||
|
- name: "💬 Discord community & support"
|
||||||
|
url: https://discord.com/channels/330944238910963714/1464387232201703547
|
||||||
|
about: Chat with the community and get help from other users.
|
||||||
|
- name: "❓ Questions & how-to (Q&A)"
|
||||||
|
url: https://github.com/OHF-Voice/linux-voice-assistant/discussions
|
||||||
|
about: Ask how-to questions and search previous answers.
|
||||||
|
- name: "💡 Feature requests & ideas"
|
||||||
|
url: https://github.com/OHF-Voice/linux-voice-assistant/discussions
|
||||||
|
about: Suggest and vote on new features and enhancements.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# What does this implement/fix?
|
||||||
|
|
||||||
|
<!-- Quick description and explanation of changes. -->
|
||||||
|
|
||||||
|
**Related issue (if applicable):**
|
||||||
|
|
||||||
|
- Fixes #<issue number>
|
||||||
|
|
||||||
|
## Types of changes
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Tick exactly one box. CI derives the label from the ticked box.
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] Bugfix (non-breaking change which fixes an issue) — `bugfix`
|
||||||
|
- [ ] New feature (non-breaking change which adds functionality) — `new-feature`
|
||||||
|
- [ ] Enhancement to an existing feature — `enhancement`
|
||||||
|
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) — `breaking-change`
|
||||||
|
- [ ] Refactor (no behaviour change) — `refactor`
|
||||||
|
- [ ] Documentation only — `documentation`
|
||||||
|
- [ ] Maintenance / chore — `maintenance`
|
||||||
|
- [ ] CI / workflow change — `ci`
|
||||||
|
- [ ] Dependencies bump — `dependencies`
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] The code change is tested and works locally.
|
||||||
|
- [ ] `./script/lint` passes.
|
||||||
|
- [ ] `./script/tests` passes, and tests have been added/updated under `tests/` where applicable.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
- package-ecosystem: "pip"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
groups:
|
||||||
|
dependencies:
|
||||||
|
patterns:
|
||||||
|
- "*"
|
||||||
@@ -27,14 +27,14 @@ jobs:
|
|||||||
echo "REPOSITORY_LOWER=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
echo "REPOSITORY_LOWER=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Log in to the Container registry
|
- name: Log in to the Container registry
|
||||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ github.token }}
|
password: ${{ github.token }}
|
||||||
# Build Docker Images (amd64 and arm64)
|
# Build Docker Images (amd64 and arm64)
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
id: push
|
id: push
|
||||||
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/aarch64
|
platforms: linux/amd64,linux/aarch64
|
||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
tags: ${{ env.REGISTRY_LOWER }}/${{ env.REPOSITORY_LOWER }}:nightly
|
tags: ${{ env.REGISTRY_LOWER }}/${{ env.REPOSITORY_LOWER }}:nightly
|
||||||
labels: "nightly"
|
labels: "nightly"
|
||||||
- name: Generate artifact attestation
|
- name: Generate artifact attestation
|
||||||
uses: actions/attest-build-provenance@v1.4.4
|
uses: actions/attest-build-provenance@v4
|
||||||
with:
|
with:
|
||||||
subject-name: ${{ env.REGISTRY }}/${{ github.repository }}
|
subject-name: ${{ env.REGISTRY }}/${{ github.repository }}
|
||||||
subject-digest: ${{ steps.push.outputs.digest }}
|
subject-digest: ${{ steps.push.outputs.digest }}
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout PR code
|
- name: Checkout PR code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
allow-unsafe-pr-checkout: true
|
||||||
|
|
||||||
- name: Set variables
|
- name: Set variables
|
||||||
run: |
|
run: |
|
||||||
@@ -32,14 +33,14 @@ jobs:
|
|||||||
echo "REPOSITORY_LOWER=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
echo "REPOSITORY_LOWER=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Log in to the Container registry
|
- name: Log in to the Container registry
|
||||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ github.token }}
|
password: ${{ github.token }}
|
||||||
# Build Docker Images (amd64 and arm64)
|
# Build Docker Images (amd64 and arm64)
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
id: push
|
id: push
|
||||||
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/aarch64
|
platforms: linux/amd64,linux/aarch64
|
||||||
@@ -59,7 +60,7 @@ jobs:
|
|||||||
tags: "${{ env.REGISTRY_LOWER }}/${{ env.REPOSITORY_LOWER }}-pr:${{ env.PR_NUMBER }}"
|
tags: "${{ env.REGISTRY_LOWER }}/${{ env.REPOSITORY_LOWER }}-pr:${{ env.PR_NUMBER }}"
|
||||||
labels: "${{ env.PR_NUMBER }}"
|
labels: "${{ env.PR_NUMBER }}"
|
||||||
- name: Generate artifact attestation
|
- name: Generate artifact attestation
|
||||||
uses: actions/attest-build-provenance@v1.4.4
|
uses: actions/attest-build-provenance@v4
|
||||||
with:
|
with:
|
||||||
subject-name: ${{ env.REGISTRY_LOWER }}/${{ env.REPOSITORY_LOWER }}-pr
|
subject-name: ${{ env.REGISTRY_LOWER }}/${{ env.REPOSITORY_LOWER }}-pr
|
||||||
subject-digest: ${{ steps.push.outputs.digest }}
|
subject-digest: ${{ steps.push.outputs.digest }}
|
||||||
|
|||||||
@@ -23,19 +23,19 @@ jobs:
|
|||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Log in to the Container registry
|
- name: Log in to the Container registry
|
||||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ github.token }}
|
password: ${{ github.token }}
|
||||||
# Build Docker Images (amd64 and arm64)
|
# Build Docker Images (amd64 and arm64)
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Extract metadata for Docker
|
- name: Extract metadata for Docker
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
|
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ github.repository }}
|
images: ${{ env.REGISTRY }}/${{ github.repository }}
|
||||||
# E.g. tag v1.2.0 produces 3 tags: '1.2.0', '1.2', and 'latest'
|
# E.g. tag v1.2.0 produces 3 tags: '1.2.0', '1.2', and 'latest'
|
||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
id: push
|
id: push
|
||||||
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
|
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/aarch64
|
platforms: linux/amd64,linux/aarch64
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
- name: Generate artifact attestation
|
- name: Generate artifact attestation
|
||||||
uses: actions/attest-build-provenance@v1
|
uses: actions/attest-build-provenance@v4
|
||||||
with:
|
with:
|
||||||
subject-name: ${{ env.REGISTRY }}/${{ github.repository }}
|
subject-name: ${{ env.REGISTRY }}/${{ github.repository }}
|
||||||
subject-digest: ${{ steps.push.outputs.digest }}
|
subject-digest: ${{ steps.push.outputs.digest }}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: main
|
ref: main
|
||||||
- uses: rhysd/changelog-from-release/action@v3
|
- uses: rhysd/changelog-from-release/action@v3
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
name: PR Labels
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- edited
|
||||||
|
- synchronize
|
||||||
|
- labeled
|
||||||
|
- unlabeled
|
||||||
|
- reopened
|
||||||
|
- ready_for_review
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
apply_label:
|
||||||
|
name: Apply
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.pull_request.user.type != 'Bot'
|
||||||
|
steps:
|
||||||
|
- name: 🏷 Apply label from PR description checkbox
|
||||||
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const known = [
|
||||||
|
'breaking-change', 'bugfix', 'refactor',
|
||||||
|
'new-feature', 'enhancement', 'maintenance',
|
||||||
|
'ci', 'dependencies', 'documentation',
|
||||||
|
];
|
||||||
|
|
||||||
|
const { owner, repo } = context.repo;
|
||||||
|
const issue_number = context.payload.pull_request.number;
|
||||||
|
const current = (context.payload.pull_request.labels || [])
|
||||||
|
.map(l => l.name);
|
||||||
|
|
||||||
|
const alreadyLabelled = current.filter(n => known.includes(n));
|
||||||
|
if (alreadyLabelled.length === 1) {
|
||||||
|
core.info(
|
||||||
|
`Skipping: PR already labelled '${alreadyLabelled[0]}'.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = context.payload.pull_request.body || '';
|
||||||
|
const re = /^\s*-\s*\[x\][^`\n]*`([^`]+)`/gim;
|
||||||
|
const ticked = [];
|
||||||
|
for (const m of body.matchAll(re)) {
|
||||||
|
const name = m[1];
|
||||||
|
if (known.includes(name) && !ticked.includes(name)) {
|
||||||
|
ticked.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticked.length === 0) {
|
||||||
|
core.setFailed(
|
||||||
|
'No "Types of changes" checkbox is ticked in the PR ' +
|
||||||
|
'description. Edit the description and tick exactly ' +
|
||||||
|
'one box so this PR can be release-noted.'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ticked.length > 1) {
|
||||||
|
core.setFailed(
|
||||||
|
`Multiple "Types of changes" checkboxes are ticked ` +
|
||||||
|
`(${ticked.join(', ')}). Tick exactly one.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const desired = ticked[0];
|
||||||
|
|
||||||
|
for (const name of current) {
|
||||||
|
if (known.includes(name) && name !== desired) {
|
||||||
|
await github.rest.issues.removeLabel({
|
||||||
|
owner, repo, issue_number, name,
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!current.includes(desired)) {
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner, repo, issue_number, labels: [desired],
|
||||||
|
});
|
||||||
|
}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"ms-python.python",
|
||||||
|
"ms-python.vscode-pylance",
|
||||||
|
"kilo.kilocode"
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Run Linux Voice Assistant",
|
||||||
|
"type": "python",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/linux_voice_assistant/__main__.py",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"justMyCode": true,
|
||||||
|
"envFile": "${workspaceFolder}/.env"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"python.defaultInterpreterPath": "./.venv/bin/python",
|
||||||
|
"python.testing.pytestEnabled": true,
|
||||||
|
"python.testing.pytestArgs": ["tests"],
|
||||||
|
"python.testing.pytestAutoInclude": false,
|
||||||
|
"python.linting.enabled": true,
|
||||||
|
"python.linting.flake8Enabled": true,
|
||||||
|
"python.linting.mypyEnabled": true,
|
||||||
|
"python.formatting.provider": "none",
|
||||||
|
"python.terminal.activateEnvironment": true,
|
||||||
|
"python.terminal.executeInShell": true,
|
||||||
|
"python.pythonPath": "./.venv/bin/python"
|
||||||
|
}
|
||||||
Vendored
+62
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Setup (incl. dev dependencies)",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "./script/setup --dev",
|
||||||
|
"group": "build",
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "new",
|
||||||
|
"clear": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run Linter",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "./script/lint",
|
||||||
|
"group": "build",
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "new"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run Tests",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "./script/tests",
|
||||||
|
"group": "test",
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "new"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run Application (Docker)",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "docker-compose",
|
||||||
|
"args": ["-f", "docker-compose.dev.yml", "up"],
|
||||||
|
"group": "none",
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "new"
|
||||||
|
},
|
||||||
|
"problemMatcher": [],
|
||||||
|
"options": {
|
||||||
|
"envFile": "${workspaceFolder}/.env"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -131,6 +131,36 @@ The documentation for the build process can be found in the [GitHub Actions Work
|
|||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
### System Requirements
|
||||||
|
|
||||||
|
**System packages (Linux):**
|
||||||
|
- libmpv-dev (`sudo apt install libmpv-dev`)
|
||||||
|
- PulseAudio/PipeWire (`sudo apt install pulseaudio pipewire`)
|
||||||
|
- ALSA utils (`sudo apt install alsa-utils`)
|
||||||
|
|
||||||
|
**Python:**
|
||||||
|
- Python 3.11+ must be installed on your system (`python3 --version` should show 3.11+)
|
||||||
|
- On Ubuntu/Debian: `sudo apt install python3.11 python3.11-venv python3.11-dev`
|
||||||
|
|
||||||
|
### VS Code Setup
|
||||||
|
|
||||||
|
VS Code development uses a local Python virtual environment (`.venv/`):
|
||||||
|
|
||||||
|
1. Open workspace in VS Code
|
||||||
|
2. Accept Workspace Trust (bottom-left status bar)
|
||||||
|
3. Install recommended extensions when prompted:
|
||||||
|
- `ms-python.python` - Python language support
|
||||||
|
- `ms-python.vscode-pylance` - Python language server
|
||||||
|
- `kilo.kilocode` - Kilo AI assistant
|
||||||
|
4. **Terminal** → **New Terminal** (or `` Ctrl+` ``) - Opens integrated terminal (uses .venv when available)
|
||||||
|
5. Run `./script/setup --dev` to create `.venv` and install dev dependencies
|
||||||
|
6. VS Code automatically detects `.venv/bin/python` as the Python interpreter
|
||||||
|
|
||||||
|
**Available VS Code Tasks:**
|
||||||
|
- `Ctrl+Shift+B` - Run Setup or Linter
|
||||||
|
- `Ctrl+Shift+T` - Run Tests
|
||||||
|
- `Ctrl+Shift+P` → "Tasks: Run Task" - Show all tasks (Setup, Linter, Tests, Run App)
|
||||||
|
|
||||||
### Code Quality Checks
|
### Code Quality Checks
|
||||||
|
|
||||||
The project uses the following tools to ensure code quality:
|
The project uses the following tools to ensure code quality:
|
||||||
|
|||||||
+20
-18
@@ -145,26 +145,28 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
### Wait for PulseAudio
|
### Wait for PulseAudio
|
||||||
# Wait for PulseAudio to be available before starting the application
|
# Skip wait if SKIP_PULSE_AUDIO_WAIT is set (for local development)
|
||||||
CP_MAX_RETRIES=30
|
if [ "$SKIP_PULSE_AUDIO_WAIT" != "1" ]; then
|
||||||
CP_RETRY_DELAY=1
|
CP_MAX_RETRIES=30
|
||||||
### while maybe besser?
|
CP_RETRY_DELAY=1
|
||||||
echo "Checking PulseAudio service status..."
|
### while maybe besser?
|
||||||
for i in $(seq 1 $CP_MAX_RETRIES); do
|
echo "Checking PulseAudio service status..."
|
||||||
# Check if PulseAudio is running
|
for i in $(seq 1 $CP_MAX_RETRIES); do
|
||||||
if pactl info >/dev/null 2>&1; then
|
# Check if PulseAudio is running
|
||||||
echo "✅ PulseAudio is running"
|
if pactl info >/dev/null 2>&1; then
|
||||||
break
|
echo "✅ PulseAudio is running"
|
||||||
fi
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $i -eq $CP_MAX_RETRIES ]; then
|
if [ $i -eq $CP_MAX_RETRIES ]; then
|
||||||
echo "❌ PulseAudio did not start after $CP_MAX_RETRIES seconds"
|
echo "❌ PulseAudio did not start after $CP_MAX_RETRIES seconds"
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "⏳ PulseAudio not running yet, retrying in $CP_RETRY_DELAY s..."
|
echo "⏳ PulseAudio not running yet, retrying in $CP_RETRY_DELAY s..."
|
||||||
sleep $CP_RETRY_DELAY
|
sleep $CP_RETRY_DELAY
|
||||||
done
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
### Start application
|
### Start application
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+2
-2
@@ -22,7 +22,7 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
requires-python = ">=3.11.0"
|
requires-python = ">=3.11.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aioesphomeapi==45.3.1",
|
"aioesphomeapi==45.6.2",
|
||||||
"netifaces2==0.0.22",
|
"netifaces2==0.0.22",
|
||||||
"soundcard<1",
|
"soundcard<1",
|
||||||
"numpy>=2,<3",
|
"numpy>=2,<3",
|
||||||
@@ -32,7 +32,7 @@ dependencies = [
|
|||||||
"zeroconf<1",
|
"zeroconf<1",
|
||||||
"getmac<1",
|
"getmac<1",
|
||||||
"types-protobuf",
|
"types-protobuf",
|
||||||
"websockets==12",
|
"websockets==16.1.1",
|
||||||
"webrtc-noise-gain>=1,<2",
|
"webrtc-noise-gain>=1,<2",
|
||||||
]
|
]
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
|
|||||||
+44
-6
@@ -1,8 +1,10 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import argparse
|
import argparse
|
||||||
import subprocess
|
import subprocess
|
||||||
import venv
|
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import ctypes.util
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
_DIR = Path(__file__).parent
|
_DIR = Path(__file__).parent
|
||||||
@@ -15,10 +17,47 @@ parser.add_argument("--cxxflags", type=str, help="CXXFLAGS for compilation (defa
|
|||||||
parser.add_argument("--makeflags", type=str, help="MAKEFLAGS for compilation (default: -j1)")
|
parser.add_argument("--makeflags", type=str, help="MAKEFLAGS for compilation (default: -j1)")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Find Python 3.11+ interpreter
|
||||||
|
def find_python_311():
|
||||||
|
for candidate in ["python3.13", "python3.12", "python3.11"]:
|
||||||
|
path = shutil.which(candidate)
|
||||||
|
if path:
|
||||||
|
result = subprocess.run([path, "--version"], capture_output=True, text=True)
|
||||||
|
version_str = result.stdout.strip() or result.stderr.strip()
|
||||||
|
ver_parts = version_str.replace("Python ", "").split(".")
|
||||||
|
if len(ver_parts) >= 2 and int(ver_parts[0]) == 3 and int(ver_parts[1]) >= 11:
|
||||||
|
return path
|
||||||
|
return None
|
||||||
|
|
||||||
|
python_311_exe = find_python_311()
|
||||||
|
if not python_311_exe:
|
||||||
|
print("ERROR: Python 3.11+ is required but not found on this system.")
|
||||||
|
print(" Ubuntu/Debian: sudo apt install python3.11 python3.11-venv python3.11-dev")
|
||||||
|
print(" macOS: brew install python@3.11")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"Using Python: {python_311_exe}")
|
||||||
|
subprocess.run([python_311_exe, "--version"])
|
||||||
|
|
||||||
|
# Check system dependencies (warning only, CI installs them separately)
|
||||||
|
missing = []
|
||||||
|
try:
|
||||||
|
if not ctypes.util.find_library("mpv"):
|
||||||
|
missing.append("libmpv-dev")
|
||||||
|
if not ctypes.util.find_library("asound"):
|
||||||
|
missing.append("libasound2-dev")
|
||||||
|
except Exception:
|
||||||
|
pass # Ignore errors in environments without ctypes
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
print(f"\nWARNING: Missing system libraries (required for audio): {', '.join(missing)}")
|
||||||
|
print("For Docker/local dev: sudo apt install libmpv-dev pulseaudio pipewire alsa-utils")
|
||||||
|
|
||||||
# Create virtual environment
|
# Create virtual environment
|
||||||
builder = venv.EnvBuilder(with_pip=True)
|
if _VENV_DIR.exists():
|
||||||
context = builder.ensure_directories(_VENV_DIR)
|
shutil.rmtree(_VENV_DIR)
|
||||||
builder.create(_VENV_DIR)
|
|
||||||
|
subprocess.check_call([python_311_exe, "-m", "venv", str(_VENV_DIR), "--symlinks"])
|
||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
env = {}
|
env = {}
|
||||||
@@ -28,14 +67,13 @@ if args.makeflags:
|
|||||||
env["MAKEFLAGS"] = args.makeflags
|
env["MAKEFLAGS"] = args.makeflags
|
||||||
|
|
||||||
# Upgrade dependencies
|
# Upgrade dependencies
|
||||||
pip = [context.env_exe, "-m", "pip"]
|
pip = [str(_VENV_DIR / "bin" / "python"), "-m", "pip"]
|
||||||
subprocess.check_call(pip + ["install", "--upgrade", "pip"])
|
subprocess.check_call(pip + ["install", "--upgrade", "pip"])
|
||||||
subprocess.check_call(pip + ["install", "--upgrade", "setuptools", "wheel"])
|
subprocess.check_call(pip + ["install", "--upgrade", "setuptools", "wheel"])
|
||||||
|
|
||||||
# Install requirements
|
# Install requirements
|
||||||
subprocess.check_call(pip + ["install", "-e", str(_PROGRAM_DIR)])
|
subprocess.check_call(pip + ["install", "-e", str(_PROGRAM_DIR)])
|
||||||
|
|
||||||
|
|
||||||
# Install dev requirements
|
# Install dev requirements
|
||||||
if args.dev:
|
if args.dev:
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
|
|||||||
Reference in new issue
Block a user