streamlit-octostar-utils 0.6.5.dev2__tar.gz → 0.6.6__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.
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/PKG-INFO +2 -1
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/pyproject.toml +2 -1
- streamlit_octostar_utils-0.6.6/streamlit_octostar_utils/metadata/__init__.py +17 -0
- streamlit_octostar_utils-0.6.6/streamlit_octostar_utils/metadata/parent_meta.py +152 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/LICENSE +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/README.md +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/celery.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/contents.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/fastapi.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/nifi.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parallelism.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/combine_fields.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/entities_parser.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/generics.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/info.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/linkchart_functions.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/matches.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/parameters.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/rules.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/api_crafter/parser/signals.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/core/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/core/dict.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/core/filetypes.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/core/opensearch_conversion.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/core/threading/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/core/threading/key_queue.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/core/timestamp.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/nlp/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/nlp/custom_recognizers.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/nlp/language.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/nlp/ner.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/octostar/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/octostar/client.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/octostar/context.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/octostar/permissions.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/ontology/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/ontology/inheritance.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/ontology/relationships.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/ontology/validation.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/style/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/style/common.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/threading/__init__.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/threading/async_task_manager.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/threading/session_callback_manager.py +0 -0
- {streamlit_octostar_utils-0.6.5.dev2 → streamlit_octostar_utils-0.6.6}/streamlit_octostar_utils/threading/session_state_hot_swapper.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: streamlit-octostar-utils
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.6
|
|
4
4
|
Summary:
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -24,6 +24,7 @@ Requires-Dist: iso639-lang (>=2.0.0,<3.0.0) ; extra == "nlp"
|
|
|
24
24
|
Requires-Dist: nltk (>=3.8.0,<4.0.0) ; extra == "nlp"
|
|
25
25
|
Requires-Dist: numpy (>=1.20.0)
|
|
26
26
|
Requires-Dist: octostar-streamlit (>=0.1.25,<0.2.0)
|
|
27
|
+
Requires-Dist: pillow (>=10.0.0)
|
|
27
28
|
Requires-Dist: pottery (>=3.0.0,<4.0.0)
|
|
28
29
|
Requires-Dist: presidio-analyzer (>=2.2.0,<3.0.0) ; extra == "nlp"
|
|
29
30
|
Requires-Dist: psutil (>=5.9.0)
|
|
@@ -5,7 +5,7 @@ include = '\.pyi?$'
|
|
|
5
5
|
|
|
6
6
|
[tool.poetry]
|
|
7
7
|
name = "streamlit-octostar-utils"
|
|
8
|
-
version = "0.6.
|
|
8
|
+
version = "0.6.6"
|
|
9
9
|
description = ""
|
|
10
10
|
license = "MIT"
|
|
11
11
|
authors = ["Octostar"]
|
|
@@ -43,6 +43,7 @@ pottery = "^3.0.0"
|
|
|
43
43
|
slowapi = "^0.1.9"
|
|
44
44
|
filetype = "^1.2.0"
|
|
45
45
|
PyJWT = "^2.5.0"
|
|
46
|
+
pillow = ">=10.0.0"
|
|
46
47
|
#octostar-python-client = "^1.0.0"
|
|
47
48
|
py3langid = { version = ">=0.2.0,<0.3.0", optional = true }
|
|
48
49
|
spacy-download = { version = "==1.1.0", optional = true }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from streamlit_octostar_utils.metadata.parent_meta import (
|
|
2
|
+
EXIF_PASSTHROUGH_FIELDS,
|
|
3
|
+
OS_PARENT_META_PREFIX,
|
|
4
|
+
embed_png_parent_meta,
|
|
5
|
+
ffmpeg_metadata_args,
|
|
6
|
+
resolve_with_aliases,
|
|
7
|
+
select_parent_meta_passthrough,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"EXIF_PASSTHROUGH_FIELDS",
|
|
12
|
+
"OS_PARENT_META_PREFIX",
|
|
13
|
+
"embed_png_parent_meta",
|
|
14
|
+
"ffmpeg_metadata_args",
|
|
15
|
+
"resolve_with_aliases",
|
|
16
|
+
"select_parent_meta_passthrough",
|
|
17
|
+
]
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Parent->child EXIF passthrough protocol.
|
|
2
|
+
|
|
3
|
+
Producer routes that create new derived files (face crops, video keyframes,
|
|
4
|
+
extracted audio) carry the parent's EXIF date/GPS tags through to downstream
|
|
5
|
+
extract-metadata by embedding ``os_parent_meta_<canonical>`` keys into the
|
|
6
|
+
child file's metadata container:
|
|
7
|
+
|
|
8
|
+
* PNG: ``tEXt`` chunks via :func:`embed_png_parent_meta`.
|
|
9
|
+
* Audio/video containers: ffmpeg ``-metadata`` flags via
|
|
10
|
+
:func:`ffmpeg_metadata_args`.
|
|
11
|
+
|
|
12
|
+
The reader recovers them through :func:`resolve_with_aliases`, which is
|
|
13
|
+
prefix-aware so it works whether exiftool surfaces the embedded key directly
|
|
14
|
+
or with a format-specific group prefix (``PNG:``, ``ID3:``, ``RIFF:``,
|
|
15
|
+
``pdf:docinfo:custom:``, ...).
|
|
16
|
+
|
|
17
|
+
Keep producer and reader on the same version of this module: the suffix-match
|
|
18
|
+
in :func:`resolve_with_aliases` is the only piece that knows what prefixes
|
|
19
|
+
the various containers slap on, and a new container format means changes here
|
|
20
|
+
that both sides must see.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from io import BytesIO
|
|
24
|
+
from typing import Any, Dict, List
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
OS_PARENT_META_PREFIX = "os_parent_meta_"
|
|
28
|
+
|
|
29
|
+
_PDF_CUSTOM_PREFIX = "pdf:docinfo:custom:"
|
|
30
|
+
|
|
31
|
+
EXIF_PASSTHROUGH_FIELDS = (
|
|
32
|
+
"EXIF:DateTimeOriginal",
|
|
33
|
+
"Composite:SubSecDateTimeOriginal",
|
|
34
|
+
"Composite:DateTimeOriginal",
|
|
35
|
+
"EXIF:CreateDate",
|
|
36
|
+
"Composite:SubSecCreateDate",
|
|
37
|
+
"QuickTime:CreateDate",
|
|
38
|
+
"QuickTime:MediaCreateDate",
|
|
39
|
+
"QuickTime:TrackCreateDate",
|
|
40
|
+
"PDF:CreateDate",
|
|
41
|
+
"XMP:CreateDate",
|
|
42
|
+
"XMP:DateCreated",
|
|
43
|
+
"IPTC:DateCreated",
|
|
44
|
+
"Composite:DateTimeCreated",
|
|
45
|
+
"EXIF:DateTime",
|
|
46
|
+
"EXIF:ModifyDate",
|
|
47
|
+
"Composite:SubSecModifyDate",
|
|
48
|
+
"PDF:ModDate",
|
|
49
|
+
"XMP:ModifyDate",
|
|
50
|
+
"Composite:GPSLatitude",
|
|
51
|
+
"EXIF:GPSLatitude",
|
|
52
|
+
"XMP:GPSLatitude",
|
|
53
|
+
"Composite:GPSLatitudeRef",
|
|
54
|
+
"EXIF:GPSLatitudeRef",
|
|
55
|
+
"XMP:GPSLatitudeRef",
|
|
56
|
+
"Composite:GPSLongitude",
|
|
57
|
+
"EXIF:GPSLongitude",
|
|
58
|
+
"XMP:GPSLongitude",
|
|
59
|
+
"Composite:GPSLongitudeRef",
|
|
60
|
+
"EXIF:GPSLongitudeRef",
|
|
61
|
+
"XMP:GPSLongitudeRef",
|
|
62
|
+
"Composite:GPSPosition",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def resolve_with_aliases(metadata: Dict[str, Any], key: str) -> Any:
|
|
67
|
+
"""Return ``metadata[key]`` respecting ``os_parent_meta_<key>`` passthrough.
|
|
68
|
+
|
|
69
|
+
Lookup order:
|
|
70
|
+
|
|
71
|
+
1. ``os_parent_meta_<key>`` -- written directly by producer routes that
|
|
72
|
+
can place a key into the child container under an exact name.
|
|
73
|
+
2. ``pdf:docinfo:custom:os_parent_meta_<key>`` -- PDF custom property
|
|
74
|
+
container (mirrors the ``os_ContextBefore`` pattern used elsewhere).
|
|
75
|
+
3. Any key ending with ``:os_parent_meta_<key>`` -- catches the
|
|
76
|
+
format-specific group prefix that exiftool prepends when reading
|
|
77
|
+
container-native tags (``PNG:`` for PNG tEXt, ``ID3:`` for MP3 TXXX,
|
|
78
|
+
``RIFF:`` for WAV INFO, etc.).
|
|
79
|
+
4. ``<key>`` -- canonical fallback (the value as it would appear if the
|
|
80
|
+
child carried real EXIF natively).
|
|
81
|
+
"""
|
|
82
|
+
aliased = f"{OS_PARENT_META_PREFIX}{key}"
|
|
83
|
+
value = metadata.get(aliased)
|
|
84
|
+
if value is not None:
|
|
85
|
+
return value
|
|
86
|
+
value = metadata.get(f"{_PDF_CUSTOM_PREFIX}{aliased}")
|
|
87
|
+
if value is not None:
|
|
88
|
+
return value
|
|
89
|
+
suffix = f":{aliased}"
|
|
90
|
+
for k, v in metadata.items():
|
|
91
|
+
if v is not None and k.endswith(suffix):
|
|
92
|
+
return v
|
|
93
|
+
return metadata.get(key)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def select_parent_meta_passthrough(metadata: Any) -> Dict[str, str]:
|
|
97
|
+
"""Pick EXIF date/GPS tags worth embedding into derived children.
|
|
98
|
+
|
|
99
|
+
Input is a parent's raw exiftool metadata dict (as stored on the parent
|
|
100
|
+
entity's ``extract:metadata`` annotation). Output is keyed by
|
|
101
|
+
``os_parent_meta_<canonical>`` with stringified values, ready to feed
|
|
102
|
+
into a container-specific embedder.
|
|
103
|
+
|
|
104
|
+
Uses :func:`resolve_with_aliases` so a parent that itself inherited tags
|
|
105
|
+
from *its* parent (e.g. a keyframe of an inherited-meta video) still
|
|
106
|
+
propagates the original values forward.
|
|
107
|
+
"""
|
|
108
|
+
if not isinstance(metadata, dict):
|
|
109
|
+
return {}
|
|
110
|
+
out: Dict[str, str] = {}
|
|
111
|
+
for key in EXIF_PASSTHROUGH_FIELDS:
|
|
112
|
+
value = resolve_with_aliases(metadata, key)
|
|
113
|
+
if value is None:
|
|
114
|
+
continue
|
|
115
|
+
if isinstance(value, (list, tuple)):
|
|
116
|
+
value = ",".join(str(v) for v in value)
|
|
117
|
+
out[f"{OS_PARENT_META_PREFIX}{key}"] = str(value)
|
|
118
|
+
return out
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def embed_png_parent_meta(png_bytes: bytes, parent_meta: Dict[str, str]) -> bytes:
|
|
122
|
+
"""Add ``parent_meta`` keys as PNG ``tEXt`` chunks. No-op if empty."""
|
|
123
|
+
if not parent_meta:
|
|
124
|
+
return png_bytes
|
|
125
|
+
from PIL import Image
|
|
126
|
+
from PIL.PngImagePlugin import PngInfo
|
|
127
|
+
|
|
128
|
+
img = Image.open(BytesIO(png_bytes))
|
|
129
|
+
info = PngInfo()
|
|
130
|
+
for k, v in (img.info or {}).items():
|
|
131
|
+
if isinstance(v, str):
|
|
132
|
+
info.add_text(k, v)
|
|
133
|
+
for k, v in parent_meta.items():
|
|
134
|
+
info.add_text(k, v)
|
|
135
|
+
out = BytesIO()
|
|
136
|
+
img.save(out, format="PNG", pnginfo=info)
|
|
137
|
+
return out.getvalue()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def ffmpeg_metadata_args(parent_meta: Dict[str, str]) -> List[str]:
|
|
141
|
+
"""Return ``-metadata key=value`` ffmpeg flag pairs for ``parent_meta``.
|
|
142
|
+
|
|
143
|
+
ffmpeg writes these into whatever metadata container the output format
|
|
144
|
+
supports (ID3v2 TXXX for MP3, INFO chunk for WAV, custom atoms for
|
|
145
|
+
MP4/M4A, vorbis comments for OGG). exiftool surfaces them with the
|
|
146
|
+
container's group prefix (``ID3:``, ``RIFF:``, ...), which
|
|
147
|
+
:func:`resolve_with_aliases` handles via its suffix match.
|
|
148
|
+
"""
|
|
149
|
+
args: List[str] = []
|
|
150
|
+
for k, v in (parent_meta or {}).items():
|
|
151
|
+
args.extend(["-metadata", f"{k}={v}"])
|
|
152
|
+
return args
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|