Commit 2b910b9d authored by Konstantin Schulz's avatar Konstantin Schulz

documentation for the REST API is now complete

parent 2e0e4b74
Pipeline #11833 failed with stages
in 2 minutes and 43 seconds
import rapidjson as json
from mcserver.app.models import AnnisResponse, TextComplexity
from mcserver.app.services import NetworkService, CorpusService, TextComplexityService
from openapi.openapi_server.models import TextComplexityForm
......@@ -5,7 +6,7 @@ from openapi.openapi_server.models import TextComplexityForm
def post(complexity_data: dict):
tcf: TextComplexityForm = TextComplexityForm.from_dict(complexity_data)
ar: AnnisResponse = AnnisResponse.from_dict(
tcf.annis_response.to_dict()) if tcf.annis_response else CorpusService.get_corpus(tcf.urn, is_csm=True)
ar: AnnisResponse = AnnisResponse.from_dict(json.loads(tcf.annis_response)) if tcf.annis_response \
else CorpusService.get_corpus(tcf.urn, is_csm=True)
tc: TextComplexity = TextComplexityService.text_complexity(tcf.measure, tcf.urn, True, ar.graph_data)
return NetworkService.make_json_response(tc.to_dict())
......@@ -39,4 +39,4 @@ paths:
content:
application/x-www-form-urlencoded:
schema:
$ref: '../openapi_models.yaml#/components/schemas/TextComplexityFormBase'
$ref: '../openapi_models.yaml#/components/schemas/TextComplexityForm'
......@@ -7,6 +7,7 @@ from mcserver.app import db
from mcserver.app.models import Language, VocabularyCorpus, ResourceType
from mcserver.app.services import NetworkService, FileService
from mcserver.models_auto import Exercise, UpdateInfo
from openapi.openapi_server.models import MatchingExercise
def get(lang: str, frequency_upper_bound: int, last_update_time: int, vocabulary: str = ""):
......@@ -29,13 +30,11 @@ def get(lang: str, frequency_upper_bound: int, last_update_time: int, vocabulary
lang = Language.English
exercises: List[Exercise] = db.session.query(Exercise).filter_by(language=lang.value)
db.session.commit()
ret_val: List[dict] = [NetworkService.serialize_exercise(x, compress=True) for x in exercises]
matching_degrees: List[float] = []
matching_exercises: List[MatchingExercise] = [MatchingExercise.from_dict(x.to_dict()) for x in exercises]
if len(vocabulary_set):
for exercise in exercises:
for exercise in matching_exercises:
conll: List[TokenList] = conllu.parse(exercise.conll)
lemmata: List[str] = [tok["lemma"] for sent in conll for tok in sent.tokens]
matching_degrees.append(sum((1 if x in vocabulary_set else 0) for x in lemmata) / len(lemmata) * 100)
for i in range(len(ret_val)):
ret_val[i]["matching_degree"] = matching_degrees[i]
exercise.matching_degree = sum((1 if x in vocabulary_set else 0) for x in lemmata) / len(lemmata) * 100
ret_val: List[dict] = [NetworkService.serialize_exercise(x, compress=True) for x in matching_exercises]
return NetworkService.make_json_response(ret_val)
......@@ -4,15 +4,10 @@ import os
import uuid
from datetime import datetime
from typing import List, Union
import connexion
import flask
from connexion.lifecycle import ConnexionResponse
from flask import send_from_directory, Response
from flask_restful import Resource, abort
from flask_restful.reqparse import RequestParser
from werkzeug.wrappers import ETagResponseMixin
from mcserver.app import db
from mcserver.app.models import FileType, ResourceType, DownloadableFile, MimeType, XapiStatement, LearningResultMC
from mcserver.app.services import FileService, NetworkService
......
......@@ -2,15 +2,17 @@ from typing import List, Union
import connexion
from connexion.lifecycle import ConnexionResponse
from flask import Response
from mcserver import Config
from mcserver.app.services import CorpusService, NetworkService, CustomCorpusService
def get(urn: str) -> Union[Response, ConnexionResponse]:
"""The GET method for the valid references REST API. It provides references for the desired text."""
reff: List[str] = CustomCorpusService.get_custom_corpus_reff(urn) if CustomCorpusService.is_custom_corpus_urn(
urn) else CorpusService.get_standard_corpus_reff(urn)
try:
reff: List[str] = CustomCorpusService.get_custom_corpus_reff(urn) if CustomCorpusService.is_custom_corpus_urn(
urn) else CorpusService.get_standard_corpus_reff(urn)
except ValueError:
return connexion.problem(400, Config.ERROR_TITLE_BAD_REQUEST, Config.ERROR_MESSAGE_BAD_REQUEST)
if not reff:
return connexion.problem(404, Config.ERROR_TITLE_NOT_FOUND, Config.ERROR_MESSAGE_CORPUS_NOT_FOUND)
return NetworkService.make_json_response(reff)
......@@ -2,12 +2,9 @@ import ntpath
import os
from collections import OrderedDict
from typing import List, Tuple, Set, Dict
import conllu
import rapidjson as json
from conllu import TokenList
from flask_restful import abort
from mcserver import Config
from mcserver.app.models import CustomCorpus, CitationLevel, TextPart, Citation, CorpusMC
from mcserver.app.services import AnnotationService, FileService
......@@ -132,7 +129,10 @@ class CustomCorpusService:
if cts_urn == target_corpus.corpus.source_urn:
disk_reff = [(":".join([cts_urn, str(x.citation.value)])) for x in target_corpus.text_parts]
else:
disk_reff = CustomCorpusService.get_custom_corpus_sub_reff(cts_urn, target_corpus)
try:
disk_reff = CustomCorpusService.get_custom_corpus_sub_reff(cts_urn, target_corpus)
except ValueError:
raise
with open(os.path.join(Config.REFF_CACHE_DIRECTORY, disk_urn), "w+") as f:
f.write(json.dumps(disk_reff))
return disk_reff
......@@ -145,7 +145,7 @@ class CustomCorpusService:
try:
citation_parts = [int(x) for x in urn_parts[-1].split(".")]
except ValueError:
abort(400)
raise
target_text_parts: List[TextPart] = target_corpus.text_parts
if len(citation_parts) > 1:
target_text_parts = next(
......
......@@ -9,7 +9,8 @@ from flask_restful.reqparse import RequestParser
from mcserver import Config
from mcserver.app.models import StaticExercise
from mcserver.models_auto import Exercise, TExercise
from mcserver.models_auto import Exercise
from openapi.openapi_server.models import MatchingExercise
class NetworkService:
......@@ -33,12 +34,12 @@ class NetworkService:
return response
@staticmethod
def serialize_exercise(exercise: TExercise, compress: bool) -> dict:
def serialize_exercise(exercise: MatchingExercise, compress: bool) -> dict:
""" Serializes an exercise to JSON format. """
ret_val: dict = exercise.to_dict()
ret_val["conll"] = "" if compress else exercise.conll
exercise.conll = "" if compress else exercise.conll
# convert the POSIX timestamp to JSON / Javascript, i.e. from seconds to milliseconds
ret_val["last_access_time"] = exercise.last_access_time * 1000
exercise.last_access_time = exercise.last_access_time * 1000
ret_val: dict = exercise.to_dict()
ret_val["search_values"] = json.loads(exercise.search_values)
ret_val["solutions"] = "[]" if compress else json.loads(exercise.solutions)
ret_val["solutions"] = [] if compress else json.loads(exercise.solutions)
return ret_val
......@@ -5,6 +5,7 @@ import requests
from mcserver import Config
from mcserver.app.models import GraphData, TextComplexity, TextComplexityMeasure, AnnisResponse
from mcserver.app.services import TextService, AnnotationService, CorpusService
from openapi.openapi_server.models import TextComplexityForm
class TextComplexityService:
......@@ -183,6 +184,7 @@ class TextComplexityService:
url: str = f"{Config.INTERNET_PROTOCOL}{Config.HOST_IP_CSM}:" + \
f"{Config.CORPUS_STORAGE_MANAGER_PORT}{Config.SERVER_URI_TEXT_COMPLEXITY}"
ar: AnnisResponse = AnnisResponse(graph_data=gd)
response: requests.Response = requests.post(url, data=json.dumps(
dict(urn=urn, measure=TextComplexityMeasure.all.name, annis_response=ar.to_dict())))
tcf: TextComplexityForm = TextComplexityForm(urn=urn, measure=TextComplexityMeasure.all.name,
annis_response=json.dumps(ar.to_dict()))
response: requests.Response = requests.post(url, data=tcf.to_dict())
return TextComplexity.from_dict(json.loads(response.text))
......@@ -73,6 +73,9 @@ class Config(object):
DEBUG = False
DOCKER_SERVICE_NAME_CSM = "csm"
DOCKER_SERVICE_NAME_MCSERVER = "mcserver"
ERROR_MESSAGE_BAD_REQUEST = \
"The server cannot or will not process the request due to something that is perceived to be a client " \
"error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing)."
ERROR_MESSAGE_CORPUS_NOT_FOUND = "A corpus with the specified ID was not found!"
ERROR_MESSAGE_EXERCISE_NOT_FOUND = "An exercise with the specified ID was not found!"
ERROR_MESSAGE_INTERNAL_SERVER_ERROR = \
......@@ -83,6 +86,7 @@ class Config(object):
ERROR_MESSAGE_UNPROCESSABLE_ENTITY = \
"The server understands the content type of the request entity, and the syntax of the request entity is " \
"correct, but it was unable to process the contained instructions."
ERROR_TITLE_BAD_REQUEST = "Bad Request"
ERROR_TITLE_INTERNAL_SERVER_ERROR = "Internal Server Error"
ERROR_TITLE_NOT_FOUND = "Not found"
ERROR_TITLE_SERVICE_UNAVAILABLE = "Service Unavailable"
......
......@@ -12,7 +12,7 @@ paths:
summary: Returns a list of corpora.
operationId: mcserver.app.api.corpusListAPI.get
responses:
200:
"200":
description: Corpus list
content:
application/json:
......@@ -39,7 +39,7 @@ paths:
summary: Deletes a single corpus by ID.
operationId: mcserver.app.api.corpusAPI.delete
responses:
200:
"200":
description: Indication of success
content:
application/json:
......@@ -50,7 +50,7 @@ paths:
summary: Returns a single corpus by ID.
operationId: mcserver.app.api.corpusAPI.get
responses:
200:
"200":
description: Corpus object
content:
application/json:
......@@ -60,7 +60,7 @@ paths:
summary: Updates a single corpus by ID.
operationId: mcserver.app.api.corpusAPI.patch
responses:
200:
"200":
description: Corpus object
content:
application/json:
......@@ -93,7 +93,7 @@ paths:
summary: Returns exercise data by ID.
operationId: mcserver.app.api.exerciseAPI.get
responses:
200:
"200":
description: Exercise data object, including a graph model for linguistic annotations.
content:
application/json:
......@@ -105,7 +105,7 @@ paths:
summary: Creates a new exercise.
operationId: mcserver.app.api.exerciseAPI.post
responses:
200:
"200":
description: Exercise data object
content:
application/json:
......@@ -122,12 +122,14 @@ paths:
summary: Provides metadata for all available exercises.
operationId: mcserver.app.api.exerciseListAPI.get
responses:
200:
"200":
description: Data for interactive exercises, excluding the linguistic details.
content:
application/json:
schema:
$ref: '../openapi_models.yaml#/components/schemas/Exercise'
type: array
items:
$ref: '../openapi_models.yaml#/components/schemas/MatchingExercise'
parameters:
- $ref: '../openapi_models.yaml#/components/parameters/LangParam'
- name: frequency_upper_bound
......@@ -157,12 +159,18 @@ paths:
summary: Provides the URL to download a specific file.
operationId: mcserver.app.api.fileAPI.get
responses:
200:
"200":
description: Data for interactive exercises, excluding the linguistic details.
content:
application/json:
application/pdf:
schema:
type: object
application/vnd.openxmlformats-officedocument.wordprocessingml.document:
schema:
type: object
application/xml:
schema:
$ref: '../openapi_models.yaml#/components/schemas/Exercise'
type: object
parameters:
- name: id
in: query
......@@ -182,7 +190,7 @@ paths:
summary: Serializes and persists learning results or HTML content for later access.
operationId: mcserver.app.api.fileAPI.post
responses:
200:
"200":
description: Indication of success, possibly a reference to the resulting file.
content:
application/json:
......@@ -218,7 +226,7 @@ paths:
summary: Returns results for a frequency query from ANNIS for a given CTS URN.
operationId: mcserver.app.api.frequencyAPI.get
responses:
200:
"200":
description: Frequency analysis, i.e. a list of frequency items.
content:
application/json:
......@@ -234,7 +242,7 @@ paths:
summary: Provides JSON templates for client-side H5P exercise layouts.
operationId: mcserver.app.api.h5pAPI.get
responses:
200:
"200":
description: JSON template for an interactive H5P exercise.
content:
application/json:
......@@ -251,7 +259,7 @@ paths:
summary: Provides example contexts for a given phenomenon in a given corpus.
operationId: mcserver.app.api.kwicAPI.post
responses:
200:
"200":
description: HTML strings with SVG elements for rendering KWIC images.
content:
application/json:
......@@ -268,7 +276,7 @@ paths:
summary: Provides the raw text for a requested text passage.
operationId: mcserver.app.api.rawTextAPI.get
responses:
200:
"200":
description: Graph data for the text passage, including raw text and annotations.
content:
application/json:
......@@ -281,7 +289,7 @@ paths:
summary: Returns metadata for static exercises.
operationId: mcserver.app.api.staticExercisesAPI.get
responses:
200:
"200":
description: Metadata for static exercises, mapped to their respective URIs in the frontend.
content:
application/json:
......@@ -294,7 +302,7 @@ paths:
summary: Gives users measures of text complexity for a given text.
operationId: mcserver.app.api.textcomplexityAPI.get
responses:
200:
"200":
description: Text complexity measures for a given text.
content:
application/json:
......@@ -314,7 +322,7 @@ paths:
summary: Gives users all the citable text references for a corpus.
operationId: mcserver.app.api.validReffAPI.get
responses:
200:
"200":
description: Valid references for the desired text.
content:
application/json:
......@@ -330,7 +338,7 @@ paths:
summary: Provides network data for the vectors in an AI model.
operationId: mcserver.app.api.vectorNetworkAPI.get
responses:
200:
"200":
description: HTML string with SVG elements for rendering the network graph.
content:
application/json:
......@@ -369,7 +377,7 @@ paths:
summary: Provides network data for the vectors in an AI model.
operationId: mcserver.app.api.vectorNetworkAPI.post
responses:
200:
"200":
description: Sentences whose content is similar to a given word.
content:
application/json:
......@@ -395,7 +403,7 @@ paths:
summary: Shows how well the vocabulary of a text matches a predefined reference vocabulary.
operationId: mcserver.app.api.vocabularyAPI.get
responses:
200:
"200":
description: Retrieves sentence ID and matching degree for each sentence in the query text.
content:
application/json:
......@@ -428,7 +436,7 @@ paths:
summary: Shows how well the vocabulary of a text matches a predefined reference vocabulary.
operationId: mcserver.app.api.vocabularyAPI.post
responses:
200:
"200":
description: Indicates for each token of a corpus whether it is covered by a reference vocabulary.
content:
application/json:
......@@ -443,7 +451,7 @@ paths:
# include this here so the data model gets generated correctly
components:
schemas:
TextComplexityForm:
TextComplexityFormExtension:
type: object
allOf:
- $ref: '../openapi_models.yaml#/components/schemas/TextComplexityFormBase'
- $ref: '../openapi_models.yaml#/components/schemas/TextComplexityForm'
......@@ -167,10 +167,10 @@ class ExerciseDict(_ExerciseDictBase, total=False):
work_title: str
conll: str
exercise_type: str
exercise_type_translation: str
solutions: str
text_complexity: float
urn: str
exercise_type_translation: str
class TExercise(typing.Protocol):
......@@ -197,13 +197,13 @@ class TExercise(typing.Protocol):
string.
eid: Unique identifier (UUID) for the exercise.
exercise_type: Type of exercise, concerning interaction and layout.
exercise_type_translation: Localized expression of the exercise type.
last_access_time: When the exercise was last accessed (as POSIX
timestamp).
solutions: Correct solutions for the exercise.
text_complexity: Overall text complexity as measured by the software's
internal language analysis.
urn: CTS URN for the text passage from which the exercise was created.
exercise_type_translation: Localized expression of the exercise type.
"""
......@@ -225,11 +225,11 @@ class TExercise(typing.Protocol):
conll: str
eid: str
exercise_type: str
exercise_type_translation: str
last_access_time: float
solutions: str
text_complexity: float
urn: str
exercise_type_translation: str
def __init__(
self,
......@@ -246,10 +246,10 @@ class TExercise(typing.Protocol):
work_title: str = "",
conll: str = "",
exercise_type: str = "",
exercise_type_translation: str = "",
solutions: str = "[]",
text_complexity: float = 0,
urn: str = "",
exercise_type_translation: str = "",
) -> None:
"""
Construct.
......@@ -273,8 +273,6 @@ class TExercise(typing.Protocol):
single string.
eid: Unique identifier (UUID) for the exercise.
exercise_type: Type of exercise, concerning interaction and layout.
exercise_type_translation: Localized expression of the exercise
type.
last_access_time: When the exercise was last accessed (as POSIX
timestamp).
solutions: Correct solutions for the exercise.
......@@ -282,6 +280,8 @@ class TExercise(typing.Protocol):
software's internal language analysis.
urn: CTS URN for the text passage from which the exercise was
created.
exercise_type_translation: Localized expression of the exercise
type.
"""
...
......@@ -302,10 +302,10 @@ class TExercise(typing.Protocol):
work_title: str = "",
conll: str = "",
exercise_type: str = "",
exercise_type_translation: str = "",
solutions: str = "[]",
text_complexity: float = 0,
urn: str = "",
exercise_type_translation: str = "",
) -> "TExercise":
"""
Construct from a dictionary (eg. a POST payload).
......@@ -329,8 +329,6 @@ class TExercise(typing.Protocol):
single string.
eid: Unique identifier (UUID) for the exercise.
exercise_type: Type of exercise, concerning interaction and layout.
exercise_type_translation: Localized expression of the exercise
type.
last_access_time: When the exercise was last accessed (as POSIX
timestamp).
solutions: Correct solutions for the exercise.
......@@ -338,6 +336,8 @@ class TExercise(typing.Protocol):
software's internal language analysis.
urn: CTS URN for the text passage from which the exercise was
created.
exercise_type_translation: Localized expression of the exercise
type.
Returns:
Model instance based on the dictionary.
......
......@@ -761,7 +761,7 @@ class Mocks:
'Romanus', 'Solomon', 'amor']
raw_text: str = "Caesar fortis est. Galli moriuntur."
static_exercises_udpipe_string: str = "1\tscribere\tscribere\n1\tcommovere\tcommovere\n1\tC\tC\n1\tgaudere\tgaudere\n1\tsignum\tsignum\n1\tvas\tvas\n1\tclarus\tclarus\n1\tcondicio\tcondicio\n1\tcom\tcum\n1\tprae\tprae\n1\tmovere\tmovere\n1\tducere\tducere\n1\tde\tde\n1\tcum\tcum\n1\tistam\tiste\n1\tnationum\tnatio\n1\tclarissimae\tclarus\n1\tmoderationem\tmoderatio\n1\tanimi\tanimus\n1\tomnium\tomnis\n1\tgentium\tgens\n1\tac\tac\n1\tvirtutem\tvirtus\n1\tprovinciae\tprovincia\n1\tCaesar\tCaesar\n1\test\tesse\n1\tsatis\tsatis\n1\tgovernment\tgovernment\n1\tsocius\tsocius\n1\tprovincia\tprovincia\n1\tpublicus\tpublicus\n1\tcivis\tcivis\n1\tatque\tatque"
subgraph_json: str = '{"exercise_id":"","exercise_type":null,"frequency_analysis":null,"graph_data":{"directed":true,"graph":{},"links":[],"multigraph":true,"nodes":[{"annis_node_name":"urn:cts:latinLit:phi0448.phi001.perseus-lat2:1.1.1-1.1.1/doc1#sent1tok3","annis_node_type":"node","annis_tok":"Galli","annis_type":"node","id":"salt:/urn:cts:latinLit:phi0448.phi001.perseus-lat2:1.1.1-1.1.1/doc1#sent1tok3","is_oov":null,"udep_lemma":"Gallo","udep_upostag":"VERB","udep_xpostag":"L3|modQ|tem1|stAC","udep_feats":"Tense=Pres|VerbForm=Inf|Voice=Pass","solution":null}]},"solutions":[],"text_complexity":null,"uri":""}'
subgraph_json: str = '{"exercise_id":"","exercise_type":"","frequency_analysis":null,"graph_data":{"directed":true,"graph":{},"links":[],"multigraph":true,"nodes":[{"annis_node_name":"urn:cts:latinLit:phi0448.phi001.perseus-lat2:1.1.1-1.1.1/doc1#sent1tok3","annis_node_type":"node","annis_tok":"Galli","annis_type":"node","id":"salt:/urn:cts:latinLit:phi0448.phi001.perseus-lat2:1.1.1-1.1.1/doc1#sent1tok3","is_oov":null,"udep_lemma":"Gallo","udep_upostag":"VERB","udep_xpostag":"L3|modQ|tem1|stAC","udep_feats":"Tense=Pres|VerbForm=Inf|Voice=Pass","solution":null}]},"solutions":[],"text_complexity":null,"uri":""}'
test_args: List[str] = ["tests.py", "-test"]
text_complexity_json_string: str = '{"all":54.53,"avg_w_len":5.79,"avg_w_per_sent":17.33,"lex_den":0.73,"n_abl_abs":0,"n_clause":1,"n_gerund":1,"n_inf":1,"n_part":1,"n_punct":3,"n_sent":3,"n_subclause":0,"n_types":48,"n_w":52,"pos":11}'
text_list: List[Tuple[str, str]] = [("urn:cts:latinLit:phi0448.phi001.perseus-lat2:1.1.1", raw_text.split(".")[0]),
......
......@@ -3,9 +3,9 @@ import six
from openapi.openapi_server.models.annis_response import AnnisResponse # noqa: E501
from openapi.openapi_server.models.corpus import Corpus # noqa: E501
from openapi.openapi_server.models.exercise import Exercise # noqa: E501
from openapi.openapi_server.models.file_type import FileType # noqa: E501
from openapi.openapi_server.models.frequency_item import FrequencyItem # noqa: E501
from openapi.openapi_server.models.matching_exercise import MatchingExercise # noqa: E501
from openapi.openapi_server.models.sentence import Sentence # noqa: E501
from openapi.openapi_server.models.static_exercise import StaticExercise # noqa: E501
from openapi.openapi_server.models.text_complexity import TextComplexity # noqa: E501
......@@ -109,7 +109,7 @@ def mcserver_app_api_exercise_list_api_get(lang, frequency_upper_bound=None, las
:param vocabulary: Identifier for a reference vocabulary.
:type vocabulary: dict | bytes
:rtype: Exercise
:rtype: List[MatchingExercise]
"""
if connexion.request.is_json:
vocabulary = VocabularyMC.from_dict(connexion.request.get_json()) # noqa: E501
......@@ -128,7 +128,7 @@ def mcserver_app_api_file_api_get(id, type, solution_indices=None): # noqa: E50
:param solution_indices: Indices for the solutions that should be included in the download.
:type solution_indices: List[int]
:rtype: Exercise
:rtype: object
"""
if connexion.request.is_json:
type = FileType.from_dict(connexion.request.get_json()) # noqa: E501
......
......@@ -5,9 +5,8 @@ from __future__ import absolute_import
# import models into model package
from openapi.openapi_server.models.annis_response import AnnisResponse
from openapi.openapi_server.models.corpus import Corpus
from openapi.openapi_server.models.exercise import Exercise
from openapi.openapi_server.models.exercise_all_of import ExerciseAllOf
from openapi.openapi_server.models.exercise_base import ExerciseBase
from openapi.openapi_server.models.exercise_extension import ExerciseExtension
from openapi.openapi_server.models.exercise_form import ExerciseForm
from openapi.openapi_server.models.exercise_form_all_of import ExerciseFormAllOf
from openapi.openapi_server.models.file_type import FileType
......@@ -16,6 +15,8 @@ from openapi.openapi_server.models.graph_data import GraphData
from openapi.openapi_server.models.inline_object import InlineObject
from openapi.openapi_server.models.kwic_form import KwicForm
from openapi.openapi_server.models.link import Link
from openapi.openapi_server.models.matching_exercise import MatchingExercise
from openapi.openapi_server.models.matching_exercise_all_of import MatchingExerciseAllOf
from openapi.openapi_server.models.node_mc import NodeMC
from openapi.openapi_server.models.phenomenon import Phenomenon
from openapi.openapi_server.models.sentence import Sentence
......@@ -24,7 +25,7 @@ from openapi.openapi_server.models.solution_element import SolutionElement
from openapi.openapi_server.models.static_exercise import StaticExercise
from openapi.openapi_server.models.text_complexity import TextComplexity
from openapi.openapi_server.models.text_complexity_form import TextComplexityForm
from openapi.openapi_server.models.text_complexity_form_base import TextComplexityFormBase
from openapi.openapi_server.models.text_complexity_form_extension import TextComplexityFormExtension
from openapi.openapi_server.models.vector_network_form import VectorNetworkForm
from openapi.openapi_server.models.vocabulary_form import VocabularyForm
from openapi.openapi_server.models.vocabulary_mc import VocabularyMC
......@@ -23,7 +23,7 @@ class AnnisResponse(Model):
Do not edit the class manually.
"""
def __init__(self, exercise_id=None, exercise_type=None, frequency_analysis=None, graph_data=None, solutions=None, text_complexity=None, uri=None): # noqa: E501
def __init__(self, exercise_id='', exercise_type='', frequency_analysis=None, graph_data=None, solutions=None, text_complexity=None, uri=''): # noqa: E501
"""AnnisResponse - a model defined in OpenAPI
:param exercise_id: The exercise_id of this AnnisResponse. # noqa: E501
......
# coding: utf-8
from __future__ import absolute_import
from datetime import date, datetime # noqa: F401
from typing import List, Dict # noqa: F401
from openapi.openapi_server.models.base_model_ import Model
from openapi.openapi_server import util