pictovap 0.2.1__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.
- pictovap-0.2.1/LICENSE +9 -0
- pictovap-0.2.1/PKG-INFO +209 -0
- pictovap-0.2.1/README.md +177 -0
- pictovap-0.2.1/pyproject.toml +58 -0
- pictovap-0.2.1/setup.cfg +4 -0
- pictovap-0.2.1/src/pictova/__init__.py +39 -0
- pictovap-0.2.1/src/pictova/app/__init__.py +1 -0
- pictovap-0.2.1/src/pictova/app/cli.py +81 -0
- pictovap-0.2.1/src/pictova/core/__init__.py +0 -0
- pictovap-0.2.1/src/pictova/core/adapters.py +76 -0
- pictovap-0.2.1/src/pictova/core/demo_metadata.py +121 -0
- pictovap-0.2.1/src/pictova/core/filter.py +454 -0
- pictovap-0.2.1/src/pictova/core/language.py +34 -0
- pictovap-0.2.1/src/pictova/core/media_publish.py +1035 -0
- pictovap-0.2.1/src/pictova/core/media_quality.py +234 -0
- pictovap-0.2.1/src/pictova/core/metadata_generator.py +685 -0
- pictovap-0.2.1/src/pictova/core/primitives.py +249 -0
- pictovap-0.2.1/src/pictova/core/profile.py +100 -0
- pictovap-0.2.1/src/pictova/core/sources.py +68 -0
- pictovap-0.2.1/src/pictova/data/__init__.py +1 -0
- pictovap-0.2.1/src/pictova/data/sample-article.md +15 -0
- pictovap-0.2.1/src/pictova/demo.py +681 -0
- pictovap-0.2.1/src/pictova/engine/__init__.py +1 -0
- pictovap-0.2.1/src/pictova/engine/geo_aliases.py +56 -0
- pictovap-0.2.1/src/pictova/engine/publisher.py +25 -0
- pictovap-0.2.1/src/pictova/engine/quality.py +75 -0
- pictovap-0.2.1/src/pictova/engine/vision_chain.py +302 -0
- pictovap-0.2.1/src/pictova/providers/__init__.py +1 -0
- pictovap-0.2.1/src/pictova/providers/deposit.py +268 -0
- pictovap-0.2.1/src/pictova/providers/local.py +79 -0
- pictovap-0.2.1/src/pictova/providers/openverse.py +77 -0
- pictovap-0.2.1/src/pictova/providers/pexels.py +82 -0
- pictovap-0.2.1/src/pictova/providers/unsplash.py +118 -0
- pictovap-0.2.1/src/pictova/publishers/__init__.py +51 -0
- pictovap-0.2.1/src/pictova/publishers/ghost.py +256 -0
- pictovap-0.2.1/src/pictova/publishers/strapi.py +255 -0
- pictovap-0.2.1/src/pictova/services/__init__.py +1 -0
- pictovap-0.2.1/src/pictova/services/post_media_guard.py +217 -0
- pictovap-0.2.1/src/pictova/services/wordpress.py +918 -0
- pictovap-0.2.1/src/pictova/utils/__init__.py +25 -0
- pictovap-0.2.1/src/pictova/utils/config.py +58 -0
- pictovap-0.2.1/src/pictova/vision_templates.py +238 -0
- pictovap-0.2.1/src/pictovap.egg-info/PKG-INFO +209 -0
- pictovap-0.2.1/src/pictovap.egg-info/SOURCES.txt +46 -0
- pictovap-0.2.1/src/pictovap.egg-info/dependency_links.txt +1 -0
- pictovap-0.2.1/src/pictovap.egg-info/entry_points.txt +3 -0
- pictovap-0.2.1/src/pictovap.egg-info/requires.txt +11 -0
- pictovap-0.2.1/src/pictovap.egg-info/top_level.txt +1 -0
pictovap-0.2.1/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kemal Kaya — yoldaolmak.com
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
pictovap-0.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pictovap
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Open-source visual finishing engine for content publishers.
|
|
5
|
+
Author-email: Pictovap Contributors <hello@yoldaolmak.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yoldaolmak/Pictovap
|
|
8
|
+
Project-URL: Documentation, https://github.com/yoldaolmak/Pictovap/blob/main/docs/README.md
|
|
9
|
+
Project-URL: Repository, https://github.com/yoldaolmak/Pictovap.git
|
|
10
|
+
Keywords: wordpress,image automation,llm,vision,seo,cms,unsplash
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: Pillow>=9.0.0
|
|
23
|
+
Requires-Dist: requests>=2.25.0
|
|
24
|
+
Requires-Dist: numpy>=1.20.0
|
|
25
|
+
Provides-Extra: providers
|
|
26
|
+
Requires-Dist: anthropic>=0.3.0; extra == "providers"
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: pytest>=7.4.0; extra == "test"
|
|
29
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# Pictovap
|
|
34
|
+
|
|
35
|
+
[](https://github.com/yoldaolmak/Pictovap/actions/workflows/ci.yml)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
|
|
38
|
+
**Pictovap is an open-source visual finishing engine for content publishers.**
|
|
39
|
+
It turns a finished article into a visually complete, rights-aware,
|
|
40
|
+
publish-ready CMS page — and shows its work at every step.
|
|
41
|
+
|
|
42
|
+
## The Problem
|
|
43
|
+
|
|
44
|
+
Every publisher runs the same manual routine before an article can go live:
|
|
45
|
+
find images that actually fit the section they're going into, check whether
|
|
46
|
+
the license permits the intended use, resize and convert them to the site's
|
|
47
|
+
format, write alt text and a caption for each one, and place them at the
|
|
48
|
+
right point in the CMS. None of this is hard, individually. It is, however,
|
|
49
|
+
*repetitive*, *easy to get wrong under deadline pressure*, and it *scales
|
|
50
|
+
linearly with how much a publisher writes*. Skipped alt text quietly erodes
|
|
51
|
+
accessibility and SEO. Untracked image provenance is a license or attribution
|
|
52
|
+
problem waiting to surface later, when it's expensive to fix. None of this
|
|
53
|
+
shows up in a style guide — it shows up as an hour of an editor's afternoon,
|
|
54
|
+
per article, forever.
|
|
55
|
+
|
|
56
|
+
Point solutions exist for pieces of this: stock photo plugins, DAM systems,
|
|
57
|
+
generic AI image generators. What's largely missing is the connective layer
|
|
58
|
+
— something that reads what the article actually needs, evaluates candidates
|
|
59
|
+
against that need with a visible, auditable reason for every accept and
|
|
60
|
+
reject, and hands a CMS a placement plan it can execute without a human
|
|
61
|
+
re-deriving the same context from scratch.
|
|
62
|
+
|
|
63
|
+
## The Solution
|
|
64
|
+
|
|
65
|
+
Pictovap is that connective layer, built as an open, adapter-based pipeline
|
|
66
|
+
rather than a closed SaaS product:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
Article Input → Visual Brief → Candidate Images → Fit Score
|
|
70
|
+
→ Provenance Pack → CMS Placement → Editor Report
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- **Visual Brief** — a structured read of what imagery the article actually
|
|
74
|
+
needs, derived from its heading structure and content, not from a generic
|
|
75
|
+
"insert 3 images" rule.
|
|
76
|
+
- **Fit Score** — every candidate is scored against the brief with a
|
|
77
|
+
transparent, deterministic reason attached (`selected`, `rejected`, or
|
|
78
|
+
`needs_review`, plus why). No black-box relevance number.
|
|
79
|
+
- **Provenance Pack** — a persistent audit trail for every selected image:
|
|
80
|
+
source, license status, attribution, a content hash, and the exact
|
|
81
|
+
processing actions applied. This is what makes "where did this image come
|
|
82
|
+
from and are we allowed to use it" answerable six months later.
|
|
83
|
+
- **CMS Placement** — a CMS-agnostic plan describing where and how each image
|
|
84
|
+
should be placed, independent of whether the destination is WordPress,
|
|
85
|
+
Ghost, Strapi, or something a contributor writes an adapter for tomorrow.
|
|
86
|
+
- **Editor Report** — a human-readable Markdown review surface, so an editor
|
|
87
|
+
signs off on a report, not raw JSON, before anything reaches production.
|
|
88
|
+
|
|
89
|
+
What makes this radical isn't any single stage — it's that the whole pipeline
|
|
90
|
+
is a public, inspectable contract instead of a hosted black box, and that it
|
|
91
|
+
is honest about its own workings by default: the credential-free demo below
|
|
92
|
+
runs the entire pipeline end-to-end, with zero API keys and zero network
|
|
93
|
+
calls, so you can read exactly what it does before you ever hand it a real
|
|
94
|
+
site.
|
|
95
|
+
|
|
96
|
+
Pictovap is not a stock photo search tool, a DAM, a generic AI image
|
|
97
|
+
generator, or a WordPress-only plugin. It has no graphical interface yet — it
|
|
98
|
+
is a CLI-first, adapter-based core, with the editor report as the intended
|
|
99
|
+
human review surface and CMS adapters as the machine-facing execution layer.
|
|
100
|
+
|
|
101
|
+
## Quickstart
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
git clone https://github.com/yoldaolmak/Pictovap.git
|
|
105
|
+
cd Pictovap
|
|
106
|
+
python3 -m venv .venv
|
|
107
|
+
source .venv/bin/activate
|
|
108
|
+
pip install -r requirements.txt
|
|
109
|
+
pip install -e .
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Run the credential-free demo:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pictovap demo
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
Brief: 4 slots from 3 sections
|
|
120
|
+
Evaluated: 5 candidates
|
|
121
|
+
Selected: 3 images
|
|
122
|
+
Rejected: 4 candidates
|
|
123
|
+
Placements: 3 instructions
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
No `.env` file, no API keys, no network calls — every candidate and score
|
|
127
|
+
above comes from deterministic mock data, on purpose. This is the demo's
|
|
128
|
+
guarantee, not just its default state.
|
|
129
|
+
|
|
130
|
+
## Try Your Own Article
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
pictovap plan \
|
|
134
|
+
--article path/to/your/article.md \
|
|
135
|
+
--profile examples/profiles/sample-publisher.yaml \
|
|
136
|
+
--output my-plan.json \
|
|
137
|
+
--report my-report.md
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`my-plan.json` is the canonical, machine-readable artifact for adapters and
|
|
141
|
+
automation. `my-report.md` is the same plan, rendered for a human editor to
|
|
142
|
+
review before anything gets published.
|
|
143
|
+
|
|
144
|
+
## Adapters
|
|
145
|
+
|
|
146
|
+
Pictovap connects to the outside world only through adapters — the core
|
|
147
|
+
pipeline has no hardcoded dependency on any specific image provider or CMS.
|
|
148
|
+
|
|
149
|
+
**Image sources:** local folder, Unsplash, DepositPhotos, Openverse (no key
|
|
150
|
+
required), and Pexels are implemented. Pixabay and Wikimedia Commons are
|
|
151
|
+
open contribution opportunities — see
|
|
152
|
+
[Good First Issues](docs/contributing/good-first-issues.md). See
|
|
153
|
+
[Image Source Adapters](docs/adapters/image-sources.md).
|
|
154
|
+
|
|
155
|
+
**CMS placement:** WordPress (production-tested), Ghost and Strapi (reference
|
|
156
|
+
implementations, real but with documented limitations). See
|
|
157
|
+
[CMS Adapters](docs/adapters/cms-adapters.md).
|
|
158
|
+
|
|
159
|
+
Every adapter degrades gracefully when unconfigured — a missing API key
|
|
160
|
+
produces an empty result, not a crash, so a partially configured profile
|
|
161
|
+
still runs. Writing a new adapter means implementing one method
|
|
162
|
+
(`search_candidates` or `place`) against a documented `Protocol`; see the
|
|
163
|
+
[Adapter Overview](docs/adapters/overview.md).
|
|
164
|
+
|
|
165
|
+
## Multi-Language by Design
|
|
166
|
+
|
|
167
|
+
Pictovap's own code, comments, and documentation are English. What it
|
|
168
|
+
*generates* — alt text, captions, titles — is not tied to any one language.
|
|
169
|
+
Article language is detected automatically (or set explicitly via the
|
|
170
|
+
publisher profile), and generated metadata follows it: a Turkish article
|
|
171
|
+
gets Turkish alt text, a French one gets French, and so on. This isn't a
|
|
172
|
+
localization afterthought bolted onto an English-only tool; it's a parameter
|
|
173
|
+
of the pipeline from the start.
|
|
174
|
+
|
|
175
|
+
## Current Status and Limitations
|
|
176
|
+
|
|
177
|
+
Pictovap is early open-source infrastructure. It has a genuinely
|
|
178
|
+
credential-free local demo, documented core primitives, a real test suite,
|
|
179
|
+
and a working adapter model — it does not yet claim broad ecosystem adoption
|
|
180
|
+
or a large external contributor base.
|
|
181
|
+
|
|
182
|
+
Specifically:
|
|
183
|
+
|
|
184
|
+
- Only the WordPress CMS adapter is production-hardened; Ghost and Strapi are
|
|
185
|
+
real, tested reference implementations with documented gaps (see
|
|
186
|
+
[CMS Adapters](docs/adapters/cms-adapters.md)).
|
|
187
|
+
- The credential-free demo always uses deterministic mock candidates by
|
|
188
|
+
design, regardless of what's configured in `.env` — `pictovap plan` is
|
|
189
|
+
where real, credentialed sources are used.
|
|
190
|
+
- Deterministic structural extraction (the rule-based, non-AI language and
|
|
191
|
+
section detection) is reliable for English and Turkish; other languages
|
|
192
|
+
are untested.
|
|
193
|
+
|
|
194
|
+
## Compatibility Note
|
|
195
|
+
|
|
196
|
+
Product name: Pictovap. The Python package, import name, and console-script
|
|
197
|
+
entry point may remain `pictova` for backward compatibility — see
|
|
198
|
+
[Brand & Naming](docs/architecture/naming.md).
|
|
199
|
+
|
|
200
|
+
## Contributing
|
|
201
|
+
|
|
202
|
+
See the [Documentation Portal](docs/README.md) for architecture, concepts,
|
|
203
|
+
and adapter-writing guides, and [DEVELOPER.md](docs/DEVELOPER.md) for the
|
|
204
|
+
contribution workflow. Pull requests that add a new image source or CMS
|
|
205
|
+
adapter, improve test coverage, or fix documentation are all welcome.
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT — see [LICENSE](LICENSE).
|
pictovap-0.2.1/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Pictovap
|
|
2
|
+
|
|
3
|
+
[](https://github.com/yoldaolmak/Pictovap/actions/workflows/ci.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
**Pictovap is an open-source visual finishing engine for content publishers.**
|
|
7
|
+
It turns a finished article into a visually complete, rights-aware,
|
|
8
|
+
publish-ready CMS page — and shows its work at every step.
|
|
9
|
+
|
|
10
|
+
## The Problem
|
|
11
|
+
|
|
12
|
+
Every publisher runs the same manual routine before an article can go live:
|
|
13
|
+
find images that actually fit the section they're going into, check whether
|
|
14
|
+
the license permits the intended use, resize and convert them to the site's
|
|
15
|
+
format, write alt text and a caption for each one, and place them at the
|
|
16
|
+
right point in the CMS. None of this is hard, individually. It is, however,
|
|
17
|
+
*repetitive*, *easy to get wrong under deadline pressure*, and it *scales
|
|
18
|
+
linearly with how much a publisher writes*. Skipped alt text quietly erodes
|
|
19
|
+
accessibility and SEO. Untracked image provenance is a license or attribution
|
|
20
|
+
problem waiting to surface later, when it's expensive to fix. None of this
|
|
21
|
+
shows up in a style guide — it shows up as an hour of an editor's afternoon,
|
|
22
|
+
per article, forever.
|
|
23
|
+
|
|
24
|
+
Point solutions exist for pieces of this: stock photo plugins, DAM systems,
|
|
25
|
+
generic AI image generators. What's largely missing is the connective layer
|
|
26
|
+
— something that reads what the article actually needs, evaluates candidates
|
|
27
|
+
against that need with a visible, auditable reason for every accept and
|
|
28
|
+
reject, and hands a CMS a placement plan it can execute without a human
|
|
29
|
+
re-deriving the same context from scratch.
|
|
30
|
+
|
|
31
|
+
## The Solution
|
|
32
|
+
|
|
33
|
+
Pictovap is that connective layer, built as an open, adapter-based pipeline
|
|
34
|
+
rather than a closed SaaS product:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Article Input → Visual Brief → Candidate Images → Fit Score
|
|
38
|
+
→ Provenance Pack → CMS Placement → Editor Report
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- **Visual Brief** — a structured read of what imagery the article actually
|
|
42
|
+
needs, derived from its heading structure and content, not from a generic
|
|
43
|
+
"insert 3 images" rule.
|
|
44
|
+
- **Fit Score** — every candidate is scored against the brief with a
|
|
45
|
+
transparent, deterministic reason attached (`selected`, `rejected`, or
|
|
46
|
+
`needs_review`, plus why). No black-box relevance number.
|
|
47
|
+
- **Provenance Pack** — a persistent audit trail for every selected image:
|
|
48
|
+
source, license status, attribution, a content hash, and the exact
|
|
49
|
+
processing actions applied. This is what makes "where did this image come
|
|
50
|
+
from and are we allowed to use it" answerable six months later.
|
|
51
|
+
- **CMS Placement** — a CMS-agnostic plan describing where and how each image
|
|
52
|
+
should be placed, independent of whether the destination is WordPress,
|
|
53
|
+
Ghost, Strapi, or something a contributor writes an adapter for tomorrow.
|
|
54
|
+
- **Editor Report** — a human-readable Markdown review surface, so an editor
|
|
55
|
+
signs off on a report, not raw JSON, before anything reaches production.
|
|
56
|
+
|
|
57
|
+
What makes this radical isn't any single stage — it's that the whole pipeline
|
|
58
|
+
is a public, inspectable contract instead of a hosted black box, and that it
|
|
59
|
+
is honest about its own workings by default: the credential-free demo below
|
|
60
|
+
runs the entire pipeline end-to-end, with zero API keys and zero network
|
|
61
|
+
calls, so you can read exactly what it does before you ever hand it a real
|
|
62
|
+
site.
|
|
63
|
+
|
|
64
|
+
Pictovap is not a stock photo search tool, a DAM, a generic AI image
|
|
65
|
+
generator, or a WordPress-only plugin. It has no graphical interface yet — it
|
|
66
|
+
is a CLI-first, adapter-based core, with the editor report as the intended
|
|
67
|
+
human review surface and CMS adapters as the machine-facing execution layer.
|
|
68
|
+
|
|
69
|
+
## Quickstart
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git clone https://github.com/yoldaolmak/Pictovap.git
|
|
73
|
+
cd Pictovap
|
|
74
|
+
python3 -m venv .venv
|
|
75
|
+
source .venv/bin/activate
|
|
76
|
+
pip install -r requirements.txt
|
|
77
|
+
pip install -e .
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Run the credential-free demo:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pictovap demo
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
Brief: 4 slots from 3 sections
|
|
88
|
+
Evaluated: 5 candidates
|
|
89
|
+
Selected: 3 images
|
|
90
|
+
Rejected: 4 candidates
|
|
91
|
+
Placements: 3 instructions
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
No `.env` file, no API keys, no network calls — every candidate and score
|
|
95
|
+
above comes from deterministic mock data, on purpose. This is the demo's
|
|
96
|
+
guarantee, not just its default state.
|
|
97
|
+
|
|
98
|
+
## Try Your Own Article
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pictovap plan \
|
|
102
|
+
--article path/to/your/article.md \
|
|
103
|
+
--profile examples/profiles/sample-publisher.yaml \
|
|
104
|
+
--output my-plan.json \
|
|
105
|
+
--report my-report.md
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`my-plan.json` is the canonical, machine-readable artifact for adapters and
|
|
109
|
+
automation. `my-report.md` is the same plan, rendered for a human editor to
|
|
110
|
+
review before anything gets published.
|
|
111
|
+
|
|
112
|
+
## Adapters
|
|
113
|
+
|
|
114
|
+
Pictovap connects to the outside world only through adapters — the core
|
|
115
|
+
pipeline has no hardcoded dependency on any specific image provider or CMS.
|
|
116
|
+
|
|
117
|
+
**Image sources:** local folder, Unsplash, DepositPhotos, Openverse (no key
|
|
118
|
+
required), and Pexels are implemented. Pixabay and Wikimedia Commons are
|
|
119
|
+
open contribution opportunities — see
|
|
120
|
+
[Good First Issues](docs/contributing/good-first-issues.md). See
|
|
121
|
+
[Image Source Adapters](docs/adapters/image-sources.md).
|
|
122
|
+
|
|
123
|
+
**CMS placement:** WordPress (production-tested), Ghost and Strapi (reference
|
|
124
|
+
implementations, real but with documented limitations). See
|
|
125
|
+
[CMS Adapters](docs/adapters/cms-adapters.md).
|
|
126
|
+
|
|
127
|
+
Every adapter degrades gracefully when unconfigured — a missing API key
|
|
128
|
+
produces an empty result, not a crash, so a partially configured profile
|
|
129
|
+
still runs. Writing a new adapter means implementing one method
|
|
130
|
+
(`search_candidates` or `place`) against a documented `Protocol`; see the
|
|
131
|
+
[Adapter Overview](docs/adapters/overview.md).
|
|
132
|
+
|
|
133
|
+
## Multi-Language by Design
|
|
134
|
+
|
|
135
|
+
Pictovap's own code, comments, and documentation are English. What it
|
|
136
|
+
*generates* — alt text, captions, titles — is not tied to any one language.
|
|
137
|
+
Article language is detected automatically (or set explicitly via the
|
|
138
|
+
publisher profile), and generated metadata follows it: a Turkish article
|
|
139
|
+
gets Turkish alt text, a French one gets French, and so on. This isn't a
|
|
140
|
+
localization afterthought bolted onto an English-only tool; it's a parameter
|
|
141
|
+
of the pipeline from the start.
|
|
142
|
+
|
|
143
|
+
## Current Status and Limitations
|
|
144
|
+
|
|
145
|
+
Pictovap is early open-source infrastructure. It has a genuinely
|
|
146
|
+
credential-free local demo, documented core primitives, a real test suite,
|
|
147
|
+
and a working adapter model — it does not yet claim broad ecosystem adoption
|
|
148
|
+
or a large external contributor base.
|
|
149
|
+
|
|
150
|
+
Specifically:
|
|
151
|
+
|
|
152
|
+
- Only the WordPress CMS adapter is production-hardened; Ghost and Strapi are
|
|
153
|
+
real, tested reference implementations with documented gaps (see
|
|
154
|
+
[CMS Adapters](docs/adapters/cms-adapters.md)).
|
|
155
|
+
- The credential-free demo always uses deterministic mock candidates by
|
|
156
|
+
design, regardless of what's configured in `.env` — `pictovap plan` is
|
|
157
|
+
where real, credentialed sources are used.
|
|
158
|
+
- Deterministic structural extraction (the rule-based, non-AI language and
|
|
159
|
+
section detection) is reliable for English and Turkish; other languages
|
|
160
|
+
are untested.
|
|
161
|
+
|
|
162
|
+
## Compatibility Note
|
|
163
|
+
|
|
164
|
+
Product name: Pictovap. The Python package, import name, and console-script
|
|
165
|
+
entry point may remain `pictova` for backward compatibility — see
|
|
166
|
+
[Brand & Naming](docs/architecture/naming.md).
|
|
167
|
+
|
|
168
|
+
## Contributing
|
|
169
|
+
|
|
170
|
+
See the [Documentation Portal](docs/README.md) for architecture, concepts,
|
|
171
|
+
and adapter-writing guides, and [DEVELOPER.md](docs/DEVELOPER.md) for the
|
|
172
|
+
contribution workflow. Pull requests that add a new image source or CMS
|
|
173
|
+
adapter, improve test coverage, or fix documentation are all welcome.
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pictovap"
|
|
7
|
+
version = "0.2.1"
|
|
8
|
+
description = "Open-source visual finishing engine for content publishers."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Pictovap Contributors", email = "hello@yoldaolmak.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"wordpress", "image automation", "llm", "vision", "seo", "cms", "unsplash"
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 4 - Beta",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Topic :: Multimedia :: Graphics",
|
|
23
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
|
+
"Programming Language :: Python :: 3.9",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"Pillow>=9.0.0",
|
|
30
|
+
"requests>=2.25.0",
|
|
31
|
+
"numpy>=1.20.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
providers = [
|
|
36
|
+
"anthropic>=0.3.0",
|
|
37
|
+
]
|
|
38
|
+
test = [
|
|
39
|
+
"pytest>=7.4.0",
|
|
40
|
+
"pytest-cov>=4.1.0",
|
|
41
|
+
"pytest-asyncio>=0.21.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/yoldaolmak/Pictovap"
|
|
46
|
+
Documentation = "https://github.com/yoldaolmak/Pictovap/blob/main/docs/README.md"
|
|
47
|
+
Repository = "https://github.com/yoldaolmak/Pictovap.git"
|
|
48
|
+
|
|
49
|
+
[project.scripts]
|
|
50
|
+
pictova = "pictova.app.cli:main"
|
|
51
|
+
pictovap = "pictova.app.cli:main"
|
|
52
|
+
|
|
53
|
+
[tool.setuptools.packages.find]
|
|
54
|
+
where = ["src"]
|
|
55
|
+
namespaces = false
|
|
56
|
+
|
|
57
|
+
[tool.setuptools.package-data]
|
|
58
|
+
"pictova.data" = ["*.md"]
|
pictovap-0.2.1/setup.cfg
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pictovap — Open-source visual finishing engine for content publishers.
|
|
3
|
+
|
|
4
|
+
This package provides modules to select, process, generate metadata for, and
|
|
5
|
+
publish images across various CMS platforms.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.2.0"
|
|
9
|
+
|
|
10
|
+
# Public library API — the framework entry point.
|
|
11
|
+
from .demo import create_visual_plan
|
|
12
|
+
|
|
13
|
+
# Adapter contracts
|
|
14
|
+
from .core.adapters import ImageSourceAdapter, CMSAdapter, ReportRenderer
|
|
15
|
+
|
|
16
|
+
# Vision template system
|
|
17
|
+
from .vision_templates import (
|
|
18
|
+
VisionTemplate,
|
|
19
|
+
TRAVEL_BLOG,
|
|
20
|
+
TECHNICAL,
|
|
21
|
+
MINIMAL,
|
|
22
|
+
ECOMMERCE,
|
|
23
|
+
get_template,
|
|
24
|
+
register_template,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"create_visual_plan",
|
|
29
|
+
"ImageSourceAdapter",
|
|
30
|
+
"CMSAdapter",
|
|
31
|
+
"ReportRenderer",
|
|
32
|
+
"VisionTemplate",
|
|
33
|
+
"TRAVEL_BLOG",
|
|
34
|
+
"TECHNICAL",
|
|
35
|
+
"MINIMAL",
|
|
36
|
+
"ECOMMERCE",
|
|
37
|
+
"get_template",
|
|
38
|
+
"register_template",
|
|
39
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Application surface for VIL."""
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Pictovap CLI entrypoint.
|
|
2
|
+
|
|
3
|
+
Three commands, matching the public library API 1:1:
|
|
4
|
+
demo - run the credential-free example pipeline
|
|
5
|
+
plan - create a visual plan for a real article (pictova.create_visual_plan)
|
|
6
|
+
report - render an existing JSON plan as a Markdown editor report
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import json
|
|
13
|
+
import sys
|
|
14
|
+
from typing import Any, Dict
|
|
15
|
+
|
|
16
|
+
from pictova.demo import create_visual_plan, generate_report_from_file, run_demo
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _print_json(payload: Dict[str, Any]) -> None:
|
|
20
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
24
|
+
parser = argparse.ArgumentParser(prog="pictovap")
|
|
25
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
26
|
+
|
|
27
|
+
sub.add_parser("demo", help="Run the built-in credential-free example")
|
|
28
|
+
|
|
29
|
+
plan = sub.add_parser("plan", help="Create a visual plan for a Markdown article")
|
|
30
|
+
plan.add_argument("--article", required=True, help="Path to a Markdown article")
|
|
31
|
+
plan.add_argument("--profile", help="Path to a Publisher Profile YAML")
|
|
32
|
+
plan.add_argument("--output", help="Path to write the JSON output plan")
|
|
33
|
+
plan.add_argument("--report", help="Path to write the Markdown report")
|
|
34
|
+
|
|
35
|
+
report = sub.add_parser("report", help="Generate an editor-readable Markdown report from a plan")
|
|
36
|
+
report.add_argument("--plan", required=True, help="Path to visual-plan.json")
|
|
37
|
+
report.add_argument("--output", required=True, help="Path to write the output report.md")
|
|
38
|
+
|
|
39
|
+
return parser
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def main() -> int:
|
|
43
|
+
parser = build_parser()
|
|
44
|
+
args = parser.parse_args()
|
|
45
|
+
|
|
46
|
+
if args.command == "demo":
|
|
47
|
+
run_demo()
|
|
48
|
+
return 0
|
|
49
|
+
|
|
50
|
+
if args.command == "plan":
|
|
51
|
+
try:
|
|
52
|
+
plan_output = create_visual_plan(
|
|
53
|
+
article=args.article,
|
|
54
|
+
profile=args.profile,
|
|
55
|
+
output=args.output,
|
|
56
|
+
report=args.report,
|
|
57
|
+
)
|
|
58
|
+
except FileNotFoundError as e:
|
|
59
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
60
|
+
return 1
|
|
61
|
+
except Exception as e:
|
|
62
|
+
print(f"Error running plan: {e}", file=sys.stderr)
|
|
63
|
+
return 1
|
|
64
|
+
if not args.output:
|
|
65
|
+
_print_json(plan_output)
|
|
66
|
+
return 0
|
|
67
|
+
|
|
68
|
+
if args.command == "report":
|
|
69
|
+
try:
|
|
70
|
+
generate_report_from_file(args.plan, args.output)
|
|
71
|
+
return 0
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print(f"Error generating report: {e}", file=sys.stderr)
|
|
74
|
+
return 1
|
|
75
|
+
|
|
76
|
+
parser.error(f"unknown command: {args.command}")
|
|
77
|
+
return 2
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
raise SystemExit(main())
|
|
File without changes
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Formal adapter contracts for Pictovap.
|
|
3
|
+
|
|
4
|
+
Pictovap's core pipeline (Visual Brief -> Fit Score -> Provenance Pack ->
|
|
5
|
+
CMS Placement) has no dependency on any specific image provider or CMS.
|
|
6
|
+
Everything external plugs in through one of the protocols defined here.
|
|
7
|
+
|
|
8
|
+
These are `typing.Protocol` classes: an adapter does not need to inherit
|
|
9
|
+
from them, it only needs to implement the matching methods (structural
|
|
10
|
+
typing / duck typing). They exist so that:
|
|
11
|
+
|
|
12
|
+
- the required shape of an adapter is documented in one importable place
|
|
13
|
+
- `isinstance(obj, ImageSourceAdapter)` works for runtime checks
|
|
14
|
+
- IDEs and type checkers can validate third-party adapters
|
|
15
|
+
|
|
16
|
+
See docs/adapters/overview.md for the conceptual model, and
|
|
17
|
+
docs/contributing/adapters.md for a walkthrough of writing a new one.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import Any, Dict, List, Protocol, runtime_checkable
|
|
23
|
+
|
|
24
|
+
from pictova.core.primitives import CMSPlacement
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@runtime_checkable
|
|
28
|
+
class ImageSourceAdapter(Protocol):
|
|
29
|
+
"""Supplies candidate images to the Fit Score stage.
|
|
30
|
+
|
|
31
|
+
Implementations may call a local folder, a stock photo API, a DAM, or
|
|
32
|
+
any other source. They must never require credentials to import or
|
|
33
|
+
construct — missing credentials should surface as an empty result or
|
|
34
|
+
a clear error only when a search is actually attempted, so the
|
|
35
|
+
credential-free demo path keeps working.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def search_candidates(self, query: str, count: int) -> List[Dict[str, Any]]:
|
|
39
|
+
"""Return up to `count` candidate images matching `query`.
|
|
40
|
+
|
|
41
|
+
Each candidate dict must contain at least:
|
|
42
|
+
id, filename, provider, source_type ("local" | "api" | "url"),
|
|
43
|
+
local_path (str | None), source_url (str | None), license,
|
|
44
|
+
attribution (str | None), keywords (list[str]), width, height
|
|
45
|
+
"""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@runtime_checkable
|
|
50
|
+
class CMSAdapter(Protocol):
|
|
51
|
+
"""Consumes a CMS Placement plan and executes it against a real CMS.
|
|
52
|
+
|
|
53
|
+
A CMS adapter translates Pictovap's CMS-agnostic placement plan into
|
|
54
|
+
the target platform's native representation (e.g. a WordPress
|
|
55
|
+
Gutenberg block, a Ghost mobiledoc card, a Strapi component).
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def place(self, placement: CMSPlacement) -> Dict[str, Any]:
|
|
59
|
+
"""Execute the placement plan. Returns a dict with at least:
|
|
60
|
+
placed (list), failed (list), warnings (list)
|
|
61
|
+
"""
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@runtime_checkable
|
|
66
|
+
class ReportRenderer(Protocol):
|
|
67
|
+
"""Renders a visual plan (JSON-shaped dict) into a human- or
|
|
68
|
+
machine-facing output format (Markdown, HTML, a CMS payload, etc.).
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def render(self, plan: Dict[str, Any]) -> str:
|
|
72
|
+
"""Return the rendered report as a string."""
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
__all__ = ["ImageSourceAdapter", "CMSAdapter", "ReportRenderer"]
|