@@ -381,6 +381,15 @@ json parse_options(bool streaming, const backend::PredictOptions* predict, const
381381 });
382382 }
383383
384+ // for each video in the request, add the video data
385+ for (int i = 0 ; i < predict->videos_size (); i++) {
386+ data[" video_data" ].push_back (json
387+ {
388+ {" id" , i},
389+ {" data" , predict->videos (i)},
390+ });
391+ }
392+
384393 data[" stop" ] = predict->stopprompts ();
385394 // data["n_probs"] = predict->nprobs();
386395 // TODO: images,
@@ -1503,7 +1512,7 @@ class BackendServiceImpl final : public backend::Backend::Service {
15031512 msg_json[" role" ] = msg.role ();
15041513
15051514 bool is_last_user_msg = (i == last_user_msg_idx);
1506- bool has_images_or_audio = (request->images_size () > 0 || request->audios_size () > 0 );
1515+ bool has_images_or_audio = (request->images_size () > 0 || request->audios_size () > 0 || request-> videos_size () > 0 );
15071516
15081517 // Handle content - can be string, null, or array
15091518 // For multimodal content, we'll embed images/audio from separate fields
@@ -1554,6 +1563,16 @@ class BackendServiceImpl final : public backend::Backend::Service {
15541563 content_array.push_back (audio_chunk);
15551564 }
15561565 }
1566+ if (request->videos_size () > 0 ) {
1567+ for (int j = 0 ; j < request->videos_size (); j++) {
1568+ json video_chunk;
1569+ video_chunk[" type" ] = " input_video" ;
1570+ json input_video;
1571+ input_video[" data" ] = request->videos (j);
1572+ video_chunk[" input_video" ] = input_video;
1573+ content_array.push_back (video_chunk);
1574+ }
1575+ }
15571576 msg_json[" content" ] = content_array;
15581577 } else {
15591578 // Use content as-is (already array or not last user message)
@@ -1588,6 +1607,16 @@ class BackendServiceImpl final : public backend::Backend::Service {
15881607 content_array.push_back (audio_chunk);
15891608 }
15901609 }
1610+ if (request->videos_size () > 0 ) {
1611+ for (int j = 0 ; j < request->videos_size (); j++) {
1612+ json video_chunk;
1613+ video_chunk[" type" ] = " input_video" ;
1614+ json input_video;
1615+ input_video[" data" ] = request->videos (j);
1616+ video_chunk[" input_video" ] = input_video;
1617+ content_array.push_back (video_chunk);
1618+ }
1619+ }
15911620 msg_json[" content" ] = content_array;
15921621 } else if (msg.role () == " tool" ) {
15931622 // Tool role messages must have content field set, even if empty
@@ -2039,6 +2068,16 @@ class BackendServiceImpl final : public backend::Backend::Service {
20392068 files.push_back (decoded_data);
20402069 }
20412070 }
2071+
2072+ const auto &video_data = data.find (" video_data" );
2073+ if (video_data != data.end () && video_data->is_array ())
2074+ {
2075+ for (const auto &video : *video_data)
2076+ {
2077+ auto decoded_data = base64_decode (video[" data" ].get <std::string>());
2078+ files.push_back (decoded_data);
2079+ }
2080+ }
20422081 }
20432082
20442083 const bool has_mtmd = ctx_server.impl ->mctx != nullptr ;
@@ -2291,7 +2330,7 @@ class BackendServiceImpl final : public backend::Backend::Service {
22912330 }
22922331
22932332 bool is_last_user_msg = (i == last_user_msg_idx);
2294- bool has_images_or_audio = (request->images_size () > 0 || request->audios_size () > 0 );
2333+ bool has_images_or_audio = (request->images_size () > 0 || request->audios_size () > 0 || request-> videos_size () > 0 );
22952334
22962335 // Handle content - can be string, null, or array
22972336 // For multimodal content, we'll embed images/audio from separate fields
@@ -2344,6 +2383,16 @@ class BackendServiceImpl final : public backend::Backend::Service {
23442383 content_array.push_back (audio_chunk);
23452384 }
23462385 }
2386+ if (request->videos_size () > 0 ) {
2387+ for (int j = 0 ; j < request->videos_size (); j++) {
2388+ json video_chunk;
2389+ video_chunk[" type" ] = " input_video" ;
2390+ json input_video;
2391+ input_video[" data" ] = request->videos (j);
2392+ video_chunk[" input_video" ] = input_video;
2393+ content_array.push_back (video_chunk);
2394+ }
2395+ }
23472396 msg_json[" content" ] = content_array;
23482397 } else {
23492398 // Use content as-is (already array or not last user message)
@@ -2383,6 +2432,16 @@ class BackendServiceImpl final : public backend::Backend::Service {
23832432 content_array.push_back (audio_chunk);
23842433 }
23852434 }
2435+ if (request->videos_size () > 0 ) {
2436+ for (int j = 0 ; j < request->videos_size (); j++) {
2437+ json video_chunk;
2438+ video_chunk[" type" ] = " input_video" ;
2439+ json input_video;
2440+ input_video[" data" ] = request->videos (j);
2441+ video_chunk[" input_video" ] = input_video;
2442+ content_array.push_back (video_chunk);
2443+ }
2444+ }
23862445 msg_json[" content" ] = content_array;
23872446 SRV_INF (" [CONTENT DEBUG] Predict: Message %d created content array with media\n " , i);
23882447 } else if (!msg.tool_calls ().empty ()) {
@@ -2845,6 +2904,16 @@ class BackendServiceImpl final : public backend::Backend::Service {
28452904 files.push_back (decoded_data);
28462905 }
28472906 }
2907+
2908+ const auto &video_data = data.find (" video_data" );
2909+ if (video_data != data.end () && video_data->is_array ())
2910+ {
2911+ for (const auto &video : *video_data)
2912+ {
2913+ auto decoded_data = base64_decode (video[" data" ].get <std::string>());
2914+ files.push_back (decoded_data);
2915+ }
2916+ }
28482917 }
28492918
28502919 // process files
0 commit comments