Quick conversion and validation of HuggingFace models to OpenVINO format with smart caching.
Conversion runs optimum-cli export openvino in a child process (subprocess.run() for convert_to_openvino() and subprocess.Popen() for get_conversion_progress()). Both paths use the same 1-hour timeout (CONVERSION_TIMEOUT_SECONDS = 3600).
The converter writes to a sibling temporary directory named .<output-name>.partial first. On success, it validates that the temporary directory contains non-empty openvino_model.xml and openvino_model.bin, then publishes the result by renaming the temporary directory to the requested output directory. On failure, timeout, missing files, or process errors, the partial directory is removed. This avoids leaving a partially-written model directory at the final output path.
Return values do not include a SHA-256 digest. Earlier documentation claimed a digest existed, but the current API returns only status/path/model/source fields and error messages.
Check if a directory contains a valid OpenVINO model.
Validates that a directory contains both required OpenVINO files as regular, non-empty files.
path(Path | str): Directory path to validate- Can be
pathlib.Pathor string path - Non-existent paths return
False - File paths return
False(directory check fails)
- Can be
bool:Trueif bothopenvino_model.xmlandopenvino_model.binexist and are non-empty,Falseotherwise
from npu_proxy.models.converter import is_openvino_model
# Check a model directory
if is_openvino_model(r"C:\models\gpt2"):
print("Ready for inference!")
# String paths work too
is_openvino_model(r"C:\models\gpt2") # True or False
# Non-existent paths
is_openvino_model(r"C:\does\not\exist") # Falseconvert_to_openvino(hf_repo: str, output_dir: Path, task: str = "text-generation-with-past", progress_callback: Callable[[str], None] | None = None) -> dict
Convert a HuggingFace model to OpenVINO format.
Uses optimum-cli export openvino to convert models. Validates the temporary output directory and returns status.
hf_repo(str): HuggingFace model repository ID- Examples:
"gpt2","meta-llama/Llama-2-7b","sentence-transformers/all-MiniLM-L6-v2"
- Examples:
output_dir(Path | str): Final directory where the converted model will be published- Parent directory is created if it doesn't exist
- Conversion first writes to
.<output-name>.partialnext to this directory - Must be writable
task(str, optional): Task type for conversion (default:"text-generation-with-past")- Valid values:
"text-generation-with-past","text-generation","feature-extraction" "text-generation-with-past"is the current default for LLM models"feature-extraction"is used for embedding models
- Valid values:
progress_callback(Callable, optional): Function called with progress messages- Called with string messages during conversion
- Useful for logging or UI updates
- Success (dict):
{ "status": "success", "path": "C:\\path\\to\\converted\\model", "model": "gpt2" } - Error (dict):
{ "error": "Error message describing what went wrong" }
No success response includes a digest field.
"optimum-cli not found..."- Install withpip install optimum-intel"Invalid task type..."- Use only"text-generation-with-past","text-generation", or"feature-extraction""Conversion failed: ..."- Model not found, network error, process error, etc."Conversion timed out..."- Took longer than 1 hour"output files not found"- Conversion succeeded but required files were missing
from pathlib import Path
from npu_proxy.models.converter import convert_to_openvino
# Basic conversion using the default task: text-generation-with-past
result = convert_to_openvino("gpt2", Path(r"C:\models\gpt2"))
if "error" not in result:
print(f"Converted to: {result['path']}")
# With progress callback
def log_progress(msg):
print(f"[Conversion] {msg}")
result = convert_to_openvino(
"meta-llama/Llama-2-7b",
Path(r"C:\models\llama2"),
progress_callback=log_progress,
)
# Feature extraction task
result = convert_to_openvino(
"sentence-transformers/all-MiniLM-L6-v2",
Path(r"C:\models\embedding"),
task="feature-extraction",
)
# Using string path
result = convert_to_openvino("gpt2", r"C:\models\gpt2")If you want the exported embedding model to be auto-detected by the running service, write it into that model's runtime cache path (for example ~/.cache/npu-proxy/models/embeddings/all-minilm-l6-v2 for sentence-transformers/all-MiniLM-L6-v2).
auto_download_and_convert(model_name: str, task: str = "text-generation-with-past", cache_dir: Path | None = None) -> dict
Download and convert a model if needed, with smart caching.
Checks cache first, skips conversion if already cached, converts if needed.
model_name(str): Model name or HuggingFace repo ID- Ollama-style names:
"tinyllama","llama2" - HuggingFace repos:
"gpt2","meta-llama/Llama-2-7b" - Names are resolved via
npu_proxy.models.mapper.resolve_model_repo()
- Ollama-style names:
task(str, optional): Task type (default:"text-generation-with-past")- Valid values:
"text-generation-with-past","text-generation","feature-extraction"
- Valid values:
cache_dir(Path | str, optional): Directory for cached models- Defaults to
~/.cache/npu-proxy/models/ - Allows custom caching location
- Defaults to
- Success (dict):
{ "status": "success", "path": "C:\\path\\to\\model", "model": "tinyllama-1.1b-chat-int4-ov", "source": "cache" # or "converted" } - Error (dict):
{ "error": "Error message" }
- Caching: If model is already in cache, returns immediately without conversion
- Source tracking: Returns
"source"to indicate if from cache or newly converted - Automatic resolution: Converts registered Ollama names to HuggingFace repos and runtime storage keys
- Safe publish: New conversions use the same partial-directory-and-rename flow as
convert_to_openvino()
from npu_proxy.models.converter import auto_download_and_convert
# Auto-convert with default cache
result = auto_download_and_convert("tinyllama")
if "error" not in result:
print(f"Model path: {result['path']}")
print(f"From: {result['source']}") # "cache" or "converted"
# Custom cache directory
result = auto_download_and_convert(
"tinyllama",
cache_dir=r"C:\custom\cache",
)
# Feature extraction model
result = auto_download_and_convert(
"sentence-transformers/all-MiniLM-L6-v2",
task="feature-extraction",
)
# Caching demo
result1 = auto_download_and_convert("gpt2") # Converts if not cached
result2 = auto_download_and_convert("gpt2") # Uses cache when validget_conversion_progress(hf_repo: str, output_dir: Path, task: str = "text-generation-with-past") -> Generator[dict, None, None]
Yield progress updates during model conversion for streaming.
Generator that yields progress updates as the conversion child process runs.
hf_repo(str): HuggingFace model repository IDoutput_dir(Path | str): Final directory where the converted model will be publishedtask(str, optional): Task type (default:"text-generation-with-past")- Valid values:
"text-generation-with-past","text-generation","feature-extraction"
- Valid values:
Progress dictionaries with these fields:
"status"(str): Current status"starting"- Conversion initialization"running"- Subprocess started"converting"- Captured conversion output"success"- Conversion completed and was renamed into place"error"- An error occurred
"message"(str): Status message or output line"path"(str, optional): Path to converted model (only on success)
from pathlib import Path
from npu_proxy.models.converter import get_conversion_progress
# Stream conversion progress
for progress in get_conversion_progress("gpt2", Path(r"C:\models\gpt2")):
print(f"{progress['status']}: {progress['message']}")
if progress["status"] == "success":
print(f"Converted to: {progress['path']}")
# For UI updates
for progress in get_conversion_progress("llama2", r"C:\models\llama2"):
if progress["status"] == "error":
display_error(progress["message"])
else:
update_progress_bar(progress["message"])
# Feature extraction conversion with progress
for p in get_conversion_progress(
"sentence-transformers/all-MiniLM-L6-v2",
r"C:\models\embedding",
task="feature-extraction",
):
if p["status"] == "converting":
logger.info(p["message"])Path.home() / ".cache" / "npu-proxy" / "models"Default cache directory for converted models. Typically: ~/.cache/npu-proxy/models/
["openvino_model.xml", "openvino_model.bin"]Files required for a valid OpenVINO model.
("text-generation-with-past", "text-generation", "feature-extraction")Task values accepted by conversion functions.
3600One-hour timeout used for conversion child processes.
result = convert_to_openvino("gpt2", r"C:\models\gpt2")
# Returns: {"error": "optimum-cli not found. Install it with: pip install optimum-intel"}Solution: pip install optimum-intel
result = convert_to_openvino("gpt2", r"C:\models\gpt2", task="invalid-task")
# Returns: {"error": "Invalid task type. Must be one of ['text-generation-with-past', 'text-generation', 'feature-extraction']"}Solution: Use only "text-generation-with-past", "text-generation", or "feature-extraction"
result = convert_to_openvino("nonexistent-model-xyz", r"C:\models\xyz")
# Returns: {"error": "Conversion failed: ..."}Solution: Verify the model name/repo exists on HuggingFace
result = convert_to_openvino("large-model", r"C:\models\large")
# If conversion takes >1 hour: {"error": "Conversion timed out after 1 hour"}Solution: Models requiring >1 hour may need custom infrastructure
result = auto_download_and_convert("unknown-xyz")
# Returns: {"error": "Model 'unknown-xyz' not found"}Solution: Use HuggingFace repo ID or a registered Ollama-style name
is_openvino_model(r"C:\models\gpt2") # True{
"status": "success",
"path": "C:\\Users\\you\\.cache\\npu-proxy\\models\\gpt2",
"model": "gpt2"
}{
"status": "success",
"path": "C:\\Users\\you\\.cache\\npu-proxy\\models\\tinyllama-1.1b-chat-int4-ov",
"model": "tinyllama-1.1b-chat-int4-ov",
"source": "cache"
}{
"status": "success",
"path": "C:\\Users\\you\\.cache\\npu-proxy\\models\\tinyllama-1.1b-chat-int4-ov",
"model": "tinyllama-1.1b-chat-int4-ov",
"source": "converted"
}{"status": "starting", "message": "Starting conversion of gpt2"}
{"status": "running", "message": "Running: optimum-cli export openvino ..."}
{"status": "converting", "message": "Exporting GPT2 model to OpenVINO format..."}
{"status": "success", "message": "Conversion complete: C:\\models\\gpt2", "path": "C:\\models\\gpt2"}from npu_proxy.models.mapper import resolve_model_repo
from npu_proxy.models.converter import auto_download_and_convert
# auto_download_and_convert uses resolve_model_repo internally
result = auto_download_and_convert("tinyllama")
# Internally resolves "tinyllama" to the registered HuggingFace repo and runtime storage key# Consistent error handling with rest of codebase
result = auto_download_and_convert("gpt2")
if "error" in result:
logger.error(result["error"])
return None
else:
return result["path"]- Caching: Second call to same model returns instantly when a valid cache exists
- Timeout: 1-hour limit prevents unbounded conversions
- Streaming:
get_conversion_progress()yields captured output after the child process completes or times out - Validation: Models are validated before the temporary directory is renamed into place
- No digest: Current converter return values do not include SHA-256 or other content digests
- Required: Python 3.9+
- For actual conversion:
optimum-intelpackage providingoptimum-cli - Internal:
npu_proxy.models.mapper.resolve_model_repo()
npu_proxy.models.downloader- For downloading pre-converted modelsnpu_proxy.models.mapper- For model name resolution- HuggingFace documentation: https://huggingface.co/docs
- Optimum documentation: https://huggingface.co/docs/optimum