File size: 6,825 Bytes
ed962ac | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | # -------------------------------------------------------------------
# This source file is available under the terms of the
# Pimcore Open Core License (POCL)
# Full copyright and license information is available in
# LICENSE.md which is distributed with this source code.
#
# @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
# @license Pimcore Open Core License (POCL)
# -------------------------------------------------------------------
"""Request/response samples for the embedding endpoints, kept out of `main.py` so the routing
stays readable.
These are meant to be *runnable*: pick one in the `/docs` "Try it out" dropdown and send it as-is.
That is why the models named here are small, standard-architecture ones rather than the multi-GB
examples elsewhere in the docs, and why the image sample carries a real (tiny) PNG instead of a
`"base64_encoded_image_string"` placeholder. `tests/test_openapi_examples.py` validates every
sample against the request model, so a sample cannot drift out of sync with the schema.
"""
from typing import Any, Union
# A real 16x16 PNG, so the image samples below can be executed unmodified.
SAMPLE_PNG_BASE64 = (
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGUlEQVR4nGNUTX7NQApgIkn1qIZRDUNKAwCg0AGTz0Gc9wAAAABJRU5ErkJggg=="
)
# ~90 MB, no custom code, downloads in seconds — the right default for a first request.
_SMALL_TEXT_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
_SMALL_IMAGE_MODEL = "google/siglip-base-patch16-224"
TEXT_EMBEDDING_EXAMPLES: dict[str, Any] = {
"single": {
"summary": "One string (start here)",
"description": (
f"Smallest useful request. `{_SMALL_TEXT_MODEL}` is a few hundred MB and needs no "
"custom code, so it loads on first call without any configuration."
),
"value": {"model": _SMALL_TEXT_MODEL, "input": "a blue sports car"},
},
"batch": {
"summary": "Several strings in one call",
"description": (
"A list is embedded in a single forward pass, which is markedly faster than one request "
"per string. `data` comes back in input order, each entry carrying its `index`."
),
"value": {
"model": _SMALL_TEXT_MODEL,
"input": ["a blue sports car", "ein blaues Sportauto", "a recipe for onion soup"],
},
},
"instruction_prefixed": {
"summary": "Nomic, with its task prefix",
"description": (
"Models in the Nomic family expect an instruction prefix on every input — "
"`search_query: ` for the thing being searched with, `search_document: ` for the things "
"being searched over. The service does not add it for you; embed queries and documents "
"with matching prefixes or the two spaces will not line up. This model carries custom "
"code, so its namespace must appear in `TRUSTED_CODE_ORGS` (it does by default)."
),
"value": {
"model": "nomic-ai/nomic-embed-text-v1.5",
"input": ["search_query: a blue sports car"],
},
},
"openai_compatible": {
"summary": "With the OpenAI compatibility fields",
"description": (
"`encoding_format` selects the wire format and only `'float'` is supported here; `user` "
"is an identifier you invent for abuse attribution and is accepted but ignored. Both "
"exist so a client written against OpenAI's /v1/embeddings works unchanged. Sending "
"`encoding_format: 'base64'` or any `dimensions` value is refused with a 422 rather "
"than silently ignored."
),
"value": {
"model": _SMALL_TEXT_MODEL,
"input": "a blue sports car",
"encoding_format": "float",
"user": "pimcore-bpt-tenant-42",
},
},
}
IMAGE_EMBEDDING_EXAMPLES: dict[str, Any] = {
"single": {
"summary": "One base64 image (runnable as-is)",
"description": (
"The `input` value is the base64 of the image bytes. The sample below is a real 16x16 "
"PNG, so this request works unmodified — swap in your own base64 to try a real asset."
),
"value": {"model": _SMALL_IMAGE_MODEL, "input": SAMPLE_PNG_BASE64},
},
"batch": {
"summary": "Several images in one call",
"description": (
"Images are embedded in one forward pass. An image that cannot be decoded is skipped: "
"it is omitted from `data`, so its `index` is missing rather than shifting the rest."
),
"value": {"model": _SMALL_IMAGE_MODEL, "input": [SAMPLE_PNG_BASE64, SAMPLE_PNG_BASE64]},
},
"data_url": {
"summary": "A data: URL",
"description": (
"A `data:image/...;base64,` prefix is accepted and stripped, so values copied straight "
"out of a browser or an HTML `src` attribute work without editing."
),
"value": {"model": _SMALL_IMAGE_MODEL, "input": f"data:image/png;base64,{SAMPLE_PNG_BASE64}"},
},
}
# Shared by both endpoints — the response shape is identical.
# `Union[int, str]` rather than `int | str`: module-level annotations are evaluated at runtime, and
# PEP 604 unions need Python 3.10 — the Dockerfile and CI both run 3.9.
EMBEDDINGS_RESPONSES: dict[Union[int, str], dict[str, Any]] = {
200: {
"description": "Embeddings in input order. Every vector is L2-normalized (length 1).",
"content": {
"application/json": {
"example": {
"object": "list",
"data": [
{"object": "embedding", "index": 0, "embedding": [0.0163, -0.0412, 0.0967]},
{"object": "embedding", "index": 1, "embedding": [-0.0271, 0.0538, 0.0114]},
],
"model": _SMALL_TEXT_MODEL,
"usage": {"prompt_tokens": 0, "total_tokens": 0},
}
}
},
},
400: {
"description": "The `model` value is not a well-formed Hugging Face repo id.",
"content": {
"application/json": {
"example": {
"detail": (
"Invalid model id '../../etc/passwd'. Expected a Hugging Face repo id such "
"as 'namespace/model' or a canonical model name."
)
}
}
},
},
404: {
"description": "The model id is well-formed but could not be loaded (unknown, gated, or "
"unavailable offline).",
"content": {
"application/json": {"example": {"detail": "Model 'acme/does-not-exist' could not be loaded: ..."}}
},
},
}
|