{"openapi":"3.1.0","info":{"title":"CPV Picker API","description":"Semantic search over the English Common Procurement Vocabulary.\n\nSubmit a plain-language procurement requirement to `/api/search` and receive the\nclosest CPV entries ranked by cosine similarity. Upload one query per line to\n`/api/search-file` to stream a CSV containing each query's best match.\n\n## Capacity notice\n\nThis is a public, best-effort API. Searches are serialized through **one inference\nworker** using a single NVIDIA A2 GPU in a **14-year-old Dell PowerEdge R820**.\nConcurrent requests wait in a bounded queue, so please avoid bursts and use sensible\nclient timeouts. Bulk files release the inference lane every eight lines so\ninteractive requests can run between chunks. The hardware is sturdy, but it is not\nhyperscale.\n","version":"0.2.2"},"servers":[{"url":"https://cpv.goblinreactor.com","description":"Public service"}],"paths":{"/api/healthz":{"get":{"tags":["Operations"],"summary":"Check service readiness","operationId":"health_api_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/search":{"post":{"tags":["CPV search"],"summary":"Rank CPV entries for a procurement requirement","description":"Encodes the query with Qwen3-Embedding-0.6B and returns the nearest normalized CPV vectors. Searches use one serialized GPU inference worker.","operationId":"search_api_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/search-file":{"post":{"tags":["CPV search"],"summary":"Match one best CPV entry per text-file line","description":"Upload a UTF-8 text file with one query per line. Blank lines are ignored. The response is a streamed CSV with `query`, `score`, `name`, and `description` columns. GPU work runs in chunks of eight and releases the single inference lane between chunks so interactive searches can proceed. Files are limited to 1 MiB and 1,000 nonblank queries.","operationId":"search_file_api_search_file_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_search_file_api_search_file_post"}}},"required":true},"responses":{"200":{"description":"Best CPV match for each nonblank input line.","content":{"application/json":{"schema":{}},"text/csv":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Body_search_file_api_search_file_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"UTF-8 text file containing one procurement query per line."}},"type":"object","required":["file"],"title":"Body_search_file_api_search_file_post"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status"},"model":{"type":"string","title":"Model"},"backend":{"type":"string","title":"Backend"},"records":{"type":"integer","title":"Records"},"dimensions":{"type":"integer","title":"Dimensions"},"inference_concurrency":{"type":"integer","title":"Inference Concurrency"}},"type":"object","required":["status","model","backend","records","dimensions","inference_concurrency"],"title":"HealthResponse"},"SearchMatch":{"properties":{"index":{"type":"integer","title":"Index"},"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"similarity":{"type":"number","title":"Similarity"},"cosine_distance":{"type":"number","title":"Cosine Distance"}},"type":"object","required":["index","code","name","description","similarity","cosine_distance"],"title":"SearchMatch"},"SearchRequest":{"properties":{"query":{"type":"string","maxLength":4096,"minLength":1,"title":"Query","description":"Description of the procurement requirement. The catalog and results are English, but the embedding model accepts multilingual queries.","examples":["supply and maintain school buses","校车"]},"n":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"N","description":"Number of ranked CPV matches to return.","default":20}},"type":"object","required":["query"],"title":"SearchRequest"},"SearchResponse":{"properties":{"query":{"type":"string","title":"Query"},"model":{"type":"string","title":"Model"},"backend":{"type":"string","title":"Backend"},"matches":{"items":{"$ref":"#/components/schemas/SearchMatch"},"type":"array","title":"Matches"}},"type":"object","required":["query","model","backend","matches"],"title":"SearchResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}