Skip to content
Snippets Groups Projects
Commit fa3b4013 authored by Tor-Einar Skog's avatar Tor-Einar Skog
Browse files

Merge branch 'model_factory' into 'main'

Model factory

See merge request !2
parents 0aab9bfd bbe9ca23
No related branches found
No related tags found
1 merge request!2Model factory
# Keeping this deployment specific
models.txt
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
......
This diff is collapsed.
......@@ -32,6 +32,8 @@ Install dependencies from requirements.txt
This was done at start of project, and must be repeated after all dependency changes:
TODO: Decide on whether to use pip freeze or manage requirements.txt manually. Ref e.g. [this blogpost](https://medium.com/@tomagee/pip-freeze-requirements-txt-considered-harmful-f0bce66cf895)
```sh
(venv)$ pip install "fastapi[all]" (and others)
(venv)$ pip freeze > requirements.txt
......@@ -44,6 +46,13 @@ $ . venv/bin/activate
(venv)$ deactivate
```
### Install VIPS models
The VIPS models available will vary between deployments of VIPSCore-Python. They are installed using pip, and specified in `models.txt` - which can be considered a deployment specific addendum to `requirements.txt`. Copy `models_example.txt` to `models.txt` to get started.
```sh
pip install -r models.txt
```
## Development
### Run application locally
......
import importlib
import pkgutil
from vipscore_common.vips_model import VIPSModel
_models = None
_packages = None
def discover_models():
"""
Searches the current Python path for packages that contains "vips" in the package or module name
"""
models = {}
global _packages
_packages = []
for package in pkgutil.walk_packages():
# Package or module has to contain "vips",
# otherwise it will not be indexed
if "vips" in package.name:
_packages.append(package)
print(package.name)
try:
importlib.import_module(package.name)
except:
pass
for vipsmodel_subclass in VIPSModel.__subclasses__():
# We must have an instance to reach the property
vipsmodel_instance = vipsmodel_subclass()
if models.get(vipsmodel_instance.model_id) is None:
models[vipsmodel_instance.model_id] = vipsmodel_subclass
else:
possible_duplicate = models.get(vipsmodel_instance.model_id)
raise ValueError("ERROR when trying to index VIPS model %s: VIPS model %s has the same ID (%s). Please check your model installations" % (vipsmodel_subclass, possible_duplicate, vipsmodel_instance.model_id))
return models
def get_model_instance(model_id):
return get_vips_models().get(model_id)()
def get_vips_model_packages():
global _packages
if _packages is None:
discover_models()
return _packages
def get_vips_models():
global _models
if _models is None:
#print("Indexing models")
_models = discover_models()
return _models
# USAGE EXAMPLE. REMOVE when U start using the module from elsewhere
#model = get_model_instance("REFERENCEM")
#print(model.get_model_name())
#print(get_vips_model_packages())
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse
from app.internal.model_factory import *
from vipscore_common.vips_model import VIPSModel
from vipscore_common.entities import ModelConfiguration, Result
description = """
Python implementation of VIPSCore, to enable models written in Python.
"""
app = FastAPI(
title = "VIPSCore-Python",
description=description,
contact= {
"name": "Berit Nordskog",
"email": "post@vips.no",
"url": "https://nibio.no/en/employees/berit-nordskog",
},
license_info={
"name": "GNU Affero General Public License v3",
"url": "https://www.gnu.org/licenses/agpl-3.0.en.html"
}
)
# TODO Create a nice welcome page
@app.get("/")
async def root():
return {"message": "Hello World"}
####### Model listing endpoints #######
@app.get("/models/json", name="List all models (Json, default language)")
async def print_model_list_json_default_language():
return _print_model_list_json(VIPSModel.default_language)
@app.get("/models/json/{language}", name="List all models (Json)")
async def print_model_list_json(language:str):
return _print_model_list_json(language)
@app.get("/models", response_class=PlainTextResponse, name="List all models (plain text, default language)")
async def print_model_list_default_language() -> str:
return _print_model_list(VIPSModel.default_language)
@app.get("/models/{language}", response_class=PlainTextResponse, name="List all models (plain text)")
async def print_model_list(language: str) -> str:
return _print_model_list(language)
####### Model running endpoints #######
@app.post("/models/run/", name="Run a model")
async def run_model_from_config_only(model_configuration:ModelConfiguration):
return _run_model(model_configuration.model_id, model_configuration)
@app.post("/models/{model_id}/run/", name="Run a model")
async def run_model_from_config_only(model_id, model_configuration:ModelConfiguration):
return _run_model(model_id, model_configuration)
####### Helper functions #######
# Dealing with no method overload in Python :-)
def _run_model(model_id:str, model_configuration:ModelConfiguration):
"""
Run a model, using provided model_id and ModelConfiguration
Return a list of Result objects
"""
requested_model = get_model_instance(model_id)
requested_model.set_configuration(model_configuration)
return requested_model.get_result()
def _print_model_list(language:str):
"""
Returns the list of available models in plain text format
"""
model_list = ""
vips_models = get_vips_models()
for model_id in vips_models:
model_list = "%s%s %s\n" %(model_list, model_id, get_model_instance(model_id).get_model_name(language))
return model_list
def _print_model_list_json(language:str):
"""
Returns the list of available models in Json format
"""
model_list = []
vips_models = get_vips_models()
for model_id in vips_models:
model_list.append({
"modelId" : model_id,
"modelName" : get_model_instance(model_id).get_model_name()
})
return model_list
\ No newline at end of file
# All the models that should be available through this instance of VIPSCore-Python must be
# installed through running pip install -r models.txt
# The file models.txt is ignored by git, so it will be instance specific.
# To start, copy the models_example.txt file to models.txt and add models from
# the preferred sources
# pyPIP example
# model_name
# Gitlab/github example
# git+https://gitlab.nibio.no/VIPS/models/python/referencemodel.git@0.1.5
# Local disk example
# /home/treinar/prosjekter/vips/Sourcecode/models/Python/ReferenceModel
\ No newline at end of file
This diff is collapsed.
anyio==3.6.2
certifi==2022.12.7
click==8.1.3
dnspython==2.3.0
email-validator==1.3.0
fastapi==0.89.1
h11==0.14.0
httpcore==0.16.3
httptools==0.5.0
httpx==0.23.3
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
orjson==3.8.5
pydantic==1.10.4
python-dotenv==0.21.0
python-multipart==0.0.5
PyYAML==6.0
rfc3986==1.5.0
six==1.16.0
sniffio==1.3.0
starlette==0.22.0
typing_extensions==4.4.0
ujson==5.7.0
uvicorn==0.20.0
uvloop==0.17.0
watchfiles==0.18.1
websockets==10.4
git+https://gitlab.nibio.no/VIPS/vipscore-python-common.git@0.1.9
\ No newline at end of file
import sys
import subprocess
import src.model_factory
# Intention: Make sure that pip freeze doesn't include VIPS models
# Only necessary if we decide to stick with using pip freeze
\ No newline at end of file
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment