tag-keeper 0.1.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.
- tag_keeper-0.1.0/.gitignore +14 -0
- tag_keeper-0.1.0/CHANGELOG.md +49 -0
- tag_keeper-0.1.0/LICENSE +21 -0
- tag_keeper-0.1.0/PKG-INFO +310 -0
- tag_keeper-0.1.0/README.ja.md +243 -0
- tag_keeper-0.1.0/README.md +276 -0
- tag_keeper-0.1.0/pyproject.toml +73 -0
- tag_keeper-0.1.0/tag_keeper/__init__.py +3 -0
- tag_keeper-0.1.0/tag_keeper/__main__.py +5 -0
- tag_keeper-0.1.0/tag_keeper/catalog.py +170 -0
- tag_keeper-0.1.0/tag_keeper/cli.py +711 -0
- tag_keeper-0.1.0/tag_keeper/config.py +269 -0
- tag_keeper-0.1.0/tag_keeper/decisions.py +175 -0
- tag_keeper-0.1.0/tag_keeper/extract.py +121 -0
- tag_keeper-0.1.0/tag_keeper/hashing.py +123 -0
- tag_keeper-0.1.0/tag_keeper/history.py +212 -0
- tag_keeper-0.1.0/tag_keeper/jobs.py +260 -0
- tag_keeper-0.1.0/tag_keeper/organize.py +759 -0
- tag_keeper-0.1.0/tag_keeper/plan.py +1050 -0
- tag_keeper-0.1.0/tag_keeper/report.py +287 -0
- tag_keeper-0.1.0/tag_keeper/rules.py +218 -0
- tag_keeper-0.1.0/tag_keeper/scan.py +323 -0
- tag_keeper-0.1.0/tag_keeper/suggest_queue.py +194 -0
- tag_keeper-0.1.0/tag_keeper/syncguard.py +234 -0
- tag_keeper-0.1.0/tag_keeper/tags.py +254 -0
- tag_keeper-0.1.0/tag_keeper/textindex.py +53 -0
- tag_keeper-0.1.0/tag_keeper/web/__init__.py +1 -0
- tag_keeper-0.1.0/tag_keeper/web/auth.py +98 -0
- tag_keeper-0.1.0/tag_keeper/web/files.py +87 -0
- tag_keeper-0.1.0/tag_keeper/web/server.py +1135 -0
- tag_keeper-0.1.0/tag_keeper/web/static/app.js +582 -0
- tag_keeper-0.1.0/tag_keeper/web/static/index.html +38 -0
- tag_keeper-0.1.0/tag_keeper/web/static/pages.js +608 -0
- tag_keeper-0.1.0/tag_keeper/web/static/style.css +218 -0
- tag_keeper-0.1.0/tests/conftest.py +50 -0
- tag_keeper-0.1.0/tests/test_config_and_cli.py +95 -0
- tag_keeper-0.1.0/tests/test_decisions.py +113 -0
- tag_keeper-0.1.0/tests/test_hashing.py +63 -0
- tag_keeper-0.1.0/tests/test_history.py +63 -0
- tag_keeper-0.1.0/tests/test_organize.py +149 -0
- tag_keeper-0.1.0/tests/test_plan.py +337 -0
- tag_keeper-0.1.0/tests/test_report.py +143 -0
- tag_keeper-0.1.0/tests/test_rules.py +70 -0
- tag_keeper-0.1.0/tests/test_scan.py +189 -0
- tag_keeper-0.1.0/tests/test_syncguard.py +173 -0
- tag_keeper-0.1.0/tests/test_tags.py +78 -0
- tag_keeper-0.1.0/tests/test_web.py +252 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-10-08
|
|
9
|
+
|
|
10
|
+
First release. The web UI and messages are in Japanese.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Inventory.** `scan` walks a root read-only into an SQLite catalog kept outside the
|
|
15
|
+
tree, tracking renames and moves by inode. Mass disappearances are held until a second
|
|
16
|
+
scan confirms them; a missing or empty root aborts the scan. `hash` computes SHA-256
|
|
17
|
+
incrementally.
|
|
18
|
+
- **Hygiene report.** `report` lists application data in synced folders, rebuildable
|
|
19
|
+
artifacts, VM images, installers, temporary files, Office lock files, sync conflict copies
|
|
20
|
+
(only when the original is next to them; differing copies are marked for review), empty
|
|
21
|
+
files and folders, and duplicates confirmed by hash.
|
|
22
|
+
- **Tidy-up plans.** `plan` writes candidates to an editable TOML file; `apply` previews,
|
|
23
|
+
then moves items to a quarantine folder outside the tree or renames and moves them inside
|
|
24
|
+
it, skipping anything that changed since the plan was written, with snapper pre/post
|
|
25
|
+
snapshots around the run. Every move is journaled and `undo` puts it back without
|
|
26
|
+
overwriting anything new. Destinations are checked against OneDrive's naming rules.
|
|
27
|
+
- **Big deletions without stopping the sync client.** With `sync_client = "onedrive"`, a
|
|
28
|
+
plan that removes a folder above the OneDrive client's `classify_as_big_delete` threshold
|
|
29
|
+
stops the resident sync, reflects the deletions with one `onedrive --sync` whose threshold
|
|
30
|
+
is raised just enough (never `--force`), and starts it again. A failed reflection leaves
|
|
31
|
+
the sync stopped, is journaled, and can be retried or abandoned (`tag-keeper sync`).
|
|
32
|
+
- **Web UI** (`serve`): roots, report, plans (untick to skip), check, apply and undo, with
|
|
33
|
+
background jobs and a progress panel. Loopback by default; other addresses require HTTP
|
|
34
|
+
Basic auth, and writes must be same-origin.
|
|
35
|
+
- **File browser** with in-page previews for types that cannot run scripts; paths never
|
|
36
|
+
leave the root.
|
|
37
|
+
- **Tags** on files and folders, inherited from folders, kept in append-only JSONL logs one
|
|
38
|
+
per machine, and following moves seen by `scan` or made by plans.
|
|
39
|
+
- **Version history** from btrfs snapshots via btrfs-timeline: versions of a file, a folder
|
|
40
|
+
at any snapshot, restoring an old version beside the current one. Moves are recorded, so
|
|
41
|
+
history continues across them.
|
|
42
|
+
- **Inbox suggestions.** Files in folders named like `tmp` or `*未整理*` are listed flat;
|
|
43
|
+
picking one asks an ollama model (local or cloud) for a `YYYYMMDD_title` name, destination
|
|
44
|
+
folders among existing ones and tags, usually within seconds. Accepted suggestions run as
|
|
45
|
+
one plan of renames and moves. Files elsewhere get suggestions on request.
|
|
46
|
+
- **Decision log.** Accepted suggestions, tag accept and reject, and undone plans are
|
|
47
|
+
appended per machine; the closest past decisions are given to the model as examples.
|
|
48
|
+
|
|
49
|
+
[0.1.0]: https://github.com/akivajp/tag-keeper/releases/tag/v0.1.0
|
tag_keeper-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Akiva Miura
|
|
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.
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: tag-keeper
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Tag, search and tidy your existing file trees from the outside, without moving a file
|
|
5
|
+
Project-URL: Homepage, https://github.com/akivajp/tag-keeper
|
|
6
|
+
Project-URL: Repository, https://github.com/akivajp/tag-keeper
|
|
7
|
+
Project-URL: Issues, https://github.com/akivajp/tag-keeper/issues
|
|
8
|
+
Author-email: Akiva Miura <akiva.miura@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: catalog,cloud-drive,file-management,onedrive,pcloud,self-hosted,tagging
|
|
12
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Framework :: Bottle
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Classifier: Intended Audience :: System Administrators
|
|
18
|
+
Classifier: Natural Language :: Japanese
|
|
19
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: System :: Filesystems
|
|
25
|
+
Classifier: Topic :: Utilities
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Requires-Dist: bottle>=0.12
|
|
28
|
+
Requires-Dist: btrfs-timeline>=0.8.4
|
|
29
|
+
Requires-Dist: rich>=13
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: webtest>=3.0; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# tag-keeper
|
|
36
|
+
|
|
37
|
+
Tag, search and tidy your existing file trees from the outside — without moving a file.
|
|
38
|
+
|
|
39
|
+
[日本語版 README はこちら](README.ja.md)
|
|
40
|
+
|
|
41
|
+
> **Status: pre-alpha.** What works today: the inventory (scanning, content hashing, a
|
|
42
|
+
> hygiene report), cleaning up with plans you approve (with undo), a file browser with tags
|
|
43
|
+
> and version history from btrfs snapshots, and name and folder suggestions for your inbox
|
|
44
|
+
> folders from a local model. Search and the rest of tagging come next. See [Roadmap](#roadmap).
|
|
45
|
+
|
|
46
|
+
## Why
|
|
47
|
+
|
|
48
|
+
Most document managers take ownership of your files: they ingest them into their own
|
|
49
|
+
storage and lay them out flat. That is the opposite of how a cloud drive is actually
|
|
50
|
+
used. Its folders already mean something — a numbered project folder, a source code
|
|
51
|
+
repository with its own layout, a year/month archive — and that meaning lives in each
|
|
52
|
+
folder, not in one global category tree.
|
|
53
|
+
|
|
54
|
+
tag-keeper leaves the tree alone. It keeps its own catalog next to the tree, and from
|
|
55
|
+
there it helps you keep the tree clean:
|
|
56
|
+
|
|
57
|
+
- **It never takes ownership.** No copying, renaming or converting. You keep using your
|
|
58
|
+
file manager and shell as before.
|
|
59
|
+
- **It follows what you do outside it.** Files you move or rename keep their records.
|
|
60
|
+
- **Changes are proposals.** Anything that would move a file is written down as a plan,
|
|
61
|
+
shown first, and only runs once you approve it. Nothing is ever deleted: files go to a
|
|
62
|
+
quarantine folder, and every plan can be undone.
|
|
63
|
+
|
|
64
|
+
## What it does today
|
|
65
|
+
|
|
66
|
+
```console
|
|
67
|
+
$ tag-keeper scan ~/CloudSync/OneDrive # read-only walk; updates the catalog
|
|
68
|
+
$ tag-keeper hash ~/CloudSync/OneDrive # SHA-256 of files that changed since last time
|
|
69
|
+
$ tag-keeper report ~/CloudSync/OneDrive # what is probably not worth keeping in the cloud
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- **scan** records path, size, mtime and inode of every file and folder. Renames and
|
|
73
|
+
moves are tracked by inode, so a moved file keeps its row (and its hash).
|
|
74
|
+
- **Safety valve:** if a large share of files vanishes at once — an unmounted drive, a
|
|
75
|
+
sync client accident — the deletions are *held*, not recorded. They are recorded only
|
|
76
|
+
if they are still missing on the next scan (or with `--accept-missing`).
|
|
77
|
+
- A root that is missing or empty aborts the scan instead of looking like "everything
|
|
78
|
+
was deleted". Folders that cannot be read are not treated as gone either.
|
|
79
|
+
- **hash** computes SHA-256 only for files that are new or changed, with a progress bar
|
|
80
|
+
and ETA. A file that changes while being hashed is skipped.
|
|
81
|
+
- **report** lists candidates by category, with sizes and examples:
|
|
82
|
+
- application data that slipped into a synced folder (game data, caches) — reported
|
|
83
|
+
once per folder, at the deepest folder that matches, so it never swallows your own
|
|
84
|
+
documents next to it
|
|
85
|
+
- rebuildable artifacts (`node_modules`, `__pycache__`, …), VM disk images, installers
|
|
86
|
+
and disk images, temporary files and Office lock files
|
|
87
|
+
- sync conflict copies (OneDrive for Linux `-safeBackup-`, pCloud `[conflicted]`,
|
|
88
|
+
rclone bisync `.conflict1`, device-name suffixes, `(1)` copies) — only when the
|
|
89
|
+
original sits next to it, since a lone "copy" may be the only version. Copies whose
|
|
90
|
+
content differs from the original are marked as needing review
|
|
91
|
+
- empty files and folders
|
|
92
|
+
- exact duplicates, confirmed by hash (never guessed from size)
|
|
93
|
+
|
|
94
|
+
The catalog is an SQLite file outside the tree (`~/.local/share/tag-keeper/catalog.db` by
|
|
95
|
+
default). None of these commands writes into the tree.
|
|
96
|
+
|
|
97
|
+
### Cleaning up with a plan
|
|
98
|
+
|
|
99
|
+
```console
|
|
100
|
+
$ tag-keeper plan onedrive # write the report's candidates to a plan file
|
|
101
|
+
$ $EDITOR ~/.local/share/tag-keeper/plans/<plan-id>.toml # delete the lines you want to keep
|
|
102
|
+
$ tag-keeper apply <plan file> # preview only
|
|
103
|
+
$ tag-keeper apply <plan file> --yes # move them to the quarantine folder
|
|
104
|
+
$ tag-keeper undo <plan-id> --yes # put everything back
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- **plan** writes one line per item, grouped by category. `--category` limits it to some
|
|
108
|
+
categories (`app-data`, `vm-image`, `conflict`, …). Candidates that need review stay out
|
|
109
|
+
unless you pass `--include-review`.
|
|
110
|
+
- **apply** previews by default. With `--yes` it moves each item, by rename, to
|
|
111
|
+
`<quarantine_dir>/<plan-id>/` under its original relative path. Right before each move
|
|
112
|
+
it checks that the item has not changed since the plan was written (inode, size,
|
|
113
|
+
modification time, and for folders the file count and total size); changed items are
|
|
114
|
+
skipped and reported.
|
|
115
|
+
- With `snapper_config` set, a snapper *pre* snapshot is taken before the run and a *post*
|
|
116
|
+
snapshot after it. If the pre snapshot fails, nothing is moved.
|
|
117
|
+
- Every move is appended to a journal (`~/.local/share/tag-keeper/journal/<plan-id>.jsonl`).
|
|
118
|
+
**undo** reads the journal and moves items back; it never overwrites something that has
|
|
119
|
+
appeared at the original path since.
|
|
120
|
+
- The catalog is updated as items move, so the next scan does not mistake a large
|
|
121
|
+
quarantine for a mass disappearance.
|
|
122
|
+
- Items leave the cloud when the sync client notices they are gone, but they stay on this
|
|
123
|
+
disk until you empty the quarantine folder yourself.
|
|
124
|
+
|
|
125
|
+
### Big deletions without stopping your sync client
|
|
126
|
+
|
|
127
|
+
The [OneDrive client for Linux](https://github.com/abraunegg/onedrive) treats the local
|
|
128
|
+
removal of a folder with many children (`classify_as_big_delete`, 1000 by default) as an
|
|
129
|
+
accident: it refuses to sync and exits. Run under systemd, it keeps exiting on every
|
|
130
|
+
restart, so syncing silently stops. When *you* approve a big deletion, tag-keeper
|
|
131
|
+
coordinates with the client instead (set `sync_client = "onedrive"` on the root):
|
|
132
|
+
|
|
133
|
+
1. stop the resident sync (`systemctl --user stop onedrive.service`),
|
|
134
|
+
2. quarantine the items,
|
|
135
|
+
3. run one `onedrive --sync` with the threshold raised just above the largest folder in this
|
|
136
|
+
plan — not `--force`, which would also let unrelated accidents through,
|
|
137
|
+
4. start the resident sync again.
|
|
138
|
+
|
|
139
|
+
If step 3 fails, the resident sync is left stopped (restarting it would only exit again),
|
|
140
|
+
the failure is journaled, and the web UI and `tag-keeper sync <plan-id> --retry` offer to
|
|
141
|
+
try again. Small plans are left to the running client as usual.
|
|
142
|
+
|
|
143
|
+
## Web UI
|
|
144
|
+
|
|
145
|
+
```console
|
|
146
|
+
$ tag-keeper serve # http://127.0.0.1:8090/
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Everything above can be done in the browser: refresh a root (scan and hash), read the
|
|
150
|
+
report, create a plan, untick what you want to keep, check it, run it and undo it. Long
|
|
151
|
+
operations run in the background, and a panel at the bottom shows each step, a progress
|
|
152
|
+
bar, speed, time remaining and the latest log lines. It works on a phone too.
|
|
153
|
+
|
|
154
|
+
- Only loopback is served by default. To listen elsewhere (for example on a Tailscale
|
|
155
|
+
address), give credentials for HTTP Basic auth with `--auth-file` (one line,
|
|
156
|
+
`user:password`) or `TAG_KEEPER_AUTH`; without them a non-loopback address is refused
|
|
157
|
+
unless you pass `--allow-no-auth`. Basic auth is not encrypted: use it over a VPN such as
|
|
158
|
+
Tailscale, or behind TLS.
|
|
159
|
+
- Writes require a same-origin request, and without auth the `Host` header must name the
|
|
160
|
+
bound address (against DNS rebinding).
|
|
161
|
+
- One job runs at a time. Each job also writes its own log under
|
|
162
|
+
`~/.local/share/tag-keeper/logs/jobs/`.
|
|
163
|
+
|
|
164
|
+
### Files, tags and history
|
|
165
|
+
|
|
166
|
+
- **Browse** a root folder by folder, preview PDFs, images, audio, video and text in the
|
|
167
|
+
page, and download anything. Only types that cannot run scripts open in the page; HTML
|
|
168
|
+
and SVG are shown as plain text, everything else downloads. Paths never leave the root,
|
|
169
|
+
symlinks included.
|
|
170
|
+
- **Tag** files and folders from the browser. A folder's tags are inherited by everything
|
|
171
|
+
under it. Tags live in append-only JSONL logs, one file per machine
|
|
172
|
+
(`~/.local/share/tag-keeper/tags/<host>.jsonl`), so they stay readable without the tool
|
|
173
|
+
and never conflict when synced. When a tagged item is moved — by you or by a plan — the
|
|
174
|
+
log records the move and the tags follow.
|
|
175
|
+
- **Version history** comes from btrfs snapshots through
|
|
176
|
+
[btrfs-timeline](https://github.com/akivajp/btrfs-timeline): the versions of a file, a
|
|
177
|
+
folder as it was at any snapshot (including what has since been deleted), and restoring
|
|
178
|
+
an old version next to the current file under a dated name (never overwriting).
|
|
179
|
+
tag-keeper records renames and moves it sees, so a file's history continues across them.
|
|
180
|
+
|
|
181
|
+
### Inbox suggestions
|
|
182
|
+
|
|
183
|
+
Folders whose name matches `inbox_patterns` (by default `tmp`, `temp`, `*未整理*`,
|
|
184
|
+
`*inbox*`) are treated as inboxes. The **整理** page lists every file in them flat, without
|
|
185
|
+
the folder hierarchy. Pick a file and a model served by [ollama](https://ollama.com/) reads
|
|
186
|
+
it — text from PDFs and Office files, the image itself for photos and scanned PDFs — and
|
|
187
|
+
suggests, usually within seconds:
|
|
188
|
+
|
|
189
|
+
- a name, by default `YYYYMMDD_title`, following past decisions and the date style of the
|
|
190
|
+
destination folder, and keeping a meaningful existing name;
|
|
191
|
+
- up to three destination folders among the folders you already have: candidates are
|
|
192
|
+
narrowed by character-bigram TF-IDF over each folder's path and file names, then the model
|
|
193
|
+
picks. Year and month folders are moved to the document's date;
|
|
194
|
+
- tags, preferring the ones you already use; new ones are marked as such.
|
|
195
|
+
|
|
196
|
+
Clicked files jump the queue and the next two are read ahead. Accepted suggestions go to an
|
|
197
|
+
accept list, which you run as one plan of renames and moves — with snapshots and undo — or
|
|
198
|
+
save to review on the plan page. Files outside the inboxes get a suggestion only when you ask
|
|
199
|
+
for one from the file browser.
|
|
200
|
+
|
|
201
|
+
**Learning from your decisions.** What you accept (suggested versus final name, folder and
|
|
202
|
+
tags), the suggested tags you add or reject, and plans you undo are appended to a log, one
|
|
203
|
+
JSONL file per machine (`~/.local/share/tag-keeper/decisions/`). Files you move out of an
|
|
204
|
+
inbox yourself count too. When suggesting, the closest past decisions are added to the prompt
|
|
205
|
+
as examples and their folders join the candidates; tags you keep rejecting are avoided. The
|
|
206
|
+
log pairs each suggestion with your decision, so it can be exported as training data.
|
|
207
|
+
|
|
208
|
+
**Models.** The default is a local model. Any ollama model can be chosen on the page or in
|
|
209
|
+
the config, including ollama's cloud models (`…:cloud`, `…-cloud`) — then the file's content
|
|
210
|
+
is sent to ollama's cloud; the page marks those models with ☁. Suggestions are stored by
|
|
211
|
+
content hash and model, so a file is read once per model.
|
|
212
|
+
|
|
213
|
+
## Install
|
|
214
|
+
|
|
215
|
+
Requires Python 3.11+ and Linux. The web UI and messages are in Japanese.
|
|
216
|
+
|
|
217
|
+
```console
|
|
218
|
+
$ pipx install tag-keeper # or: uv tool install tag-keeper
|
|
219
|
+
$ tag-keeper --help
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Optional tools, each used only by the feature that needs it:
|
|
223
|
+
|
|
224
|
+
| Tool | Used for |
|
|
225
|
+
|---|---|
|
|
226
|
+
| poppler-utils (`pdftotext`, `pdftoppm`) | reading PDFs for inbox suggestions |
|
|
227
|
+
| [ollama](https://ollama.com/) | inbox suggestions |
|
|
228
|
+
| btrfs and snapper | version history, and snapshots around plans |
|
|
229
|
+
| OneDrive client for Linux | coordinating big deletions with the sync |
|
|
230
|
+
|
|
231
|
+
From source:
|
|
232
|
+
|
|
233
|
+
```console
|
|
234
|
+
$ git clone https://github.com/akivajp/tag-keeper.git
|
|
235
|
+
$ cd tag-keeper
|
|
236
|
+
$ uv run tag-keeper --help
|
|
237
|
+
$ uv run --extra dev pytest
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Configuration
|
|
241
|
+
|
|
242
|
+
Optional. `~/.config/tag-keeper/config.toml`:
|
|
243
|
+
|
|
244
|
+
```toml
|
|
245
|
+
[[roots]]
|
|
246
|
+
name = "onedrive"
|
|
247
|
+
path = "~/CloudSync/OneDrive"
|
|
248
|
+
exclude = ["*.partial"] # never scanned (glob on the path relative to the root)
|
|
249
|
+
|
|
250
|
+
[hygiene]
|
|
251
|
+
allow = ["archive/**"] # never reported ("I decided to keep these")
|
|
252
|
+
device_names = ["zefat", "hermon"] # suffixes your sync client adds to conflict copies
|
|
253
|
+
app_data_names = ["MyLauncher"] # extra folder names to treat as application data
|
|
254
|
+
|
|
255
|
+
[safety]
|
|
256
|
+
mass_missing_ratio = 0.2 # hold deletions when more than this share vanishes
|
|
257
|
+
mass_missing_min = 100
|
|
258
|
+
|
|
259
|
+
[plan]
|
|
260
|
+
quarantine_dir = "~/.local/share/tag-keeper/quarantine" # must be on the root's filesystem
|
|
261
|
+
snapper_config = "home" # snapper config for pre/post snapshots ("" = none)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Per root, for coordinating with a sync client:
|
|
265
|
+
|
|
266
|
+
```toml
|
|
267
|
+
[[roots]]
|
|
268
|
+
name = "onedrive"
|
|
269
|
+
path = "~/CloudSync/OneDrive"
|
|
270
|
+
sync_client = "onedrive" # "" (default) = no coordination
|
|
271
|
+
sync_service = "onedrive.service" # the systemd --user unit running `onedrive --monitor`
|
|
272
|
+
sync_guard = "auto" # "auto": only for big deletions / "always": every run
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Tags and inbox suggestions:
|
|
276
|
+
|
|
277
|
+
```toml
|
|
278
|
+
[tags]
|
|
279
|
+
dir = "~/.local/share/tag-keeper/tags" # where the per-machine tag logs live
|
|
280
|
+
|
|
281
|
+
[organize]
|
|
282
|
+
inbox_patterns = ["tmp", "temp", "*未整理*", "*inbox*"] # case-insensitive globs on folder names
|
|
283
|
+
ollama_url = "http://127.0.0.1:11434"
|
|
284
|
+
model = "gemma3:12b" # e.g. "gemma4:31b-cloud" (content is sent to ollama's cloud)
|
|
285
|
+
vision_model = "" # model for images when `model` cannot read them
|
|
286
|
+
model_choices = ["gemma4:31b-cloud"] # extra models offered on the page
|
|
287
|
+
think = "" # "true" / "false" for thinking models; "" = model default
|
|
288
|
+
use_images = true
|
|
289
|
+
max_chars = 4000 # text passed to the model
|
|
290
|
+
candidates = 15 # destination folders the model chooses from
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
With roots configured, `tag-keeper scan` (no arguments) scans all of them.
|
|
294
|
+
Every command accepts `--log-file PATH` to keep a timestamped log.
|
|
295
|
+
|
|
296
|
+
## Roadmap
|
|
297
|
+
|
|
298
|
+
1. **Inventory and hygiene report**, and tidy-up plans that quarantine what you approve,
|
|
299
|
+
with snapper snapshots and undo. *(done)*
|
|
300
|
+
2. **Tags and search** — *partly done:* tags inherited from folders in append-only logs, a
|
|
301
|
+
file browser, version history across moves. *Next:* aliases and parents, typed fields,
|
|
302
|
+
search by tag, name and content.
|
|
303
|
+
3. **Content extraction** — *partly done:* text from PDF and Office files, images through a
|
|
304
|
+
local model, for inbox suggestions. *Next:* OCR and transcripts for full-text search.
|
|
305
|
+
4. **Placement and structure** — *partly done:* name and folder suggestions for inbox files.
|
|
306
|
+
*Next:* directory cards, structure review.
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
MIT
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# tag-keeper
|
|
2
|
+
|
|
3
|
+
既存のフォルダ構造を動かさずに、外側からタグ付け・検索・整理を行うツールです。
|
|
4
|
+
|
|
5
|
+
[English README](README.md)
|
|
6
|
+
|
|
7
|
+
> **状況: プレアルファ版。** 今動くのは、棚卸し(走査・内容ハッシュ・衛生レポート)、
|
|
8
|
+
> 承認した整理プランによる片付け(取り消し可能)、タグと btrfs スナップショットの版の履歴つきのファイルブラウザ、
|
|
9
|
+
> 手元のモデルによる受け皿のファイルの名前と移動先の提案です。検索とタグの残りはこれから作ります。
|
|
10
|
+
> [ロードマップ](#ロードマップ) を参照してください。
|
|
11
|
+
|
|
12
|
+
## なぜ作るのか
|
|
13
|
+
|
|
14
|
+
多くの文書管理ソフトは、ファイルを取り込んで自分の保管場所に一律に並べ直します。
|
|
15
|
+
これは、クラウドドライブの実際の使い方と正反対です。フォルダには既に意味があります
|
|
16
|
+
(番号付きの案件フォルダ、独自の構成を持つソースコードのリポジトリ、年月で分けた保管庫など)。
|
|
17
|
+
その意味はフォルダごとに決まっていて、全体共通のカテゴリでは表せません。
|
|
18
|
+
|
|
19
|
+
tag-keeper はツリーに手を付けません。ツリーの外に自分の台帳(カタログ)を持ち、そこからツリーをきれいに保つ手助けをします。
|
|
20
|
+
|
|
21
|
+
- **ファイルを取り込まない。** コピー・改名・変換をしません。ファイラーやシェルはこれまでどおり使えます。
|
|
22
|
+
- **ツールの外での操作に追従する。** 移動・改名したファイルも、記録を引き継ぎます。
|
|
23
|
+
- **変更は提案として出す。** ファイルを動かす操作はプランとして書き出し、先に示して、承認されてから実行します。
|
|
24
|
+
削除はしません。隔離フォルダへ移すだけで、プランごとに取り消せます。
|
|
25
|
+
|
|
26
|
+
## 今できること
|
|
27
|
+
|
|
28
|
+
```console
|
|
29
|
+
$ tag-keeper scan ~/CloudSync/OneDrive # 読み取り専用で走査し、カタログを更新する
|
|
30
|
+
$ tag-keeper hash ~/CloudSync/OneDrive # 前回から変わったファイルだけ SHA-256 を計算する
|
|
31
|
+
$ tag-keeper report ~/CloudSync/OneDrive # クラウドに置く価値が薄そうなものを報告する
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- **scan** は、すべてのファイルとフォルダのパス・サイズ・更新日時・inode を記録します。
|
|
35
|
+
移動・改名は inode で追跡するので、動かしたファイルも行(とハッシュ)を引き継ぎます。
|
|
36
|
+
- **安全弁:** 一度に多くのファイルが消えたように見えたら(ドライブのマウントが外れた、同期クライアントの事故など)、
|
|
37
|
+
削除として記録せずに**保留**します。次の走査でも見えなければ記録します(`--accept-missing` で即時に記録)。
|
|
38
|
+
- ルートが存在しないか空なら、「全部消えた」と扱わずに走査を止めます。読めなかったフォルダの中身も、消えたとは扱いません。
|
|
39
|
+
- **hash** は、新しいファイルと変わったファイルだけ SHA-256 を計算します(進捗バーと残り時間を表示)。
|
|
40
|
+
計算の途中で変わったファイルは飛ばします。
|
|
41
|
+
- **report** は、候補をカテゴリごとに、容量と例を添えて一覧します。
|
|
42
|
+
- 同期フォルダに入り込んだアプリのデータ(ゲームのデータ、キャッシュ)。フォルダ単位で1件として報告し、
|
|
43
|
+
条件に合う最も深いフォルダを選ぶので、隣にある利用者の書類まで巻き込みません
|
|
44
|
+
- 作り直せる生成物(`node_modules`、`__pycache__` など)、仮想マシンのディスク、インストーラーとディスクイメージ、
|
|
45
|
+
一時ファイル、Office のロックファイル
|
|
46
|
+
- 同期の競合コピー(Linux 版 onedrive クライアントの `-safeBackup-`、pCloud の `[conflicted]`、
|
|
47
|
+
rclone bisync の `.conflict1`、端末名の付いたもの、`(1)` 付きの複製)。同じフォルダに元のファイルがあるものだけです
|
|
48
|
+
(元が無ければ、それが唯一の版かもしれないため)。元と内容が異なるものには「中身の確認が必要」と付けます
|
|
49
|
+
- 空のファイルとフォルダ
|
|
50
|
+
- 内容が同じファイル(ハッシュで確定したものだけ。サイズからの推測では報告しません)
|
|
51
|
+
|
|
52
|
+
カタログはツリーの外の SQLite ファイルです(既定は `~/.local/share/tag-keeper/catalog.db`)。
|
|
53
|
+
ここまでのコマンドは、ツリーに何も書き込みません。
|
|
54
|
+
|
|
55
|
+
### 整理プランで片付ける
|
|
56
|
+
|
|
57
|
+
```console
|
|
58
|
+
$ tag-keeper plan onedrive # 報告の候補をプランのファイルに書き出す
|
|
59
|
+
$ $EDITOR ~/.local/share/tag-keeper/plans/<プラン ID>.toml # 残したいものの行を消す
|
|
60
|
+
$ tag-keeper apply <プランのファイル> # 確認だけ
|
|
61
|
+
$ tag-keeper apply <プランのファイル> --yes # 隔離フォルダへ移す
|
|
62
|
+
$ tag-keeper undo <プラン ID> --yes # すべて元に戻す
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- **plan** は、1件を1行にして、カテゴリごとにまとめて書き出します。`--category` でカテゴリを絞れます
|
|
66
|
+
(`app-data`、`vm-image`、`conflict` など)。中身の確認が要る候補は、`--include-review` を付けたときだけ含めます。
|
|
67
|
+
- **apply** は、既定では確認だけです。`--yes` を付けると、各対象を `<quarantine_dir>/<プラン ID>/` の下へ、
|
|
68
|
+
元の相対パスのまま改名で移します。移す直前に、プランの作成時から変わっていないか
|
|
69
|
+
(inode・サイズ・更新日時、フォルダなら配下のファイル数と合計サイズも)を確かめ、変わっていれば飛ばして報告します。
|
|
70
|
+
- `snapper_config` を設定すると、実行の前に snapper の pre スナップショット、後に post スナップショットを撮ります。
|
|
71
|
+
pre を撮れなければ、何も動かしません。
|
|
72
|
+
- 移した操作は、すべて実行記録(`~/.local/share/tag-keeper/journal/<プラン ID>.jsonl`)に追記します。
|
|
73
|
+
**undo** はこの記録をもとに元へ戻します。元の場所に新しく別のものができていれば、上書きせずに飛ばします。
|
|
74
|
+
- 移すたびにカタログも更新するので、大量に隔離しても、次の走査で大量消失と誤認しません。
|
|
75
|
+
- 同期クライアントが消えたことに気付けば、クラウドからは消えます。ただし、隔離フォルダを自分で空にするまでは、このディスクに残ります。
|
|
76
|
+
|
|
77
|
+
### 大量の削除で同期を止めない
|
|
78
|
+
|
|
79
|
+
[Linux 版 onedrive クライアント](https://github.com/abraunegg/onedrive)は、子の多いフォルダ
|
|
80
|
+
(`classify_as_big_delete`、既定 1000 件)がローカルで消えると事故とみなし、同期をやめて終了します。
|
|
81
|
+
systemd で常駐させていると再起動のたびに同じ理由で終了するので、気付かないうちに同期が止まります。
|
|
82
|
+
利用者が承認した大量の削除では、tag-keeper が同期クライアントと連携します(ルートに `sync_client = "onedrive"` を設定)。
|
|
83
|
+
|
|
84
|
+
1. 常駐の同期を止める(`systemctl --user stop onedrive.service`)
|
|
85
|
+
2. 隔離する
|
|
86
|
+
3. `onedrive --sync` を1回だけ、しきい値を「このプランで一番大きいフォルダ」より少し上に上げて実行し、削除をクラウドに反映する。
|
|
87
|
+
`--force` は使いません(関係のない事故まで通してしまうため)
|
|
88
|
+
4. 常駐の同期を再開する
|
|
89
|
+
|
|
90
|
+
3 が失敗したら、常駐の同期は止めたままにします(再開しても同じ理由で終了を繰り返すため)。
|
|
91
|
+
失敗は実行記録に残り、Web の画面か `tag-keeper sync <プラン ID> --retry` から再試行できます。
|
|
92
|
+
小さなプランでは連携せず、動いている同期クライアントにそのまま任せます。
|
|
93
|
+
|
|
94
|
+
## Web の画面
|
|
95
|
+
|
|
96
|
+
```console
|
|
97
|
+
$ tag-keeper serve # http://127.0.0.1:8090/
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
ここまでの操作は、すべてブラウザからできます。ルートを最新にする(走査とハッシュ計算)、レポートを見る、
|
|
101
|
+
プランを作る、残したいもののチェックを外す、確認する、実行する、取り消す。
|
|
102
|
+
時間のかかる処理は裏で動き、画面の下に、段階・進捗バー・速さ・残り時間・直近のログを表示します。スマートフォンでも使えます。
|
|
103
|
+
|
|
104
|
+
- 既定ではループバックだけで待ち受けます。他のアドレス(Tailscale のアドレスなど)で待ち受けるには、
|
|
105
|
+
BASIC 認証の資格情報を `--auth-file`(`user:password` の1行)か `TAG_KEEPER_AUTH` で渡してください。
|
|
106
|
+
渡さなければ、`--allow-no-auth` を付けない限り起動しません。BASIC 認証は暗号化しないので、
|
|
107
|
+
Tailscale などの VPN 越しか、TLS の後ろで使ってください。
|
|
108
|
+
- 書き込みは同一オリジンからだけ受け付けます。認証なしのときは、Host ヘッダが待ち受けているアドレスであることも確かめます(DNS リバインディング対策)。
|
|
109
|
+
- 同時に動かす処理は1つだけです。処理ごとのログは `~/.local/share/tag-keeper/logs/jobs/` にも残ります。
|
|
110
|
+
|
|
111
|
+
### ファイル・タグ・版の履歴
|
|
112
|
+
|
|
113
|
+
- **ファイルブラウザ**: ルートの中をフォルダごとにたどり、PDF・画像・音声・動画・テキストを画面の中でプレビューし、何でもダウンロードできます。
|
|
114
|
+
画面の中で開くのはスクリプトを実行しない種類だけで、HTML や SVG はテキストとして見せ、それ以外はダウンロードにします。
|
|
115
|
+
シンボリックリンクを含め、ルートの外には出ません。
|
|
116
|
+
- **タグ**: ファイルブラウザから、ファイルやフォルダにタグを付け外しできます。フォルダのタグは配下に継承されます。
|
|
117
|
+
タグは端末ごとの追記専用の JSONL(`~/.local/share/tag-keeper/tags/<ホスト名>.jsonl`)に記録するので、
|
|
118
|
+
ツールが無くても読め、同期しても競合しません。タグの付いたものが(手作業でもプランでも)動いたら、移動を記録してタグを追従させます。
|
|
119
|
+
- **版の履歴**: [btrfs-timeline](https://github.com/akivajp/btrfs-timeline) を使い、btrfs のスナップショットから、
|
|
120
|
+
ファイルの版の一覧、過去のある時点のフォルダの中身(今は消えたものを含む)を見られます。
|
|
121
|
+
過去の版は、今のファイルの隣に日時付きの別名で復元します(上書きしません)。
|
|
122
|
+
tag-keeper が見た移動・改名を記録しているので、移動・改名の前の版もたどれます。
|
|
123
|
+
|
|
124
|
+
### 受け皿の整理の提案
|
|
125
|
+
|
|
126
|
+
名前が `inbox_patterns`(既定は `tmp`・`temp`・`*未整理*`・`*inbox*`)に一致するフォルダを受け皿とみなします。
|
|
127
|
+
「整理」の画面に、受け皿の中のファイルをフォルダの階層なしで並べます。ファイルを選ぶと、
|
|
128
|
+
[ollama](https://ollama.com/) のモデルが内容を読み(PDF や Office 文書は文字、写真やスキャンの PDF は画像そのもの)、
|
|
129
|
+
多くは数秒で次を提案します。
|
|
130
|
+
|
|
131
|
+
- 名前: 既定は `YYYYMMDD_題名`。過去の判断や、移動先のフォルダの日付の付け方に合わせ、意味のある今の名前は尊重します
|
|
132
|
+
- 移動先: 既存のフォルダから最大3つ。各フォルダのパスと中のファイル名の文字の2文字組(TF-IDF)で候補を絞ってから、モデルが選びます。
|
|
133
|
+
年・月のフォルダは、書類の日付の年・月に置き換えます
|
|
134
|
+
- タグ: 既に使っているタグを優先します。新しいタグには「新規」と付けます
|
|
135
|
+
|
|
136
|
+
選んだファイルは待ち行列の先頭に割り込み、次の2件は先読みします。採用した提案は採用リストにたまり、
|
|
137
|
+
1つの「移動・改名」のプランとして実行するか(スナップショットと取り消しつき)、プランとして保存して確かめてから実行します。
|
|
138
|
+
受け皿の外のファイルは、ファイルブラウザで頼んだときだけ提案を作ります。
|
|
139
|
+
|
|
140
|
+
**判断から学ぶ仕組み**: 採用したもの(提案と最終的な名前・移動先・タグ)、提案されたタグを付けた・却下したこと、取り消したプランを、
|
|
141
|
+
端末ごとの JSONL(`~/.local/share/tag-keeper/decisions/`)に追記します。受け皿から手作業で移したものも例に使います。
|
|
142
|
+
提案を作るときは、似た過去の判断を例として指示文に添え、その移動先を候補に入れます。何度も却下したタグは使わせません。
|
|
143
|
+
ログは提案と判断が対になっているので、そのまま学習データとして書き出せます。
|
|
144
|
+
|
|
145
|
+
**モデル**: 既定は手元のモデルです。画面や設定で ollama のどのモデルも選べ、ollama のクラウドのモデル(`…:cloud`・`…-cloud`)も使えます。
|
|
146
|
+
その場合、ファイルの内容は ollama のクラウドに送られます。画面ではクラウドのモデルに ☁ を付けます。
|
|
147
|
+
提案は内容ハッシュとモデルごとに保存するので、同じファイルを同じモデルで読むのは1回だけです。
|
|
148
|
+
|
|
149
|
+
## インストール
|
|
150
|
+
|
|
151
|
+
Python 3.11 以上と Linux が必要です。画面とメッセージは日本語です。
|
|
152
|
+
|
|
153
|
+
```console
|
|
154
|
+
$ pipx install tag-keeper # または: uv tool install tag-keeper
|
|
155
|
+
$ tag-keeper --help
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
次の道具は任意で、それぞれ必要な機能でだけ使います。
|
|
159
|
+
|
|
160
|
+
| 道具 | 使う機能 |
|
|
161
|
+
|---|---|
|
|
162
|
+
| poppler-utils(`pdftotext`・`pdftoppm`) | 受け皿の整理の提案での PDF の読み取り |
|
|
163
|
+
| [ollama](https://ollama.com/) | 受け皿の整理の提案 |
|
|
164
|
+
| btrfs と snapper | 版の履歴、プランの実行前後のスナップショット |
|
|
165
|
+
| Linux 版 onedrive クライアント | 大量の削除での同期との連携 |
|
|
166
|
+
|
|
167
|
+
ソースから使う場合:
|
|
168
|
+
|
|
169
|
+
```console
|
|
170
|
+
$ git clone https://github.com/akivajp/tag-keeper.git
|
|
171
|
+
$ cd tag-keeper
|
|
172
|
+
$ uv run tag-keeper --help
|
|
173
|
+
$ uv run --extra dev pytest
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## 設定
|
|
177
|
+
|
|
178
|
+
任意です。`~/.config/tag-keeper/config.toml`:
|
|
179
|
+
|
|
180
|
+
```toml
|
|
181
|
+
[[roots]]
|
|
182
|
+
name = "onedrive"
|
|
183
|
+
path = "~/CloudSync/OneDrive"
|
|
184
|
+
exclude = ["*.partial"] # 走査しない(ルートからの相対パスに対する glob)
|
|
185
|
+
|
|
186
|
+
[hygiene]
|
|
187
|
+
allow = ["archive/**"] # 報告しない(「残す」と判断したもの)
|
|
188
|
+
device_names = ["zefat", "hermon"] # 同期クライアントが競合コピーに付ける端末名
|
|
189
|
+
app_data_names = ["MyLauncher"] # 既定に加えて、アプリのデータとみなすフォルダ名
|
|
190
|
+
|
|
191
|
+
[safety]
|
|
192
|
+
mass_missing_ratio = 0.2 # これを超える割合が消えたら、削除の記録を保留する
|
|
193
|
+
mass_missing_min = 100
|
|
194
|
+
|
|
195
|
+
[plan]
|
|
196
|
+
quarantine_dir = "~/.local/share/tag-keeper/quarantine" # ルートと同じファイルシステムに置く
|
|
197
|
+
snapper_config = "home" # 前後のスナップショットを撮る snapper の設定名("" で撮らない)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
同期クライアントとの連携は、ルートごとに設定します。
|
|
201
|
+
|
|
202
|
+
```toml
|
|
203
|
+
[[roots]]
|
|
204
|
+
name = "onedrive"
|
|
205
|
+
path = "~/CloudSync/OneDrive"
|
|
206
|
+
sync_client = "onedrive" # ""(既定)なら連携しない
|
|
207
|
+
sync_service = "onedrive.service" # `onedrive --monitor` を動かしている systemd --user のユニット
|
|
208
|
+
sync_guard = "auto" # "auto": 大量削除のときだけ / "always": 実行のたびに
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
タグと受け皿の整理の提案:
|
|
212
|
+
|
|
213
|
+
```toml
|
|
214
|
+
[tags]
|
|
215
|
+
dir = "~/.local/share/tag-keeper/tags" # 端末ごとのタグのログの置き場所
|
|
216
|
+
|
|
217
|
+
[organize]
|
|
218
|
+
inbox_patterns = ["tmp", "temp", "*未整理*", "*inbox*"] # フォルダ名に照合する(大文字・小文字を区別しない)
|
|
219
|
+
ollama_url = "http://127.0.0.1:11434"
|
|
220
|
+
model = "gemma3:12b" # 例: "gemma4:31b-cloud"(内容が ollama のクラウドに送られる)
|
|
221
|
+
vision_model = "" # model が画像を読めないときに、画像を読むモデル
|
|
222
|
+
model_choices = ["gemma4:31b-cloud"] # 画面で選べるモデルの候補
|
|
223
|
+
think = "" # 思考に対応したモデルで "true" / "false"。空ならモデルに任せる
|
|
224
|
+
use_images = true
|
|
225
|
+
max_chars = 4000 # モデルに渡す本文の上限
|
|
226
|
+
candidates = 15 # モデルに選ばせる移動先の候補の数
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
ルートを設定しておけば、`tag-keeper scan`(引数なし)で全ルートを走査します。
|
|
230
|
+
どのコマンドも `--log-file PATH` で日時付きのログを残せます。
|
|
231
|
+
|
|
232
|
+
## ロードマップ
|
|
233
|
+
|
|
234
|
+
1. **棚卸しと衛生レポート**、承認したものを隔離する整理プラン(snapper のスナップショットと取り消しつき)(済み)
|
|
235
|
+
2. **タグと検索** — 済み: フォルダから継承するタグ(追記専用ログ)、ファイルブラウザ、移動をまたぐ版の履歴。
|
|
236
|
+
これから: タグの別名・親子、型付きの属性、タグ・名前・内容による検索
|
|
237
|
+
3. **内容の抽出** — 済み: 受け皿の提案のための PDF・Office 文書の文字と、手元のモデルによる画像の読み取り。
|
|
238
|
+
これから: 全文検索のための OCR と書き起こし
|
|
239
|
+
4. **配置と構造** — 済み: 受け皿のファイルの名前と移動先の提案。これから: ディレクトリカード、構造の見直し
|
|
240
|
+
|
|
241
|
+
## ライセンス
|
|
242
|
+
|
|
243
|
+
MIT
|