Skip to content

Commit 486987f

Browse files
committed
fix(example): avoid MTMD video stdin double close
1 parent e6a6dc9 commit 486987f

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

‎examples/server/server.py‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import shutil
3838
import inspect
3939
import sys
40+
import tempfile
4041
import urllib.error
4142
import urllib.parse
4243
import urllib.request
@@ -10399,6 +10400,8 @@ class MTMDLoadedMedia:
1039910400
key: str
1040010401
bitmap: Any
1040110402
video_ctx: Optional[Any] = None
10403+
video_temp_path: Optional[Path] = None
10404+
video_callback: Optional[Any] = None
1040210405
video_frame_count: int = 0
1040310406
video_frames_used: int = 0
1040410407

@@ -10593,6 +10596,8 @@ def _create_loaded_media(
1059310596
media_bytes=media_bytes,
1059410597
)
1059510598
)
10599+
if media.kind == "video":
10600+
return self._create_loaded_video_media(media, media_bytes, key)
1059610601
buffer = (ctypes.c_uint8 * len(media_bytes)).from_buffer_copy(media_bytes)
1059710602
wrapper = mtmd_cpp.mtmd_helper_bitmap_init_from_buf_wrapper(
1059810603
self.ctx,
@@ -10618,6 +10623,73 @@ def _create_loaded_media(
1061810623
video_frame_count=video_frame_count,
1061910624
)
1062010625

10626+
@staticmethod
10627+
def _video_temp_suffix(media: MediaInput) -> str:
10628+
extension = (media.format or "mp4").lstrip(".").lower()
10629+
if not extension or any(not char.isalnum() for char in extension):
10630+
extension = "video"
10631+
return f".{extension}"
10632+
10633+
def _create_loaded_video_media(
10634+
self,
10635+
media: MediaInput,
10636+
media_bytes: bytes,
10637+
key: str,
10638+
) -> MTMDLoadedMedia:
10639+
temp_file = tempfile.NamedTemporaryFile(
10640+
prefix="llama-cpp-python-mtmd-",
10641+
suffix=self._video_temp_suffix(media),
10642+
delete=False,
10643+
)
10644+
temp_path = Path(temp_file.name)
10645+
try:
10646+
with temp_file:
10647+
temp_file.write(media_bytes)
10648+
params = mtmd_cpp.mtmd_helper_video_init_params_default()
10649+
video_ctx = mtmd_cpp.mtmd_helper_video_init(
10650+
self.ctx,
10651+
str(temp_path).encode("utf-8"),
10652+
params,
10653+
)
10654+
if video_ctx is None:
10655+
raise CompletionRequestValidationError("failed to create MTMD video context")
10656+
10657+
def read_next(
10658+
_chunk_index: int,
10659+
_user_data: Any,
10660+
out_bitmap: Any,
10661+
out_text: Any,
10662+
) -> int:
10663+
return int(mtmd_cpp.mtmd_helper_video_read_next(video_ctx, out_bitmap, out_text))
10664+
10665+
callback = mtmd_cpp.mtmd_bitmap_lazy_callback(read_next)
10666+
bitmap = mtmd_cpp.mtmd_bitmap_init_lazy(
10667+
self.ctx,
10668+
key.encode("utf-8"),
10669+
ctypes.c_void_p(),
10670+
callback,
10671+
)
10672+
if bitmap is None:
10673+
mtmd_cpp.mtmd_helper_video_free(video_ctx)
10674+
raise CompletionRequestValidationError("failed to create MTMD video bitmap")
10675+
video_info = mtmd_cpp.mtmd_helper_video_get_info(video_ctx)
10676+
return MTMDLoadedMedia(
10677+
media=media,
10678+
media_bytes=media_bytes,
10679+
key=key,
10680+
bitmap=bitmap,
10681+
video_ctx=video_ctx,
10682+
video_temp_path=temp_path,
10683+
video_callback=callback,
10684+
video_frame_count=max(0, int(video_info.n_frames)),
10685+
)
10686+
except Exception:
10687+
try:
10688+
temp_path.unlink()
10689+
except OSError:
10690+
pass
10691+
raise
10692+
1062110693
def _media_identity_tokens(
1062210694
self,
1062310695
kind: Literal["image", "audio", "video"],
@@ -10922,6 +10994,11 @@ def _build_prompt_plan_locked(
1092210994
mtmd_cpp.mtmd_bitmap_free(media.bitmap)
1092310995
if media.video_ctx:
1092410996
mtmd_cpp.mtmd_helper_video_free(media.video_ctx)
10997+
if media.video_temp_path is not None:
10998+
try:
10999+
media.video_temp_path.unlink()
11000+
except OSError:
11001+
pass
1092511002

1092611003

1092711004
class Model:

0 commit comments

Comments
 (0)