From 084676eca04f4df2beacd2937f1441a68a8edb58 Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 6 Oct 2026 07:52:36 +0200 Subject: [PATCH] metadata writer: some progress --- .env.template | 2 ++ src/photools3/llm_session.py | 4 +--- src/photools3/metadata_writer.py | 33 ++++++++++++++++++++++++++++++++ src/photools3/settings.py | 5 +++++ test/test_metadata_writer.py | 8 ++++++++ 5 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 test/test_metadata_writer.py diff --git a/.env.template b/.env.template index 69a0aea..a23d47b 100644 --- a/.env.template +++ b/.env.template @@ -1,3 +1,5 @@ LLM_API_BASE_URL = "http://localhost:1234/v1" LLM_API_KEY = "not-relevant" LLM_DEFAULT_TEMPERATURE = 1.0 + +METADATA_PREFIX = "photools:" diff --git a/src/photools3/llm_session.py b/src/photools3/llm_session.py index e3b1f4a..430e2c4 100644 --- a/src/photools3/llm_session.py +++ b/src/photools3/llm_session.py @@ -17,12 +17,10 @@ from photools3.models import ( LlmResponseQuality, ) from photools3.photo import Photo -from photools3.settings import Settings +from photools3.settings import settings logger = logging.getLogger(__name__) -settings = Settings() # type: ignore[reportCallIssue] - class LlmSession: base_url: str = str(settings.llm_api_base_url) diff --git a/src/photools3/metadata_writer.py b/src/photools3/metadata_writer.py index 6f92e91..ca7714a 100644 --- a/src/photools3/metadata_writer.py +++ b/src/photools3/metadata_writer.py @@ -1,15 +1,48 @@ import logging from pathlib import Path +from typing import Annotated, Any + +import exiftool +from pydantic import StringConstraints + +from photools3.settings import settings log = logging.getLogger(__name__) # File extensions that should use XMP sidecars SIDECAR_EXTENSIONS = {".dng", ".nef", ".cr2", ".cr3", ".arw", ".raf", ".orf", ".rw2"} +XmpKey = Annotated[str, StringConstraints(pattern=r"^\w+\:\w+")] type Caption = str | None type Keywords = list[str] | None type Color = str | None +type XmpMetadata = dict[str, Any] + +XMO_KEYS_CAPTION: list[XmpKey] = [ + "EXIF:ImageDescription", + "XMP:Description", + "IPTC:Caption-Abstract", +] + +XMP_KEYS_TAG: list[XmpKey] = [ + "XMP:HierarchicalSubject", + "XMP:Subject", + "IPTC:Keywords", +] + + +def _prefixed(txt: str) -> str: + return f"{settings.metadata_prefix} {txt}" + + +def read_metadata(path: Path) -> XmpMetadata | None: + try: + with exiftool.ExifToolHelper() as exif: + return exif.get_metadata([str(path)])[0] + except Exception as exc: # noqa: BLE001 + log.error(f"Could not read metadata from {path}: {exc}") + class MetadataWriter: diff --git a/src/photools3/settings.py b/src/photools3/settings.py index 3e0d1b4..22d65cb 100644 --- a/src/photools3/settings.py +++ b/src/photools3/settings.py @@ -18,3 +18,8 @@ class Settings(BaseSettings): llm_api_base_url: Url llm_api_key: str llm_default_temperature: float + + metadata_prefix: str + + +settings = Settings() # type: ignore[reportCallIssue] diff --git a/test/test_metadata_writer.py b/test/test_metadata_writer.py new file mode 100644 index 0000000..dc0a938 --- /dev/null +++ b/test/test_metadata_writer.py @@ -0,0 +1,8 @@ + +from photools3.metadata_writer import read_metadata +from test.test_photo import PATHS_DNG_EXAMPLES + + +def test_read_metadata(): + result = read_metadata(PATHS_DNG_EXAMPLES[0]) + assert result