Initial upload: aesthetic-immich-starter

This commit is contained in:
Abderrahim-Mouhcine
2026-08-16 19:59:33 +01:00
commit 8938106e99
4777 changed files with 2176899 additions and 0 deletions
@@ -0,0 +1,23 @@
# Copyright 2024 The MediaPipe Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""MediaPipe Tasks GenAI Bundler API."""
import mediapipe.tasks.python.genai.bundler.llm_bundler
BundleConfig = llm_bundler.BundleConfig
create_bundle = llm_bundler.create_bundle
# Remove unnecessary modules to avoid duplication in API docs.
del llm_bundler
@@ -0,0 +1,236 @@
# Copyright 2024 The MediaPipe Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Functions to perform llm packing."""
import ctypes
import dataclasses
import enum
from typing import List, Optional
from mediapipe.tasks.python.core import mediapipe_c_bindings
from mediapipe.tasks.python.core import mediapipe_c_utils
from mediapipe.tasks.python.core import serial_dispatcher
from mediapipe.tasks.python.genai.bundler import llm_bundler_metadata_options
from mediapipe.tasks.python.genai.bundler import llm_bundler_metadata_options_c
from mediapipe.tasks.python.genai.converter import external_dependencies
from mediapipe.tasks.python.metadata.metadata_writers import model_asset_bundle_utils
sentencepiece = external_dependencies.sentencepiece
_CTYPES_SIGNATURES = (
mediapipe_c_utils.CFunction(
func_name="MpLlmBundlerGenerateMetadata",
argtypes=[
ctypes.POINTER(
llm_bundler_metadata_options_c.LlmBundlerMetadataOptionsC
),
ctypes.POINTER(ctypes.c_int),
],
restype=ctypes.POINTER(ctypes.c_char),
),
mediapipe_c_utils.CFunction(
func_name="MpLlmBundlerFreeMetadata",
argtypes=[
ctypes.POINTER(ctypes.c_char),
],
restype=None,
),
)
@dataclasses.dataclass(frozen=True)
class BundleConfig:
"""Config for LLM Bundler.
Attributes:
tflite_model: Path to the multi-signature tflite model with "prefill" and
"decode" signatures converted using ODML Transformers APIs.
tokenizer_model: Path to the tokenizer model. Currently only SentencePience
tokenizer is supported. As such, tokenizer.model proto is expected to be
passed here.
start_token: Token that will be used to signify the beginning of a sequence.
stop_tokens: Tokens that will be used to signify the end of a sequence.
output_filename: Name of the generated `.task` file containing the Bundle.
enable_bytes_to_unicode_mapping: Enables GPT-2 style bytes to unicode
mapping. For more details see:
https://github.com/openai/gpt-2/blob/master/src/encoder.py#L9
system_prompt: The starting text would be feed to the model on the start of
each session, commonly called the System prompt. This is useful for
instruction tuned models and pre-conditioning the model behavior. This
field is mutually exclusive with prompt_prefix_system and
prompt_suffix_system.
prompt_prefix_user: The prefix that should be prepended to each user portion
of prompts passed to the model.
prompt_suffix_user: The suffix that should be appended to each user portion
of prompts passed to the model.
prompt_prefix_model: The prefix that should be prepended to each model
portion of prompts passed to the model.
prompt_suffix_model: The suffix that should be appended to each model
portion of prompts passsed to the model.
prompt_prefix_system: The prefix that should be prepended to each system
portion of prompts passed to the model.
prompt_suffix_system: The suffix that should be appended to each system
portion of prompts passsed to the model.
user_role_token: The token that indicates the user's turn.
system_role_token: The token that indicates the system's turn.
model_role_token: The token that indicates the model's turn.
end_role_token: The token that indicates the end of the prompt.
tflite_embedder: Path to the embedding model if the embedding lookup is done
externally.
tflite_per_layer_embedder: Path to the per layer embedding model if the per
layer embedding lookup is done externally.
tflite_vision_encoder: Path to the vision encoder model.
tflite_vision_adapter: Path to the vision adapter model.
"""
tflite_model: str
tokenizer_model: str
start_token: str
stop_tokens: List[str]
output_filename: str
enable_bytes_to_unicode_mapping: bool = False
system_prompt: Optional[str] = None
prompt_prefix_user: Optional[str] = None
prompt_suffix_user: Optional[str] = None
prompt_prefix_model: Optional[str] = None
prompt_suffix_model: Optional[str] = None
prompt_prefix_system: Optional[str] = None
prompt_suffix_system: Optional[str] = None
user_role_token: Optional[str] = None
system_role_token: Optional[str] = None
model_role_token: Optional[str] = None
end_role_token: Optional[str] = None
tflite_embedder: Optional[str] = None
tflite_per_layer_embedder: Optional[str] = None
tflite_vision_encoder: Optional[str] = None
tflite_vision_adapter: Optional[str] = None
class _BundleTags(enum.Enum):
"""Bundle tags."""
TF_LITE_PREFILL_DECODE = 1
TOKENIZER_MODEL = 2
METADATA = 3
TF_LITE_EMBEDDER = 4
TF_LITE_PER_LAYER_EMBEDDER = 5
TF_LITE_VISION_ENCODER = 6
TF_LITE_VISION_ADAPTER = 7
def _validate_config(config: BundleConfig):
"""Validates the given config.
Args:
config: The config to validate.
Raises:
ValueError if the config is invalid. Invalid configs can be:
- tokenizer_model is not a valid SentencePiece model.
- start_token is not a valid token in the tokenizer_model.
- stop_tokens is not a list of valid tokens in the tokenizer_model.
- system_prompt and prompt_*_system are both set.
"""
if not isinstance(config.stop_tokens, list):
raise ValueError("stop_tokens must be a list of strings.")
if not config.stop_tokens:
raise ValueError("stop_tokens must be non-empty.")
try:
sp = sentencepiece.SentencePieceProcessor()
sp.Load(config.tokenizer_model)
except Exception as e:
raise ValueError(
f"Failed to load tokenizer model from {config.tokenizer_model}. "
"Please ensure you are passing a valid SentencePiece model."
) from e
if config.system_prompt and (
config.prompt_prefix_system or config.prompt_suffix_system
):
raise ValueError(
"system_prompt and prompt_*_system are mutually exclusive."
)
def create_bundle(config: BundleConfig):
"""Creates a bundle from the given config."""
_validate_config(config)
artifacts = {}
with open(config.tflite_model, "rb") as f:
artifacts[_BundleTags.TF_LITE_PREFILL_DECODE.name] = f.read()
with open(config.tokenizer_model, "rb") as f:
artifacts[_BundleTags.TOKENIZER_MODEL.name] = f.read()
lib = mediapipe_c_bindings.load_raw_library(_CTYPES_SIGNATURES)
with serial_dispatcher.SerialDispatcher(
lib, _CTYPES_SIGNATURES
) as bundler_lib:
metadata_options = llm_bundler_metadata_options.LlmBundlerMetadataOptions(
start_token=config.start_token,
stop_tokens=config.stop_tokens,
enable_bytes_to_unicode_mapping=config.enable_bytes_to_unicode_mapping,
system_prompt=config.system_prompt,
prompt_prefix_user=config.prompt_prefix_user,
prompt_suffix_user=config.prompt_suffix_user,
prompt_prefix_model=config.prompt_prefix_model,
prompt_suffix_model=config.prompt_suffix_model,
prompt_prefix_system=config.prompt_prefix_system,
prompt_suffix_system=config.prompt_suffix_system,
user_role_token=config.user_role_token,
system_role_token=config.system_role_token,
model_role_token=config.model_role_token,
end_role_token=config.end_role_token,
)
metadata_options_c = metadata_options.to_ctypes()
buffer_size = ctypes.c_int()
metadata_buffer = None
try:
metadata_buffer = bundler_lib.MpLlmBundlerGenerateMetadata(
ctypes.byref(metadata_options_c), ctypes.byref(buffer_size)
)
artifacts[_BundleTags.METADATA.name] = ctypes.string_at(
metadata_buffer, buffer_size.value
)
finally:
if metadata_buffer:
bundler_lib.MpLlmBundlerFreeMetadata(metadata_buffer)
if config.tflite_embedder:
with open(config.tflite_embedder, "rb") as f:
artifacts[_BundleTags.TF_LITE_EMBEDDER.name] = f.read()
if config.tflite_per_layer_embedder:
with open(config.tflite_per_layer_embedder, "rb") as f:
artifacts[_BundleTags.TF_LITE_PER_LAYER_EMBEDDER.name] = f.read()
if config.tflite_vision_encoder:
with open(config.tflite_vision_encoder, "rb") as f:
artifacts[_BundleTags.TF_LITE_VISION_ENCODER.name] = f.read()
if config.tflite_vision_adapter:
with open(config.tflite_vision_adapter, "rb") as f:
artifacts[_BundleTags.TF_LITE_VISION_ADAPTER.name] = f.read()
output_filename = config.output_filename
if not output_filename.endswith(".task"):
output_filename = config.output_filename + ".task"
model_asset_bundle_utils.create_model_asset_bundle(
artifacts,
output_filename,
)
@@ -0,0 +1,142 @@
# Copyright 2026 The MediaPipe Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""LlmBundlerMetadataOptions Python dataclass."""
import ctypes
import dataclasses
from typing import Optional
from mediapipe.tasks.python.genai.bundler import llm_bundler_metadata_options_c
@dataclasses.dataclass
class LlmBundlerMetadataOptions:
"""Options for bundling LLM metadata.
Attributes:
start_token: Token that will be used to signify the beginning of a sequence.
stop_tokens: Tokens that will be used to signify the end of a sequence.
enable_bytes_to_unicode_mapping: Enables GPT-2 style bytes to unicode
mapping. For more details see:
https://github.com/openai/gpt-2/blob/master/src/encoder.py#L9
system_prompt: The starting text would be feed to the model on the start of
each session, commonly called the System prompt. This is useful for
instruction tuned models and pre-conditioning the model behavior. This
field is mutually exclusive with prompt_prefix_system and
prompt_suffix_system.
prompt_prefix_user: The prefix that should be prepended to each user portion
of prompts passed to the model.
prompt_suffix_user: The suffix that should be appended to each user portion
of prompts passed to the model.
prompt_prefix_model: The prefix that should be prepended to each model
portion of prompts passed to the model.
prompt_suffix_model: The suffix that should be appended to each model
portion of prompts passsed to the model.
prompt_prefix_system: The prefix that should be prepended to each system
portion of prompts passed to the model.
prompt_suffix_system: The suffix that should be appended to each system
portion of prompts passsed to the model.
user_role_token: The token that indicates the user's turn.
system_role_token: The token that indicates the system's turn.
model_role_token: The token that indicates the model's turn.
end_role_token: The token that indicates the end of the prompt.
"""
start_token: str
stop_tokens: list[str]
enable_bytes_to_unicode_mapping: bool = False
system_prompt: Optional[str] = None
prompt_prefix_user: Optional[str] = None
prompt_suffix_user: Optional[str] = None
prompt_prefix_model: Optional[str] = None
prompt_suffix_model: Optional[str] = None
prompt_prefix_system: Optional[str] = None
prompt_suffix_system: Optional[str] = None
user_role_token: Optional[str] = None
system_role_token: Optional[str] = None
model_role_token: Optional[str] = None
end_role_token: Optional[str] = None
def to_ctypes(
self,
) -> llm_bundler_metadata_options_c.LlmBundlerMetadataOptionsC:
"""Converts the object to a ctypes structure."""
stop_tokens_c = (ctypes.c_char_p * len(self.stop_tokens))()
for i, token in enumerate(self.stop_tokens):
stop_tokens_c[i] = token.encode("utf-8")
start_token_c = self.start_token.encode("utf-8")
system_prompt_c = (
self.system_prompt.encode("utf-8") if self.system_prompt else None
)
prompt_prefix_user_c = (
self.prompt_prefix_user.encode("utf-8")
if self.prompt_prefix_user
else None
)
prompt_suffix_user_c = (
self.prompt_suffix_user.encode("utf-8")
if self.prompt_suffix_user
else None
)
prompt_prefix_model_c = (
self.prompt_prefix_model.encode("utf-8")
if self.prompt_prefix_model
else None
)
prompt_suffix_model_c = (
self.prompt_suffix_model.encode("utf-8")
if self.prompt_suffix_model
else None
)
prompt_prefix_system_c = (
self.prompt_prefix_system.encode("utf-8")
if self.prompt_prefix_system
else None
)
prompt_suffix_system_c = (
self.prompt_suffix_system.encode("utf-8")
if self.prompt_suffix_system
else None
)
user_role_token_c = (
self.user_role_token.encode("utf-8") if self.user_role_token else None
)
system_role_token_c = (
self.system_role_token.encode("utf-8")
if self.system_role_token
else None
)
model_role_token_c = (
self.model_role_token.encode("utf-8") if self.model_role_token else None
)
end_role_token_c = (
self.end_role_token.encode("utf-8") if self.end_role_token else None
)
return llm_bundler_metadata_options_c.LlmBundlerMetadataOptionsC(
start_token=start_token_c,
stop_tokens=stop_tokens_c,
num_stop_tokens=len(self.stop_tokens),
enable_bytes_to_unicode_mapping=self.enable_bytes_to_unicode_mapping,
system_prompt=system_prompt_c,
prompt_prefix_user=prompt_prefix_user_c,
prompt_suffix_user=prompt_suffix_user_c,
prompt_prefix_model=prompt_prefix_model_c,
prompt_suffix_model=prompt_suffix_model_c,
prompt_prefix_system=prompt_prefix_system_c,
prompt_suffix_system=prompt_suffix_system_c,
user_role_token=user_role_token_c,
system_role_token=system_role_token_c,
model_role_token=model_role_token_c,
end_role_token=end_role_token_c,
)
@@ -0,0 +1,38 @@
# Copyright 2026 The MediaPipe Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Ctypes wrapper for LlmBundlerMetadataOptions."""
import ctypes
class LlmBundlerMetadataOptionsC(ctypes.Structure):
"""Wrapper for LlmBundlerMetadataOptions in C."""
_fields_ = [
("start_token", ctypes.c_char_p),
("stop_tokens", ctypes.POINTER(ctypes.c_char_p)),
("num_stop_tokens", ctypes.c_int),
("enable_bytes_to_unicode_mapping", ctypes.c_bool),
("system_prompt", ctypes.c_char_p),
("prompt_prefix_user", ctypes.c_char_p),
("prompt_suffix_user", ctypes.c_char_p),
("prompt_prefix_model", ctypes.c_char_p),
("prompt_suffix_model", ctypes.c_char_p),
("prompt_prefix_system", ctypes.c_char_p),
("prompt_suffix_system", ctypes.c_char_p),
("user_role_token", ctypes.c_char_p),
("system_role_token", ctypes.c_char_p),
("model_role_token", ctypes.c_char_p),
("end_role_token", ctypes.c_char_p),
]
@@ -0,0 +1,60 @@
# Copyright 2026 The MediaPipe Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from absl.testing import absltest
from mediapipe.tasks.python.genai.bundler import llm_bundler_metadata_options
class LlmBundlerMetadataOptionsTest(absltest.TestCase):
def test_to_ctypes(self):
options = llm_bundler_metadata_options.LlmBundlerMetadataOptions(
start_token="start",
stop_tokens=["stop1", "stop2"],
enable_bytes_to_unicode_mapping=True,
system_prompt="system",
prompt_prefix_user="user_prefix",
prompt_suffix_user="user_suffix",
prompt_prefix_model="model_prefix",
prompt_suffix_model="model_suffix",
prompt_prefix_system=None,
prompt_suffix_system=None,
user_role_token="user_role",
system_role_token=None,
model_role_token="model_role",
end_role_token="end_role",
)
options_c = options.to_ctypes()
self.assertEqual(options_c.start_token, b"start")
self.assertEqual(options_c.stop_tokens[0], b"stop1")
self.assertEqual(options_c.stop_tokens[1], b"stop2")
self.assertEqual(options_c.num_stop_tokens, 2)
self.assertTrue(options_c.enable_bytes_to_unicode_mapping)
self.assertEqual(options_c.system_prompt, b"system")
self.assertEqual(options_c.prompt_prefix_user, b"user_prefix")
self.assertEqual(options_c.prompt_suffix_user, b"user_suffix")
self.assertEqual(options_c.prompt_prefix_model, b"model_prefix")
self.assertEqual(options_c.prompt_suffix_model, b"model_suffix")
self.assertIsNone(options_c.prompt_prefix_system)
self.assertIsNone(options_c.prompt_suffix_system)
self.assertEqual(options_c.user_role_token, b"user_role")
self.assertIsNone(options_c.system_role_token)
self.assertEqual(options_c.model_role_token, b"model_role")
self.assertEqual(options_c.end_role_token, b"end_role")
if __name__ == "__main__":
absltest.main()