@@ -713,3 +713,113 @@ def test_voyageai_context_model_detection():
713713 for model_name , expected in test_cases :
714714 # The _is_context_model method simply checks: "context" in self.model
715715 assert ("context" in model_name ) == expected , f"Failed for { model_name } "
716+
717+
718+ @pytest .mark .requires_api_keys
719+ def test_voyageai_multimodal_text_only ():
720+ """Test VoyageAI multimodal vectorizer with text-only input."""
721+ vectorizer = VoyageAIVectorizer (model = "voyage-multimodal-3" )
722+
723+ # Test single text embedding via embed()
724+ embedding = vectorizer .embed ("A red apple on a wooden table" )
725+ assert isinstance (embedding , list )
726+ assert len (embedding ) > 0
727+ assert all (isinstance (x , float ) for x in embedding )
728+
729+ # Test another text embedding to verify consistency
730+ embedding2 = vectorizer .embed ("A cat sleeping on a couch" )
731+ assert isinstance (embedding2 , list )
732+ assert len (embedding2 ) == len (embedding )
733+
734+
735+ @pytest .mark .requires_api_keys
736+ def test_voyageai_multimodal_image ():
737+ """Test VoyageAI multimodal vectorizer with image input."""
738+ import os
739+ import tempfile
740+
741+ from PIL import Image
742+
743+ vectorizer = VoyageAIVectorizer (model = "voyage-multimodal-3" )
744+
745+ # Create a simple test image
746+ img = Image .new ("RGB" , (100 , 100 ), color = "red" )
747+ with tempfile .NamedTemporaryFile (suffix = ".png" , delete = False ) as f :
748+ img .save (f , format = "PNG" )
749+ temp_path = f .name
750+
751+ try :
752+ # Test embed_image
753+ embedding = vectorizer .embed_image (temp_path )
754+ assert isinstance (embedding , list )
755+ assert len (embedding ) > 0
756+ assert all (isinstance (x , float ) for x in embedding )
757+ finally :
758+ os .unlink (temp_path )
759+
760+
761+ @pytest .mark .requires_api_keys
762+ def test_voyageai_multimodal_video ():
763+ """Test VoyageAI multimodal vectorizer with video input."""
764+ import os
765+ import subprocess
766+ import tempfile
767+
768+ from PIL import Image
769+
770+ vectorizer = VoyageAIVectorizer (model = "voyage-multimodal-3.5" )
771+
772+ # Create a minimal test video using ffmpeg
773+ with tempfile .TemporaryDirectory () as tmpdir :
774+ # Create 3 frames
775+ for i in range (3 ):
776+ img = Image .new ("RGB" , (64 , 64 ), color = (i * 80 , 100 , 150 ))
777+ img .save (os .path .join (tmpdir , f"frame_{ i :03d} .png" ))
778+
779+ video_path = os .path .join (tmpdir , "test_video.mp4" )
780+
781+ # Create video from frames
782+ result = subprocess .run (
783+ [
784+ "ffmpeg" ,
785+ "-y" ,
786+ "-framerate" ,
787+ "1" ,
788+ "-i" ,
789+ os .path .join (tmpdir , "frame_%03d.png" ),
790+ "-c:v" ,
791+ "libx264" ,
792+ "-pix_fmt" ,
793+ "yuv420p" ,
794+ "-t" ,
795+ "3" ,
796+ video_path ,
797+ ],
798+ capture_output = True ,
799+ )
800+
801+ if result .returncode != 0 :
802+ pytest .skip ("ffmpeg not available or failed to create test video" )
803+
804+ # Test embed_video
805+ embedding = vectorizer .embed_video (video_path )
806+ assert isinstance (embedding , list )
807+ assert len (embedding ) > 0
808+ assert all (isinstance (x , float ) for x in embedding )
809+
810+
811+ @pytest .mark .requires_api_keys
812+ @pytest .mark .asyncio
813+ async def test_voyageai_multimodal_async ():
814+ """Test VoyageAI multimodal vectorizer async methods."""
815+ vectorizer = VoyageAIVectorizer (model = "voyage-multimodal-3" )
816+
817+ # Test async text embedding
818+ embedding = await vectorizer .aembed ("A beautiful sunset over mountains" )
819+ assert isinstance (embedding , list )
820+ assert len (embedding ) > 0
821+
822+ # Test async batch
823+ texts = ["Ocean waves" , "Forest trees" ]
824+ embeddings = await vectorizer .aembed_many (texts )
825+ assert len (embeddings ) == 2
0 commit comments