char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
9cffdcc80
char/aliceai-t5-moe
1import pytest 2from utils import * 3import base64 4import requests 5 6server :ServerProcess 7 8def get_img_url (id :str )-> str : 9IMG_URL_0 = "https://huggingface.co/ggml-org/tinygemma3-GGUF/resolve/main/test/11_truck.png" 10IMG_URL_1 = "https://huggingface.co/ggml-org/tinygemma3-GGUF/resolve/main/test/91_cat.png" 11if id == "IMG_URL_0" : 12return IMG_URL_0 13elif id == "IMG_URL_1" : 14return IMG_URL_1 15elif id == "IMG_BASE64_URI_0" : 16response = requests .get (IMG_URL_0 ) 17response .raise_for_status ()# Raise an exception for bad status codes 18return "data:image/png;base64," + base64 .b64encode (response .content ).decode ("utf-8" ) 19elif id == "IMG_BASE64_0" : 20response = requests .get (IMG_URL_0 ) 21response .raise_for_status ()# Raise an exception for bad status codes 22return base64 .b64encode (response .content ).decode ("utf-8" ) 23elif id == "IMG_BASE64_URI_1" : 24response = requests .get (IMG_URL_1 ) 25response .raise_for_status ()# Raise an exception for bad status codes 26return "data:image/png;base64," + base64 .b64encode (response .content ).decode ("utf-8" ) 27elif id == "IMG_BASE64_1" : 28response = requests .get (IMG_URL_1 ) 29response .raise_for_status ()# Raise an exception for bad status codes 30return base64 .b64encode (response .content ).decode ("utf-8" ) 31else : 32return id 33 34JSON_MULTIMODAL_KEY = "multimodal_data" 35JSON_PROMPT_STRING_KEY = "prompt_string" 36 37@ pytest . fixture ( autouse = True ) 38def create_server (): 39global server 40os .environ ['LLAMA_MEDIA_MARKER' ]= '<__media__>' 41server = ServerPreset .tinygemma3 () 42 43def test_models_supports_multimodal_capability (): 44global server 45server .start () 46res = server .make_request ("GET" ,"/models" ,data = {}) 47assert res .status_code == 200 48model_info = res .body ["models" ][0 ] 49model_info ) 50assert "completion" in model_info ["capabilities" ] 51assert "multimodal" in model_info ["capabilities" ] 52 53def test_v1_models_supports_multimodal_capability (): 54global server 55server .start () 56res = server .make_request ("GET" ,"/v1/models" ,data = {}) 57assert res .status_code == 200 58model_info = res .body ["models" ][0 ] 59model_info ) 60assert "completion" in model_info ["capabilities" ] 61assert "multimodal" in model_info ["capabilities" ] 62 63@ pytest . mark . parametrize ( 64"prompt, image_url, success, re_content" , 65[ 66# test model is trained on CIFAR-10, but it's quite dumb due to small size 67( "What is this:\n" , "IMG_URL_0" , True , "(cat)+" ), 68( "What is this:\n" , "IMG_BASE64_URI_0" , True , "(cat)+" ), 69( "What is this:\n" , "IMG_URL_1" , True , "(frog)+" ), 70( "Test test\n" , "IMG_URL_1" , True , "(frog)+" ), # test invalidate cache 71( "What is this:\n" , "malformed" , False , None ), 72( "What is this:\n" , "https://google.com/404" , False , None ), # non-existent image 73( "What is this:\n" , "https://ggml.ai" , False , None ), # non-image data 74( "What is this:\n" , "data:text/html;base64,aGVsbG8=" , False , None ), # unsupported data uri mime 75# TODO @ngxson : test with multiple images, no images and with audio 76] 77) 78def test_vision_chat_completion (prompt ,image_url ,success ,re_content ): 79global server 80server .start () 81res = server .make_request ("POST" ,"/chat/completions" ,data = { 82"temperature" :0.0 , 83"top_k" :1 , 84"messages" : [ 85 {"role" :"user" ,"content" : [ 86 {"type" :"text" ,"text" :prompt }, 87 {"type" :"image_url" ,"image_url" : { 88"url" :get_img_url (image_url ), 89 }}, 90 ]}, 91 ], 92 }) 93if success : 94assert res .status_code == 200 95choice = res .body ["choices" ][0 ] 96assert "assistant" == choice ["message" ]["role" ] 97assert match_regex (re_content ,choice ["message" ]["content" ]) 98else : 99assert res .status_code != 200 100 101 102def test_vision_chat_completion_token_count (): 103global server 104server .start () 105res = server .make_request ("POST" ,"/chat/completions/input_tokens" ,data = { 106"temperature" :0.0 , 107"top_k" :1 , 108"messages" : [ 109 {"role" :"user" ,"content" : [ 110 {"type" :"text" ,"text" :"What is this:" }, 111 {"type" :"image_url" ,"image_url" : { 112"url" :get_img_url ("IMG_URL_0" ), 113 }}, 114 ]}, 115 ], 116 }) 117assert res .status_code == 200 118assert res .body ["input_tokens" ]> 10 119 120 121@ pytest . mark . parametrize ( 122"prompt, image_data, success, re_content" , 123[ 124# test model is trained on CIFAR-10, but it's quite dumb due to small size 125( "What is this: <__media__>\n" , "IMG_BASE64_0" , True , "(cat)+|(automobile)+" ), 126( "What is this: <__media__>\n" , "IMG_BASE64_1" , True , "(frog)+" ), 127( "What is this: <__media__>\n" , "malformed" , False , None ), # non-image data 128( "What is this:\n" , "" , False , None ), # empty string 129] 130) 131def test_vision_completion (prompt ,image_data ,success ,re_content ): 132global server 133server .start () 134res = server .make_request ("POST" ,"/completions" ,data = { 135"temperature" :0.0 , 136"top_k" :1 , 137"prompt" : { 138JSON_PROMPT_STRING_KEY :prompt , 139JSON_MULTIMODAL_KEY : [get_img_url (image_data ) ], 140 }, 141 }) 142if success : 143assert res .status_code == 200 144content = res .body ["content" ] 145assert match_regex (re_content ,content ) 146else : 147assert res .status_code != 200 148 149 150@ pytest . mark . parametrize ( 151"prompt, image_data, success" , 152[ 153# test model is trained on CIFAR-10, but it's quite dumb due to small size 154( "What is this: <__media__>\n" , "IMG_BASE64_0" , True ), 155( "What is this: <__media__>\n" , "IMG_BASE64_1" , True ), 156( "What is this: <__media__>\n" , "malformed" , False ), # non-image data 157( "What is this:\n" , "base64" , False ), # non-image data 158] 159) 160def test_vision_embeddings (prompt ,image_data ,success ): 161global server 162server .server_embeddings = True 163server .n_batch = 512 164server .start () 165image_data = get_img_url (image_data ) 166res = server .make_request ("POST" ,"/embeddings" ,data = { 167"content" : [ 168 {JSON_PROMPT_STRING_KEY :prompt ,JSON_MULTIMODAL_KEY : [image_data ] }, 169 {JSON_PROMPT_STRING_KEY :prompt ,JSON_MULTIMODAL_KEY : [image_data ] }, 170 {JSON_PROMPT_STRING_KEY :prompt , }, 171 ], 172 }) 173if success : 174assert res .status_code == 200 175content = res .body 176# Ensure embeddings are stable when multimodal. 177assert content [0 ]['embedding' ]== content [1 ]['embedding' ] 178# Ensure embeddings without multimodal but same prompt do not match multimodal embeddings. 179assert content [0 ]['embedding' ]!= content [2 ]['embedding' ] 180else : 181assert res .status_code != 200