Compare commits

...
5 Commits
Author SHA1 Message Date
Brian Bjarke Jensen eaca23f27a updated to use new class
CI Pipeline / Test (pull_request) Successful in 2m7s
CI Pipeline / Build and Publish (./Dockerfile.model, ${{ vars.docker_repo_url }}/${{ gitea.repository }}/model) (pull_request) Successful in 6m26s
CI Pipeline / Build and Publish (./Dockerfile.web_ui, ${{ vars.docker_repo_url }}/${{ gitea.repository }}/web_ui) (pull_request) Successful in 5m40s
2024-06-15 23:18:27 +02:00
Brian Bjarke Jensen 0bd4008e72 updated to use new class 2024-06-15 23:17:28 +02:00
Brian Bjarke Jensen 123cab2500 updated to use new functions 2024-06-15 23:16:42 +02:00
Brian Bjarke Jensen d09cb9dd20 added delete function 2024-06-15 23:15:31 +02:00
Brian Bjarke Jensen e1075b3551 ignore outdated class reference 2024-06-15 23:14:55 +02:00
9 changed files with 200 additions and 81 deletions
+1 -1
View File
@@ -98,7 +98,7 @@ if __name__ == '__main__':
try:
# save image to buffer
buffer = BytesIO()
vis_com.image.save(buffer, 'png')
vis_com.image.save(buffer, 'png') # type: ignore
# put buffer in minio
object_name = put(
client=minio_client,
+1
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
from .connect import connect
from .delete import delete
from .get import get
from .put import put
+29
View File
@@ -0,0 +1,29 @@
"""Definition of delete function."""
from __future__ import annotations
import logging
import os
from minio import Minio
def delete(
client: Minio,
object_name: str,
) -> None:
"""Delete object from MinIO."""
assert isinstance(client, Minio)
assert isinstance(object_name, str)
bucket_name = os.getenv('MINIO_BUCKET_NAME', default=None)
assert isinstance(bucket_name, str)
# remove object
try:
client.remove_object(
bucket_name=bucket_name,
object_name=object_name,
)
except Exception as exc:
logging.debug(exc)
logging.error('failed deleting %s', object_name)
else:
logging.debug('deleted %s', object_name)
@@ -10,6 +10,7 @@ from pathlib import Path
from minio import Minio
from PIL import Image
from pydantic import BaseModel
from pymongo.collection import Collection
from shared.data_store import get
from shared.data_store import put
@@ -34,23 +35,60 @@ class VisualCommunication(BaseModel):
return cls.__name__
@classmethod
def from_file(cls, path: Path, minio_client: Minio) -> VisualCommunication:
"""Instantiate from file."""
assert isinstance(path, Path)
def upload_image_to_minio(
cls,
image: Image.Image,
minio_client: Minio,
) -> str:
"""Upload image to MinIO and return MD5 checksum of hashed image."""
assert isinstance(image, Image.Image)
assert isinstance(minio_client, Minio)
# determine name
name = path.stem
# open and upload image to minio
image = Image.open(path)
image.load()
buffer = BytesIO()
image.save(buffer, 'png')
object_name = put(
client=minio_client,
buffer=buffer,
)
return object_name
@classmethod
def from_name_and_image(
cls,
name: str,
image: Image.Image,
minio_client: Minio,
) -> VisualCommunication:
"""
Instantiate from filename and image
that is automatically uploaded to MinIO.
"""
assert isinstance(name, str)
assert isinstance(image, Image.Image)
assert isinstance(minio_client, Minio)
# upload file to minio
object_name = VisualCommunication.upload_image_to_minio(
image=image,
minio_client=minio_client,
)
return VisualCommunication(name=name, object_name=object_name)
@classmethod
def from_file(cls, path: Path, minio_client: Minio) -> VisualCommunication:
"""Instantiate from file."""
assert isinstance(path, Path)
assert isinstance(minio_client, Minio)
# determine name
name = path.stem
# open image
image = Image.open(path)
image.load()
# instantiate object
return VisualCommunication.from_name_and_image(
name=name,
image=image,
minio_client=minio_client,
)
@classmethod
def decode_image(cls, content: str) -> Image.Image:
"""Extract image from webencoded content."""
@@ -69,6 +107,13 @@ class VisualCommunication(BaseModel):
im = Image.open(buffer)
return im
def save_to_mongo(self, collection: Collection) -> None:
"""Save self as document in MongoDB."""
res = collection.insert_one(
document=self.model_dump(),
)
assert res.acknowledged
def webencoded_image(self, minio_client: Minio) -> str:
"""Convert image to be displayed on webpage."""
assert isinstance(minio_client, Minio)
+19 -2
View File
@@ -2,10 +2,27 @@ from __future__ import annotations
from pathlib import Path
from shared.database.classes import VisualCommunication
from dotenv import load_dotenv
from shared.data_store import connect as connect_minio
from shared.database import connect as connect_mongo
from shared.database.classes import VisualCommunication
from shared.utils import check_env
from shared.utils import setup_logging
if __name__ == '__main__':
# load in env file
env_path = Path(__file__).parent.parent / 'server.env'
assert env_path.exists()
load_dotenv(env_path)
# ensure env vars set
check_env()
# setup logging
setup_logging()
# connect to minIO
minio_client = connect_minio()
# connect to MongoDB
collection, db, client = connect_mongo()
# get list of image paths
test_dir = Path(__file__).parent
img_dir = test_dir / 'imgs'
@@ -13,7 +30,7 @@ if __name__ == '__main__':
print(img_path_list)
# instantiate data object
vis_com_list = [
VisualCommunication.from_file(path)
VisualCommunication.from_file(path, minio_client=minio_client)
for path
in img_path_list
]
+17 -11
View File
@@ -1,15 +1,29 @@
from __future__ import annotations
import os
from pathlib import Path
from dotenv import load_dotenv
from pymongo.errors import DuplicateKeyError
from shared.database import connect
from shared.data_store import connect as connect_minio
from shared.database import connect as connect_mongo
from shared.database.classes import VisualCommunication
from shared.utils import check_env
from shared.utils import setup_logging
if __name__ == '__main__':
# load in env file
env_path = Path(__file__).parent.parent / 'server.env'
assert env_path.exists()
load_dotenv(env_path)
# ensure env vars set
check_env()
# setup logging
setup_logging()
# connect to minIO
minio_client = connect_minio()
# connect to MongoDB
collection, db, client = connect_mongo()
# get list of image paths
test_dir = Path(__file__).parent
img_dir = test_dir / 'imgs'
@@ -17,20 +31,12 @@ if __name__ == '__main__':
print(img_path_list)
# instantiate data object
vis_com_list = [
VisualCommunication.from_file(path)
VisualCommunication.from_file(path, minio_client=minio_client)
for path
in img_path_list
]
for vis_com in vis_com_list:
print(repr(vis_com))
# prepare env vars
env_path = test_dir.parent / 'local.env'
assert env_path.exists()
load_dotenv(env_path)
os.environ['MONGO_HOST'] = 'localhost'
# connect to database
collection, db, client = connect()
print(client.server_info())
# upload images
for vis_com in vis_com_list:
try:
+17 -10
View File
@@ -5,10 +5,25 @@ from pathlib import Path
from dotenv import load_dotenv
from pymongo.errors import DuplicateKeyError
from shared.database import connect
from shared.data_store import connect as connect_minio
from shared.database import connect as connect_mongo
from shared.database import VisualCommunication
from shared.utils import check_env
from shared.utils import setup_logging
if __name__ == '__main__':
# load in env file
env_path = Path(__file__).parent.parent / 'server.env'
assert env_path.exists()
load_dotenv(env_path)
# ensure env vars set
check_env()
# setup logging
setup_logging()
# connect to minIO
minio_client = connect_minio()
# connect to MongoDB
collection, db, client = connect_mongo()
# get list of image paths
ext_img_dir = Path('/Volumes/BW-PSSD/Mixed Methods/')
assert ext_img_dir.exists()
@@ -20,19 +35,11 @@ if __name__ == '__main__':
print(f"found {len(img_path_list)} images")
# create visual communication objects
vis_com_list = [
VisualCommunication.from_file(path)
VisualCommunication.from_file(path, minio_client=minio_client)
for path
in img_path_list
]
print(f"created {len(vis_com_list)} visual communication objects")
# prepare env vars
env_path = Path(__file__).parent.parent / 'server.env'
assert env_path.exists()
load_dotenv(env_path)
# connect to database
collection, db, client = connect()
assert client.server_info() is not None
print('connected to database')
# upload images
for vis_com in vis_com_list:
try:
+16 -20
View File
@@ -1,46 +1,42 @@
from __future__ import annotations
import logging
import os
from pathlib import Path
from dotenv import load_dotenv
from shared.database import connect
from shared.data_store import connect as connect_minio
from shared.database import connect as connect_mongo
from shared.database import upsert_prediction
from shared.database.classes import VisualCommunication
from shared.utils import check_env
from shared.utils import setup_logging
if __name__ == '__main__':
# load in env file
env_path = Path(__file__).parent.parent / 'server.env'
assert env_path.exists()
load_dotenv(env_path)
# ensure env vars set
check_env()
# setup logging
fmt = (
'%(asctime)s | '
'%(levelname)s | '
'%(filename)s | '
'%(funcName)s | '
'%(message)s'
)
datefmt = '%Y-%m-%d %H:%M:%S'
logging.basicConfig(format=fmt, datefmt=datefmt, level=logging.INFO)
setup_logging()
# connect to minIO
minio_client = connect_minio()
# connect to MongoDB
collection, db, client = connect_mongo()
# get list of image paths
test_dir = Path(__file__).parent
img_dir = test_dir / 'imgs'
img_path_list = [path for path in img_dir.glob('*.jpeg') if path.is_file()]
# instantiate data object
vis_com_list = [
VisualCommunication.from_file(path)
VisualCommunication.from_file(path, minio_client=minio_client)
for path
in img_path_list
]
# generate random predictions
for vis_com in vis_com_list:
vis_com.generate_random_prediction()
# prepare env vars
env_path = test_dir.parent / 'local.env'
assert env_path.exists()
load_dotenv(env_path)
os.environ['MONGO_HOST'] = 'localhost'
# connect to database
collection, db, client = connect()
# upload visual communication
for vis_com in vis_com_list:
if vis_com.prediction is None:
+36 -18
View File
@@ -16,11 +16,11 @@ from pydantic import ValidationError
from pymongo.collection import Collection
from .layout import app_layout
from shared.data_store import delete as delete_from_minio
from shared.database import count_documents
from shared.database import get_visual_communication
from shared.database import NoDocumentFoundException
from shared.database import upsert_annotation
from shared.database import upsert_visual_communication
from shared.database import VisualCommunication
from shared.dto import ModelData
@@ -120,34 +120,52 @@ def init_app(
filename_list: list[str] | None,
) -> tuple[str | None, str | None]:
"""Upload image to database through web ui."""
# stop early if possible
if content_list is None or filename_list is None:
logging.info('nothing to upload.')
return None, 'nothing to upload'.title()
# build list of visual communication
vis_com_list = []
try:
# stop if no input
assert (
content_list is not None
) and (
filename_list is not None
), 'nothing to upload'
# handle input
failed_filename_list = []
for content, filename in zip(content_list, filename_list):
try:
# decode image content
image = VisualCommunication.decode_image(content=content)
vis_com = VisualCommunication(
except Exception:
logging.debug('failed decoding %s', filename)
failed_filename_list.append(filename)
continue
try:
# instantiate to upload image to minio
vis_com = VisualCommunication.from_name_and_image(
name=filename,
image=image,
minio_client=minio_client,
)
except Exception as exc:
logging.error('failed handling data from file: %s', filename)
logging.debug(exc)
failed_filename_list.append(filename)
continue
vis_com_list.append(vis_com)
# upsert documents
success = upsert_visual_communication(
collection=mongo_collection,
visual_communication_list=vis_com_list,
try:
# save to mongodb
vis_com.save_to_mongo(collection=mongo_collection)
except Exception as exc:
logging.debug(exc)
failed_filename_list.append(filename)
# remove document from minio
delete_from_minio(
client=minio_client,
object_name=vis_com.object_name,
)
if success:
logging.info('uploaded %s files to database', len(vis_com_list))
assert len(failed_filename_list) == 0, f"failed uploading:{
'\n'.join(failed_filename_list)
}"
except Exception as exc:
logging.debug(exc)
return None, str(exc).title()
return 'successfully uploaded images'.title(), None
logging.error('failed uploading images to database')
return None, 'failed uploading images'.title()
# define callback: cycle visual communication data
@app.callback(