| from typing import Any |
|
|
| from .models import OllamaModel |
|
|
|
|
| class OllamaManifestParser: |
| """Parses and aggregates Ollama model discovery results.""" |
|
|
| @staticmethod |
| def parse_tags_response(data: dict, instance_url: str) -> list[OllamaModel]: |
| """Parses the raw JSON response from /api/tags into a list of OllamaModel.""" |
| models = [] |
| if "models" in data: |
| for model_data in data["models"]: |
| model = OllamaModel( |
| name=model_data.get("name", "unknown"), |
| tag=model_data.get("name", "unknown"), |
| size=model_data.get("size", 0), |
| digest=model_data.get("digest", ""), |
| capabilities=[], |
| instance_url=instance_url, |
| ) |
|
|
| details = model_data.get("details", {}) |
| if details: |
| model.parameters = { |
| "family": details.get("family", ""), |
| "parameter_size": details.get("parameter_size", ""), |
| "quantization": details.get("quantization_level", ""), |
| } |
|
|
| models.append(model) |
| return models |
|
|
| @staticmethod |
| def aggregate_discovery_results(instance_urls: list[str], results: list[Any]) -> dict[str, Any]: |
| """Aggregates results from multiple instances into a single discovery dictionary.""" |
| all_models: list[OllamaModel] = [] |
| chat_models = [] |
| embedding_models = [] |
| host_status = {} |
| discovery_errors = [] |
|
|
| for url, result in zip(instance_urls, results, strict=False): |
| if isinstance(result, Exception): |
| error_msg = f"Failed to discover models from {url}: {str(result)}" |
| discovery_errors.append(error_msg) |
| host_status[url] = {"status": "error", "error": str(result)} |
| else: |
| models = result |
| all_models.extend(models) |
| host_status[url] = {"status": "online", "models_count": str(len(models)), "instance_url": url} |
|
|
| for model in models: |
| if "chat" in model.capabilities: |
| chat_models.append( |
| { |
| "name": model.name, |
| "instance_url": model.instance_url, |
| "size": model.size, |
| "parameters": model.parameters, |
| "context_window": model.context_window, |
| "max_context_length": model.max_context_length, |
| "base_context_length": model.base_context_length, |
| "custom_context_length": model.custom_context_length, |
| "architecture": model.architecture, |
| "format": model.format, |
| "parent_model": model.parent_model, |
| "capabilities": model.capabilities, |
| } |
| ) |
|
|
| if "embedding" in model.capabilities: |
| embedding_models.append( |
| { |
| "name": model.name, |
| "instance_url": model.instance_url, |
| "dimensions": model.embedding_dimensions, |
| "size": model.size, |
| "parameters": model.parameters, |
| "context_window": model.context_window, |
| "max_context_length": model.max_context_length, |
| "base_context_length": model.base_context_length, |
| "custom_context_length": model.custom_context_length, |
| "architecture": model.architecture, |
| "format": model.format, |
| "parent_model": model.parent_model, |
| "capabilities": model.capabilities, |
| } |
| ) |
|
|
| |
| unique_models = {} |
| for model in all_models: |
| key = f"{model.name}@{model.instance_url}" |
| unique_models[key] = model |
|
|
| return { |
| "total_models": len(unique_models), |
| "chat_models": chat_models, |
| "embedding_models": embedding_models, |
| "host_status": host_status, |
| "discovery_errors": discovery_errors, |
| "unique_model_names": list({model.name for model in unique_models.values()}), |
| } |
|
|