Commit d0acaf14 authored by Matteo's avatar Matteo
Browse files

update

parent 4088391c
version: 1
formatters:
brief:
format: '%(message)s'
precise:
format: '[%(levelname)s %(name)s %(module)s:%(lineno)s - %(funcName)s() - %(asctime)s]\n\t %(message)s \n'
datefmt: '%d/%m/%Y %H:%M:%S'
handlers:
file:
class: logging.handlers.RotatingFileHandler
formatter: precise
filename: /var/log/video-analyzer/server.log
maxBytes: 10485760
backupCount: 3
console:
class: logging.StreamHandler
formatter: brief
loggers:
uvicorn:
level: INFO
handlers: [file, console]
propagate: no
\ No newline at end of file
from fastapi import FastAPI, Response, status, Path, Query
from typing import Annotated
from mpai_cae_arp.files import File, FileType
from mpai_cae_arp.types.irregularity import IrregularityFile
from mpai_cae_arp.types.schema import Info
import server.utils as utils
info = File('server/documentation.yaml', FileType.YAML).get_content()
app = FastAPI(**info)
@app.get("/")
async def list_endpoints() -> list[str]:
return ["irregularityFile/{id}", "description", "docs"]
@app.get("/description")
async def get_server_info() -> Info:
return info
@app.get("/irregularityFile/{id}", status_code=200)
async def get_irregularity_file(
response: Response,
id: Annotated[int, Path(
gt=0, lt=3,
description="Id of the irregularity file to be returned."
)],
files_name: Annotated[str, Query(
description="Name of the video file to be analyzed without the extension.",
example="video"
)],
working_path: Annotated[str, Query(
description="Path to the directory containing the preservation files.",
examples={
"Absolute path": {"value": "/home/user/preservation"},
"Relative path": {"value": "preservation"}
}
)] = None
) -> IrregularityFile:
required_file = f'VideoAnalyser_IrregularityFileOutput{id}.json'
try:
return File(required_file, FileType.JSON).get_content()
except:
process = await utils.analyze(files_name, working_path)
if process.returncode == 0:
return File(required_file, FileType.JSON).get_content()
else:
response.status_code = status.HTTP_412_PRECONDITION_FAILED
return {"error": {
"returncode": process.returncode,
"stdout": process.stdout.decode("utf-8"),
"stderr": process.stderr.decode("utf-8"),
}}
This diff is collapsed.
[tool.poetry]
name = "server"
version = "0.1.0"
description = ""
authors = ["Matteo <spartacus990@gmail.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.10"
mpai-cae-arp = "^0.3.2"
grpcio-tools = "^1.53.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
anyio==3.6.2
appdirs==1.4.4
audioread==3.0.0
certifi==2022.12.7
cffi==1.15.1
charset-normalizer==3.1.0
click==8.1.3
decorator==5.1.1
dnspython==2.3.0
email-validator==1.3.1
fastapi==0.95.0
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
joblib==1.2.0
lazy_loader==0.2
librosa==0.10.0.post2
llvmlite==0.39.1
MarkupSafe==2.1.2
mpai-cae-arp==0.2.0
msgpack==1.0.5
numba==0.56.4
numpy==1.23.3
orjson==3.8.9
packaging==23.0
pooch==1.6.0
pycparser==2.21
pydantic==1.10.7
python-dotenv==1.0.0
python-multipart==0.0.6
PyYAML==6.0
requests==2.28.2
rfc3986==1.5.0
scikit-learn==1.2.2
scipy==1.10.1
sniffio==1.3.0
soundfile==0.12.1
soxr==0.3.4
starlette==0.26.1
threadpoolctl==3.1.0
typing_extensions==4.5.0
ujson==5.7.0
urllib3==1.26.15
uvicorn==0.21.1
uvloop==0.17.0
watchfiles==0.19.0
websockets==11.0
import os
from concurrent import futures
from typing import Any, Callable
import grpc
from grpc import StatusCode
from rich.console import Console
from mpai_cae_arp.files import File, FileType
from mpai_cae_arp.types.irregularity import IrregularityFile, Source
from mpai_cae_arp.network import arp_pb2_grpc as arp_pb2_grpc
from mpai_cae_arp.network.arp_pb2 import (
JobRequest,
JobResponse,
Contact,
InfoResponse,
License,
)
info = File('config/server.yaml', FileType.YAML).get_content()
def try_or_error_response(
context,
on_success_message: str,
on_error_message: str,
func: Callable,
args,
on_success_status: StatusCode = StatusCode.OK,
on_error_status: StatusCode = StatusCode.INTERNAL,
) -> tuple[JobResponse, Any]:
try:
result = func(*args)
context.set_code(on_success_status)
context.set_details(on_success_message)
return JobResponse(status="success", message=on_success_message), result
except:
context.set_code(on_error_status)
context.set_details(on_error_message)
return JobResponse(status="error", message=on_error_message), None
def error_response(context, status, message):
context.set_code(status)
context.set_details(message)
return JobResponse(status="error", message=message)
class VideoAnalyserServicer(arp_pb2_grpc.AIMServicer):
def __init__(self, console: Console):
self.console = console
def getInfo(self, request, context) -> InfoResponse:
self.console.log('Received request for AIM info')
context.set_code(StatusCode.OK)
context.set_details('Success')
return InfoResponse(
title=info['title'],
description=info['description'],
version=info['version'],
contact=Contact(
name=info['contact']['name'],
email=info['contact']['email'],
),
license=License(
name=info['license_info']['name'],
url=info['license_info']['url'],
)
)
def work(self, request: JobRequest, context):
self.console.log('Received request for computation')
self.console.log(request)
working_dir: str = request.working_dir
files_name: str = request.files_name
index: int = request.index
video_src = os.path.join(working_dir, "PreservationAudioVisualFile", f"{files_name}.mov")
temp_dir = os.path.join(working_dir, "temp", files_name)
audio_irreg_1 = os.path.join(temp_dir, "AudioAnalyser_IrregularityFileOutput_1.json")
video_irreg_1 = os.path.join(temp_dir, "VideoAnalyser_IrregularityFileOutput_1.json")
video_irreg_2 = os.path.join(temp_dir, "VideoAnalyser_IrregularityFileOutput_2.json")
response, _ = try_or_error_response(
context=context,
func=os.makedirs,
args=[temp_dir],
on_success_message="Folders created successfully",
on_error_message="Unable to create temporary directory, output path already exists",
on_error_status=StatusCode.ALREADY_EXISTS,
)
yield response
try:
File(audio_irreg_1, FileType.JSON).write_content(irreg1.to_json())
context.set_code(StatusCode.OK)
yield JobResponse(status="success", message="Irregularity file 1 saved to disk")
except:
yield error_response(context, StatusCode.INTERNAL, "Failed to save irregularity file 1")
File(audio_irreg_2, FileType.JSON).write_content(irreg2.to_json())
yield JobResponse(status="success", message="Irregularity file 2 created")
def serve(console):
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
arp_pb2_grpc.add_AIMServicer_to_server(VideoAnalyserServicer(console), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
if __name__ == '__main__':
console = Console()
console.print('Server started at localhost:50051 :satellite:')
serve(console)
import os
import subprocess
from mpai_cae_arp.files import File, FileType
def analyze(files_name: str, working_path: str | None = None) -> subprocess.CompletedProcess:
executable = os.path.abspath("bin/video_analyser")
config_file = File("config/config.json", FileType.JSON)
config = config_file.get_content()
# Update configuration file with query parameters
config["FilesName"] = files_name
if working_path is not None:
config["WorkingPath"] = working_path
config_file.write_content(config)
process = subprocess.run([executable], capture_output=True)
return process
...@@ -55,10 +55,6 @@ namespace po = boost::program_options; ...@@ -55,10 +55,6 @@ namespace po = boost::program_options;
/*************************************************************************************************/
/******************************************* VARIABLES *******************************************/
/*************************************************************************************************/
// For capstan detection, there are two alternative approaches: // For capstan detection, there are two alternative approaches:
// Generalized Hough Transform and SURF. // Generalized Hough Transform and SURF.
bool useSURF = true; bool useSURF = true;
...@@ -133,7 +129,7 @@ bool getArguments(int argc, char** argv) { ...@@ -133,7 +129,7 @@ bool getArguments(int argc, char** argv) {
try { try {
po::options_description desc( po::options_description desc(
"A tool that implements MPAI CAE-ARP Video Analyser Technical Specification.\n" "A tool that implements MPAI CAE-ARP Video Analyser Technical Specification.\n"
"By default, the configuartion parameters are loaded from ./config.json file,\n" "By default, the configuartion parameters are loaded from config/config.json file,\n"
"but, alternately, you can pass command line arguments to replace them" "but, alternately, you can pass command line arguments to replace them"
); );
desc.add_options() desc.add_options()
...@@ -194,7 +190,7 @@ bool findProcessingAreas(json configurationFile) { ...@@ -194,7 +190,7 @@ bool findProcessingAreas(json configurationFile) {
Mat myFrameGrayscale; Mat myFrameGrayscale;
cvtColor(myFrame, myFrameGrayscale, COLOR_BGR2GRAY); cvtColor(myFrame, myFrameGrayscale, COLOR_BGR2GRAY);
// Get input shape in grayscale // Get input shape in grayscale
Mat templateImage = imread("../input/readingHead.png", IMREAD_GRAYSCALE); Mat templateImage = imread("input/readingHead.png", IMREAD_GRAYSCALE);
// Downsample myFrameGrayscale in half pixels for performance reasons // Downsample myFrameGrayscale in half pixels for performance reasons
Mat myFrameGrayscaleHalf; Mat myFrameGrayscaleHalf;
pyrDown(myFrameGrayscale, myFrameGrayscaleHalf, Size(myFrame.cols/2, myFrame.rows/2)); pyrDown(myFrameGrayscale, myFrameGrayscaleHalf, Size(myFrame.cols/2, myFrame.rows/2));
...@@ -338,7 +334,7 @@ bool findProcessingAreas(json configurationFile) { ...@@ -338,7 +334,7 @@ bool findProcessingAreas(json configurationFile) {
/*********************************************************************************************/ /*********************************************************************************************/
// Read template image - it is smaller than before, therefore there is no need to downsample // Read template image - it is smaller than before, therefore there is no need to downsample
templateShape = imread("../input/capstanBERIO058prova.png", IMREAD_GRAYSCALE); // WORKING templateShape = imread("input/capstanBERIO058prova.png", IMREAD_GRAYSCALE); // WORKING
// templateShape = imread("../input/capstanBERIO058.png", IMREAD_GRAYSCALE); // templateShape = imread("../input/capstanBERIO058.png", IMREAD_GRAYSCALE);
cout << DARK_CYAN << "Capstan" << END << endl; cout << DARK_CYAN << "Capstan" << END << endl;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment