cappv1 1.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cappv1-1.7.0/.editorconfig +12 -0
- cappv1-1.7.0/.env.example +33 -0
- cappv1-1.7.0/.git-blame-ignore-revs +3 -0
- cappv1-1.7.0/.github/ISSUE_TEMPLATE/bug_report.yml +64 -0
- cappv1-1.7.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- cappv1-1.7.0/.github/ISSUE_TEMPLATE/feature_request.yml +23 -0
- cappv1-1.7.0/.github/PULL_REQUEST_TEMPLATE.md +10 -0
- cappv1-1.7.0/.github/dependabot.yml +13 -0
- cappv1-1.7.0/.github/scripts/check_release_tag.py +38 -0
- cappv1-1.7.0/.github/workflows/ci.yml +57 -0
- cappv1-1.7.0/.github/workflows/links.yml +20 -0
- cappv1-1.7.0/.github/workflows/release.yml +68 -0
- cappv1-1.7.0/.gitignore +22 -0
- cappv1-1.7.0/.lycheeignore +10 -0
- cappv1-1.7.0/.pre-commit-config.yaml +29 -0
- cappv1-1.7.0/CHANGELOG.md +140 -0
- cappv1-1.7.0/CLAUDE.md +2 -0
- cappv1-1.7.0/CODE_OF_CONDUCT.md +5 -0
- cappv1-1.7.0/CONTRIBUTING.md +7 -0
- cappv1-1.7.0/LICENSE +21 -0
- cappv1-1.7.0/PKG-INFO +138 -0
- cappv1-1.7.0/README.md +93 -0
- cappv1-1.7.0/SECURITY.md +25 -0
- cappv1-1.7.0/docs/API.md +71 -0
- cappv1-1.7.0/docs/ARCHITECTURE.md +36 -0
- cappv1-1.7.0/docs/README.md +27 -0
- cappv1-1.7.0/docs/adr/0001-web-ui.md +25 -0
- cappv1-1.7.0/docs/configuration.md +21 -0
- cappv1-1.7.0/docs/development.md +64 -0
- cappv1-1.7.0/docs/images/terminal-commands.png +0 -0
- cappv1-1.7.0/docs/images/terminal-help.png +0 -0
- cappv1-1.7.0/docs/images/terminal-web-launch.png +0 -0
- cappv1-1.7.0/docs/images/terminal-welcome.png +0 -0
- cappv1-1.7.0/docs/images/web-files.png +0 -0
- cappv1-1.7.0/docs/images/web-health.png +0 -0
- cappv1-1.7.0/docs/images/web-overview.png +0 -0
- cappv1-1.7.0/docs/images/web-services.png +0 -0
- cappv1-1.7.0/docs/images/web-your-data.png +0 -0
- cappv1-1.7.0/docs/install.md +55 -0
- cappv1-1.7.0/docs/privacy.md +56 -0
- cappv1-1.7.0/docs/providers.md +61 -0
- cappv1-1.7.0/docs/scope.md +89 -0
- cappv1-1.7.0/docs/troubleshooting.md +15 -0
- cappv1-1.7.0/docs/usage.md +69 -0
- cappv1-1.7.0/docs/word-support.md +5 -0
- cappv1-1.7.0/examples/README.md +12 -0
- cappv1-1.7.0/examples/sample.pptx +0 -0
- cappv1-1.7.0/git-skills.md +91 -0
- cappv1-1.7.0/input/.gitkeep +0 -0
- cappv1-1.7.0/output/.gitkeep +0 -0
- cappv1-1.7.0/pyproject.toml +110 -0
- cappv1-1.7.0/src/cappv1/__init__.py +0 -0
- cappv1-1.7.0/src/cappv1/__main__.py +5 -0
- cappv1-1.7.0/src/cappv1/audit.py +377 -0
- cappv1-1.7.0/src/cappv1/audit_color.py +87 -0
- cappv1-1.7.0/src/cappv1/config.py +101 -0
- cappv1-1.7.0/src/cappv1/doctor.py +216 -0
- cappv1-1.7.0/src/cappv1/docx_check.py +234 -0
- cappv1-1.7.0/src/cappv1/docx_pipeline.py +300 -0
- cappv1-1.7.0/src/cappv1/docx_reader.py +358 -0
- cappv1-1.7.0/src/cappv1/docx_structure.py +210 -0
- cappv1-1.7.0/src/cappv1/events.py +31 -0
- cappv1-1.7.0/src/cappv1/home.py +23 -0
- cappv1-1.7.0/src/cappv1/image_filter.py +26 -0
- cappv1-1.7.0/src/cappv1/llm_client.py +315 -0
- cappv1-1.7.0/src/cappv1/llm_prompts.py +109 -0
- cappv1-1.7.0/src/cappv1/llm_providers.py +87 -0
- cappv1-1.7.0/src/cappv1/logsetup.py +63 -0
- cappv1-1.7.0/src/cappv1/main.py +77 -0
- cappv1-1.7.0/src/cappv1/models.py +147 -0
- cappv1-1.7.0/src/cappv1/outputs.py +79 -0
- cappv1-1.7.0/src/cappv1/pipeline.py +544 -0
- cappv1-1.7.0/src/cappv1/pptx_reader.py +458 -0
- cappv1-1.7.0/src/cappv1/services/__init__.py +7 -0
- cappv1-1.7.0/src/cappv1/services/audit.py +27 -0
- cappv1-1.7.0/src/cappv1/services/envfile.py +36 -0
- cappv1-1.7.0/src/cappv1/services/errors.py +9 -0
- cappv1-1.7.0/src/cappv1/services/files.py +191 -0
- cappv1-1.7.0/src/cappv1/services/health.py +80 -0
- cappv1-1.7.0/src/cappv1/services/models.py +86 -0
- cappv1-1.7.0/src/cappv1/services/runs.py +181 -0
- cappv1-1.7.0/src/cappv1/services/settings.py +143 -0
- cappv1-1.7.0/src/cappv1/services/storage.py +65 -0
- cappv1-1.7.0/src/cappv1/services/workspace.py +39 -0
- cappv1-1.7.0/src/cappv1/state.py +73 -0
- cappv1-1.7.0/src/cappv1/tui/__init__.py +1 -0
- cappv1-1.7.0/src/cappv1/tui/__main__.py +5 -0
- cappv1-1.7.0/src/cappv1/tui/anim.py +64 -0
- cappv1-1.7.0/src/cappv1/tui/commands.py +382 -0
- cappv1-1.7.0/src/cappv1/tui/common.py +31 -0
- cappv1-1.7.0/src/cappv1/tui/menu.py +73 -0
- cappv1-1.7.0/src/cappv1/tui/runview.py +187 -0
- cappv1-1.7.0/src/cappv1/tui/session.py +277 -0
- cappv1-1.7.0/src/cappv1/tui/setup_flow.py +211 -0
- cappv1-1.7.0/src/cappv1/tui/theme.py +19 -0
- cappv1-1.7.0/src/cappv1/version.py +4 -0
- cappv1-1.7.0/src/cappv1/web/__init__.py +5 -0
- cappv1-1.7.0/src/cappv1/web/api.py +263 -0
- cappv1-1.7.0/src/cappv1/web/changelog.py +79 -0
- cappv1-1.7.0/src/cappv1/web/pages/404.html +4 -0
- cappv1-1.7.0/src/cappv1/web/pages/about.html +27 -0
- cappv1-1.7.0/src/cappv1/web/pages/appearance.html +31 -0
- cappv1-1.7.0/src/cappv1/web/pages/changelog.html +4 -0
- cappv1-1.7.0/src/cappv1/web/pages/data.html +19 -0
- cappv1-1.7.0/src/cappv1/web/pages/faq.html +55 -0
- cappv1-1.7.0/src/cappv1/web/pages/files.html +57 -0
- cappv1-1.7.0/src/cappv1/web/pages/health.html +15 -0
- cappv1-1.7.0/src/cappv1/web/pages/how-it-works.html +44 -0
- cappv1-1.7.0/src/cappv1/web/pages/index.html +92 -0
- cappv1-1.7.0/src/cappv1/web/pages/privacy.html +78 -0
- cappv1-1.7.0/src/cappv1/web/pages/services.html +22 -0
- cappv1-1.7.0/src/cappv1/web/server.py +341 -0
- cappv1-1.7.0/src/cappv1/web/static/app.css +287 -0
- cappv1-1.7.0/src/cappv1/web/static/app.js +73 -0
- cappv1-1.7.0/src/cappv1/web/static/appearance.js +23 -0
- cappv1-1.7.0/src/cappv1/web/static/dashboard.js +77 -0
- cappv1-1.7.0/src/cappv1/web/static/data.js +34 -0
- cappv1-1.7.0/src/cappv1/web/static/favicon.svg +6 -0
- cappv1-1.7.0/src/cappv1/web/static/files.js +506 -0
- cappv1-1.7.0/src/cappv1/web/static/fonts/NOTICE.txt +3 -0
- cappv1-1.7.0/src/cappv1/web/static/fonts/ah-400.woff2 +0 -0
- cappv1-1.7.0/src/cappv1/web/static/fonts/ah-700.woff2 +0 -0
- cappv1-1.7.0/src/cappv1/web/static/health.js +31 -0
- cappv1-1.7.0/src/cappv1/web/static/icon-192.png +0 -0
- cappv1-1.7.0/src/cappv1/web/static/icon-512.png +0 -0
- cappv1-1.7.0/src/cappv1/web/static/manifest.webmanifest +15 -0
- cappv1-1.7.0/src/cappv1/web/static/services.js +122 -0
- cappv1-1.7.0/src/cappv1/web/static/shell.js +12 -0
- cappv1-1.7.0/src/cappv1/web/static/theme.js +8 -0
- cappv1-1.7.0/src/cappv1/web/templates/app.html +75 -0
- cappv1-1.7.0/tests/__init__.py +0 -0
- cappv1-1.7.0/tests/conftest.py +90 -0
- cappv1-1.7.0/tests/helpers.py +34 -0
- cappv1-1.7.0/tests/test_audit.py +137 -0
- cappv1-1.7.0/tests/test_docx.py +697 -0
- cappv1-1.7.0/tests/test_error_handling.py +158 -0
- cappv1-1.7.0/tests/test_existing_alt_text.py +134 -0
- cappv1-1.7.0/tests/test_files.py +62 -0
- cappv1-1.7.0/tests/test_health_and_models.py +54 -0
- cappv1-1.7.0/tests/test_history.py +94 -0
- cappv1-1.7.0/tests/test_only_alt_text_changes.py +52 -0
- cappv1-1.7.0/tests/test_runs.py +142 -0
- cappv1-1.7.0/tests/test_settings.py +57 -0
- cappv1-1.7.0/tests/test_web_api.py +302 -0
- cappv1-1.7.0/tests/test_web_command.py +33 -0
- cappv1-1.7.0/tests/test_web_pages.py +282 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Which AI service to use: openrouter, openai, anthropic, or ollama.
|
|
2
|
+
# ollama runs the model on this computer: free, offline, and nothing leaves it
|
|
3
|
+
# (see the README, "Private mode"). It needs no key.
|
|
4
|
+
# Leave PROVIDER out and the first key you fill in below is used.
|
|
5
|
+
PROVIDER=openrouter
|
|
6
|
+
|
|
7
|
+
# Fill in the key for the provider you chose (the others can stay blank).
|
|
8
|
+
OPENROUTER_API_KEY=your-key-here
|
|
9
|
+
OPENAI_API_KEY=
|
|
10
|
+
ANTHROPIC_API_KEY=
|
|
11
|
+
|
|
12
|
+
# MODEL / FALLBACK_MODEL must be models from the provider you chose.
|
|
13
|
+
# Leave MODEL blank to use that provider's default:
|
|
14
|
+
# openrouter: minimax/minimax-m3:free (fallback google/gemma-3-12b-it)
|
|
15
|
+
# openai: gpt-4o-mini
|
|
16
|
+
# anthropic: claude-haiku-5-5
|
|
17
|
+
# ollama: gemma3:4b (must be a vision model you've downloaded with: ollama pull <name>)
|
|
18
|
+
# FALLBACK_MODEL is tried when MODEL is unavailable, rate-limited, or out of credits.
|
|
19
|
+
# Avoid "reasoning" models here - they burn completion tokens on hidden thinking,
|
|
20
|
+
# which can starve short caption outputs.
|
|
21
|
+
MODEL=
|
|
22
|
+
FALLBACK_MODEL=
|
|
23
|
+
# Leave blank for the default: 4 at a time (1 for ollama).
|
|
24
|
+
CONCURRENCY=
|
|
25
|
+
MIN_IMAGE_SIZE_PX=40
|
|
26
|
+
# Alt text the author already wrote that is shorter than this is treated as unfinished
|
|
27
|
+
# and improved; longer text is kept unless the AI judges it inadequate. Blank = 30.
|
|
28
|
+
MIN_EXISTING_ALT_CHARS=
|
|
29
|
+
MAX_ALT_TEXT_CHARS=125
|
|
30
|
+
|
|
31
|
+
# Ollama only. Defaults shown; you normally don't need to touch these.
|
|
32
|
+
# OLLAMA_BASE_URL=http://localhost:11434
|
|
33
|
+
# REQUEST_TIMEOUT=300
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something doesn't work as expected
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: Please don't attach decks or documents with private content. A description or a small example file is enough.
|
|
8
|
+
- type: textarea
|
|
9
|
+
id: happened
|
|
10
|
+
attributes:
|
|
11
|
+
label: What happened
|
|
12
|
+
validations:
|
|
13
|
+
required: true
|
|
14
|
+
- type: textarea
|
|
15
|
+
id: expected
|
|
16
|
+
attributes:
|
|
17
|
+
label: What you expected
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: steps
|
|
22
|
+
attributes:
|
|
23
|
+
label: Steps to reproduce
|
|
24
|
+
placeholder: "1. ..."
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
- type: input
|
|
28
|
+
id: version
|
|
29
|
+
attributes:
|
|
30
|
+
label: cappv1 version
|
|
31
|
+
description: Run `cappv1 --version`.
|
|
32
|
+
validations:
|
|
33
|
+
required: true
|
|
34
|
+
- type: dropdown
|
|
35
|
+
id: provider
|
|
36
|
+
attributes:
|
|
37
|
+
label: AI service
|
|
38
|
+
options: [OpenRouter, OpenAI, Anthropic, "Ollama (on this computer)", Not sure]
|
|
39
|
+
validations:
|
|
40
|
+
required: true
|
|
41
|
+
- type: input
|
|
42
|
+
id: model
|
|
43
|
+
attributes:
|
|
44
|
+
label: Model
|
|
45
|
+
description: Shown by `/status`.
|
|
46
|
+
- type: dropdown
|
|
47
|
+
id: frontend
|
|
48
|
+
attributes:
|
|
49
|
+
label: Where did it happen
|
|
50
|
+
options: [Terminal, Browser, "Batch (cappv1 --batch)"]
|
|
51
|
+
validations:
|
|
52
|
+
required: true
|
|
53
|
+
- type: dropdown
|
|
54
|
+
id: os
|
|
55
|
+
attributes:
|
|
56
|
+
label: Operating system
|
|
57
|
+
options: [macOS, Linux, "Windows (WSL)", Other]
|
|
58
|
+
validations:
|
|
59
|
+
required: true
|
|
60
|
+
- type: dropdown
|
|
61
|
+
id: filetype
|
|
62
|
+
attributes:
|
|
63
|
+
label: File type
|
|
64
|
+
options: [".pptx", ".docx", Both, Not file related]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an improvement
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: What problem are you trying to solve?
|
|
9
|
+
validations:
|
|
10
|
+
required: true
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: wanted
|
|
13
|
+
attributes:
|
|
14
|
+
label: What would you like to happen?
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: alternatives
|
|
19
|
+
attributes:
|
|
20
|
+
label: Anything you considered instead?
|
|
21
|
+
- type: markdown
|
|
22
|
+
attributes:
|
|
23
|
+
value: cappv1 only writes alt text, plus a short list of visually inert fixes (see docs/scope.md). Requests that change how a file looks are out of scope.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## What and why
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences. -->
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] The tool still only writes alt text (see `docs/scope.md`)
|
|
8
|
+
- [ ] Tests added or updated, and `python -m pytest` passes
|
|
9
|
+
- [ ] Docs updated (`README.md`, `docs/`, in-app pages) and `CHANGELOG.md` has an entry
|
|
10
|
+
- [ ] If behavior about data changed (what is sent or stored), the Privacy page is updated
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Check that a release tag matches the package version, without running any project code.
|
|
2
|
+
|
|
3
|
+
check_release_tag.py v1.7.0 exit 0 if src/cappv1/version.py says 1.7.0, else exit 1 with a message
|
|
4
|
+
check_release_tag.py --print print the version
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
VERSION_FILE = Path(__file__).resolve().parents[2] / "src" / "cappv1" / "version.py"
|
|
12
|
+
PATTERN = re.compile(r'^VERSION\s*=\s*"(\d+\.\d+\.\d+)"\s*$', re.MULTILINE)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def read_version() -> str:
|
|
16
|
+
match = PATTERN.search(VERSION_FILE.read_text(encoding="utf-8"))
|
|
17
|
+
if not match:
|
|
18
|
+
sys.exit(f'{VERSION_FILE} has no line like VERSION = "1.2.3"; cannot read the package version.')
|
|
19
|
+
return match.group(1)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main(argv: list[str]) -> int:
|
|
23
|
+
if argv == ["--print"]:
|
|
24
|
+
print(read_version())
|
|
25
|
+
return 0
|
|
26
|
+
if len(argv) != 1:
|
|
27
|
+
print(__doc__, file=sys.stderr)
|
|
28
|
+
return 2
|
|
29
|
+
version = read_version()
|
|
30
|
+
if argv[0] != f"v{version}":
|
|
31
|
+
print(f"Tag {argv[0]} does not match the package version {version} (expected v{version}).", file=sys.stderr)
|
|
32
|
+
return 1
|
|
33
|
+
print(f"Tag {argv[0]} matches version {version}.")
|
|
34
|
+
return 0
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
if __name__ == "__main__":
|
|
38
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, "fix/**", "docs/**", "feature/**", "release/**"]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.12"
|
|
16
|
+
- run: pip install -e ".[dev]"
|
|
17
|
+
- run: ruff check src tests
|
|
18
|
+
- run: ruff format --check src tests
|
|
19
|
+
- run: mypy
|
|
20
|
+
|
|
21
|
+
test:
|
|
22
|
+
runs-on: ${{ matrix.os }}
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
os: [ubuntu-latest, macos-latest]
|
|
27
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: ${{ matrix.python-version }}
|
|
33
|
+
- run: pip install -e ".[dev]"
|
|
34
|
+
- run: python -m compileall -q src
|
|
35
|
+
- run: python -m pytest -q --cov=cappv1 --cov-report=term --cov-report=xml
|
|
36
|
+
|
|
37
|
+
package:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
- uses: actions/setup-python@v5
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.12"
|
|
44
|
+
- name: Test the release tag check (the same script the Release workflow runs)
|
|
45
|
+
run: |
|
|
46
|
+
tag="v$(python .github/scripts/check_release_tag.py --print)"
|
|
47
|
+
python .github/scripts/check_release_tag.py "$tag"
|
|
48
|
+
if python .github/scripts/check_release_tag.py v0.0.0; then echo "a wrong tag was accepted"; exit 1; fi
|
|
49
|
+
- run: pip install build twine
|
|
50
|
+
- run: python -m build
|
|
51
|
+
- run: twine check dist/*
|
|
52
|
+
- name: Install the built wheel and run it
|
|
53
|
+
run: |
|
|
54
|
+
pip install dist/*.whl
|
|
55
|
+
cd "$RUNNER_TEMP"
|
|
56
|
+
cappv1 --version
|
|
57
|
+
python -c "from cappv1.home import bundled_file; assert bundled_file('CHANGELOG.md') and bundled_file('.env.example')"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Links
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, "fix/**", "docs/**", "feature/**", "release/**"]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
markdown-links:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: lycheeverse/lychee-action@v2
|
|
14
|
+
with:
|
|
15
|
+
args: >-
|
|
16
|
+
--no-progress --include-fragments --max-retries 3 --accept '200..=299,429'
|
|
17
|
+
--exclude '^https?://(localhost|127\.0\.0\.1)' '**/*.md'
|
|
18
|
+
fail: true
|
|
19
|
+
env:
|
|
20
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Runs only when a version tag (vX.Y.Z) is pushed: build once, publish to PyPI
|
|
4
|
+
# with Trusted Publishing (no API token stored anywhere), then create the
|
|
5
|
+
# GitHub Release from the CHANGELOG section.
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags: ["v*"]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
- run: pip install build twine
|
|
19
|
+
- name: Check the tag matches the package version
|
|
20
|
+
run: python .github/scripts/check_release_tag.py "$GITHUB_REF_NAME"
|
|
21
|
+
- run: python -m build
|
|
22
|
+
- run: twine check dist/*
|
|
23
|
+
- uses: actions/upload-artifact@v4
|
|
24
|
+
with:
|
|
25
|
+
name: dist
|
|
26
|
+
path: dist/
|
|
27
|
+
|
|
28
|
+
publish-pypi:
|
|
29
|
+
needs: build
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
environment:
|
|
32
|
+
name: pypi
|
|
33
|
+
url: https://pypi.org/project/cappv1/
|
|
34
|
+
permissions:
|
|
35
|
+
id-token: write # lets PyPI verify this workflow run (OIDC); no token needed
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/download-artifact@v4
|
|
38
|
+
with:
|
|
39
|
+
name: dist
|
|
40
|
+
path: dist/
|
|
41
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
42
|
+
|
|
43
|
+
github-release:
|
|
44
|
+
needs: publish-pypi
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
permissions:
|
|
47
|
+
contents: write
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@v4
|
|
50
|
+
- uses: actions/download-artifact@v4
|
|
51
|
+
with:
|
|
52
|
+
name: dist
|
|
53
|
+
path: dist/
|
|
54
|
+
- name: Take the release notes from CHANGELOG.md
|
|
55
|
+
run: |
|
|
56
|
+
python3 - <<'PY' > notes.md
|
|
57
|
+
import os, re
|
|
58
|
+
version = os.environ["GITHUB_REF_NAME"].lstrip("v")
|
|
59
|
+
text = open("CHANGELOG.md", encoding="utf-8").read()
|
|
60
|
+
match = re.search(rf"^## {re.escape(version)}\b.*?\n(.*?)(?=^## |\Z)", text, re.S | re.M)
|
|
61
|
+
if not match:
|
|
62
|
+
raise SystemExit(f"No section for {version} in CHANGELOG.md")
|
|
63
|
+
print(match.group(1).strip())
|
|
64
|
+
PY
|
|
65
|
+
- uses: softprops/action-gh-release@v2
|
|
66
|
+
with:
|
|
67
|
+
body_path: notes.md
|
|
68
|
+
files: dist/*
|
cappv1-1.7.0/.gitignore
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.env
|
|
2
|
+
keys.txt
|
|
3
|
+
.DS_Store
|
|
4
|
+
.venv/
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.pyc
|
|
7
|
+
.state/
|
|
8
|
+
logs/
|
|
9
|
+
output/*
|
|
10
|
+
!output/.gitkeep
|
|
11
|
+
input/*
|
|
12
|
+
!input/.gitkeep
|
|
13
|
+
.idea/
|
|
14
|
+
.vscode/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
dist/
|
|
17
|
+
build/
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
coverage.xml
|
|
21
|
+
.mypy_cache/
|
|
22
|
+
.ruff_cache/
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Sites that block automated checkers or rate-limit GitHub's runners. The links stay in the docs.
|
|
2
|
+
^https://(www\.)?openai\.com/
|
|
3
|
+
^https://platform\.openai\.com/
|
|
4
|
+
^https://(www\.)?anthropic\.com/
|
|
5
|
+
^https://console\.anthropic\.com/
|
|
6
|
+
^https://platform\.claude\.com/
|
|
7
|
+
^https://openrouter\.ai/
|
|
8
|
+
^https://img\.shields\.io/
|
|
9
|
+
^https://codecov\.io/
|
|
10
|
+
^https://(www\.)?(anthology|blackboard)\.com/
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.6.9
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
9
|
+
rev: v5.0.0
|
|
10
|
+
hooks:
|
|
11
|
+
- id: trailing-whitespace
|
|
12
|
+
args: [--markdown-linebreak-ext=md]
|
|
13
|
+
- id: end-of-file-fixer
|
|
14
|
+
- id: check-yaml
|
|
15
|
+
- id: check-added-large-files
|
|
16
|
+
args: [--maxkb=500]
|
|
17
|
+
- id: detect-private-key
|
|
18
|
+
- repo: local
|
|
19
|
+
hooks:
|
|
20
|
+
- id: block-env-files
|
|
21
|
+
name: block committed .env files
|
|
22
|
+
entry: ".env holds API keys and must never be committed"
|
|
23
|
+
language: fail
|
|
24
|
+
files: '(^|/)\.env$'
|
|
25
|
+
- id: block-user-files
|
|
26
|
+
name: block decks and documents in input/ and output/
|
|
27
|
+
entry: "input/ and output/ hold your own files and must never be committed"
|
|
28
|
+
language: fail
|
|
29
|
+
files: '^(input|output|logs|\.state)/(?!\.gitkeep$)'
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to cappv1. Versions follow [Semantic Versioning](https://semver.org): MAJOR.MINOR.PATCH.
|
|
4
|
+
|
|
5
|
+
## 1.7.0 - 2026-10-30
|
|
6
|
+
|
|
7
|
+
### New
|
|
8
|
+
|
|
9
|
+
- Changelog page under Learn: a card per release with its date, grouped into new, improved and fixed. It is read from this file, so it is always current.
|
|
10
|
+
- Appearance page under Learn: choose the theme and an accent color (blue, teal, green, purple, rose or amber) for buttons and links, each checked for contrast in light and dark. Remembered in this browser. They are no longer in the sidebar.
|
|
11
|
+
- Install with `pipx install cappv1` (or `pipx install git+https://github.com/srsuiux/cappv1.git`). No cloning, symlink or virtual environment.
|
|
12
|
+
- cappv1 is published on PyPI, so `pipx install cappv1` works. Releases are built and uploaded by GitHub Actions when a version tag is pushed, using PyPI Trusted Publishing (no stored token).
|
|
13
|
+
- Install cappv1 from the browser as an app with its own window. It still needs to be running, and the address it prints, to connect.
|
|
14
|
+
- Each run keeps its finished copies in `output/<date>_<time>/` instead of replacing the last ones. Download or delete one copy or a whole run from the Files page, or in the terminal with `/history` and `/remove`; both see the change. Copies left loose in `output/` by older versions show as the oldest run.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **You will notice:** `cappv1 --batch` now runs in the foreground and prints the log, instead of starting a background job and returning. A script that relied on it returning at once should run `cappv1 --batch &` itself.
|
|
19
|
+
- **You will notice:** when cappv1 is installed with pipx, your settings (`.env`), `input`, `output`, saved progress and logs live in `~/cappv1` (or the folder in `CAPPV1_HOME`). A cloned copy still uses its own project folder, so nothing moves for existing users; if you switch from a clone to pipx, copy `.env` and the folders you want into `~/cappv1`.
|
|
20
|
+
|
|
21
|
+
### Improved
|
|
22
|
+
|
|
23
|
+
- The Python package is now `cappv1` (it was `src`), and `pyproject.toml` is the only place dependencies are listed. `python -m cappv1` also works.
|
|
24
|
+
- Checks on every push and pull request: ruff (lint and format), mypy, tests on Linux and macOS with Python 3.11 to 3.13 and coverage, a wheel build that is installed and run, and a link check for the docs. Dependabot keeps dependencies and Actions up to date, and `pre-commit` runs the same lint locally.
|
|
25
|
+
- Type checking: mypy now covers every module except a short list still being fixed (tracked in issue #1). Five modules were fixed in this release.
|
|
26
|
+
- A test runs the sample deck and checks that only alt text changed in the finished copy.
|
|
27
|
+
- The docs are split into focused pages under `docs/`, with an index.
|
|
28
|
+
- Every page now uses the full window width, in the same card layout as Files, with a shared page header.
|
|
29
|
+
- The window is fixed to the screen and only the content scrolls; the sidebar no longer folds.
|
|
30
|
+
- Files page: three panels (Current files, Past files, Finished copies), with sizes and dates on each card. Long processing notes moved into a ? on the card that shows them on hover, focus or tap.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- PowerPoint: finished decks open without the repair prompt and preview in Blackboard. The output is now the original file with only the slides that got alt text replaced, instead of a python-pptx re-save, which dropped embedded-object relationships with `Target="NULL"` and left slides pointing at nothing.
|
|
35
|
+
|
|
36
|
+
## 1.6.0 - 2026-10-29
|
|
37
|
+
|
|
38
|
+
### New
|
|
39
|
+
|
|
40
|
+
- Word: Blackboard Ally structure fixes. Heading levels are renumbered to start at Heading 1 with no gaps, using copies of the existing heading styles so nothing looks different; captions become Heading 1 in a document with no headings; empty headings stop being headings; every table gets a header row, including one-row boxes; the Title property is filled when empty or wrong; text that fails the 4.5:1 contrast check is darkened to 7:1 and noted (the one visible change). `python -m src.docx_check` checks a file against these rules.
|
|
41
|
+
- Word: a table's first row is now marked as its header (the Header Row box and Repeat as header row), which Blackboard Ally needs: a test file scored 100% with both and 68% with the box alone. Only plain tables: no table style, two or more rows and columns, text in every first-row cell, nothing merged. One visible effect, which the owner accepted: a table that runs onto a second page repeats its header row there. Applied even in documents where table descriptions are skipped.
|
|
42
|
+
- Word: embedded objects (for example Visio drawings) now get alt text, so an accessibility checker no longer sees them as undescribed pictures. The Privacy page now lists the text read from an embedded object.
|
|
43
|
+
- Files page: every file has a checkbox, with Select all and a count. "Improve accessibility" runs only the ticked files (`POST /runs` takes `files`). New files are ticked for you; previous files can be ticked too. "Remove all" empties the Current files list after an inline confirmation.
|
|
44
|
+
|
|
45
|
+
### Improved
|
|
46
|
+
|
|
47
|
+
- Sidebar: an icon beside every link, and a button that folds it to an icon rail (remembered in this browser). The theme choice is now three icon buttons (System, Light, Dark) with tooltips and screen-reader names.
|
|
48
|
+
- A damaged item no longer stops a file. A slide or document item that cannot be read (for example an embedded object whose part is missing, which used to end the file with "no relationship with key 'rId4'") is skipped, noted in the file's saved progress and the log, and the rest finishes. The Files page lists what was skipped under each file and marks the slide, and the terminal run view prints it. Applies to decks and Word documents.
|
|
49
|
+
- A run started from the browser now prints its log in the terminal that started cappv1 (`--web`, or `/web` in the terminal session).
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- Word: finished copies open in Word and preview in Blackboard. The output is now the original file with only `word/document.xml` replaced, instead of a python-docx re-save. Documents saved in Word compatibility mode 11 or 12 (what LibreOffice writes) get no table alt text, because Word refuses to open them with it; picture alt text is unaffected, and one note says to use Save As in Word first.
|
|
54
|
+
- Fixes a stray "null" shown on the finished-run card.
|
|
55
|
+
|
|
56
|
+
## 1.5.0 - 2026-10-29
|
|
57
|
+
|
|
58
|
+
### New
|
|
59
|
+
|
|
60
|
+
- Word documents (`.docx`): pictures and tables get alt text (`wp:docPr` description and `w:tblDescription`), through the terminal, the batch command and the web UI. Charts, SmartArt, embedded objects and headers/footers are not handled yet, and `/audit` stays decks-only.
|
|
61
|
+
|
|
62
|
+
### Improved
|
|
63
|
+
|
|
64
|
+
- The Files page shows a deck's slide tiles or a document's item chips, lists current files apart from previous (already finished) ones, and always shows the "replace alt text" option, off by default.
|
|
65
|
+
- Wording now describes cappv1 as improving accessibility (by writing alt text) for PowerPoint and Word.
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- API: the upload error code `not_pptx` is now `unsupported_file`; the audit of a Word file returns `audit_unsupported`. Run events carry `kind`.
|
|
70
|
+
|
|
71
|
+
## 1.4.3 - 2026-10-27
|
|
72
|
+
|
|
73
|
+
- On the Files page, a finished run shows every slide tile instead of clipping long decks.
|
|
74
|
+
|
|
75
|
+
## 1.4.2 - 2026-10-27
|
|
76
|
+
|
|
77
|
+
- The contrast audit now also checks text in table cells and in grouped shapes.
|
|
78
|
+
|
|
79
|
+
## 1.4.1 - 2026-10-27
|
|
80
|
+
|
|
81
|
+
- Fixes a syntax error that stopped cappv1 from installing on Python 3.11 (1.4.0 only works on 3.12 and newer, so use 1.4.1).
|
|
82
|
+
|
|
83
|
+
## 1.4.0 - 2026-10-27
|
|
84
|
+
|
|
85
|
+
- The Files page now puts a run front and center: a card at the top shows each slide lighting up and ticking off, what cappv1 is reading, and, when done, a clear "Your finished document is ready" card with Download, the saved location, and a note that the original is unchanged. The finished file is marked in the list too. Animations respect reduced-motion settings.
|
|
86
|
+
- The Files page has a Check accessibility button that shows the same report in the browser.
|
|
87
|
+
- New `/audit` command and `GET /api/v1/files/<name>/audit`: reports low-contrast text (WCAG AA, judged against the real backdrop including template shapes, patterns and gradients) and slides whose reading order doesn't follow the layout. Findings with the same cause are grouped across slides. It only reports; colors and layout are never changed.
|
|
88
|
+
|
|
89
|
+
## 1.3.0 - 2026-10-27
|
|
90
|
+
|
|
91
|
+
- A table's first row is now flagged as its header when that changes nothing visually (no table style, two or more rows, every first-row cell filled, nothing merged). This fixes Blackboard Ally's "tables are missing headers". Tables where it would change the look are left alone and the reason is logged.
|
|
92
|
+
- `skills.md` now allows a short list of visually inert accessibility fixes beyond alt text. Colors, including low contrast, are never changed.
|
|
93
|
+
|
|
94
|
+
## 1.2.0 - 2026-10-27
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
- **Local web interface** (`cappv1 --web`, or `/web` inside cappv1; `/init` now ends by offering the browser or the terminal). It is a small site served on this computer only:
|
|
98
|
+
- A front page that introduces cappv1 to new visitors and, once you're set up, leads with an Overview (next step, file counts, service, health, data) and moves the introduction below it.
|
|
99
|
+
- Files (add decks, run, live feed of the alt text being written, stop, download), Services (choose service, model and key), Health, and Your data (what is kept and where, with an erase button).
|
|
100
|
+
- How it works, Privacy, FAQ and About pages. The Privacy page states exactly what is sent to an AI service and what is stored, and a test keeps it in step with the code.
|
|
101
|
+
- Light, dark and system themes with a switch in the side panel, applied before the page paints; a test checks the contrast of every color pair in both themes. Keyboard, screen-reader and small-screen friendly; a favicon.
|
|
102
|
+
- **Web server and API** (`src/web`, standard library only, documented in `docs/API.md`): bound to this computer, per-launch token, Host check, strict content policy, size-limited validated uploads, live progress over Server-Sent Events that resumes after a dropped connection.
|
|
103
|
+
- Each service says what it does with your slides and links to its privacy policy; saved API keys can be removed from Services.
|
|
104
|
+
- A new `alt_written` progress event carrying each piece of alt text as it is settled.
|
|
105
|
+
- `src/services/`, a service layer between the engine and the screens, with a pytest suite and GitHub Actions CI.
|
|
106
|
+
- `CAPPV1_HOME` to keep settings, decks and progress in a folder of your choice.
|
|
107
|
+
- Project files: `SECURITY.md`, `CODE_OF_CONDUCT.md`, issue and pull request templates, `.editorconfig`, `pyproject.toml`, and `docs/ARCHITECTURE.md`.
|
|
108
|
+
|
|
109
|
+
### Fixed
|
|
110
|
+
- Pictures are matched by their exact bytes. Before, flat or near-identical images (for example two solid-color pictures) could share one caption.
|
|
111
|
+
- A picture whose "alt text" is only its file name (`image1.png`, filled in by some tools) is no longer treated as text the author wrote.
|
|
112
|
+
- The terminal toolbar no longer re-reads every deck on each keystroke.
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
- No more colored bars down one side of panels, menu items or messages; they use whole, subtle borders instead. The three steps and other boxes follow the same paper-like style.
|
|
116
|
+
- `cappv1` is now the only command in the shell. `cappv1 doctor`, `models`, `clean`, `init` and `start` are refused; use `/doctor`, `/models`, `/clean` and the others inside the session. `cappv1 --batch` remains for scripts, plus `--version` and `--help`.
|
|
117
|
+
- `/init` shows the current service and model first and lets you keep it, change only the model, or switch service, instead of asking everything again. `/models` goes straight to the service and model pickers. Both are listed in `/help` and in the `/` menu.
|
|
118
|
+
|
|
119
|
+
## 1.1.0 - 2026-10-26
|
|
120
|
+
|
|
121
|
+
### Added
|
|
122
|
+
- Interactive terminal session (`cappv1`, `cappv1 start`, `cappv1 init`): slash commands with completion, arrow-key menus, drag-and-drop of `.pptx` files, and a live run view whose animation follows what is happening (picture, chart, table, diagram, saving).
|
|
123
|
+
- Local, private captioning with Ollama (`PROVIDER=ollama`); nothing leaves the computer, and a remote Ollama address is refused unless explicitly allowed.
|
|
124
|
+
- `/models`: one flow to switch AI service and model, including free and paid OpenRouter vision models with prices (reaches DeepSeek, Google, OpenAI and more).
|
|
125
|
+
- Alt text that authors already wrote is built on, not replaced: short text is improved, adequate text is kept as written. `/run --force` replaces it after confirmation.
|
|
126
|
+
- Edited decks are recognised by content hash and reprocessed; unchanged items reuse saved captions. Unchanged files are reported as already captioned.
|
|
127
|
+
|
|
128
|
+
### Fixed
|
|
129
|
+
- Resuming after a crash lost the captions of slides finished before the crash.
|
|
130
|
+
- One unreadable progress file stopped the whole run; it is now set aside.
|
|
131
|
+
- Output and progress files are written atomically, so a crash cannot leave a half-written file.
|
|
132
|
+
- An edited deck with the same filename was skipped as "already complete".
|
|
133
|
+
|
|
134
|
+
### Changed
|
|
135
|
+
- `cappv1 start` opens the interactive session. The old background behavior is `cappv1 start --batch` (also used automatically when there is no terminal).
|
|
136
|
+
|
|
137
|
+
## 1.0.0 - 2026-10-26 (tag `engine-cappv1-1.0.0`)
|
|
138
|
+
|
|
139
|
+
- Terminal engine: alt text for pictures, tables, charts, SmartArt and embedded objects; invisible shapes marked decorative; files processed in sequence and resumable.
|
|
140
|
+
- Providers: OpenRouter, OpenAI, Anthropic, and Ollama.
|
cappv1-1.7.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
This project follows the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/). In short: be respectful, assume good intent, give and accept feedback graciously, and keep discussion focused on the work. Harassment of any kind isn't tolerated.
|
|
4
|
+
|
|
5
|
+
To report a concern, contact the maintainer through the repository's GitHub profile. Reports are handled privately.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Contributing to cappv1
|
|
2
|
+
|
|
3
|
+
cappv1 is open source under the [MIT License](LICENSE). Issues and pull requests are welcome.
|
|
4
|
+
|
|
5
|
+
**The ground rule:** the tool never changes how a slide looks. It writes alt text, plus a short list of visually inert accessibility fixes, and every change must keep that true. Read [`docs/scope.md`](docs/scope.md) first.
|
|
6
|
+
|
|
7
|
+
Everything else (branches, layers, tests, the Web pages and privacy rule, commits, versions and releases, and what never to commit) is in [`docs/development.md`](docs/development.md). Security problems go to [`SECURITY.md`](SECURITY.md). LLM agents also read `git-skills.md`, which `CLAUDE.md` loads automatically.
|
cappv1-1.7.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 sundar raj sharma
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|