char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
f17b3be63
char/aliceai-t5-moe
1import base64 2import struct 3import pytest 4from openai import OpenAI 5from utils import * 6 7server = ServerPreset .bert_bge_small () 8 9EPSILON = 1e-3 10 11@ pytest . fixture ( autouse = True ) 12def create_server (): 13global server 14server = ServerPreset .bert_bge_small () 15 16 17def test_embedding_single (): 18global server 19server .pooling = 'last' 20server .start () 21res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 22"input" :"I believe the meaning of life is" , 23 }) 24assert res .status_code == 200 25assert len (res .body ['data' ])== 1 26assert 'embedding' in res .body ['data' ][0 ] 27assert len (res .body ['data' ][0 ]['embedding' ])> 1 28 29# make sure embedding vector is normalized 30assert abs (sum ([x ** 2 for x in res .body ['data' ][0 ]['embedding' ]])- 1 )< EPSILON 31 32 33def test_embedding_multiple (): 34global server 35server .pooling = 'last' 36server .start () 37res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 38"input" : [ 39"I believe the meaning of life is" , 40"Write a joke about AI from a very long prompt which will not be truncated" , 41"This is a test" , 42"This is another test" , 43 ], 44 }) 45assert res .status_code == 200 46assert len (res .body ['data' ])== 4 47for d in res .body ['data' ]: 48assert 'embedding' in d 49assert len (d ['embedding' ])> 1 50 51 52def test_embedding_multiple_with_fa (): 53server = ServerPreset .bert_bge_small_with_fa () 54server .pooling = 'last' 55server .start () 56# one of these should trigger the FA branch (i.e. context size % 256 == 0) 57res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 58"input" : [ 59"a " * 253 , 60"b " * 254 , 61"c " * 255 , 62"d " * 256 , 63 ], 64 }) 65assert res .status_code == 200 66assert len (res .body ['data' ])== 4 67for d in res .body ['data' ]: 68assert 'embedding' in d 69assert len (d ['embedding' ])> 1 70 71 72@ pytest . mark . parametrize ( 73"input,is_multi_prompt" , 74[ 75# do not crash on empty input 76( "" , False ), 77# single prompt 78( "string" , False ), 79([ 12 , 34 , 56 ], False ), 80([ 12 , 34 , "string" , 56 , 78 ], False ), 81# multiple prompts 82([ "string1" , "string2" ], True ), 83([ "string1" , [ 12 , 34 , 56 ]], True ), 84([[ 12 , 34 , 56 ], [ 12 , 34 , 56 ]], True ), 85([[ 12 , 34 , 56 ], [ 12 , "string" , 34 , 56 ]], True ), 86] 87) 88def test_embedding_mixed_input (input ,is_multi_prompt :bool ): 89global server 90server .start () 91res = server .make_request ("POST" ,"/v1/embeddings" ,data = {"input" :input }) 92assert res .status_code == 200 93data = res .body ['data' ] 94if is_multi_prompt : 95assert len (data )== len (input ) 96for d in data : 97assert 'embedding' in d 98assert len (d ['embedding' ])> 1 99else : 100assert 'embedding' in data [0 ] 101assert len (data [0 ]['embedding' ])> 1 102 103 104def test_embedding_pooling_mean (): 105global server 106server .pooling = 'mean' 107server .start () 108res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 109"input" :"I believe the meaning of life is" , 110 }) 111assert res .status_code == 200 112assert len (res .body ['data' ])== 1 113assert 'embedding' in res .body ['data' ][0 ] 114assert len (res .body ['data' ][0 ]['embedding' ])> 1 115 116# make sure embedding vector is normalized 117assert abs (sum ([x ** 2 for x in res .body ['data' ][0 ]['embedding' ]])- 1 )< EPSILON 118 119 120def test_embedding_pooling_mean_multiple (): 121global server 122server .pooling = 'mean' 123server .start () 124res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 125"input" : [ 126"I believe the meaning of life is" , 127"Write a joke about AI" , 128"This is a test" , 129 ], 130 }) 131assert res .status_code == 200 132assert len (res .body ['data' ])== 3 133for d in res .body ['data' ]: 134assert 'embedding' in d 135assert len (d ['embedding' ])> 1 136 137 138def test_embedding_pooling_none (): 139global server 140server .pooling = 'none' 141server .start () 142res = server .make_request ("POST" ,"/embeddings" ,data = { 143"input" :"hello hello hello" , 144 }) 145assert res .status_code == 200 146assert 'embedding' in res .body [0 ] 147assert len (res .body [0 ]['embedding' ])== 5 # 3 text tokens + 2 special 148 149# make sure embedding vector is not normalized 150for x in res .body [0 ]['embedding' ]: 151assert abs (sum ([x ** 2 for x in x ])- 1 )> EPSILON 152 153 154def test_embedding_pooling_none_oai (): 155global server 156server .pooling = 'none' 157server .start () 158res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 159"input" :"hello hello hello" , 160 }) 161 162# /v1/embeddings does not support pooling type 'none' 163assert res .status_code == 400 164assert "error" in res .body 165 166 167def test_embedding_openai_library_single (): 168global server 169server .pooling = 'last' 170server .start () 171client = OpenAI (api_key = "dummy" ,base_url = f"http:// { server . server_host } : { server . server_port } /v1" ) 172res = client .embeddings .create (model = "text-embedding-3-small" ,input = "I believe the meaning of life is" ) 173assert len (res .data )== 1 174assert len (res .data [0 ].embedding )> 1 175 176 177def test_embedding_openai_library_multiple (): 178global server 179server .pooling = 'last' 180server .start () 181client = OpenAI (api_key = "dummy" ,base_url = f"http:// { server . server_host } : { server . server_port } /v1" ) 182res = client .embeddings .create (model = "text-embedding-3-small" ,input = [ 183"I believe the meaning of life is" , 184"Write a joke about AI from a very long prompt which will not be truncated" , 185"This is a test" , 186"This is another test" , 187 ]) 188assert len (res .data )== 4 189for d in res .data : 190assert len (d .embedding )> 1 191 192 193def test_embedding_error_prompt_too_long (): 194global server 195server .pooling = 'last' 196server .start () 197res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 198"input" :"This is a test " * 512 , 199 }) 200assert res .status_code != 200 201assert "too large" in res .body ["error" ]["message" ] 202 203 204def test_same_prompt_give_same_result (): 205server .pooling = 'last' 206server .start () 207res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 208"input" : [ 209"I believe the meaning of life is" , 210"I believe the meaning of life is" , 211"I believe the meaning of life is" , 212"I believe the meaning of life is" , 213"I believe the meaning of life is" , 214 ], 215 }) 216assert res .status_code == 200 217assert len (res .body ['data' ])== 5 218for i in range (1 ,len (res .body ['data' ])): 219v0 = res .body ['data' ][0 ]['embedding' ] 220vi = res .body ['data' ][i ]['embedding' ] 221for x ,y in zip (v0 ,vi ): 222assert abs (x - y )< EPSILON 223 224 225@ pytest . mark . parametrize ( 226"content,n_tokens" , 227[ 228( "I believe the meaning of life is" , 9 ), 229( "This is a test" , 6 ), 230] 231) 232def test_embedding_usage_single (content ,n_tokens ): 233global server 234server .start () 235res = server .make_request ("POST" ,"/v1/embeddings" ,data = {"input" :content }) 236assert res .status_code == 200 237assert res .body ['usage' ]['prompt_tokens' ]== res .body ['usage' ]['total_tokens' ] 238assert res .body ['usage' ]['prompt_tokens' ]== n_tokens 239 240 241def test_embedding_usage_multiple (): 242global server 243server .start () 244res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 245"input" : [ 246"I believe the meaning of life is" , 247"I believe the meaning of life is" , 248 ], 249 }) 250assert res .status_code == 200 251assert res .body ['usage' ]['prompt_tokens' ]== res .body ['usage' ]['total_tokens' ] 252assert res .body ['usage' ]['prompt_tokens' ]== 2 * 9 253 254 255def test_embedding_openai_library_base64 (): 256server .start () 257test_input = "Test base64 embedding output" 258 259# get embedding in default format 260res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 261"input" :test_input 262 }) 263assert res .status_code == 200 264vec0 = res .body ["data" ][0 ]["embedding" ] 265 266# get embedding in base64 format 267res = server .make_request ("POST" ,"/v1/embeddings" ,data = { 268"input" :test_input , 269"encoding_format" :"base64" 270 }) 271 272assert res .status_code == 200 273assert "data" in res .body 274assert len (res .body ["data" ])== 1 275 276embedding_data = res .body ["data" ][0 ] 277assert "embedding" in embedding_data 278assert isinstance (embedding_data ["embedding" ],str ) 279 280# Verify embedding is valid base64 281decoded = base64 .b64decode (embedding_data ["embedding" ]) 282# Verify decoded data can be converted back to float array 283float_count = len (decoded )// 4 # 4 bytes per float 284floats = struct .unpack (f' { float_count } f' ,decoded ) 285assert len (floats )> 0 286assert all (isinstance (x ,float )for x in floats ) 287assert len (floats )== len (vec0 ) 288 289# make sure the decoded data is the same as the original 290for x ,y in zip (floats ,vec0 ): 291assert abs (x - y )< EPSILON