Custom file provider
IModelFileProvider abstracts file resolution — the step that turns a ModelSourceParameters into a local file path. The default SDK ships two providers: LocalFilesystemProvider (for ModelFilePath) and HuggingFaceProvider (for HuggingFaceRepoId + HuggingFaceFileName).
Implement a custom provider when you need to source models from a location the defaults do not cover — private S3 buckets, artifact repositories (Artifactory, Nexus), encrypted storage, or signed internal model catalogs.
This is a narrower surface than IModelLoader and usually what you actually need.
Interface reference
namespace Aspose.LLM.Abstractions.Interfaces;
public interface IModelFileProvider
{
Task<string> GetModelFileAsync(
ModelSourceParameters modelParameters,
IProgress<double>? progress = null,
CancellationToken cancellationToken = default);
}
The method:
- Takes
ModelSourceParameters— resolve whichever fields are set, by priority. - Reports progress via
IProgress<double>(0.0 to 1.0) for downloads. - Returns the path to a local file that downstream loaders can read.
- Throws
ArgumentNullExceptionon nullmodelParameters. - Throws
InvalidOperationExceptionwhen the file cannot be retrieved. - Throws
OperationCanceledExceptionwhen the operation is canceled.
Example — S3 provider
using Amazon.S3;
using Amazon.S3.Model;
using Aspose.LLM.Abstractions.Interfaces;
using Aspose.LLM.Abstractions.Parameters;
public class S3ModelFileProvider : IModelFileProvider
{
private readonly IAmazonS3 _s3;
private readonly string _bucketName;
private readonly string _localCacheFolder;
public S3ModelFileProvider(IAmazonS3 s3, string bucketName, string cacheFolder)
{
_s3 = s3;
_bucketName = bucketName;
_localCacheFolder = cacheFolder;
Directory.CreateDirectory(_localCacheFolder);
}
public async Task<string> GetModelFileAsync(
ModelSourceParameters modelParameters,
IProgress<double>? progress = null,
CancellationToken cancellationToken = default)
{
if (modelParameters is null)
throw new ArgumentNullException(nameof(modelParameters));
// Map the AsposeModelId field to an S3 key.
string s3Key = modelParameters.AsposeModelId
?? throw new InvalidOperationException("AsposeModelId is required for S3 resolution.");
string localPath = Path.Combine(_localCacheFolder, Path.GetFileName(s3Key));
// Cache hit.
if (File.Exists(localPath))
{
progress?.Report(1.0);
return localPath;
}
// Download.
var response = await _s3.GetObjectAsync(
new GetObjectRequest { BucketName = _bucketName, Key = s3Key },
cancellationToken);
using var outStream = File.Create(localPath);
long total = response.ContentLength;
long read = 0;
byte[] buffer = new byte[81920];
int n;
while ((n = await response.ResponseStream.ReadAsync(buffer, cancellationToken)) > 0)
{
await outStream.WriteAsync(buffer.AsMemory(0, n), cancellationToken);
read += n;
progress?.Report((double)read / total);
}
return localPath;
}
}
Usage in a preset: set AsposeModelId to the S3 key, leave HuggingFaceRepoId unset.
Example — air-gapped internal registry
For air-gapped deployments where models are prepopulated in a shared directory:
public class InternalRegistryProvider : IModelFileProvider
{
private readonly string _registryRoot;
public InternalRegistryProvider(string registryRoot) => _registryRoot = registryRoot;
public Task<string> GetModelFileAsync(
ModelSourceParameters modelParameters,
IProgress<double>? progress = null,
CancellationToken cancellationToken = default)
{
string relative = modelParameters.AsposeModelId
?? throw new InvalidOperationException("AsposeModelId required.");
string path = Path.Combine(_registryRoot, relative);
if (!File.Exists(path))
throw new InvalidOperationException($"Model not found: {path}");
progress?.Report(1.0);
return Task.FromResult(path);
}
}
Priority handling
ModelSourceParameters has three priority-ordered fields: ModelFilePath, AsposeModelId, HuggingFaceRepoId + HuggingFaceFileName. Your provider decides which field(s) to respect. Common patterns:
- Single-source provider: respect one field only (e.g.,
AsposeModelIdfor an internal registry). Let callers set that field explicitly. - Multi-source provider: honor the full priority chain — check
ModelFilePathfirst, then your custom source, then fall back to Hugging Face.
Registration
using Microsoft.Extensions.DependencyInjection;
using Aspose.LLM.Abstractions.Interfaces;
using Aspose.LLM.Core.DependencyInjection;
services.AddLlamaServices(new Qwen25Preset());
services.AddSingleton<IModelFileProvider>(new InternalRegistryProvider(@"/opt/models"));
The default ModelManager is registered by AddLlamaServices. Adding your own IModelFileProvider registration overrides it only if the downstream consumer (ModelManager) is wired to consume IModelFileProvider directly — in the current SDK, ModelManager uses concrete providers (LocalFilesystemProvider, HuggingFaceProvider). You may need a custom IModelLoader that uses your IModelFileProvider instead of ModelManager.
Confirm the current wiring before committing to a custom provider — contact Aspose support if the injection point does not behave as you expect.
What’s next
- Custom model loader — broader surface when you need full pipeline control.
- Model source parameters — what
ModelSourceParameterscarries. - Dependency injection — standard service wiring.