| 4254 | } |
| 4255 | |
| 4256 | std::unique_ptr<server_res_generator> server_routes::handle_embeddings_impl(const server_http_req & req, task_response_type res_type) { |
| 4257 | auto res = create_response(); |
| 4258 | if (!params.embedding) { |
| 4259 | res->error(format_error_response("This server does not support embeddings. Start it with `--embeddings`", ERROR_TYPE_NOT_SUPPORTED)); |
| 4260 | return res; |
| 4261 | } |
| 4262 | |
| 4263 | if (res_type != TASK_RESPONSE_TYPE_NONE && meta->pooling_type == LLAMA_POOLING_TYPE_NONE) { |
| 4264 | res->error(format_error_response("Pooling type 'none' is not OAI compatible. Please use a different pooling type", ERROR_TYPE_INVALID_REQUEST)); |
| 4265 | return res; |
| 4266 | } |
| 4267 | |
| 4268 | const json body = json::parse(req.body); |
| 4269 | |
| 4270 | // for the shape of input/content, see tokenize_input_prompts() |
| 4271 | json prompt; |
| 4272 | if (body.count("input") != 0) { |
| 4273 | prompt = body.at("input"); |
| 4274 | } else if (body.contains("content")) { |
| 4275 | res_type = TASK_RESPONSE_TYPE_NONE; // "content" field is not OAI compatible |
| 4276 | prompt = body.at("content"); |
| 4277 | } else { |
| 4278 | res->error(format_error_response("\"input\" or \"content\" must be provided", ERROR_TYPE_INVALID_REQUEST)); |
| 4279 | return res; |
| 4280 | } |
| 4281 | |
| 4282 | bool use_base64 = false; |
| 4283 | if (body.count("encoding_format") != 0) { |
| 4284 | const std::string & format = body.at("encoding_format"); |
| 4285 | if (format == "base64") { |
| 4286 | use_base64 = true; |
| 4287 | } else if (format != "float") { |
| 4288 | res->error(format_error_response("The format to return the embeddings in. Can be either float or base64", ERROR_TYPE_INVALID_REQUEST)); |
| 4289 | return res; |
| 4290 | } |
| 4291 | } |
| 4292 | |
| 4293 | auto tokenized_prompts = tokenize_input_prompts(ctx_server.vocab, ctx_server.mctx, prompt, true, true); |
| 4294 | for (const auto & tokens : tokenized_prompts) { |
| 4295 | // this check is necessary for models that do not add BOS token to the input |
| 4296 | if (tokens.empty()) { |
| 4297 | res->error(format_error_response("Input content cannot be empty", ERROR_TYPE_INVALID_REQUEST)); |
| 4298 | return res; |
| 4299 | } |
| 4300 | } |
| 4301 | |
| 4302 | int embd_normalize = 2; // default to Euclidean/L2 norm |
| 4303 | if (body.count("embd_normalize") != 0) { |
| 4304 | embd_normalize = body.at("embd_normalize"); |
| 4305 | if (meta->pooling_type == LLAMA_POOLING_TYPE_NONE) { |
| 4306 | SRV_DBG("embd_normalize is not supported by pooling type %d, ignoring it\n", meta->pooling_type); |
| 4307 | } |
| 4308 | } |
| 4309 | |
| 4310 | // create and queue the task |
| 4311 | json responses = json::array(); |
| 4312 | auto & rd = res->rd; |
| 4313 | { |
nothing calls this directly
no test coverage detected