@@ -1011,6 +1011,79 @@ func TestConvertRequestAutoConvertsAudioAndVideoURLs(t *testing.T) {
10111011 assert .Nil (t , geminiReq .Contents [0 ].Parts [1 ].FileData )
10121012}
10131013
1014+ func TestConvertRequestAutoConvertsAudioHTTPDataURL (t * testing.T ) {
1015+ t .Parallel ()
1016+
1017+ audioData := []byte ("audio bytes" )
1018+
1019+ ts := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
1020+ assert .Equal (t , "/audio.wav" , r .URL .Path )
1021+ w .Header ().Set ("Content-Type" , "audio/wav" )
1022+ _ , _ = w .Write (audioData )
1023+ }))
1024+ defer ts .Close ()
1025+
1026+ channel := & model.Channel {
1027+ Type : model .ChannelTypeGoogleGemini ,
1028+ }
1029+ meta := meta .NewMeta (
1030+ channel ,
1031+ mode .ChatCompletions ,
1032+ "gemini-2.5-flash" ,
1033+ model.ModelConfig {},
1034+ )
1035+
1036+ openAIReq := map [string ]any {
1037+ "model" : "gemini-2.5-flash" ,
1038+ "messages" : []map [string ]any {
1039+ {
1040+ "role" : "user" ,
1041+ "content" : []map [string ]any {
1042+ {
1043+ "type" : "input_audio" ,
1044+ "input_audio" : map [string ]any {
1045+ "data" : ts .URL + "/audio.wav" ,
1046+ "format" : "wav" ,
1047+ },
1048+ },
1049+ },
1050+ },
1051+ },
1052+ }
1053+
1054+ jsonData , err := sonic .Marshal (openAIReq )
1055+ assert .NoError (t , err )
1056+
1057+ req , err := http .NewRequestWithContext (
1058+ t .Context (),
1059+ http .MethodPost ,
1060+ "http://localhost/v1/chat/completions" ,
1061+ bytes .NewBuffer (jsonData ),
1062+ )
1063+ assert .NoError (t , err )
1064+
1065+ result , err := gemini .ConvertRequest (meta , req )
1066+ assert .NoError (t , err )
1067+
1068+ bodyBytes , err := io .ReadAll (result .Body )
1069+ assert .NoError (t , err )
1070+
1071+ var geminiReq relaymodel.GeminiChatRequest
1072+
1073+ err = json .Unmarshal (bodyBytes , & geminiReq )
1074+ assert .NoError (t , err )
1075+ assert .Len (t , geminiReq .Contents , 1 )
1076+ assert .Len (t , geminiReq .Contents [0 ].Parts , 1 )
1077+ assert .NotNil (t , geminiReq .Contents [0 ].Parts [0 ].InlineData )
1078+ assert .Equal (t , "audio/wav" , geminiReq .Contents [0 ].Parts [0 ].InlineData .MimeType )
1079+ assert .Equal (
1080+ t ,
1081+ base64 .StdEncoding .EncodeToString (audioData ),
1082+ geminiReq .Contents [0 ].Parts [0 ].InlineData .Data ,
1083+ )
1084+ assert .Nil (t , geminiReq .Contents [0 ].Parts [0 ].FileData )
1085+ }
1086+
10141087func TestConvertRequestCanDisableAudioAndVideoURLAutoBase64 (t * testing.T ) {
10151088 t .Parallel ()
10161089
@@ -1092,6 +1165,105 @@ func TestConvertRequestCanDisableAudioAndVideoURLAutoBase64(t *testing.T) {
10921165 )
10931166}
10941167
1168+ func TestConvertRequestVertexAIAlwaysConvertsAudioAndVideoURLs (t * testing.T ) {
1169+ t .Parallel ()
1170+
1171+ audioData := []byte ("audio bytes" )
1172+ videoData := []byte ("video bytes" )
1173+
1174+ ts := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
1175+ switch r .URL .Path {
1176+ case "/audio.wav" :
1177+ w .Header ().Set ("Content-Type" , "audio/wav" )
1178+ _ , _ = w .Write (audioData )
1179+ case "/video.mp4" :
1180+ w .Header ().Set ("Content-Type" , "video/mp4" )
1181+ _ , _ = w .Write (videoData )
1182+ default :
1183+ http .NotFound (w , r )
1184+ }
1185+ }))
1186+ defer ts .Close ()
1187+
1188+ channel := & model.Channel {
1189+ Type : model .ChannelTypeVertexAI ,
1190+ Configs : model.ChannelConfigs {
1191+ "disable_auto_audio_url_to_base64" : true ,
1192+ "disable_auto_video_url_to_base64" : true ,
1193+ },
1194+ }
1195+ meta := meta .NewMeta (
1196+ channel ,
1197+ mode .ChatCompletions ,
1198+ "gemini-2.5-flash" ,
1199+ model.ModelConfig {},
1200+ )
1201+
1202+ openAIReq := map [string ]any {
1203+ "model" : "gemini-2.5-flash" ,
1204+ "messages" : []map [string ]any {
1205+ {
1206+ "role" : "user" ,
1207+ "content" : []map [string ]any {
1208+ {
1209+ "type" : "input_audio" ,
1210+ "input_audio" : map [string ]any {
1211+ "data" : ts .URL + "/audio.wav" ,
1212+ "format" : "wav" ,
1213+ },
1214+ },
1215+ {
1216+ "type" : "video_url" ,
1217+ "video_url" : map [string ]any {
1218+ "url" : ts .URL + "/video.mp4" ,
1219+ },
1220+ },
1221+ },
1222+ },
1223+ },
1224+ }
1225+
1226+ jsonData , err := sonic .Marshal (openAIReq )
1227+ assert .NoError (t , err )
1228+
1229+ req , err := http .NewRequestWithContext (
1230+ t .Context (),
1231+ http .MethodPost ,
1232+ "http://localhost/v1/chat/completions" ,
1233+ bytes .NewBuffer (jsonData ),
1234+ )
1235+ assert .NoError (t , err )
1236+
1237+ result , err := gemini .ConvertRequest (meta , req )
1238+ assert .NoError (t , err )
1239+
1240+ bodyBytes , err := io .ReadAll (result .Body )
1241+ assert .NoError (t , err )
1242+
1243+ var geminiReq relaymodel.GeminiChatRequest
1244+
1245+ err = json .Unmarshal (bodyBytes , & geminiReq )
1246+ assert .NoError (t , err )
1247+ assert .Len (t , geminiReq .Contents , 1 )
1248+ assert .Len (t , geminiReq .Contents [0 ].Parts , 2 )
1249+ assert .NotNil (t , geminiReq .Contents [0 ].Parts [0 ].InlineData )
1250+ assert .Equal (t , "audio/wav" , geminiReq .Contents [0 ].Parts [0 ].InlineData .MimeType )
1251+ assert .Equal (
1252+ t ,
1253+ base64 .StdEncoding .EncodeToString (audioData ),
1254+ geminiReq .Contents [0 ].Parts [0 ].InlineData .Data ,
1255+ )
1256+ assert .Nil (t , geminiReq .Contents [0 ].Parts [0 ].FileData )
1257+ assert .NotNil (t , geminiReq .Contents [0 ].Parts [1 ].InlineData )
1258+ assert .Equal (t , "video/mp4" , geminiReq .Contents [0 ].Parts [1 ].InlineData .MimeType )
1259+ assert .Equal (
1260+ t ,
1261+ base64 .StdEncoding .EncodeToString (videoData ),
1262+ geminiReq .Contents [0 ].Parts [1 ].InlineData .Data ,
1263+ )
1264+ assert .Nil (t , geminiReq .Contents [0 ].Parts [1 ].FileData )
1265+ }
1266+
10951267func TestProcessMediaTasksKeepsFileDataWhenConversionFails (t * testing.T ) {
10961268 t .Parallel ()
10971269
0 commit comments