collective.aitools 1.0.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.
- collective_aitools-1.0.0/.dockerignore +14 -0
- collective_aitools-1.0.0/.editorconfig +35 -0
- collective_aitools-1.0.0/.flake8 +22 -0
- collective_aitools-1.0.0/.gitignore +50 -0
- collective_aitools-1.0.0/AGENTS.md +203 -0
- collective_aitools-1.0.0/CHANGELOG.md +56 -0
- collective_aitools-1.0.0/CONTRIBUTORS.md +3 -0
- collective_aitools-1.0.0/Dockerfile +38 -0
- collective_aitools-1.0.0/Dockerfile.acceptance +40 -0
- collective_aitools-1.0.0/LICENSE.GPL +339 -0
- collective_aitools-1.0.0/LICENSE.md +15 -0
- collective_aitools-1.0.0/Makefile +207 -0
- collective_aitools-1.0.0/PKG-INFO +155 -0
- collective_aitools-1.0.0/README.md +116 -0
- collective_aitools-1.0.0/bobtemplate.cfg +7 -0
- collective_aitools-1.0.0/instance.yaml +5 -0
- collective_aitools-1.0.0/mx.ini +37 -0
- collective_aitools-1.0.0/news/.changelog_template.jinja +15 -0
- collective_aitools-1.0.0/news/.gitkeep +1 -0
- collective_aitools-1.0.0/package-lock.json +23070 -0
- collective_aitools-1.0.0/package.json +30 -0
- collective_aitools-1.0.0/pyproject.toml +186 -0
- collective_aitools-1.0.0/resources/aitools-config.js +8 -0
- collective_aitools-1.0.0/resources/index.js +3 -0
- collective_aitools-1.0.0/resources/js/assistant.pattern.js +255 -0
- collective_aitools-1.0.0/resources/js/assistant.scss +241 -0
- collective_aitools-1.0.0/resources/js/help-me-write.pattern.js +431 -0
- collective_aitools-1.0.0/resources/js/help-me-write.scss +123 -0
- collective_aitools-1.0.0/resources/js/recognize-image.pattern.js +236 -0
- collective_aitools-1.0.0/resources/js/recognize-image.scss +69 -0
- collective_aitools-1.0.0/resources/js/suggest-tags.pattern.js +15 -0
- collective_aitools-1.0.0/resources/js/summarize.pattern.js +15 -0
- collective_aitools-1.0.0/scripts/create_site.py +71 -0
- collective_aitools-1.0.0/scripts/recognize_images.py +132 -0
- collective_aitools-1.0.0/scripts/suggest_tags.py +92 -0
- collective_aitools-1.0.0/scripts/summarize_content.py +91 -0
- collective_aitools-1.0.0/src/collective/aitools/AGENTS.md +289 -0
- collective_aitools-1.0.0/src/collective/aitools/__init__.py +14 -0
- collective_aitools-1.0.0/src/collective/aitools/backfill.py +110 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/__init__.py +0 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/assistant.py +66 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/configure.zcml +57 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/help_me_write.py +70 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/recognize_image.py +57 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/aitools-remote.min.js +2 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/aitools.min.js +2 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/chunks/46.17392fd62e1893d8f4e0.min.js +2 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/chunks/46.17392fd62e1893d8f4e0.min.js.map +1 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/chunks/692.cd4653742130a6d95d03.min.js +12 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/chunks/692.cd4653742130a6d95d03.min.js.map +1 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/chunks/709.828f420ec7e88f982470.min.js +2 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/chunks/709.828f420ec7e88f982470.min.js.map +1 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/chunks/87.2eb8178be9c49f8e5ae5.min.js +2 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/static/chunks/87.2eb8178be9c49f8e5ae5.min.js.map +1 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/suggest_tags.py +53 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/summarize.py +53 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/templates/assistant_viewlet.pt +7 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/templates/help_me_write_viewlet.pt +8 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/templates/recognize_image_viewlet.pt +8 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/templates/suggest_tags_viewlet.pt +8 -0
- collective_aitools-1.0.0/src/collective/aitools/browser/templates/summarize_viewlet.pt +8 -0
- collective_aitools-1.0.0/src/collective/aitools/capabilities/__init__.py +18 -0
- collective_aitools-1.0.0/src/collective/aitools/capabilities/base.py +76 -0
- collective_aitools-1.0.0/src/collective/aitools/capabilities/configure.zcml +24 -0
- collective_aitools-1.0.0/src/collective/aitools/capabilities/propose_draft.py +250 -0
- collective_aitools-1.0.0/src/collective/aitools/capabilities/search_site.py +68 -0
- collective_aitools-1.0.0/src/collective/aitools/capabilities/types.py +151 -0
- collective_aitools-1.0.0/src/collective/aitools/capabilities/where_to_add.py +103 -0
- collective_aitools-1.0.0/src/collective/aitools/configure.zcml +30 -0
- collective_aitools-1.0.0/src/collective/aitools/content/__init__.py +0 -0
- collective_aitools-1.0.0/src/collective/aitools/controlpanels/__init__.py +0 -0
- collective_aitools-1.0.0/src/collective/aitools/controlpanels/ai_tools.py +36 -0
- collective_aitools-1.0.0/src/collective/aitools/controlpanels/configure.zcml +22 -0
- collective_aitools-1.0.0/src/collective/aitools/dependencies.zcml +8 -0
- collective_aitools-1.0.0/src/collective/aitools/indexers/__init__.py +0 -0
- collective_aitools-1.0.0/src/collective/aitools/indexers/configure.zcml +7 -0
- collective_aitools-1.0.0/src/collective/aitools/interfaces.py +312 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/__init__.py +0 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/__main__.py +69 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/collective.aitools.pot +239 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/de/LC_MESSAGES/collective.aitools.mo +0 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/de/LC_MESSAGES/collective.aitools.po +236 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/en/LC_MESSAGES/collective.aitools.mo +0 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/en/LC_MESSAGES/collective.aitools.po +236 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/es/LC_MESSAGES/collective.aitools.mo +0 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/es/LC_MESSAGES/collective.aitools.po +236 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/it/LC_MESSAGES/collective.aitools.mo +0 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/it/LC_MESSAGES/collective.aitools.po +236 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/pt_BR/LC_MESSAGES/collective.aitools.mo +0 -0
- collective_aitools-1.0.0/src/collective/aitools/locales/pt_BR/LC_MESSAGES/collective.aitools.po +236 -0
- collective_aitools-1.0.0/src/collective/aitools/permissions.zcml +5 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/browserlayer.xml +6 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/catalog.xml +13 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/controlpanel.xml +21 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/diff_tool.xml +6 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/metadata.xml +7 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/registry/.gitkeep +0 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/registry/main.xml +10 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/registry/resources.xml +18 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/repositorytool.xml +6 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/rolemap.xml +6 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/types/.gitkeep +0 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/default/types.xml +10 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/initial/metadata.xml +4 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/uninstall/browserlayer.xml +6 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles/uninstall/registry.xml +10 -0
- collective_aitools-1.0.0/src/collective/aitools/profiles.zcml +41 -0
- collective_aitools-1.0.0/src/collective/aitools/serializers/__init__.py +0 -0
- collective_aitools-1.0.0/src/collective/aitools/serializers/configure.zcml +10 -0
- collective_aitools-1.0.0/src/collective/aitools/serializers/summary.py +10 -0
- collective_aitools-1.0.0/src/collective/aitools/services/__init__.py +0 -0
- collective_aitools-1.0.0/src/collective/aitools/services/assistant.py +187 -0
- collective_aitools-1.0.0/src/collective/aitools/services/configure.zcml +59 -0
- collective_aitools-1.0.0/src/collective/aitools/services/help_me_write.py +79 -0
- collective_aitools-1.0.0/src/collective/aitools/services/recognize_image.py +65 -0
- collective_aitools-1.0.0/src/collective/aitools/services/suggest_tags.py +55 -0
- collective_aitools-1.0.0/src/collective/aitools/services/summarize.py +55 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/__init__.py +17 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/.gitkeep +0 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/content/__metadata__.json +40 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/content/a58ccead718140c1baa98d43595fc3e6/data.json +56 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/content/a58ccead718140c1baa98d43595fc3e6/image/plone-foundation.png +0 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/content/a720393b3c0240e5bd27c43fcd2cfd1e/data.json +98 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/content/plone_site_root/data.json +267 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/principals.json +4 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/redirects.json +1 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/relations.json +1 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/examplecontent/translations.json +1 -0
- collective_aitools-1.0.0/src/collective/aitools/setuphandlers/initial.py +16 -0
- collective_aitools-1.0.0/src/collective/aitools/testing.py +49 -0
- collective_aitools-1.0.0/src/collective/aitools/tools/__init__.py +13 -0
- collective_aitools-1.0.0/src/collective/aitools/tools/assistant.py +124 -0
- collective_aitools-1.0.0/src/collective/aitools/tools/base.py +75 -0
- collective_aitools-1.0.0/src/collective/aitools/tools/configure.zcml +35 -0
- collective_aitools-1.0.0/src/collective/aitools/tools/help_me_write.py +83 -0
- collective_aitools-1.0.0/src/collective/aitools/tools/recognize_image.py +131 -0
- collective_aitools-1.0.0/src/collective/aitools/tools/suggest_tags.py +102 -0
- collective_aitools-1.0.0/src/collective/aitools/tools/summarize.py +53 -0
- collective_aitools-1.0.0/src/collective/aitools/tools/text.py +108 -0
- collective_aitools-1.0.0/src/collective/aitools/upgrades/__init__.py +0 -0
- collective_aitools-1.0.0/src/collective/aitools/upgrades/configure.zcml +21 -0
- collective_aitools-1.0.0/src/collective/aitools/vocabularies/__init__.py +0 -0
- collective_aitools-1.0.0/src/collective/aitools/vocabularies/configure.zcml +5 -0
- collective_aitools-1.0.0/tests/conftest.py +16 -0
- collective_aitools-1.0.0/tests/controlpanels/test_ai_tools.py +26 -0
- collective_aitools-1.0.0/tests/services/test_help_me_write.py +94 -0
- collective_aitools-1.0.0/tests/services/test_recognize_image.py +90 -0
- collective_aitools-1.0.0/tests/services/test_text_tools.py +107 -0
- collective_aitools-1.0.0/tests/setup/test_setup_install.py +28 -0
- collective_aitools-1.0.0/tests/setup/test_setup_uninstall.py +30 -0
- collective_aitools-1.0.0/tests/tools/test_text.py +63 -0
- collective_aitools-1.0.0/tests/tools/test_tools.py +252 -0
- collective_aitools-1.0.0/version.txt +1 -0
- collective_aitools-1.0.0/webpack.config.js +36 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
# EditorConfig Configuration file, for more details see:
|
|
3
|
+
# https://EditorConfig.org
|
|
4
|
+
# EditorConfig is a convention description, that could be interpreted
|
|
5
|
+
# by multiple editors to enforce common coding conventions for specific
|
|
6
|
+
# file types
|
|
7
|
+
|
|
8
|
+
# top-most EditorConfig file:
|
|
9
|
+
# Will ignore other EditorConfig files in Home directory or upper tree level.
|
|
10
|
+
root = true
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
[*] # For All Files
|
|
14
|
+
# Unix-style newlines with a newline ending every file
|
|
15
|
+
end_of_line = lf
|
|
16
|
+
insert_final_newline = true
|
|
17
|
+
trim_trailing_whitespace = true
|
|
18
|
+
# Set default charset
|
|
19
|
+
charset = utf-8
|
|
20
|
+
# Indent style default
|
|
21
|
+
indent_style = space
|
|
22
|
+
|
|
23
|
+
[*.{py,cfg,ini}]
|
|
24
|
+
# 4 space indentation
|
|
25
|
+
indent_size = 4
|
|
26
|
+
|
|
27
|
+
[*.{html,dtml,pt,zpt,xml,zcml,js,json,ts,less,scss,css,sass,yml,yaml}]
|
|
28
|
+
# 2 space indentation
|
|
29
|
+
indent_size = 2
|
|
30
|
+
|
|
31
|
+
[{Makefile,.gitmodules}]
|
|
32
|
+
# Tab indentation (no size specified, but view as 4 spaces)
|
|
33
|
+
indent_style = tab
|
|
34
|
+
indent_size = unset
|
|
35
|
+
tab_width = unset
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generated from:
|
|
2
|
+
# https://github.com/plone/meta/tree/master/config/default
|
|
3
|
+
# See the inline comments on how to expand/tweak this configuration file
|
|
4
|
+
[flake8]
|
|
5
|
+
doctests = 1
|
|
6
|
+
ignore =
|
|
7
|
+
# black takes care of line length
|
|
8
|
+
E501,
|
|
9
|
+
# black takes care of where to break lines
|
|
10
|
+
W503,
|
|
11
|
+
# black takes care of spaces within slicing (list[:])
|
|
12
|
+
E203,
|
|
13
|
+
# black takes care of spaces after commas
|
|
14
|
+
E231,
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# Add extra configuration options in .meta.toml:
|
|
18
|
+
# [flake8]
|
|
19
|
+
# extra_lines = """
|
|
20
|
+
# _your own configuration lines_
|
|
21
|
+
# """
|
|
22
|
+
##
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# python related
|
|
2
|
+
*.egg-info
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
|
|
6
|
+
# tools related
|
|
7
|
+
__pycache__/
|
|
8
|
+
.coverage
|
|
9
|
+
.mypy_cache
|
|
10
|
+
.pytest_cache
|
|
11
|
+
.ruff_cache
|
|
12
|
+
/build/
|
|
13
|
+
coverage.xml
|
|
14
|
+
dist/
|
|
15
|
+
docs/_build
|
|
16
|
+
node_modules/
|
|
17
|
+
|
|
18
|
+
# Classic UI resources build (webpack); source lives in resources/, output
|
|
19
|
+
# under src/collective/aitools/browser/static is committed.
|
|
20
|
+
/stats.json
|
|
21
|
+
/src/collective/aitools/browser/static/*.map
|
|
22
|
+
|
|
23
|
+
# venv / buildout related
|
|
24
|
+
.eggs/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
.mr.developer.cfg
|
|
27
|
+
.venv/
|
|
28
|
+
bin/
|
|
29
|
+
develop-eggs/
|
|
30
|
+
eggs/
|
|
31
|
+
etc/
|
|
32
|
+
include/
|
|
33
|
+
lib/
|
|
34
|
+
lib64
|
|
35
|
+
parts/
|
|
36
|
+
pyvenv.cfg
|
|
37
|
+
var/
|
|
38
|
+
|
|
39
|
+
# mxdev
|
|
40
|
+
.installed.txt
|
|
41
|
+
.lock
|
|
42
|
+
/.mxdev_cache/
|
|
43
|
+
/.make-sentinels/
|
|
44
|
+
/*-mxdev.txt
|
|
45
|
+
/instance/
|
|
46
|
+
/reports/
|
|
47
|
+
/sources/
|
|
48
|
+
/venv/
|
|
49
|
+
constraints*.txt
|
|
50
|
+
requirements*.txt
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# AGENTS.md — backend
|
|
2
|
+
|
|
3
|
+
Agent guide for the `collective.aitools` Plone add-on (`backend/`). For
|
|
4
|
+
the cross-cutting picture of how this half relates to the Volto half
|
|
5
|
+
and to the `collective.aisettings` dependency, read
|
|
6
|
+
[`../AGENTS.md`](../AGENTS.md) first.
|
|
7
|
+
|
|
8
|
+
## Scope
|
|
9
|
+
|
|
10
|
+
Anything under `backend/src/collective/aitools/` plus the package
|
|
11
|
+
metadata (`pyproject.toml`, `instance.yaml`, `mx.ini`, profiles, ZCML).
|
|
12
|
+
|
|
13
|
+
The frontend Volto add-on (`frontend/packages/volto-collective-aitools/`)
|
|
14
|
+
is documented at [`../frontend/AGENTS.md`](../frontend/AGENTS.md). Don't
|
|
15
|
+
edit it from this side; coordinate cross-half changes via REST/registry
|
|
16
|
+
contracts and land both sides together.
|
|
17
|
+
|
|
18
|
+
**Do not edit `backend/sources/`** — it is an mxdev checkout of
|
|
19
|
+
`collective.aisettings` (and any other VCS sources from `mx.ini`),
|
|
20
|
+
read-only as far as this repo is concerned.
|
|
21
|
+
|
|
22
|
+
## The `collective.aisettings` dependency
|
|
23
|
+
|
|
24
|
+
This add-on connects to LLMs **only** through `collective.aisettings`.
|
|
25
|
+
It is a hard dependency (declared in [`pyproject.toml`](pyproject.toml)
|
|
26
|
+
`dependencies`) and pulled into the dev venv from a local checkout via
|
|
27
|
+
[`mx.ini`](mx.ini) (`url = collective.aisettings`,
|
|
28
|
+
`subdirectory = backend`). `mx.ini` also pins a few transitive
|
|
29
|
+
versions (`pydantic-ai-slim`, `pydantic`, `h11`, …) to keep
|
|
30
|
+
`collective.aisettings`' pydantic-ai stack compatible with Plone's
|
|
31
|
+
constraints — see the comments there before changing any pin.
|
|
32
|
+
|
|
33
|
+
To make an AI call from Python, get the `IAIService` utility from
|
|
34
|
+
`collective.aisettings` rather than calling an LLM SDK directly:
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from zope.component import getUtility
|
|
38
|
+
from collective.aisettings.interfaces import IAIService
|
|
39
|
+
|
|
40
|
+
service = getUtility(IAIService)
|
|
41
|
+
result = service.chat(prompt="…", context=context)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Capability resolution, the permission gate, and the registry JSON
|
|
45
|
+
schema all live in `collective.aisettings`. Its
|
|
46
|
+
`backend/sources/collective.aisettings/backend/AGENTS.md` is the
|
|
47
|
+
reference; don't reimplement model resolution or key handling here.
|
|
48
|
+
|
|
49
|
+
## Package layout
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
backend/src/collective/aitools/
|
|
53
|
+
├── __init__.py ← __version__, PACKAGE_NAME, MessageFactory (_), logger
|
|
54
|
+
├── configure.zcml ← package root: translations + includes subpackages
|
|
55
|
+
├── AGENTS.md ← in-package guide: the AI tools framework + control panel ← READ
|
|
56
|
+
├── dependencies.zcml ← <include> plone.restapi + plone.volto + collective.aisettings
|
|
57
|
+
├── permissions.zcml ← add/declare permissions here
|
|
58
|
+
├── profiles.zcml ← GenericSetup profile registrations (default/uninstall/initial)
|
|
59
|
+
├── interfaces.py ← IBrowserLayer + IAITool + IAIAssistantCapability + IContentTypeSynonyms + IAIToolsSettings
|
|
60
|
+
├── testing.py ← PloneSandboxLayer + INTEGRATION/FUNCTIONAL/ACCEPTANCE layers
|
|
61
|
+
├── setuphandlers/ ← INonInstallable (hidden profiles) + post-install + example content
|
|
62
|
+
├── tools/ ← the AI tools (named IAITool utilities) — see src AGENTS.md
|
|
63
|
+
├── capabilities/ ← assistant capabilities (named IAIAssistantCapability utilities) — see src AGENTS.md
|
|
64
|
+
├── controlpanels/ ← "AI Tools" control panel (RegistryEditForm + restapi adapter)
|
|
65
|
+
├── services/ ← plone.restapi services — @aitools-* endpoints (incl. @aitools-assistant)
|
|
66
|
+
├── browser/ ← viewlets (Patternslib triggers) + static/ (committed webpack bundle output)
|
|
67
|
+
├── content/ ← (empty stub) dexterity content types
|
|
68
|
+
├── indexers/ ← (empty stub) portal_catalog indexers
|
|
69
|
+
├── serializers/ ← plone.restapi serializers — summary.py adds listing metadata
|
|
70
|
+
├── vocabularies/ ← (empty stub) zope.schema vocabularies
|
|
71
|
+
├── upgrades/ ← (empty stub) GenericSetup upgrade steps
|
|
72
|
+
├── locales/ ← i18n (.pot/.po); __main__.py drives `make i18n`
|
|
73
|
+
└── profiles/
|
|
74
|
+
├── default/ ← install profile (registry, catalog, types, browserlayer, controlpanel)
|
|
75
|
+
├── initial/ ← initial metadata
|
|
76
|
+
└── uninstall/ ← uninstall profile (hidden via setuphandlers)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The product's features are **AI tools** — named `IAITool` utilities under
|
|
80
|
+
`tools/`, enabled/configured from the "AI Tools" control panel
|
|
81
|
+
(`controlpanels/`), each calling the `collective.aisettings` `IAIService`. One
|
|
82
|
+
of them, `assistant`, is an **agentic chat** that dispatches to **capabilities**
|
|
83
|
+
(named `IAIAssistantCapability` utilities under `capabilities/`) via
|
|
84
|
+
`IAIService.tool_call`, with a classic-UI floating chat widget. The detailed
|
|
85
|
+
framework docs (anatomy of a tool, the assistant + capabilities, the add-a-tool
|
|
86
|
+
/ add-a-capability checklists, what's deferred) live in
|
|
87
|
+
[`src/collective/aitools/AGENTS.md`](src/collective/aitools/AGENTS.md) — read
|
|
88
|
+
that before adding or changing a tool.
|
|
89
|
+
|
|
90
|
+
`serializers/summary.py` is the other non-trivial piece: an
|
|
91
|
+
`IJSONSummarySerializerMetadata` utility that adds `image_field`,
|
|
92
|
+
`image_scales`, `effective`, and `Subject` to REST listing summaries. The
|
|
93
|
+
`content` / `indexers` / `vocabularies` / `upgrades` subpackages are still
|
|
94
|
+
empty `__init__.py` stubs wired into
|
|
95
|
+
[`configure.zcml`](src/collective/aitools/configure.zcml).
|
|
96
|
+
|
|
97
|
+
## How it's wired (ZCML cheat sheet)
|
|
98
|
+
|
|
99
|
+
- [`configure.zcml`](src/collective/aitools/configure.zcml) — registers
|
|
100
|
+
`locales`, includes `Products.CMFCore` permissions, then
|
|
101
|
+
`dependencies.zcml`, `profiles.zcml`, `permissions.zcml`, and the
|
|
102
|
+
`.browser` / `.controlpanels` / `.indexers` / `.serializers` /
|
|
103
|
+
`.services` / `.tools` / `.vocabularies` subpackages. **Add new
|
|
104
|
+
subpackages to the include list here.** The `++plone++collective.aitools`
|
|
105
|
+
static directory (`browser/static/`, the committed webpack bundle output) is
|
|
106
|
+
registered with `<plone:static>` in `browser/configure.zcml`; the Classic UI
|
|
107
|
+
source lives in `backend/resources/` (see the src AGENTS.md for the build).
|
|
108
|
+
- Auto-included into Plone via the `z3c.autoinclude.plugin` entry point
|
|
109
|
+
(`target = "plone"`) in [`pyproject.toml`](pyproject.toml).
|
|
110
|
+
- [`dependencies.zcml`](src/collective/aitools/dependencies.zcml) —
|
|
111
|
+
`plone.restapi` + `plone.volto` + `collective.aisettings`. Add backend
|
|
112
|
+
dependency ZCML here.
|
|
113
|
+
- Profile metadata version is `1000`
|
|
114
|
+
([`profiles/default/metadata.xml`](src/collective/aitools/profiles/default/metadata.xml));
|
|
115
|
+
it depends on `profile-plone.volto:default` and
|
|
116
|
+
`profile-collective.aisettings:default`. The install test asserts this
|
|
117
|
+
version, so when you add an upgrade step, bump the version here and add
|
|
118
|
+
the step under `upgrades/`.
|
|
119
|
+
- `plone.exportimport` (Plone 6.1 core, used by `setuphandlers/initial.py`
|
|
120
|
+
for example content) must be present in the venv — both this package and
|
|
121
|
+
`collective.aisettings` import it at profile-registration time. If a
|
|
122
|
+
fresh `make install` lacks it, install `plone.exportimport==2.0.1`.
|
|
123
|
+
|
|
124
|
+
## Conventions
|
|
125
|
+
|
|
126
|
+
- Imports: ruff isort config is `force-single-line`, `from-first`,
|
|
127
|
+
`no-sections` (one import per line, `from x import y` style, no
|
|
128
|
+
grouping). `make format` enforces it.
|
|
129
|
+
- Use the module-level `_ = MessageFactory("collective.aitools")` from
|
|
130
|
+
`__init__.py` for translatable strings; i18n domain is
|
|
131
|
+
`collective.aitools` everywhere (ZCML `i18n_domain`, locales).
|
|
132
|
+
- Use the package `logger` from `__init__.py` rather than ad-hoc
|
|
133
|
+
logging.
|
|
134
|
+
- Python ≥ 3.11; line length 88; target Plone 6.1 / 6.2.
|
|
135
|
+
|
|
136
|
+
## Tests
|
|
137
|
+
|
|
138
|
+
Pytest via `pytest-plone`, configured in
|
|
139
|
+
[`pyproject.toml`](pyproject.toml) (`testpaths = ["tests"]`). Tests live
|
|
140
|
+
in [`tests/`](tests/) (sibling of `src/`, not inside the package):
|
|
141
|
+
|
|
142
|
+
- [`tests/conftest.py`](tests/conftest.py) builds fixtures from the
|
|
143
|
+
three layers in
|
|
144
|
+
[`testing.py`](src/collective/aitools/testing.py) via
|
|
145
|
+
`pytest_plone.fixtures_factory` (`integration`, `functional`,
|
|
146
|
+
`acceptance` fixtures).
|
|
147
|
+
- [`tests/setup/`](tests/setup/) covers install/uninstall (profile
|
|
148
|
+
version, browserlayer registration, product (un)installed).
|
|
149
|
+
- [`tests/tools/`](tests/tools/) covers tool registration, enable/model
|
|
150
|
+
resolution, and `run` (using a `fake_service` fixture that swaps the
|
|
151
|
+
global `IAIService` for a recorder — no network/model needed).
|
|
152
|
+
- [`tests/controlpanels/`](tests/controlpanels/) covers the AI Tools
|
|
153
|
+
control panel (registry records, classic page, restapi configlet).
|
|
154
|
+
|
|
155
|
+
Mirror the `tests/<area>/test_*.py` layout when you add a feature.
|
|
156
|
+
`tests/*` files relax some ruff rules (`E501`, `RUF001`, `S101`) so
|
|
157
|
+
asserts and long lines are fine in tests.
|
|
158
|
+
|
|
159
|
+
## Validation commands
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
# From backend/
|
|
163
|
+
make install # uv venv + mxdev-resolved deps (pulls collective.aisettings) + instance config
|
|
164
|
+
make create-site # create the Plone site with the addon profile
|
|
165
|
+
make start # backend on :8080 (runwsgi)
|
|
166
|
+
make console # zconsole debug shell into the instance
|
|
167
|
+
|
|
168
|
+
make format # ruff (incl. import sort) + zpretty for XML/ZCML
|
|
169
|
+
make lint # ruff check + pyroma + check-python-versions + zpretty --check
|
|
170
|
+
make test # pytest
|
|
171
|
+
make test-coverage # pytest --cov
|
|
172
|
+
make i18n # rebuild .pot/.po (python -m collective.aitools.locales)
|
|
173
|
+
make install-npm # npm install (Classic UI resources, first time)
|
|
174
|
+
make build-resources # npm run build → browser/static/aitools-*.min.js (webpack)
|
|
175
|
+
make check-resources # CI: build + fail if the committed bundle is stale
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`make install` is required before tests (it creates `.venv` and
|
|
179
|
+
resolves dependencies through mxdev). Lint/format run via `uvx` and
|
|
180
|
+
don't need the venv.
|
|
181
|
+
|
|
182
|
+
## Editing rules
|
|
183
|
+
|
|
184
|
+
- **Keep this file and the in-package guide current.** When you add real
|
|
185
|
+
code under `src/collective/aitools/` — a content type, REST service,
|
|
186
|
+
control panel, vocabulary, indexer, upgrade step — update the layout
|
|
187
|
+
and the relevant section above. If the package grows enough that a
|
|
188
|
+
subtree needs its own detailed notes, create an `AGENTS.md` inside
|
|
189
|
+
`src/collective/aitools/` (or the specific subpackage) and keep it in
|
|
190
|
+
sync as that code changes. Treat a code change in those folders and
|
|
191
|
+
its `AGENTS.md` update as one unit of work.
|
|
192
|
+
- Anything AI/LLM-related goes through `collective.aisettings`' public
|
|
193
|
+
API (the `IAIService` utility / its REST endpoints). Don't add LLM
|
|
194
|
+
SDK calls, API-key fields, or model-resolution logic here.
|
|
195
|
+
- When you add a subpackage with ZCML, include it from
|
|
196
|
+
`configure.zcml`; when you add an upgrade, bump the profile version in
|
|
197
|
+
`profiles/default/metadata.xml` and register the step under
|
|
198
|
+
`upgrades/`.
|
|
199
|
+
- Don't edit `backend/sources/` or import private internals of
|
|
200
|
+
`collective.aisettings`; depend on its documented interfaces.
|
|
201
|
+
- Changes sharing a contract with the Volto add-on (a REST service it
|
|
202
|
+
calls, a registry record both UIs read) must land together with the
|
|
203
|
+
frontend change — see [`../frontend/AGENTS.md`](../frontend/AGENTS.md).
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
You should *NOT* be adding new change log entries to this file.
|
|
5
|
+
You should create a file in the news directory instead.
|
|
6
|
+
For helpful instructions, please see:
|
|
7
|
+
https://github.com/plone/plone.releaser/blob/master/ADD-A-NEWS-ITEM.rst
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<!-- towncrier release notes start -->
|
|
11
|
+
|
|
12
|
+
## 1.0.0 (2026-07-15)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### New features:
|
|
16
|
+
|
|
17
|
+
- "Recognize image" now returns structured metadata — a title, a description and
|
|
18
|
+
5–10 tags — as JSON. A new "Get image details" button on Classic UI edit/add
|
|
19
|
+
forms sends the chosen image to the ``@aitools-recognize-image`` REST endpoint
|
|
20
|
+
and fills in the Title, Description and Tags fields that are still empty. A
|
|
21
|
+
``scripts/recognize_images.py`` CLI script (``make recognize-images``) backfills
|
|
22
|
+
those fields across every image on the site, with an optional ``--path`` to
|
|
23
|
+
limit it to a subtree. @frapell
|
|
24
|
+
- Add an "AI Tools" control panel and a tools framework (named ``IAITool``
|
|
25
|
+
utilities), with two initial Classic UI tools: "Recognize image" (vision)
|
|
26
|
+
and "Help me write" (drafting/rewriting). "Help me write" adds a button to
|
|
27
|
+
TinyMCE rich-text fields on edit/add forms, backed by the
|
|
28
|
+
``@aitools-help-me-write`` REST endpoint. Tools reach a model through
|
|
29
|
+
``collective.aisettings``. @frapell
|
|
30
|
+
- Add an agentic chat "Assistant" for authenticated users. It runs a tool-calling
|
|
31
|
+
loop (via ``collective.aisettings``' ``IAIService.tool_call``) over a set of
|
|
32
|
+
*capabilities* — named ``IAIAssistantCapability`` utilities — that ground its
|
|
33
|
+
answers: "Search the site", "Where to add" (suggest folders for a content type)
|
|
34
|
+
and "Propose a draft" (generate a draft from a rough brief for the editor to
|
|
35
|
+
confirm). Capabilities are permission-gated per user, and any content creation
|
|
36
|
+
only happens after an explicit confirmation, re-validated server-side by the
|
|
37
|
+
``@aitools-assistant`` / ``@aitools-assistant-apply`` endpoints. Ships a
|
|
38
|
+
Classic UI floating chat widget (Markdown rendering, session persistence,
|
|
39
|
+
"start new chat"). Loose content-type names are accepted and add-ons can
|
|
40
|
+
contribute more via an ``IContentTypeSynonyms`` utility. @frapell
|
|
41
|
+
- Add two editor tools: "Summarize" fills an item's Description from its body
|
|
42
|
+
text (also usable as the SEO meta description), and "Suggest tags" proposes
|
|
43
|
+
Subject keywords from the body text, reusing tags already in use on the site.
|
|
44
|
+
Both offer a Classic UI edit-form button (``@aitools-summarize`` /
|
|
45
|
+
``@aitools-suggest-tags`` endpoints) and a CLI backfill script
|
|
46
|
+
(``make summarize-content`` / ``make suggest-tags``, with an optional
|
|
47
|
+
``--path``). @frapell
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### Internal:
|
|
51
|
+
|
|
52
|
+
- Refactor the Classic UI JavaScript into ES6 Patternslib modules under
|
|
53
|
+
``backend/resources/``, built with webpack (``@patternslib/dev``) into a single
|
|
54
|
+
``aitools`` bundle registered through the Plone resource registry — replacing
|
|
55
|
+
the hand-minified ``browser/static`` assets and the ``rjsmin``/``rcssmin`` step.
|
|
56
|
+
Build with ``make build-resources``. @frapell
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
ARG PLONE_VERSION=6.0.15
|
|
3
|
+
FROM plone/server-builder:${PLONE_VERSION} AS builder
|
|
4
|
+
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Add local code
|
|
9
|
+
COPY scripts/ scripts/
|
|
10
|
+
COPY . src
|
|
11
|
+
|
|
12
|
+
# Install local requirements and pre-compile mo files
|
|
13
|
+
RUN <<EOT
|
|
14
|
+
set -e
|
|
15
|
+
bin/pip install mxdev uv
|
|
16
|
+
sed -i 's/-e .\[test\]/./g' src/mx.ini
|
|
17
|
+
cd /app/src
|
|
18
|
+
# remove potentially existing virtualenv from local build
|
|
19
|
+
rm -rf .venv
|
|
20
|
+
../bin/mxdev -c mx.ini
|
|
21
|
+
../bin/uv pip install -r requirements-mxdev.txt
|
|
22
|
+
../bin/python /compile_mo.py
|
|
23
|
+
EOT
|
|
24
|
+
|
|
25
|
+
FROM plone/server-prod-config:${PLONE_VERSION}
|
|
26
|
+
|
|
27
|
+
LABEL maintainer="Franco Pellegrini <frapell@gmail.com>" \
|
|
28
|
+
org.label-schema.name="collective-ai-tools-backend" \
|
|
29
|
+
org.label-schema.description="Collective AI Tools backend image." \
|
|
30
|
+
org.label-schema.vendor="Franco Pellegrini"
|
|
31
|
+
|
|
32
|
+
# Copy /app from builder
|
|
33
|
+
COPY --from=builder /app /app
|
|
34
|
+
|
|
35
|
+
RUN <<EOT
|
|
36
|
+
set -e
|
|
37
|
+
ln -s /data /app/var
|
|
38
|
+
EOT
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
ARG PLONE_VERSION=6.0.15
|
|
3
|
+
FROM plone/server-builder:${PLONE_VERSION} AS builder
|
|
4
|
+
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Add local code
|
|
9
|
+
COPY scripts/ scripts/
|
|
10
|
+
COPY . src
|
|
11
|
+
|
|
12
|
+
# Install local requirements and pre-compile mo files
|
|
13
|
+
RUN <<EOT
|
|
14
|
+
set -e
|
|
15
|
+
bin/pip install mxdev uv
|
|
16
|
+
sed -i 's/-e .\[test\]/./g' src/mx.ini
|
|
17
|
+
cd /app/src
|
|
18
|
+
# remove potentially existing virtualenv from local build
|
|
19
|
+
rm -rf .venv
|
|
20
|
+
../bin/mxdev -c mx.ini
|
|
21
|
+
../bin/uv pip install -r requirements-mxdev.txt
|
|
22
|
+
../bin/python /compile_mo.py
|
|
23
|
+
EOT
|
|
24
|
+
|
|
25
|
+
FROM plone/server-acceptance:${PLONE_VERSION}
|
|
26
|
+
|
|
27
|
+
LABEL maintainer="Franco Pellegrini <frapell@gmail.com>" \
|
|
28
|
+
org.label-schema.name="collective-ai-tools-acceptance" \
|
|
29
|
+
org.label-schema.description="Collective AI Tools backend acceptance image." \
|
|
30
|
+
org.label-schema.vendor="Franco Pellegrini"
|
|
31
|
+
|
|
32
|
+
ENV CONFIGURE_PACKAGES="plone.restapi,plone.volto,plone.volto.cors,collective.aitools"
|
|
33
|
+
ENV APPLY_PROFILES="collective.aitools:default"
|
|
34
|
+
|
|
35
|
+
# Copy /app from builder
|
|
36
|
+
COPY --from=builder /app /app
|
|
37
|
+
|
|
38
|
+
RUN <<EOT
|
|
39
|
+
ln -s /data /app/var
|
|
40
|
+
EOT
|