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