@@ -9,7 +9,9 @@ use anyhow::Result;
99use dynamo_async_openai:: types:: ChatCompletionRequestUserMessageContentPart ;
1010
1111use super :: common:: EncodedMediaData ;
12- use super :: decoders:: { DecodedMediaData , Decoder , MediaDecoder } ;
12+ use super :: decoders:: { Decoder , MediaDecoder } ;
13+ use super :: rdma:: { RdmaMediaDataDescriptor , get_nixl_agent} ;
14+ use nixl_sys:: Agent as NixlAgent ;
1315
1416const DEFAULT_HTTP_USER_AGENT : & str = "dynamo-ai/dynamo" ;
1517const DEFAULT_HTTP_TIMEOUT : Duration = Duration :: from_secs ( 30 ) ;
@@ -39,7 +41,7 @@ pub struct MediaLoader {
3941 media_decoder : MediaDecoder ,
4042 http_client : reqwest:: Client ,
4143 media_fetcher : MediaFetcher ,
42- // TODO: NIXL agent
44+ nixl_agent : NixlAgent ,
4345}
4446
4547impl MediaLoader {
@@ -53,10 +55,13 @@ impl MediaLoader {
5355
5456 let http_client = http_client_builder. build ( ) ?;
5557
58+ let nixl_agent = get_nixl_agent ( ) ?;
59+
5660 Ok ( Self {
5761 media_decoder,
5862 http_client,
5963 media_fetcher,
64+ nixl_agent,
6065 } )
6166 }
6267
@@ -90,9 +95,8 @@ impl MediaLoader {
9095 & self ,
9196 oai_content_part : & ChatCompletionRequestUserMessageContentPart ,
9297 // TODO: request-level options
93- ) -> Result < DecodedMediaData > {
94- // fetch the media
95- // TODO: decode and NIXL-register
98+ ) -> Result < RdmaMediaDataDescriptor > {
99+ // fetch the media, decode and NIXL-register
96100 let decoded = match oai_content_part {
97101 ChatCompletionRequestUserMessageContentPart :: ImageUrl ( image_part) => {
98102 let url = & image_part. image_url . url ;
@@ -112,14 +116,16 @@ impl MediaLoader {
112116 _ => anyhow:: bail!( "Unsupported media type" ) ,
113117 } ;
114118
115- Ok ( decoded)
119+ let rdma_descriptor = decoded. into_rdma_descriptor ( & self . nixl_agent ) ?;
120+ Ok ( rdma_descriptor)
116121 }
117122}
118123
119124#[ cfg( test) ]
120125mod tests {
121- use super :: super :: decoders :: DataType ;
126+ use super :: super :: rdma :: DataType ;
122127 use super :: * ;
128+ use crate :: block_manager:: storage:: nixl:: NixlRegisterableStorage ;
123129 use dynamo_async_openai:: types:: { ChatCompletionRequestMessageContentPartImage , ImageUrl } ;
124130
125131 #[ tokio:: test]
@@ -157,17 +163,52 @@ mod tests {
157163 result. err( )
158164 ) ;
159165
160- let data = result. unwrap ( ) ;
161- assert_eq ! ( data . dtype, DataType :: UINT8 ) ;
166+ let descriptor = result. unwrap ( ) ;
167+ assert_eq ! ( descriptor . tensor_info . dtype, DataType :: UINT8 ) ;
162168
163169 // Verify image dimensions: 1,999px × 1,125px (width × height)
164170 // Shape format is [height, width, channels]
165- assert_eq ! ( data. shape. len( ) , 3 ) ;
166- assert_eq ! ( data. shape[ 0 ] , 1125 , "Height should be 1125" ) ;
167- assert_eq ! ( data. shape[ 1 ] , 1999 , "Width should be 1999" ) ;
168- assert_eq ! ( data. shape[ 2 ] , 4 , "RGBA channels should be 4" ) ;
171+ assert_eq ! ( descriptor. tensor_info. shape. len( ) , 3 ) ;
172+ assert_eq ! (
173+ descriptor. tensor_info. shape[ 0 ] , 1125 ,
174+ "Height should be 1125"
175+ ) ;
176+ assert_eq ! (
177+ descriptor. tensor_info. shape[ 1 ] , 1999 ,
178+ "Width should be 1999"
179+ ) ;
180+ assert_eq ! (
181+ descriptor. tensor_info. shape[ 2 ] , 4 ,
182+ "RGBA channels should be 4"
183+ ) ;
169184
170185 mock. assert_async ( ) . await ;
186+
187+ assert ! (
188+ !descriptor. tensor_info. shape. is_empty( ) ,
189+ "Shape should not be empty"
190+ ) ;
191+ assert_eq ! (
192+ descriptor. tensor_info. shape[ 0 ] , 1125 ,
193+ "Height should be 1125"
194+ ) ;
195+ assert_eq ! (
196+ descriptor. tensor_info. shape[ 1 ] , 1999 ,
197+ "Width should be 1999"
198+ ) ;
199+ assert_eq ! (
200+ descriptor. tensor_info. shape[ 2 ] , 4 ,
201+ "RGBA channels should be 4"
202+ ) ;
203+
204+ assert ! (
205+ descriptor. source_storage. is_some( ) ,
206+ "Source storage should be present"
207+ ) ;
208+ assert ! (
209+ descriptor. source_storage. unwrap( ) . is_nixl_registered( ) ,
210+ "Source storage should be registered with NIXL"
211+ ) ;
171212 }
172213
173214 #[ test]
0 commit comments