Main brez modelov

This commit is contained in:
Marko Ferme
2022-12-07 06:22:36 +01:00
parent 89fa62796e
commit 1cd7663d49
93 changed files with 98496 additions and 508 deletions
@@ -1,30 +0,0 @@
import connexion
import six
from swagger_server import util
def datoteka_v_besedilo_post(file=None): # noqa: E501
"""Pretvori datoteko formata pdf, doc, docx, ppt, xls,... v besedilo
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
return 'do some magic!'
def get_text_ocr(file=None): # noqa: E501
"""Pretvori datoteko formata pdf, doc, docx, ppt, xls,... v besedilo s pomočjo ocr razpoznavanja
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
return 'do some magic!'
@@ -1,21 +1,88 @@
import codecs
import os
import connexion
import six
import json
from pathlib import Path
from swagger_server.models.izlusci_async_body import IzlusciAsyncBody # noqa: E501
from swagger_server.models.izlusci_sync_body import IzlusciSyncBody # noqa: E501
from swagger_server.requets_db.models.vrsta import JobManager
from swagger_server.utils import cl_utils
from swagger_server.util import get_random_filename, create_random_file_in_tmp_folder
import requests
from werkzeug.utils import secure_filename
from swagger_server.models.izlusci_body import IzlusciBody # noqa: E501
from swagger_server.models.terminoloski_kandidat import TerminoloskiKandidat # noqa: E501
from swagger_server import util
ATEapi_endpoint = "http://ate-api:5000/predict"
# endpoint below to be used only for development purposes (don't need to run docker)
# ATEapi_endpoint = "http://localhost:5000/predict"
def get_candidates(body): # noqa: E501
"""Izlusci terminološke kandidate iz seznama besedil v conllu obliki
def do_izlusci(conllus, prepovedane_besede):
tmp_file_path = ""
try:
big_conllu = cl_utils.multipla_conllus_to_one_from_conllus_arr(conllus)
tmp_file_path = create_random_file_in_tmp_folder(big_conllu, ".conllu")
fp = open(tmp_file_path, 'rb')
try:
files = [
('file', ('temp_1.conllu', fp, 'application/octet-stream'))
]
res = requests.post(ATEapi_endpoint, files=files)
data = json.loads(res.text)
finally:
fp.close()
os.remove(tmp_file_path)
ret = {'terminoloski_kandidati': [
{
'POSoznake': tk['msd'],
'kandidat': tk['terms'], # more to bit lemma al terms?
'kanonicnaoblika': tk['canonical'],
'ranking': tk['ranking'],
'podporneutezi': [
0.0, # ????????
0.0 # ??????
],
'pogostostpojavljanja': [0, 0] # ???????
}
for tk in data if tk['terms'] not in prepovedane_besede
]}
return ret, 200
except Exception as e:
return str(e), 500
def get_candidates_async(body): # noqa: E501
"""Izlusci terminološke kandidate iz seznama besedil v conllu obliki [asinhrono, ustvari novi job]
# noqa: E501
:param body:
:param body:
:type body: dict | bytes
:rtype: str
"""
if connexion.request.is_json:
body = IzlusciAsyncBody.from_dict(connexion.request.get_json()) # noqa: E501
job, is_old_job = JobManager.create_job(4, json.dumps(body.to_dict()))
if job is None:
return "Something went wrong", 500
ret = {'check_job_url': f'{connexion.request.url_root}/job/{job.id}'}
return ret, 200
def get_candidates_sync(body): # noqa: E501
"""Izlusci terminološke kandidate iz seznama besedil v conllu obliki [sihrono, rezultat v sami zahtevi]
# noqa: E501
:param body:
:type body: dict | bytes
:rtype: List[TerminoloskiKandidat]
"""
if connexion.request.is_json:
body = IzlusciBody.from_dict(connexion.request.get_json()) # noqa: E501
return 'do some magic!'
body = IzlusciSyncBody.from_dict(connexion.request.get_json()) # noqa: E501
return do_izlusci(body.conllus, body.prepovedane_besede)
@@ -0,0 +1,233 @@
import datetime
import json
import os.path
import traceback
import peewee
import asyncio
import concurrent.futures as cf
from swagger_server.controllers.extract_controller import do_izlusci
from swagger_server.models.job_response import JobResponse # noqa: E501
from swagger_server.requets_db.models.vrsta import (Job)
from threading import Thread
from swagger_server.utils import cl_utils
from swagger_server.utils import txt_utils
from werkzeug.datastructures import FileStorage
import threading
import time
CLASSLA_CONCURANCE_LIMIT = 3
DOC2TEXT_CONCURANCE_LIMIT = 3
ATEAPI_CONCURANCE_LIMIT = 2
classla_sem = threading.Semaphore(CLASSLA_CONCURANCE_LIMIT)
doc2text_sem = threading.Semaphore(DOC2TEXT_CONCURANCE_LIMIT)
ateapi_sem = threading.Semaphore(ATEAPI_CONCURANCE_LIMIT)
def delete_job(job_id): # noqa: E501
"""Izbriše job
# noqa: E501
:param job_id:
:type job_id: int
:rtype: str
"""
return 'Endpoint currently disabled'
def get_job_status(job_id): # noqa: E501
"""Vrne status
# noqa: E501
:param job_id:
:type job_id: int
:rtype: JobResponse
"""
try:
job = Job.get_by_id(job_id)
if job.started_on is None:
return JobResponse(job_status="waiting in que", created_on=job.created_on), 200
if job.started_on is not None and job.finished_on is None:
return JobResponse(job_status="currently processing", created_on=job.created_on,
started_on=job.started_on), 200
if job.started_on is not None and job.finished_on is not None:
return JobResponse(job_status="finished processing", created_on=job.created_on, started_on=job.started_on,
finished_on=job.finished_on, job_result=job.job_output), 200
except peewee.DoesNotExist:
return "Job with this ID does not exist", 404
def clear_up_unfinished_jobs():
"""
In case server crashed while jobs were in queue...
"""
Job.update(started_on=None).where(Job.started_on.is_null(False), Job.finished_on.is_null()).execute()
if os.path.exists('tmp'):
for tmp_file in os.listdir('tmp'):
if not Job.select().where(Job.input_file == tmp_file).exists():
os.remove(f'tmp/{tmp_file}')
async def try_do_jobs():
with cf.ThreadPoolExecutor(max_workers=3) as ex:
ex.submit(try_do_jobs_classla)
ex.submit(try_do_jobs_doc2text)
ex.submit(try_do_jobs_ateapi)
### Job looping
def try_do_jobs_ateapi():
while True:
try:
if ateapi_sem._value > 0:
unfinished_jobs = Job.select() \
.where(Job.finished_on.is_null(), Job.started_on.is_null(), Job.job_type == 4) \
.limit(ateapi_sem._value)
with cf.ThreadPoolExecutor(max_workers=ATEAPI_CONCURANCE_LIMIT) as ex:
[ex.submit(execute_ateapi_job, job) for job in unfinished_jobs]
except Exception as e:
print(f"Exception in try_do_jobs_ateapi")
traceback.print_exc()
finally:
time.sleep(3)
### Job looping
def try_do_jobs_classla():
time.sleep(15) # wait for tokenizers to load for classla ...
while True:
try:
if cl_utils.nlp_loaded:
if classla_sem._value > 0:
unfinished_jobs_txt = Job.select() \
.where(Job.finished_on.is_null(), Job.job_type == 2,
Job.input_file.is_null(False)) \
.limit(classla_sem._value)
unfinished_jobs_no_txt = Job.select() \
.where(Job.finished_on.is_null(), Job.started_on.is_null(), Job.job_type == 2,
Job.input_file.is_null()) \
.limit(classla_sem._value)
unfinished_jobs = [j for j in unfinished_jobs_txt] + [j for j in unfinished_jobs_no_txt]
unfinished_jobs = unfinished_jobs[:classla_sem._value]
with cf.ThreadPoolExecutor(max_workers=CLASSLA_CONCURANCE_LIMIT) as ex:
[ex.submit(execute_classla_job, job) for job in unfinished_jobs]
except Exception as e:
print(f"Exception in try_do_jobs_classla")
traceback.print_exc()
finally:
time.sleep(3)
### Job looping
def try_do_jobs_doc2text():
while True:
try:
if doc2text_sem._value > 0:
unfinished_jobs = Job.select() \
.where(Job.finished_on.is_null(), Job.started_on.is_null(), Job.job_type << [1, 12, 3, 32]) \
.limit(doc2text_sem._value)
with cf.ThreadPoolExecutor(max_workers=DOC2TEXT_CONCURANCE_LIMIT) as ex:
[ex.submit(execute_doc2text_job, job) for job in unfinished_jobs]
except Exception as e:
print(f"Exception in try_do_jobs_doc2text")
traceback.print_exc()
finally:
time.sleep(3)
async def prep_jobs(tasks):
await asyncio.gather(*tasks)
def execute_doc2text_job(job: Job):
try:
doc2text_sem.acquire()
del_file = False
job.started_on = datetime.datetime.utcnow()
job.save()
tmp_file_path = job.input_file
if not os.path.exists(tmp_file_path):
job.finished_on = datetime.datetime.utcnow()
job.job_output = "ERROR - Temporary file went missing, couldn't properly finish job"
job.save()
return
with open(tmp_file_path, 'rb+') as f:
file = FileStorage(f)
jtype = job.job_type
text = ""
if jtype in [1, 12]:
text, _ = txt_utils.extract_text_prepResp(file)
elif jtype in [3, 32]:
text, _ = txt_utils.ocr_text_prepResp(file)
if jtype in [1, 3]:
job.job_output = text
job.finished_on = datetime.datetime.utcnow()
elif jtype in [12, 32]:
job.job_input = text
job.job_type = 2
job.input_size = len(text)
del_file = True
job.save()
if del_file:
try:
os.remove(tmp_file_path)
except:
pass
except:
job.started_on = None
job.save()
finally:
doc2text_sem.release()
def execute_classla_job(job: Job):
try:
classla_sem.acquire()
job.started_on = datetime.datetime.utcnow()
job.save()
conllu, _ = cl_utils.raw_text_to_conllu(job.job_input)
job.job_output = conllu
job.finished_on = datetime.datetime.utcnow()
job.save()
finally:
classla_sem.release()
def execute_ateapi_job(job: Job):
try:
ateapi_sem.acquire()
job.started_on = datetime.datetime.utcnow()
job.save()
info = json.loads(job.job_input)
ret_json, _ = do_izlusci(info['conllus'], info['prepovedane_besede'])
job.job_output = ret_json
job.finished_on = datetime.datetime.utcnow()
job.save()
finally:
ateapi_sem.release()
clear_up_unfinished_jobs()
loop = asyncio.get_event_loop()
def loop_in_thread(loop):
asyncio.set_event_loop(loop)
loop.run_until_complete(try_do_jobs())
t = Thread(target=loop_in_thread, args=(loop,))
t.start()
@@ -0,0 +1,96 @@
import connexion
from swagger_server.models.oznaci_besedilo_async_body import OznaciBesediloAsyncBody # noqa: E501
from swagger_server.requets_db.models.vrsta import (JobManager)
def get_text(body): # noqa: E501
"""Označi besedilo s classlo/stanzo z uporabo slovenskih modelov ter vrne conll-u format
# noqa: E501
:param body:
:type body: dict | bytes
:rtype: str
"""
if connexion.request.is_json:
body = OznaciBesediloAsyncBody.from_dict(connexion.request.get_json()) # noqa: E501
else:
return "Request in wrong format", 400
# conllu = cl_utils.raw_text_to_conllu(body.besedilo)
# return conllu
job, is_old_job = JobManager.create_job(2, body.besedilo)
if job is None:
return "Something went wrong", 500
ret = {'check_job_url': f'{connexion.request.url_root}/job/{job.id}'}
return ret, 200 # Todo: Update swagger to the newest response template later
def get_conllu_from_file_async(file=None): # noqa: E501
"""Pretvori datoteko v besedilo in označi s classlo/stanzo z uporabo slovenskih modelov ter vrne conll-u format
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
job, is_old_job = JobManager.create_job(12, file)
if job is None:
return "Something went wrong", 500
ret = {'check_job_url': f'{connexion.request.url_root}/job/{job.id}'}
return ret, 200
def get_conllu_from_file_ocr_async(file=None): # noqa: E501
"""Pretvori datoteko v besedilo in označi s classlo/stanzo z uporabo slovenskih modelov ter vrne conll-u format
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
job, is_old_job = JobManager.create_job(32, file)
if job is None:
return "Something went wrong", 500
ret = {'check_job_url': f'{connexion.request.url_root}/job/{job.id}'}
return ret, 200
def get_text_from_doc_async(file=None): # noqa: E501
"""Pretvori datoteko v besedilo, vrača tekst
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
job, is_old_job = JobManager.create_job(1, file)
if job is None:
return "Something went wrong", 500
ret = {'check_job_url': f'{connexion.request.url_root}/job/{job.id}'}
return ret, 200
def get_text_from_file_ocr_async(file=None): # noqa: E501
"""Pretvori datoteko v besedilo s pomočjo ocr razpoznavanja, vrača tekst
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
job, is_old_job = JobManager.create_job(3, file)
if job is None:
return "Something went wrong", 500
ret = {'check_job_url': f'{connexion.request.url_root}/job/{job.id}'}
return ret, 200
@@ -1,19 +0,0 @@
import connexion
import six
from swagger_server import util
def get_text(body): # noqa: E501
"""Označi besedilo s classlo/stanzo z uporabo slovenskih modelov ter vrne conll-u format
# noqa: E501
:param body:
:type body: dict | bytes
:rtype: str
"""
if connexion.request.is_json:
body = str.from_dict(connexion.request.get_json()) # noqa: E501
return 'do some magic!'
@@ -0,0 +1,81 @@
from swagger_server.utils import cl_utils
from swagger_server.utils import txt_utils
def datoteka_v_besedilo_in_classla(file=None): # noqa: E501
"""Pretvori datoteko formata pdf, doc, docx, ppt, xls,... vrača conllu
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
if not cl_utils.nlp_loaded:
return "NLP Models still loading up since server restart, please try again later.", 500
if file is None:
return "No file provided", 400
try:
txt, _ = txt_utils.extract_text_prepResp(file)
return cl_utils.raw_text_to_conllu(txt)
except Exception as e:
return str(e), 500
def datoteka_v_besedilo_sync_post(file=None): # noqa: E501
"""Pretvori datoteko formata pdf, doc, docx, ppt, xls,... vrača besedilo
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
if file is None:
return "No file provided", 400
try:
return txt_utils.extract_text_prepResp(file)
except Exception as e:
print(e)
return str(e), 500
def get_conllu_ocr(file=None): # noqa: E501
"""Pretvori datoteko formata pdf, doc, docx, ppt, xls,... v conllu s pomočjo ocr razpoznavanja
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
if not cl_utils.nlp_loaded:
return "NLP Models still loading up since server restart, please try again later.", 500
if file is None:
return "No file provided", 400
try:
txt, _ = txt_utils.ocr_text_prepResp(file)
return cl_utils.raw_text_to_conllu(txt)
except Exception as e:
return str(e), 500
def get_text_ocr(file=None): # noqa: E501
"""Pretvori datoteko formata pdf, doc, docx, ppt, xls,... v besedilo s pomočjo ocr razpoznavanja
# noqa: E501
:param file:
:type file: strstr
:rtype: str
"""
if file is None:
return "No file provided", 400
try:
return txt_utils.ocr_text_prepResp(file)
except Exception as e:
return str(e), 500
+74 -41
View File
@@ -1,21 +1,6 @@
import connexion
import six
from swagger_server.models.terminoloski_kandidat import TerminoloskiKandidat # noqa: E501
from swagger_server.utils import db_utils
from swagger_server import util
def get_conllu(id): # noqa: E501
"""Vrne CoNNL-U po id-ju datoteke
# noqa: E501
:param id:
:type id: int
:rtype: str
"""
return 'do some magic!'
from flask import send_file
def get_conllus(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E501
@@ -34,10 +19,16 @@ def get_conllus(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E501
:rtype: List[str]
"""
return 'do some magic!'
if not kljucnebesede:
return "Manjkajo kljucne besede", 400
#zaenkrat ne potrebujemo te storitve
files = db_utils.get_files_by_udc(kljucnebesede)
if not files:
return 'Nobena datoteka ne ustreza iskalnemu pogoju', 404
return ' '.join(files), 200
def get_extracted_words(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E501
def get_extracted_words(leta=None, vrste=None, kljucnebesede=None, udk=None): # noqa: E501
"""Vrne terminloške kandidate glede na
# noqa: E501
@@ -53,21 +44,10 @@ def get_extracted_words(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E50
:rtype: List[TerminoloskiKandidat]
"""
return 'do some magic!'
files = db_utils.vrni_oss_terminoloske_kandidate(leta, vrste, kljucnebesede, udk)
return files, 200
def get_file(id): # noqa: E501
"""Vrne binarni zapis v originalnem formatu po id-ju datoteke
# noqa: E501
:param id:
:type id: int
:rtype: List[bytearray]
"""
return 'do some magic!'
def get_files(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E501
"""Vrne seznam binarnih zapisov v originalnem formatu glede na iskalne pogoje
@@ -85,10 +65,16 @@ def get_files(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E501
:rtype: List[List[bytearray]]
"""
return 'do some magic!'
if not kljucnebesede:
return "Manjkajo kljucne besede", 400
#zaenkrat ne potrebujemo te storitve
files = db_utils.get_files_by_udc(kljucnebesede)
if not files:
return 'Nobena datoteka ne ustreza iskalnemu pogoju', 404
return ' '.join(files), 200
def get_number_texts(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E501
def get_number_texts(leta=None, vrste=None, kljucnebesede=None, udk=None): # noqa: E501
"""Vrne število besedil glede na iskalne pogoje
# noqa: E501
@@ -100,11 +86,15 @@ def get_number_texts(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E501
:param kljucnebesede:
:type kljucnebesede: List[str]
:param cerifpodrocja:
:type cerifpodrocja: List[int]
:type udc: List[int]
:rtype: int
"""
return 'do some magic!'
#if not kljucnebesede:
# return "Manjkajo kljucne besede", 400
files = db_utils.vrni_oss_dokumente(leta, vrste, kljucnebesede, udk)
return len(files), 200
def get_texts(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E501
@@ -123,17 +113,60 @@ def get_texts(leta, vrste, kljucnebesede, cerifpodrocja): # noqa: E501
:rtype: List[str]
"""
return 'do some magic!'
if not kljucnebesede:
return "Manjkajo kljucne besede", 400
#zaenkrat ne potrebujemo te storitve
files = db_utils.get_files_by_udc(kljucnebesede)
if not files:
return 'Nobena datoteka ne ustreza iskalnemu pogoju', 404
return ' '.join(files), 200
def oss_besedilo_po_id_get(id): # noqa: E501
def get_conllu(file_id): # noqa: E501
"""Vrne CoNNL-U po id-ju datoteke
# noqa: E501
:param file_id:
:type file_id: int
:rtype: str
"""
try:
return send_file(util.get_conllu_file_path_by_id(file_id), download_name=f'{file_id}.conllu')
except FileNotFoundError as e:
return "The conllu with this ID doesn't exist.", 404
def get_file(file_id): # noqa: E501
"""Vrne binarni zapis v originalnem formatu po id-ju datoteke
# noqa: E501
:param file_id:
:type file_id: int
:rtype: List[bytearray]
"""
try:
return send_file(util.get_original_file_path_by_id(file_id), download_name=f'{file_id}.xml')
except FileNotFoundError as e:
return "The file with this ID doesn't exist.", 404
def oss_besedilo_po_id_get(file_id): # noqa: E501
"""Vrne besedilo po id-ju datoteke
# noqa: E501
:param id:
:type id: int
:param file_id:
:type file_id: int
:rtype: str
"""
return 'do some magic!'
try:
f = util.get_original_file_path_by_id(file_id)
print(f) # for debugging purposes on the server, delete this later
return send_file(util.get_original_file_path_by_id(file_id), download_name=f'{file_id}.xml')
except FileNotFoundError as e:
return "The file with this ID doesn't exist.", 404