ai-edge-litert-nightly 2.2.0.dev20260102__cp312-cp312-manylinux_2_27_x86_64.whl

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.
Files changed (78) hide show
  1. ai_edge_litert/__init__.py +1 -0
  2. ai_edge_litert/_pywrap_analyzer_wrapper.so +0 -0
  3. ai_edge_litert/_pywrap_litert_compiled_model_wrapper.so +0 -0
  4. ai_edge_litert/_pywrap_litert_interpreter_wrapper.so +0 -0
  5. ai_edge_litert/_pywrap_litert_tensor_buffer_wrapper.so +0 -0
  6. ai_edge_litert/_pywrap_modify_model_interface.so +0 -0
  7. ai_edge_litert/_pywrap_string_util.so +0 -0
  8. ai_edge_litert/_pywrap_tensorflow_lite_calibration_wrapper.so +0 -0
  9. ai_edge_litert/_pywrap_tensorflow_lite_metrics_wrapper.so +0 -0
  10. ai_edge_litert/any_pb2.py +37 -0
  11. ai_edge_litert/aot/__init__.py +0 -0
  12. ai_edge_litert/aot/ai_pack/__init__.py +0 -0
  13. ai_edge_litert/aot/ai_pack/export_lib.py +300 -0
  14. ai_edge_litert/aot/aot_compile.py +153 -0
  15. ai_edge_litert/aot/core/__init__.py +0 -0
  16. ai_edge_litert/aot/core/apply_plugin.py +148 -0
  17. ai_edge_litert/aot/core/common.py +97 -0
  18. ai_edge_litert/aot/core/components.py +93 -0
  19. ai_edge_litert/aot/core/mlir_transforms.py +36 -0
  20. ai_edge_litert/aot/core/tflxx_util.py +30 -0
  21. ai_edge_litert/aot/core/types.py +374 -0
  22. ai_edge_litert/aot/prepare_for_npu.py +152 -0
  23. ai_edge_litert/aot/vendors/__init__.py +22 -0
  24. ai_edge_litert/aot/vendors/example/__init__.py +0 -0
  25. ai_edge_litert/aot/vendors/example/example_backend.py +157 -0
  26. ai_edge_litert/aot/vendors/fallback_backend.py +128 -0
  27. ai_edge_litert/aot/vendors/google_tensor/__init__.py +0 -0
  28. ai_edge_litert/aot/vendors/google_tensor/google_tensor_backend.py +168 -0
  29. ai_edge_litert/aot/vendors/google_tensor/target.py +84 -0
  30. ai_edge_litert/aot/vendors/import_vendor.py +132 -0
  31. ai_edge_litert/aot/vendors/mediatek/__init__.py +0 -0
  32. ai_edge_litert/aot/vendors/mediatek/mediatek_backend.py +196 -0
  33. ai_edge_litert/aot/vendors/mediatek/target.py +94 -0
  34. ai_edge_litert/aot/vendors/qualcomm/__init__.py +0 -0
  35. ai_edge_litert/aot/vendors/qualcomm/qualcomm_backend.py +161 -0
  36. ai_edge_litert/aot/vendors/qualcomm/target.py +75 -0
  37. ai_edge_litert/api_pb2.py +43 -0
  38. ai_edge_litert/compiled_model.py +250 -0
  39. ai_edge_litert/descriptor_pb2.py +3361 -0
  40. ai_edge_litert/duration_pb2.py +37 -0
  41. ai_edge_litert/empty_pb2.py +37 -0
  42. ai_edge_litert/field_mask_pb2.py +37 -0
  43. ai_edge_litert/format_converter_wrapper_pybind11.so +0 -0
  44. ai_edge_litert/hardware_accelerator.py +22 -0
  45. ai_edge_litert/internal/__init__.py +0 -0
  46. ai_edge_litert/internal/litertlm_builder.py +584 -0
  47. ai_edge_litert/internal/litertlm_core.py +58 -0
  48. ai_edge_litert/internal/litertlm_header_schema_py_generated.py +1596 -0
  49. ai_edge_litert/internal/llm_metadata_pb2.py +45 -0
  50. ai_edge_litert/internal/llm_model_type_pb2.py +51 -0
  51. ai_edge_litert/internal/sampler_params_pb2.py +39 -0
  52. ai_edge_litert/internal/token_pb2.py +38 -0
  53. ai_edge_litert/interpreter.py +1039 -0
  54. ai_edge_litert/libLiteRt.so +0 -0
  55. ai_edge_litert/libpywrap_litert_common.so +0 -0
  56. ai_edge_litert/metrics_interface.py +48 -0
  57. ai_edge_litert/metrics_portable.py +70 -0
  58. ai_edge_litert/model_runtime_info_pb2.py +66 -0
  59. ai_edge_litert/plugin_pb2.py +46 -0
  60. ai_edge_litert/profiling_info_pb2.py +47 -0
  61. ai_edge_litert/pywrap_genai_ops.so +0 -0
  62. ai_edge_litert/schema_py_generated.py +19640 -0
  63. ai_edge_litert/source_context_pb2.py +37 -0
  64. ai_edge_litert/struct_pb2.py +47 -0
  65. ai_edge_litert/tensor_buffer.py +167 -0
  66. ai_edge_litert/timestamp_pb2.py +37 -0
  67. ai_edge_litert/tools/__init__.py +0 -0
  68. ai_edge_litert/tools/apply_plugin_main +0 -0
  69. ai_edge_litert/tools/flatbuffer_utils.py +534 -0
  70. ai_edge_litert/type_pb2.py +53 -0
  71. ai_edge_litert/vendors/google_tensor/compiler/libLiteRtCompilerPlugin_google_tensor.so +0 -0
  72. ai_edge_litert/vendors/mediatek/compiler/libLiteRtCompilerPlugin_MediaTek.so +0 -0
  73. ai_edge_litert/vendors/qualcomm/compiler/libLiteRtCompilerPlugin_Qualcomm.so +0 -0
  74. ai_edge_litert/wrappers_pb2.py +53 -0
  75. ai_edge_litert_nightly-2.2.0.dev20260102.dist-info/METADATA +52 -0
  76. ai_edge_litert_nightly-2.2.0.dev20260102.dist-info/RECORD +78 -0
  77. ai_edge_litert_nightly-2.2.0.dev20260102.dist-info/WHEEL +5 -0
  78. ai_edge_litert_nightly-2.2.0.dev20260102.dist-info/top_level.txt +1 -0
@@ -0,0 +1,584 @@
1
+ # Copyright 2025 The ODML Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ """Builder class for LiteRT-LM files.
17
+
18
+ Example usage:
19
+ ```
20
+ builder = litertlm_builder.LitertLmFileBuilder()
21
+ builder.add_system_metadata(
22
+ litertlm_builder.Metadata(
23
+ key="Authors",
24
+ value="The ODML Authors",
25
+ dtype=litertlm_builder.DType.STRING,
26
+ )
27
+ )
28
+ builder.add_tflite_model(
29
+ model_path,
30
+ litertlm_builder.TfLiteModelType.PREFILL_DECODE,
31
+ )
32
+ builder.add_sentencepiece_tokenizer(tokenizer_path)
33
+ builder.add_llm_metadata(llm_metadata_path)
34
+ with litertlm_core.open_file(output_path, "wb") as f:
35
+ builder.build(f)
36
+ ```
37
+ """
38
+
39
+ # TODO(b/445163709): Remove this module once litert_lm publishes a pypi package.
40
+
41
+ import dataclasses
42
+ import enum
43
+ import os # pylint: disable=unused-import
44
+ from typing import Any, BinaryIO, Callable, IO, Optional, TypeVar, Union
45
+ import zlib
46
+ import flatbuffers
47
+ from google.protobuf import message
48
+ from google.protobuf import text_format
49
+ from ai_edge_litert.internal import litertlm_core
50
+ from ai_edge_litert.internal import litertlm_header_schema_py_generated as schema
51
+ from ai_edge_litert.internal import llm_metadata_pb2
52
+
53
+
54
+ @enum.unique
55
+ class DType(enum.Enum):
56
+ """DType enum.
57
+
58
+ This enum maps to the data types defined in the LiteRT-LM flatbuffers schema.
59
+ """
60
+
61
+ INT8 = "int8"
62
+ INT16 = "int16"
63
+ INT32 = "int32"
64
+ INT64 = "int64"
65
+ UINT8 = "uint8"
66
+ UINT16 = "uint16"
67
+ UINT32 = "uint32"
68
+ UINT64 = "uint64"
69
+ FLOAT32 = "float32"
70
+ DOUBLE = "double"
71
+ BOOL = "bool"
72
+ STRING = "string"
73
+
74
+
75
+ @dataclasses.dataclass
76
+ class Metadata:
77
+ """Metadata class."""
78
+
79
+ key: str
80
+ value: Any
81
+ dtype: DType
82
+
83
+
84
+ @enum.unique
85
+ class TfLiteModelType(enum.Enum):
86
+ """TfLiteModelType enum.
87
+
88
+ This enum maps to the model types defined in the LiteRT-LM flatbuffers schema.
89
+ """
90
+
91
+ PREFILL_DECODE = "tf_lite_prefill_decode"
92
+
93
+ EMBEDDER = "tf_lite_embedder"
94
+ PER_LAYER_EMBEDDER = "tf_lite_per_layer_embedder"
95
+
96
+ AUX = "tf_lite_aux"
97
+
98
+ AUDIO_FRONTEND = "tf_lite_audio_frontend"
99
+ AUDIO_ENCODER_HW = "tf_lite_audio_encoder_hw"
100
+ AUDIO_ADAPTER = "tf_lite_audio_adapter"
101
+ END_OF_AUDIO = "tf_lite_end_of_audio"
102
+
103
+ VISION_ENCODER = "tf_lite_vision_encoder"
104
+ VISION_ADAPTER = "tf_lite_vision_adapter"
105
+
106
+ @classmethod
107
+ def get_enum_from_tf_free_value(cls, tf_free_value: str) -> "TfLiteModelType":
108
+ """A helper method to get the enum value from the TF-free value."""
109
+ value = "tf_lite_" + tf_free_value.lower()
110
+ return cls(value)
111
+
112
+
113
+ @dataclasses.dataclass
114
+ class _SectionObject:
115
+ # Metadata for the section.
116
+ metadata: list[Metadata]
117
+ # The data type of the section.
118
+ data_type: schema.AnySectionDataType | int
119
+ # The data reader for the section. This should return the data as a byte
120
+ # string.
121
+ data_reader: Callable[[], bytes]
122
+
123
+
124
+ @enum.unique
125
+ class LlmModelType(enum.StrEnum):
126
+ """LLM model type for the LiteRT LM model."""
127
+
128
+ GENERIC = "generic"
129
+ GEMMA3N = "gemma3n"
130
+ GEMMA3 = "gemma3"
131
+ QWEN3 = "qwen3"
132
+ QWEN2P5 = "qwen2p5"
133
+
134
+
135
+ LitertLmFileBuilderT = TypeVar(
136
+ "LitertLmFileBuilderT", bound="LitertLmFileBuilder"
137
+ )
138
+
139
+
140
+ class LitertLmFileBuilder:
141
+ """LitertLmFileBuilder class.
142
+
143
+ This is the primary entry point for building a LiteRT-LM file. It provides
144
+ methods to add system metadata, sections, and llm metadata to the file.
145
+
146
+ Example usage:
147
+ ```
148
+ builder = litertlm_builder.LitertLmFileBuilder()
149
+ builder.add_system_metadata(
150
+ litertlm_builder.Metadata(
151
+ key="Authors",
152
+ value="The ODML Authors",
153
+ dtype=litertlm_builder.DType.STRING,
154
+ )
155
+ )
156
+ builder.add_tflite_model(
157
+ model_path,
158
+ litertlm_builder.TfLiteModelType.PREFILL_DECODE,
159
+ )
160
+ builder.add_sentencepiece_tokenizer(tokenizer_path)
161
+ builder.add_llm_metadata(llm_metadata_path)
162
+ with litertlm_core.open_file(output_path, "wb") as f:
163
+ builder.build(f)
164
+ ```
165
+ """
166
+
167
+ def __init__(self):
168
+ self._system_metadata: list[Metadata] = []
169
+ self._sections: list[_SectionObject] = []
170
+ self._has_llm_metadata = False
171
+ self._has_tokenizer = False
172
+
173
+ def add_system_metadata(
174
+ self,
175
+ metadata: Metadata,
176
+ ) -> LitertLmFileBuilderT:
177
+ """Adds system level metadata to the litertlm file."""
178
+ for existing_metadata in self._system_metadata:
179
+ if existing_metadata.key == metadata.key:
180
+ raise ValueError(
181
+ f"System metadata already exists for key: {metadata.key}"
182
+ )
183
+ self._system_metadata.append(metadata)
184
+ return self
185
+
186
+ def add_llm_metadata(
187
+ self,
188
+ llm_metadata_path: str,
189
+ additional_metadata: Optional[list[Metadata]] = None,
190
+ ) -> LitertLmFileBuilderT:
191
+ """Adds llm metadata to the litertlm file.
192
+
193
+ Args:
194
+ llm_metadata_path: The path to the llm metadata file. Can be binary or
195
+ textproto format.
196
+ additional_metadata: Additional metadata to add to the llm metadata.
197
+
198
+ Returns:
199
+ The currentLitertLmFileBuilder object.
200
+
201
+ Raises:
202
+ FileNotFoundError: If the llm metadata file is not found.
203
+ """
204
+ assert not self._has_llm_metadata, "Llm metadata already added."
205
+ self._has_llm_metadata = True
206
+ if not litertlm_core.path_exists(llm_metadata_path):
207
+ raise FileNotFoundError(
208
+ f"Llm metadata file not found: {llm_metadata_path}"
209
+ )
210
+
211
+ if _is_binary_proto(llm_metadata_path):
212
+
213
+ def data_reader():
214
+ with litertlm_core.open_file(llm_metadata_path, "rb") as f:
215
+ return f.read()
216
+
217
+ else:
218
+
219
+ def data_reader():
220
+ with litertlm_core.open_file(llm_metadata_path, "r") as f:
221
+ return text_format.Parse(
222
+ f.read(), llm_metadata_pb2.LlmMetadata()
223
+ ).SerializeToString()
224
+
225
+ section_object = _SectionObject(
226
+ metadata=additional_metadata if additional_metadata else [],
227
+ data_type=schema.AnySectionDataType.LlmMetadataProto,
228
+ data_reader=data_reader,
229
+ )
230
+ self._sections.append(section_object)
231
+ return self
232
+
233
+ def add_tflite_model(
234
+ self,
235
+ tflite_model_path: str,
236
+ model_type: TfLiteModelType,
237
+ additional_metadata: Optional[list[Metadata]] = None,
238
+ ) -> LitertLmFileBuilderT:
239
+ """Adds a tflite model to the litertlm file.
240
+
241
+ Args:
242
+ tflite_model_path: The path to the tflite model file.
243
+ model_type: The type of the tflite model.
244
+ additional_metadata: Additional metadata to add to the tflite model.
245
+
246
+ Returns:
247
+ The current LitertLmFileBuilder object.
248
+
249
+ Raises:
250
+ FileNotFoundError: If the tflite model file is not found.
251
+ ValueError: If the model type metadata is overridden.
252
+ """
253
+ if not litertlm_core.path_exists(tflite_model_path):
254
+ raise FileNotFoundError(
255
+ f"Tflite model file not found: {tflite_model_path}"
256
+ )
257
+ metadata = [
258
+ Metadata(key="model_type", value=model_type.value, dtype=DType.STRING)
259
+ ]
260
+ if additional_metadata:
261
+ for metadata_item in additional_metadata:
262
+ if metadata_item.key == "model_type":
263
+ raise ValueError("Model type metadata cannot be overridden.")
264
+ metadata.extend(additional_metadata)
265
+
266
+ def data_reader():
267
+ with litertlm_core.open_file(tflite_model_path, "rb") as f:
268
+ return f.read()
269
+
270
+ section_object = _SectionObject(
271
+ metadata=metadata,
272
+ data_type=schema.AnySectionDataType.TFLiteModel,
273
+ data_reader=data_reader,
274
+ )
275
+ self._sections.append(section_object)
276
+ return self
277
+
278
+ def add_sentencepiece_tokenizer(
279
+ self,
280
+ sp_tokenizer_path: str,
281
+ additional_metadata: Optional[list[Metadata]] = None,
282
+ ) -> LitertLmFileBuilderT:
283
+ """Adds a sentencepiece tokenizer to the litertlm file.
284
+
285
+ Args:
286
+ sp_tokenizer_path: The path to the sentencepiece tokenizer file.
287
+ additional_metadata: Additional metadata to add to the sentencepiece
288
+ tokenizer.
289
+
290
+ Returns:
291
+ The current LitertLmFileBuilder object.
292
+
293
+ Raises:
294
+ FileNotFoundError: If the sentencepiece tokenizer file is not found.
295
+ """
296
+ assert not self._has_tokenizer, "Tokenizer already added."
297
+ self._has_tokenizer = True
298
+ if not litertlm_core.path_exists(sp_tokenizer_path):
299
+ raise FileNotFoundError(
300
+ f"Sentencepiece tokenizer file not found: {sp_tokenizer_path}"
301
+ )
302
+
303
+ def data_reader():
304
+ with litertlm_core.open_file(sp_tokenizer_path, "rb") as f:
305
+ return f.read()
306
+
307
+ section_object = _SectionObject(
308
+ metadata=additional_metadata if additional_metadata else [],
309
+ data_type=schema.AnySectionDataType.SP_Tokenizer,
310
+ data_reader=data_reader,
311
+ )
312
+ self._sections.append(section_object)
313
+ return self
314
+
315
+ def add_hf_tokenizer(
316
+ self,
317
+ hf_tokenizer_path: str,
318
+ additional_metadata: Optional[list[Metadata]] = None,
319
+ ) -> LitertLmFileBuilderT:
320
+ """Adds a hf tokenizer to the litertlm file.
321
+
322
+ Args:
323
+ hf_tokenizer_path: The path to the hf tokenizer `tokenizer.json` file.
324
+ additional_metadata: Additional metadata to add to the hf tokenizer.
325
+
326
+ Returns:
327
+ The current LitertLmFileBuilder object.
328
+
329
+ Raises:
330
+ FileNotFoundError: If the hf tokenizer file is not found.
331
+ """
332
+ assert not self._has_tokenizer, "Tokenizer already added."
333
+ self._has_tokenizer = True
334
+ if not litertlm_core.path_exists(hf_tokenizer_path):
335
+ raise FileNotFoundError(
336
+ f"HF tokenizer file not found: {hf_tokenizer_path}"
337
+ )
338
+
339
+ def read_and_compress(path: str) -> bytes:
340
+ with litertlm_core.open_file(path, "rb") as f:
341
+ content = f.read()
342
+ uncompressed_size = len(content)
343
+ compressed_content = zlib.compress(content)
344
+ return uncompressed_size.to_bytes(8, "little") + compressed_content
345
+
346
+ section_object = _SectionObject(
347
+ metadata=additional_metadata if additional_metadata else [],
348
+ data_type=schema.AnySectionDataType.HF_Tokenizer_Zlib,
349
+ data_reader=lambda: read_and_compress(hf_tokenizer_path),
350
+ )
351
+ self._sections.append(section_object)
352
+ return self
353
+
354
+ def build(
355
+ self,
356
+ stream: BinaryIO | IO[Union[bytes, str]],
357
+ ) -> None:
358
+ """Builds the litertlm into the given stream."""
359
+ stream.seek(0)
360
+ # To simplify the build logic, we reserved the first block for the header.
361
+ # This translates to the first block will be padded to `BLOCK_SIZE`.
362
+ # TODO(b/413978412): support headers > 16KB.
363
+ stream.write(b"\0" * litertlm_core.BLOCK_SIZE)
364
+
365
+ # Write sections
366
+ offsets = []
367
+ for section in self._sections:
368
+ start_offset = stream.tell()
369
+ stream.write(section.data_reader())
370
+ end_offset = stream.tell()
371
+ offsets.append((start_offset, end_offset))
372
+ _write_padding(stream, litertlm_core.BLOCK_SIZE)
373
+
374
+ # write header
375
+ self._write_header(stream, offsets)
376
+
377
+ def _write_header(
378
+ self, stream: BinaryIO, offsets: list[tuple[int, int]]
379
+ ) -> None:
380
+ """Writes the header to the stream."""
381
+ assert self._system_metadata, "System metadata is empty."
382
+
383
+ stream.seek(0)
384
+ stream.write(b"LITERTLM")
385
+ stream.write(litertlm_core.LITERTLM_MAJOR_VERSION.to_bytes(4, "little"))
386
+ stream.write(litertlm_core.LITERTLM_MINOR_VERSION.to_bytes(4, "little"))
387
+ stream.write(litertlm_core.LITERTLM_PATCH_VERSION.to_bytes(4, "little"))
388
+ _write_padding(stream, litertlm_core.HEADER_BEGIN_BYTE_OFFSET)
389
+ stream.write(self._get_header_data(offsets))
390
+ header_end_offset = stream.tell()
391
+ if header_end_offset > litertlm_core.BLOCK_SIZE:
392
+ raise ValueError("Header size exceeds 16KB limit.")
393
+ stream.seek(litertlm_core.HEADER_END_LOCATION_BYTE_OFFSET)
394
+ stream.write(header_end_offset.to_bytes(8, "little"))
395
+
396
+ def _get_header_data(self, offsets: list[tuple[int, int]]) -> bytearray:
397
+ builder = flatbuffers.Builder(1024)
398
+ system_metadata_offset = self._write_system_metadata(builder)
399
+ section_metadata_offset = self._write_section_metadata(builder, offsets)
400
+ schema.LiteRTLMMetaDataStart(builder)
401
+ schema.LiteRTLMMetaDataAddSystemMetadata(builder, system_metadata_offset)
402
+ schema.LiteRTLMMetaDataAddSectionMetadata(builder, section_metadata_offset)
403
+ root = schema.LiteRTLMMetaDataEnd(builder)
404
+ builder.Finish(root)
405
+ return builder.Output()
406
+
407
+ def _write_system_metadata(self, builder: flatbuffers.Builder) -> int:
408
+ """Writes the system metadata to the builder."""
409
+ system_metadata_offsets = [
410
+ _write_metadata(builder, m) for m in self._system_metadata
411
+ ]
412
+ schema.SystemMetadataStartEntriesVector(
413
+ builder, len(system_metadata_offsets)
414
+ )
415
+ for offsets in reversed(system_metadata_offsets):
416
+ builder.PrependUOffsetTRelative(offsets)
417
+ entries_vec = builder.EndVector()
418
+ schema.SystemMetadataStart(builder)
419
+ schema.SystemMetadataAddEntries(builder, entries_vec)
420
+ return schema.SystemMetadataEnd(builder)
421
+
422
+ def _write_section_metadata(
423
+ self, builder: flatbuffers.Builder, offsets: list[tuple[int, int]]
424
+ ) -> int:
425
+ """Writes the section metadata to the builder."""
426
+ assert len(self._sections) == len(offsets)
427
+
428
+ section_objects_offsets = []
429
+ for section, offset in zip(self._sections, offsets):
430
+ section_objects_offsets.append(
431
+ _write_section_object(
432
+ builder, section.metadata, offset, section.data_type
433
+ )
434
+ )
435
+
436
+ schema.SectionMetadataStartObjectsVector(
437
+ builder, len(section_objects_offsets)
438
+ )
439
+ for obj in reversed(section_objects_offsets):
440
+ builder.PrependUOffsetTRelative(obj)
441
+ objects_vec = builder.EndVector()
442
+
443
+ schema.SectionMetadataStart(builder)
444
+ schema.SectionMetadataAddObjects(builder, objects_vec)
445
+ return schema.SectionMetadataEnd(builder)
446
+
447
+
448
+ def _is_binary_proto(filepath: str) -> bool:
449
+ """Checks if a file is a binary protobuf or a textproto version of LlmMetadata.
450
+
451
+ Args:
452
+ filepath (str): The path to the file.
453
+
454
+ Returns:
455
+ bool: True if the file is a binary protobuf, False if it's a textproto.
456
+ TextProto.
457
+ """
458
+ assert litertlm_core.path_exists(filepath), f"File {filepath} does not exist."
459
+
460
+ try:
461
+ with litertlm_core.open_file(filepath, "rb") as f:
462
+ content = f.read()
463
+ msg = llm_metadata_pb2.LlmMetadata()
464
+ msg.ParseFromString(content)
465
+ if msg.IsInitialized():
466
+ return True
467
+ except message.DecodeError:
468
+ # This is expected if the file is in text format. We'll just pass and try
469
+ # the next format.
470
+ pass
471
+
472
+ try:
473
+ with litertlm_core.open_file(filepath, "r") as f:
474
+ content = f.read()
475
+ msg = text_format.Parse(content, llm_metadata_pb2.LlmMetadata())
476
+ if msg.IsInitialized():
477
+ return False
478
+ except (text_format.ParseError, UnicodeDecodeError) as e:
479
+ raise ValueError(f"Failed to parse LlmMetadata from {filepath}.") from e
480
+
481
+
482
+ def _write_padding(stream: BinaryIO, block_size: int) -> None:
483
+ """Writes zero padding to align to the next block size."""
484
+ current_pos = stream.tell()
485
+ padding_needed = (block_size - (current_pos % block_size)) % block_size
486
+ if padding_needed > 0:
487
+ stream.write(b"\0" * padding_needed)
488
+
489
+
490
+ def _write_metadata(builder: flatbuffers.Builder, metadata: Metadata) -> int:
491
+ """Writes a FlatBuffers KeyValuePair."""
492
+ key_offset = builder.CreateString(metadata.key)
493
+
494
+ if metadata.dtype == DType.BOOL:
495
+ schema.BoolStart(builder)
496
+ schema.BoolAddValue(builder, metadata.value)
497
+ value_offset = schema.BoolEnd(builder)
498
+ value_type = schema.VData.Bool
499
+ elif metadata.dtype == DType.INT8:
500
+ schema.Int8Start(builder)
501
+ schema.Int8AddValue(builder, metadata.value)
502
+ value_offset = schema.Int8End(builder)
503
+ value_type = schema.VData.Int8
504
+ elif metadata.dtype == DType.INT16:
505
+ schema.Int16Start(builder)
506
+ schema.Int16AddValue(builder, metadata.value)
507
+ value_offset = schema.Int16End(builder)
508
+ value_type = schema.VData.Int16
509
+ elif metadata.dtype == DType.INT32:
510
+ schema.Int32Start(builder)
511
+ schema.Int32AddValue(builder, metadata.value)
512
+ value_offset = schema.Int32End(builder)
513
+ value_type = schema.VData.Int32
514
+ elif metadata.dtype == DType.INT64:
515
+ schema.Int64Start(builder)
516
+ schema.Int64AddValue(builder, metadata.value)
517
+ value_offset = schema.Int64End(builder)
518
+ value_type = schema.VData.Int64
519
+ elif metadata.dtype == DType.UINT8:
520
+ schema.UInt8Start(builder)
521
+ schema.UInt8AddValue(builder, metadata.value)
522
+ value_offset = schema.UInt8End(builder)
523
+ value_type = schema.VData.UInt8
524
+ elif metadata.dtype == DType.UINT16:
525
+ schema.UInt16Start(builder)
526
+ schema.UInt16AddValue(builder, metadata.value)
527
+ value_offset = schema.UInt16End(builder)
528
+ value_type = schema.VData.UInt16
529
+ elif metadata.dtype == DType.UINT32:
530
+ schema.UInt32Start(builder)
531
+ schema.UInt32AddValue(builder, metadata.value)
532
+ value_offset = schema.UInt32End(builder)
533
+ value_type = schema.VData.UInt32
534
+ elif metadata.dtype == DType.UINT64:
535
+ schema.UInt64Start(builder)
536
+ schema.UInt64AddValue(builder, metadata.value)
537
+ value_offset = schema.UInt64End(builder)
538
+ value_type = schema.VData.UInt64
539
+ elif metadata.dtype == DType.FLOAT32:
540
+ schema.Float32Start(builder)
541
+ schema.Float32AddValue(builder, metadata.value)
542
+ value_offset = schema.Float32End(builder)
543
+ value_type = schema.VData.Float32
544
+ elif metadata.dtype == DType.DOUBLE:
545
+ schema.DoubleStart(builder)
546
+ schema.DoubleAddValue(builder, metadata.value)
547
+ value_offset = schema.DoubleEnd(builder)
548
+ value_type = schema.VData.Double
549
+ elif metadata.dtype == DType.STRING:
550
+ value_offset_str = builder.CreateString(str(metadata.value))
551
+ schema.StringValueStart(builder)
552
+ schema.StringValueAddValue(builder, value_offset_str)
553
+ value_offset = schema.StringValueEnd(builder)
554
+ value_type = schema.VData.StringValue
555
+ else:
556
+ raise ValueError(f"Unsupported dtype: {metadata.dtype}")
557
+
558
+ schema.KeyValuePairStart(builder)
559
+ schema.KeyValuePairAddKey(builder, key_offset)
560
+ schema.KeyValuePairAddValueType(builder, value_type)
561
+ schema.KeyValuePairAddValue(builder, value_offset)
562
+ return schema.KeyValuePairEnd(builder)
563
+
564
+
565
+ def _write_section_object(
566
+ builder: flatbuffers.Builder,
567
+ section_metadata: list[Metadata],
568
+ section_offset: tuple[int, int],
569
+ section_type: schema.AnySectionDataType,
570
+ ) -> int:
571
+ """Writes a FlatBuffers SectionObject."""
572
+ section_metadata_offsets = [
573
+ _write_metadata(builder, m) for m in section_metadata
574
+ ]
575
+ schema.SectionObjectStartItemsVector(builder, len(section_metadata_offsets))
576
+ for offsets in reversed(section_metadata_offsets):
577
+ builder.PrependUOffsetTRelative(offsets)
578
+ items_vec = builder.EndVector()
579
+ schema.SectionObjectStart(builder)
580
+ schema.SectionObjectAddItems(builder, items_vec)
581
+ schema.SectionObjectAddBeginOffset(builder, section_offset[0])
582
+ schema.SectionObjectAddEndOffset(builder, section_offset[1])
583
+ schema.SectionObjectAddDataType(builder, section_type)
584
+ return schema.SectionObjectEnd(builder)
@@ -0,0 +1,58 @@
1
+ # Copyright 2025 The ODML Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Core library with shared constants and utilities for LiteRT-LM tools."""
16
+
17
+ # TODO(b/445163709): Remove this module once litert_lm publishes a pypi package.
18
+
19
+ import os # pylint: disable=unused-import
20
+
21
+ from ai_edge_litert.internal import litertlm_header_schema_py_generated as schema
22
+
23
+ # --- File Format Constants ---
24
+ # LINT.IfChange(litertlm_version_constants) # copybara:comment
25
+ LITERTLM_MAJOR_VERSION = 1
26
+ LITERTLM_MINOR_VERSION = 5
27
+ LITERTLM_PATCH_VERSION = 0
28
+ # copybara:comment_begin(google-only)
29
+ # LINT.ThenChange(
30
+ # litert_lm/schema/core/litertlm_header.h:litertlm_version_constants,
31
+ # litert_lm/schema/py/litertlm_core.py:litertlm_version_constants
32
+ # )
33
+ # copybara:comment_end(google-only)
34
+ BLOCK_SIZE = 16 * 1024
35
+ HEADER_BEGIN_BYTE_OFFSET = 32
36
+ HEADER_END_LOCATION_BYTE_OFFSET = 24
37
+
38
+ SECTION_DATA_TYPE_TO_STRING_MAP = {
39
+ v: k for k, v in schema.AnySectionDataType.__dict__.items()
40
+ }
41
+
42
+
43
+ def any_section_data_type_to_string(data_type: int):
44
+ """Converts AnySectionDataType enum to its string representation."""
45
+ if data_type in SECTION_DATA_TYPE_TO_STRING_MAP:
46
+ return SECTION_DATA_TYPE_TO_STRING_MAP[data_type]
47
+ else:
48
+ raise ValueError(f"Unknown AnySectionDataType value: {data_type}")
49
+
50
+
51
+ def path_exists(file_path: str) -> bool:
52
+ """Checks if a file exists."""
53
+ return os.path.exists(file_path)
54
+
55
+
56
+ def open_file(file_path: str, mode: str = "rb"):
57
+ """Opens a file using the given mode."""
58
+ return open(file_path, mode)