Metadata writer #17
@@ -1,3 +1,5 @@
|
|||||||
LLM_API_BASE_URL = "http://localhost:1234/v1"
|
LLM_API_BASE_URL = "http://localhost:1234/v1"
|
||||||
LLM_API_KEY = "not-relevant"
|
LLM_API_KEY = "not-relevant"
|
||||||
LLM_DEFAULT_TEMPERATURE = 1.0
|
LLM_DEFAULT_TEMPERATURE = 1.0
|
||||||
|
|
||||||
|
METADATA_PREFIX = "photools:"
|
||||||
|
|||||||
@@ -17,12 +17,10 @@ from photools3.models import (
|
|||||||
LlmResponseQuality,
|
LlmResponseQuality,
|
||||||
)
|
)
|
||||||
from photools3.photo import Photo
|
from photools3.photo import Photo
|
||||||
from photools3.settings import Settings
|
from photools3.settings import settings
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
settings = Settings() # type: ignore[reportCallIssue]
|
|
||||||
|
|
||||||
|
|
||||||
class LlmSession:
|
class LlmSession:
|
||||||
base_url: str = str(settings.llm_api_base_url)
|
base_url: str = str(settings.llm_api_base_url)
|
||||||
|
|||||||
@@ -1,15 +1,48 @@
|
|||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Annotated, Any
|
||||||
|
|
||||||
|
import exiftool
|
||||||
|
from pydantic import StringConstraints
|
||||||
|
|
||||||
|
from photools3.settings import settings
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
# File extensions that should use XMP sidecars
|
# File extensions that should use XMP sidecars
|
||||||
SIDECAR_EXTENSIONS = {".dng", ".nef", ".cr2", ".cr3", ".arw", ".raf", ".orf", ".rw2"}
|
SIDECAR_EXTENSIONS = {".dng", ".nef", ".cr2", ".cr3", ".arw", ".raf", ".orf", ".rw2"}
|
||||||
|
|
||||||
|
XmpKey = Annotated[str, StringConstraints(pattern=r"^\w+\:\w+")]
|
||||||
|
|
||||||
type Caption = str | None
|
type Caption = str | None
|
||||||
type Keywords = list[str] | None
|
type Keywords = list[str] | None
|
||||||
type Color = 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:
|
class MetadataWriter:
|
||||||
|
|||||||
@@ -18,3 +18,8 @@ class Settings(BaseSettings):
|
|||||||
llm_api_base_url: Url
|
llm_api_base_url: Url
|
||||||
llm_api_key: str
|
llm_api_key: str
|
||||||
llm_default_temperature: float
|
llm_default_temperature: float
|
||||||
|
|
||||||
|
metadata_prefix: str
|
||||||
|
|
||||||
|
|
||||||
|
settings = Settings() # type: ignore[reportCallIssue]
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user