yaffo 0.0.11__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.
- yaffo-0.0.11/LICENSE +21 -0
- yaffo-0.0.11/PKG-INFO +254 -0
- yaffo-0.0.11/README.md +188 -0
- yaffo-0.0.11/VERSION +1 -0
- yaffo-0.0.11/pyproject.toml +103 -0
- yaffo-0.0.11/setup.cfg +4 -0
- yaffo-0.0.11/yaffo/__init__.py +0 -0
- yaffo-0.0.11/yaffo/__main__.py +144 -0
- yaffo-0.0.11/yaffo/app.py +79 -0
- yaffo-0.0.11/yaffo/common.py +69 -0
- yaffo-0.0.11/yaffo/config.py +154 -0
- yaffo-0.0.11/yaffo/distance_units.py +72 -0
- yaffo-0.0.11/yaffo/i18n.py +183 -0
- yaffo-0.0.11/yaffo/logging_config.py +110 -0
- yaffo-0.0.11/yaffo/template_filters.py +144 -0
- yaffo-0.0.11/yaffo/themes.py +346 -0
- yaffo-0.0.11/yaffo/version.py +45 -0
- yaffo-0.0.11/yaffo.egg-info/PKG-INFO +254 -0
- yaffo-0.0.11/yaffo.egg-info/SOURCES.txt +20 -0
- yaffo-0.0.11/yaffo.egg-info/dependency_links.txt +1 -0
- yaffo-0.0.11/yaffo.egg-info/requires.txt +54 -0
- yaffo-0.0.11/yaffo.egg-info/top_level.txt +1 -0
yaffo-0.0.11/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jason Turan
|
|
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.
|
yaffo-0.0.11/PKG-INFO
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: yaffo
|
|
3
|
+
Version: 0.0.11
|
|
4
|
+
Summary: An app to organize photos
|
|
5
|
+
Author: Jason Turan
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Jason-Turan0/yaffo
|
|
8
|
+
Project-URL: Documentation, https://jason-turan0.github.io/yaffo/
|
|
9
|
+
Project-URL: Repository, https://github.com/Jason-Turan0/yaffo
|
|
10
|
+
Requires-Python: ~=3.13.0
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: anthropic
|
|
14
|
+
Requires-Dist: openai
|
|
15
|
+
Requires-Dist: blinker==1.9.0
|
|
16
|
+
Requires-Dist: click==8.3.0
|
|
17
|
+
Requires-Dist: croniter==6.2.2
|
|
18
|
+
Requires-Dist: cachetools==7.1.4
|
|
19
|
+
Requires-Dist: Flask==3.1.2
|
|
20
|
+
Requires-Dist: Flask-Babel==4.0.0
|
|
21
|
+
Requires-Dist: Flask-SQLAlchemy==3.1.1
|
|
22
|
+
Requires-Dist: ImageHash==4.3.2
|
|
23
|
+
Requires-Dist: insightface==1.0.1
|
|
24
|
+
Requires-Dist: onnxruntime==1.27.0
|
|
25
|
+
Requires-Dist: invoke==2.2.0
|
|
26
|
+
Requires-Dist: itsdangerous==2.2.0
|
|
27
|
+
Requires-Dist: Jinja2==3.1.6
|
|
28
|
+
Requires-Dist: joblib==1.5.2
|
|
29
|
+
Requires-Dist: jsonschema==4.23.0
|
|
30
|
+
Requires-Dist: keyring
|
|
31
|
+
Requires-Dist: MarkupSafe==3.0.2
|
|
32
|
+
Requires-Dist: numpy==2.2.6
|
|
33
|
+
Requires-Dist: opencv-python==4.12.0.88
|
|
34
|
+
Requires-Dist: pathspec==0.12.1
|
|
35
|
+
Requires-Dist: piexif==1.1.3
|
|
36
|
+
Requires-Dist: pillow==11.3.0
|
|
37
|
+
Requires-Dist: pillow_heif==1.1.0
|
|
38
|
+
Requires-Dist: platformdirs
|
|
39
|
+
Requires-Dist: pydash
|
|
40
|
+
Requires-Dist: PyWavelets==1.9.0
|
|
41
|
+
Requires-Dist: requests==2.32.3
|
|
42
|
+
Requires-Dist: rumps==0.4.0
|
|
43
|
+
Requires-Dist: scikit-learn==1.7.2
|
|
44
|
+
Requires-Dist: scipy==1.16.2
|
|
45
|
+
Requires-Dist: send2trash==1.8.3
|
|
46
|
+
Requires-Dist: setuptools==80.9.0
|
|
47
|
+
Requires-Dist: starlark-pyo3==2026.1
|
|
48
|
+
Requires-Dist: SQLAlchemy==2.0.43
|
|
49
|
+
Requires-Dist: threadpoolctl==3.6.0
|
|
50
|
+
Requires-Dist: tqdm==4.67.1
|
|
51
|
+
Requires-Dist: typing_extensions==4.15.0
|
|
52
|
+
Requires-Dist: waitress==3.0.2
|
|
53
|
+
Requires-Dist: watchdog==6.0.0
|
|
54
|
+
Requires-Dist: Werkzeug==3.1.3
|
|
55
|
+
Provides-Extra: dev
|
|
56
|
+
Requires-Dist: pytest==8.3.4; extra == "dev"
|
|
57
|
+
Requires-Dist: pytest-cov==6.0.0; extra == "dev"
|
|
58
|
+
Requires-Dist: deep-translator==1.11.4; extra == "dev"
|
|
59
|
+
Requires-Dist: snakeviz; extra == "dev"
|
|
60
|
+
Requires-Dist: pyinstaller==6.11.1; extra == "dev"
|
|
61
|
+
Requires-Dist: mypy==1.18.2; extra == "dev"
|
|
62
|
+
Requires-Dist: mypy_extensions==1.1.0; extra == "dev"
|
|
63
|
+
Provides-Extra: docs
|
|
64
|
+
Requires-Dist: mkdocs-material==9.6.21; extra == "docs"
|
|
65
|
+
Dynamic: license-file
|
|
66
|
+
|
|
67
|
+
# Yaffo - Photo Organizer
|
|
68
|
+
|
|
69
|
+
A Flask-based photo organization tool that uses EXIF metadata, face recognition, and duplicate detection to automatically organize and index photos.
|
|
70
|
+
|
|
71
|
+
## Features
|
|
72
|
+
|
|
73
|
+
- **Photo Organization**: Automatically organize and index photos by date using EXIF metadata
|
|
74
|
+
- **Face Detection & Recognition**: Detect, group, and tag faces by person using InsightFace (SCRFD detection + ArcFace embeddings, on ONNX Runtime)
|
|
75
|
+
- **Duplicate Detection**: Find duplicate photos using perceptual hashing
|
|
76
|
+
- **EXIF Metadata**: Extract and display photo metadata
|
|
77
|
+
- **Location Support**: Geocoding, reverse-geocoding, and time-correlation geotagging from neighboring photos
|
|
78
|
+
- **Auto-Labeling**: Offline zero-shot classification (CLIP) tags photos against a user vocabulary
|
|
79
|
+
- **Automations**: Scheduled and event-driven background behaviors (system-built and AI-generated)
|
|
80
|
+
- **AI Page Builder**: Build custom pages from AI-generated, sandboxed widgets over your own photo data
|
|
81
|
+
|
|
82
|
+
## Prerequisites
|
|
83
|
+
|
|
84
|
+
- Python 3.13+
|
|
85
|
+
- Node.js 18+ (for UI tests)
|
|
86
|
+
- ExifTool (see [EXIFTOOL_SETUP.md](EXIFTOOL_SETUP.md))
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
### 1. Clone and Setup
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
git clone <repository-url>
|
|
94
|
+
cd yaffo
|
|
95
|
+
|
|
96
|
+
# Create virtual environment
|
|
97
|
+
python -m venv venv
|
|
98
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
99
|
+
|
|
100
|
+
# Install dependencies
|
|
101
|
+
pip install -e .
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2. Install Git Hooks
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
./hooks/install.sh
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
This installs pre-commit hooks that prevent accidental commit of API keys and secrets.
|
|
111
|
+
|
|
112
|
+
### 3. Configure the Data Directory
|
|
113
|
+
|
|
114
|
+
`YAFFO_DATA_DIR` is the **root for the app's own state** — the SQLite databases
|
|
115
|
+
(`yaffo.db`, `yaffo-queue.db`), generated thumbnails, logs, and temp/trash. It
|
|
116
|
+
defaults to the OS user-data dir (e.g. `~/Library/Application Support/yaffo` on
|
|
117
|
+
macOS); set it to override:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
export YAFFO_DATA_DIR=/path/to/data
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Your actual **photo (media) directories** are configured separately, in the app's
|
|
124
|
+
**Settings** page — they aren't a fixed subfolder. The file sync / watcher scans
|
|
125
|
+
the configured media dirs and indexes what it finds.
|
|
126
|
+
|
|
127
|
+
### 4. Run the Application
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Start the Flask web app
|
|
131
|
+
flask run
|
|
132
|
+
|
|
133
|
+
# In a separate terminal, start the background task host (spawn worker pool)
|
|
134
|
+
python -m yaffo.taskq.host
|
|
135
|
+
|
|
136
|
+
# Or launch the whole local stack (Flask + task host + watcher) at once
|
|
137
|
+
inv app-local
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The app will be available at http://127.0.0.1:5000
|
|
141
|
+
|
|
142
|
+
## Project Structure
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
yaffo/
|
|
146
|
+
├── yaffo/ # Main application
|
|
147
|
+
│ ├── app.py # Flask app factory
|
|
148
|
+
│ ├── common.py # Configuration and paths
|
|
149
|
+
│ ├── db/ # Database models and repositories
|
|
150
|
+
│ ├── routes/ # API endpoints
|
|
151
|
+
│ ├── templates/ # Jinja2 templates
|
|
152
|
+
│ ├── static/ # CSS, JavaScript
|
|
153
|
+
│ ├── utils/ # Utility functions
|
|
154
|
+
│ ├── background_tasks/ # Background task definitions
|
|
155
|
+
│ ├── taskq/ # SQLite-backed task queue + spawn worker host
|
|
156
|
+
│ ├── site_agents/ # AI page builder: agent, model clients, tools, schemas
|
|
157
|
+
│ └── scripts/ # CLI tools + db/ (init_db, dev migrations)
|
|
158
|
+
├── tests/ # Python unit tests
|
|
159
|
+
├── yaffo_ui_tests/ # Playwright UI tests
|
|
160
|
+
├── hooks/ # Git hooks
|
|
161
|
+
├── docs/ # Design references (taskq, automations, page builder, video)
|
|
162
|
+
└── resources/ # ExifTool binaries + bundled face models
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Development
|
|
166
|
+
|
|
167
|
+
### Running Tests
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Python unit tests
|
|
171
|
+
pytest
|
|
172
|
+
|
|
173
|
+
# UI tests (requires app running)
|
|
174
|
+
cd yaffo_ui_tests
|
|
175
|
+
npm install
|
|
176
|
+
npm test
|
|
177
|
+
|
|
178
|
+
# UI tests in isolated environment
|
|
179
|
+
npm run test:isolated
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Database
|
|
183
|
+
|
|
184
|
+
The app uses SQLite. The database file is stored at `{YAFFO_DATA_DIR}/yaffo.db`.
|
|
185
|
+
|
|
186
|
+
To reset the database:
|
|
187
|
+
```bash
|
|
188
|
+
rm /path/to/data/yaffo.db
|
|
189
|
+
flask run # Will recreate on startup
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Background Tasks
|
|
193
|
+
|
|
194
|
+
Background tasks (photo indexing, face detection, etc.) run on a small
|
|
195
|
+
purpose-built queue (`yaffo/taskq`): a SQLite-durable queue plus a host process
|
|
196
|
+
that supervises a pool of `spawn`-started worker children, so CPU-bound native ML
|
|
197
|
+
inference (InsightFace/ONNX Runtime) runs in parallel, isolated, and
|
|
198
|
+
crash-contained. See `docs/development/task-queue.md`.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Start the task host with 4 workers, recycling each after 200 tasks
|
|
202
|
+
python -m yaffo.taskq.host --workers 4 --recycle 200
|
|
203
|
+
|
|
204
|
+
# Or via invoke
|
|
205
|
+
inv start-tasks --workers=4
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Tests drive tasks synchronously by setting `task_queue.immediate = True`.
|
|
209
|
+
|
|
210
|
+
## UI Testing
|
|
211
|
+
|
|
212
|
+
The project includes an AI-augmented UI testing framework. See [yaffo_ui_tests/README.md](yaffo_ui_tests/README.md) for details.
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
cd yaffo_ui_tests
|
|
216
|
+
|
|
217
|
+
# Install dependencies
|
|
218
|
+
npm install
|
|
219
|
+
npx playwright install
|
|
220
|
+
|
|
221
|
+
# Run tests against running app
|
|
222
|
+
npm test
|
|
223
|
+
|
|
224
|
+
# Run tests in isolated environment (recommended)
|
|
225
|
+
npm run test:isolated
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Environment Variables
|
|
229
|
+
|
|
230
|
+
| Variable | Description | Default |
|
|
231
|
+
|----------|-------------|----------------------------------|
|
|
232
|
+
| `YAFFO_DATA_DIR` | Root for app state (DBs, thumbnails, logs, temp) | OS user-data dir (e.g. `~/Library/Application Support/yaffo`); `inv` sets `~/Pictures` for dev |
|
|
233
|
+
| `FLASK_APP` | Flask application module | `yaffo.app:create_app` |
|
|
234
|
+
| `FLASK_ENV` | Flask environment | `development` |
|
|
235
|
+
| `ANTHROPIC_API_KEY` | Anthropic API key for the AI Page Builder and AI-generated automations. Optional override — the key is normally stored in the OS keychain (set via Settings); the env var wins when present (headless/CI). | (unset; keychain used) |
|
|
236
|
+
|
|
237
|
+
## Git Hooks
|
|
238
|
+
|
|
239
|
+
The project includes pre-commit hooks to prevent accidental commit of secrets:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Install hooks (run once after cloning)
|
|
243
|
+
./hooks/install.sh
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The pre-commit hook scans for:
|
|
247
|
+
- Anthropic API keys (`sk-ant-...`)
|
|
248
|
+
- OpenAI API keys (`sk-...`)
|
|
249
|
+
- Generic API key patterns
|
|
250
|
+
|
|
251
|
+
## Licenses
|
|
252
|
+
|
|
253
|
+
- [LICENSE](LICENSE)
|
|
254
|
+
- [THIRD_PARTY_LICENSES](THIRD_PARTY_LICENSES.txt)
|
yaffo-0.0.11/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Yaffo - Photo Organizer
|
|
2
|
+
|
|
3
|
+
A Flask-based photo organization tool that uses EXIF metadata, face recognition, and duplicate detection to automatically organize and index photos.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Photo Organization**: Automatically organize and index photos by date using EXIF metadata
|
|
8
|
+
- **Face Detection & Recognition**: Detect, group, and tag faces by person using InsightFace (SCRFD detection + ArcFace embeddings, on ONNX Runtime)
|
|
9
|
+
- **Duplicate Detection**: Find duplicate photos using perceptual hashing
|
|
10
|
+
- **EXIF Metadata**: Extract and display photo metadata
|
|
11
|
+
- **Location Support**: Geocoding, reverse-geocoding, and time-correlation geotagging from neighboring photos
|
|
12
|
+
- **Auto-Labeling**: Offline zero-shot classification (CLIP) tags photos against a user vocabulary
|
|
13
|
+
- **Automations**: Scheduled and event-driven background behaviors (system-built and AI-generated)
|
|
14
|
+
- **AI Page Builder**: Build custom pages from AI-generated, sandboxed widgets over your own photo data
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
- Python 3.13+
|
|
19
|
+
- Node.js 18+ (for UI tests)
|
|
20
|
+
- ExifTool (see [EXIFTOOL_SETUP.md](EXIFTOOL_SETUP.md))
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### 1. Clone and Setup
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
git clone <repository-url>
|
|
28
|
+
cd yaffo
|
|
29
|
+
|
|
30
|
+
# Create virtual environment
|
|
31
|
+
python -m venv venv
|
|
32
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
33
|
+
|
|
34
|
+
# Install dependencies
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Install Git Hooks
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
./hooks/install.sh
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This installs pre-commit hooks that prevent accidental commit of API keys and secrets.
|
|
45
|
+
|
|
46
|
+
### 3. Configure the Data Directory
|
|
47
|
+
|
|
48
|
+
`YAFFO_DATA_DIR` is the **root for the app's own state** — the SQLite databases
|
|
49
|
+
(`yaffo.db`, `yaffo-queue.db`), generated thumbnails, logs, and temp/trash. It
|
|
50
|
+
defaults to the OS user-data dir (e.g. `~/Library/Application Support/yaffo` on
|
|
51
|
+
macOS); set it to override:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export YAFFO_DATA_DIR=/path/to/data
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Your actual **photo (media) directories** are configured separately, in the app's
|
|
58
|
+
**Settings** page — they aren't a fixed subfolder. The file sync / watcher scans
|
|
59
|
+
the configured media dirs and indexes what it finds.
|
|
60
|
+
|
|
61
|
+
### 4. Run the Application
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Start the Flask web app
|
|
65
|
+
flask run
|
|
66
|
+
|
|
67
|
+
# In a separate terminal, start the background task host (spawn worker pool)
|
|
68
|
+
python -m yaffo.taskq.host
|
|
69
|
+
|
|
70
|
+
# Or launch the whole local stack (Flask + task host + watcher) at once
|
|
71
|
+
inv app-local
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The app will be available at http://127.0.0.1:5000
|
|
75
|
+
|
|
76
|
+
## Project Structure
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
yaffo/
|
|
80
|
+
├── yaffo/ # Main application
|
|
81
|
+
│ ├── app.py # Flask app factory
|
|
82
|
+
│ ├── common.py # Configuration and paths
|
|
83
|
+
│ ├── db/ # Database models and repositories
|
|
84
|
+
│ ├── routes/ # API endpoints
|
|
85
|
+
│ ├── templates/ # Jinja2 templates
|
|
86
|
+
│ ├── static/ # CSS, JavaScript
|
|
87
|
+
│ ├── utils/ # Utility functions
|
|
88
|
+
│ ├── background_tasks/ # Background task definitions
|
|
89
|
+
│ ├── taskq/ # SQLite-backed task queue + spawn worker host
|
|
90
|
+
│ ├── site_agents/ # AI page builder: agent, model clients, tools, schemas
|
|
91
|
+
│ └── scripts/ # CLI tools + db/ (init_db, dev migrations)
|
|
92
|
+
├── tests/ # Python unit tests
|
|
93
|
+
├── yaffo_ui_tests/ # Playwright UI tests
|
|
94
|
+
├── hooks/ # Git hooks
|
|
95
|
+
├── docs/ # Design references (taskq, automations, page builder, video)
|
|
96
|
+
└── resources/ # ExifTool binaries + bundled face models
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
### Running Tests
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Python unit tests
|
|
105
|
+
pytest
|
|
106
|
+
|
|
107
|
+
# UI tests (requires app running)
|
|
108
|
+
cd yaffo_ui_tests
|
|
109
|
+
npm install
|
|
110
|
+
npm test
|
|
111
|
+
|
|
112
|
+
# UI tests in isolated environment
|
|
113
|
+
npm run test:isolated
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Database
|
|
117
|
+
|
|
118
|
+
The app uses SQLite. The database file is stored at `{YAFFO_DATA_DIR}/yaffo.db`.
|
|
119
|
+
|
|
120
|
+
To reset the database:
|
|
121
|
+
```bash
|
|
122
|
+
rm /path/to/data/yaffo.db
|
|
123
|
+
flask run # Will recreate on startup
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Background Tasks
|
|
127
|
+
|
|
128
|
+
Background tasks (photo indexing, face detection, etc.) run on a small
|
|
129
|
+
purpose-built queue (`yaffo/taskq`): a SQLite-durable queue plus a host process
|
|
130
|
+
that supervises a pool of `spawn`-started worker children, so CPU-bound native ML
|
|
131
|
+
inference (InsightFace/ONNX Runtime) runs in parallel, isolated, and
|
|
132
|
+
crash-contained. See `docs/development/task-queue.md`.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Start the task host with 4 workers, recycling each after 200 tasks
|
|
136
|
+
python -m yaffo.taskq.host --workers 4 --recycle 200
|
|
137
|
+
|
|
138
|
+
# Or via invoke
|
|
139
|
+
inv start-tasks --workers=4
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Tests drive tasks synchronously by setting `task_queue.immediate = True`.
|
|
143
|
+
|
|
144
|
+
## UI Testing
|
|
145
|
+
|
|
146
|
+
The project includes an AI-augmented UI testing framework. See [yaffo_ui_tests/README.md](yaffo_ui_tests/README.md) for details.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
cd yaffo_ui_tests
|
|
150
|
+
|
|
151
|
+
# Install dependencies
|
|
152
|
+
npm install
|
|
153
|
+
npx playwright install
|
|
154
|
+
|
|
155
|
+
# Run tests against running app
|
|
156
|
+
npm test
|
|
157
|
+
|
|
158
|
+
# Run tests in isolated environment (recommended)
|
|
159
|
+
npm run test:isolated
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Environment Variables
|
|
163
|
+
|
|
164
|
+
| Variable | Description | Default |
|
|
165
|
+
|----------|-------------|----------------------------------|
|
|
166
|
+
| `YAFFO_DATA_DIR` | Root for app state (DBs, thumbnails, logs, temp) | OS user-data dir (e.g. `~/Library/Application Support/yaffo`); `inv` sets `~/Pictures` for dev |
|
|
167
|
+
| `FLASK_APP` | Flask application module | `yaffo.app:create_app` |
|
|
168
|
+
| `FLASK_ENV` | Flask environment | `development` |
|
|
169
|
+
| `ANTHROPIC_API_KEY` | Anthropic API key for the AI Page Builder and AI-generated automations. Optional override — the key is normally stored in the OS keychain (set via Settings); the env var wins when present (headless/CI). | (unset; keychain used) |
|
|
170
|
+
|
|
171
|
+
## Git Hooks
|
|
172
|
+
|
|
173
|
+
The project includes pre-commit hooks to prevent accidental commit of secrets:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Install hooks (run once after cloning)
|
|
177
|
+
./hooks/install.sh
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The pre-commit hook scans for:
|
|
181
|
+
- Anthropic API keys (`sk-ant-...`)
|
|
182
|
+
- OpenAI API keys (`sk-...`)
|
|
183
|
+
- Generic API key patterns
|
|
184
|
+
|
|
185
|
+
## Licenses
|
|
186
|
+
|
|
187
|
+
- [LICENSE](LICENSE)
|
|
188
|
+
- [THIRD_PARTY_LICENSES](THIRD_PARTY_LICENSES.txt)
|
yaffo-0.0.11/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.0.11
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
[tool.setuptools]
|
|
2
|
+
packages = ["yaffo"]
|
|
3
|
+
|
|
4
|
+
[tool.setuptools.dynamic]
|
|
5
|
+
version = {file = "VERSION"}
|
|
6
|
+
|
|
7
|
+
# Build configuration
|
|
8
|
+
[build-system]
|
|
9
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
10
|
+
build-backend = "setuptools.build_meta"
|
|
11
|
+
|
|
12
|
+
[project]
|
|
13
|
+
name = "yaffo"
|
|
14
|
+
dynamic = ["version"]
|
|
15
|
+
description = "An app to organize photos"
|
|
16
|
+
readme = "README.md"
|
|
17
|
+
authors = [{name = "Jason Turan"}]
|
|
18
|
+
license = "MIT"
|
|
19
|
+
license-files = ["LICENSE"]
|
|
20
|
+
requires-python = "~=3.13.0"
|
|
21
|
+
dependencies = [
|
|
22
|
+
"anthropic",
|
|
23
|
+
"openai",
|
|
24
|
+
"blinker==1.9.0",
|
|
25
|
+
"click==8.3.0",
|
|
26
|
+
"croniter==6.2.2",
|
|
27
|
+
"cachetools==7.1.4",
|
|
28
|
+
"Flask==3.1.2",
|
|
29
|
+
"Flask-Babel==4.0.0",
|
|
30
|
+
"Flask-SQLAlchemy==3.1.1",
|
|
31
|
+
"ImageHash==4.3.2",
|
|
32
|
+
"insightface==1.0.1",
|
|
33
|
+
"onnxruntime==1.27.0",
|
|
34
|
+
"invoke==2.2.0",
|
|
35
|
+
"itsdangerous==2.2.0",
|
|
36
|
+
"Jinja2==3.1.6",
|
|
37
|
+
"joblib==1.5.2",
|
|
38
|
+
"jsonschema==4.23.0",
|
|
39
|
+
"keyring",
|
|
40
|
+
"MarkupSafe==3.0.2",
|
|
41
|
+
"numpy==2.2.6",
|
|
42
|
+
"opencv-python==4.12.0.88",
|
|
43
|
+
"pathspec==0.12.1",
|
|
44
|
+
"piexif==1.1.3",
|
|
45
|
+
"pillow==11.3.0",
|
|
46
|
+
"pillow_heif==1.1.0",
|
|
47
|
+
"platformdirs",
|
|
48
|
+
"pydash",
|
|
49
|
+
"PyWavelets==1.9.0",
|
|
50
|
+
"requests==2.32.3",
|
|
51
|
+
"rumps==0.4.0",
|
|
52
|
+
"scikit-learn==1.7.2",
|
|
53
|
+
"scipy==1.16.2",
|
|
54
|
+
"send2trash==1.8.3",
|
|
55
|
+
"setuptools==80.9.0",
|
|
56
|
+
"starlark-pyo3==2026.1",
|
|
57
|
+
"SQLAlchemy==2.0.43",
|
|
58
|
+
"threadpoolctl==3.6.0",
|
|
59
|
+
"tqdm==4.67.1",
|
|
60
|
+
"typing_extensions==4.15.0",
|
|
61
|
+
"waitress==3.0.2",
|
|
62
|
+
"watchdog==6.0.0",
|
|
63
|
+
"Werkzeug==3.1.3",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[project.optional-dependencies]
|
|
67
|
+
dev = [
|
|
68
|
+
"pytest==8.3.4",
|
|
69
|
+
"pytest-cov==6.0.0",
|
|
70
|
+
"deep-translator==1.11.4",
|
|
71
|
+
"snakeviz",
|
|
72
|
+
"pyinstaller==6.11.1",
|
|
73
|
+
"mypy==1.18.2",
|
|
74
|
+
"mypy_extensions==1.1.0",
|
|
75
|
+
]
|
|
76
|
+
docs = [
|
|
77
|
+
"mkdocs-material==9.6.21",
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
[project.urls]
|
|
81
|
+
Homepage = "https://github.com/Jason-Turan0/yaffo"
|
|
82
|
+
Documentation = "https://jason-turan0.github.io/yaffo/"
|
|
83
|
+
Repository = "https://github.com/Jason-Turan0/yaffo"
|
|
84
|
+
|
|
85
|
+
[tool.coverage.run]
|
|
86
|
+
source = ["yaffo"]
|
|
87
|
+
branch = true
|
|
88
|
+
omit = [
|
|
89
|
+
# Operational scripts run by hand (CLI tools, DB migrations, seed data).
|
|
90
|
+
"yaffo/scripts/*",
|
|
91
|
+
# Process entry point: YAFFO_ROLE dispatch + rumps menubar launch glue.
|
|
92
|
+
"yaffo/__main__.py",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[tool.coverage.report]
|
|
96
|
+
show_missing = true
|
|
97
|
+
exclude_lines = [
|
|
98
|
+
"pragma: no cover",
|
|
99
|
+
"if __name__ == .__main__.:",
|
|
100
|
+
"if TYPE_CHECKING:",
|
|
101
|
+
"raise NotImplementedError",
|
|
102
|
+
"@(abc\\.)?abstractmethod",
|
|
103
|
+
]
|
yaffo-0.0.11/setup.cfg
ADDED
|
File without changes
|