Passed
Pull Request — master (#658)
by
unknown
05:27
created

annif.rest.show_info()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
"""Definitions for REST API operations. These are wired via Connexion to
2
methods defined in the Swagger specification."""
3
4
import importlib
5
6
import connexion
7
8
import annif.registry
9
from annif.corpus import Document, DocumentList, SubjectSet
10
from annif.exception import AnnifException
11
from annif.project import Access
12
from annif.suggestion import SuggestionFilter
13
14
15
def project_not_found_error(project_id):
16
    """return a Connexion error object when a project is not found"""
17
18
    return connexion.problem(
19
        status=404,
20
        title="Project not found",
21
        detail="Project '{}' not found".format(project_id),
22
    )
23
24
25
def server_error(err):
26
    """return a Connexion error object when there is a server error (project
27
    or backend problem)"""
28
29
    return connexion.problem(
30
        status=503, title="Service unavailable", detail=err.format_message()
31
    )
32
33
34
def show_info():
35
    """return version of annif and a title for the api according to Swager spec"""
36
37
    return {
38
        "title": "Annif REST API",
39
        "version": importlib.metadata.version("annif")
40
    }
41
42
43
def list_projects():
44
    """return a dict with projects formatted according to Swagger spec"""
45
46
    return {
47
        "projects": [
48
            proj.dump()
49
            for proj in annif.registry.get_projects(min_access=Access.public).values()
50
        ]
51
    }
52
53
54
def show_project(project_id):
55
    """return a single project formatted according to Swagger spec"""
56
57
    try:
58
        project = annif.registry.get_project(project_id, min_access=Access.hidden)
59
    except ValueError:
60
        return project_not_found_error(project_id)
61
    return project.dump()
62
63
64
def _suggestion_to_dict(suggestion, subject_index, language):
65
    subject = subject_index[suggestion.subject_id]
66
    return {
67
        "uri": subject.uri,
68
        "label": subject.labels[language],
69
        "notation": subject.notation,
70
        "score": suggestion.score,
71
    }
72
73
74
def suggest(project_id, body):
75
    """suggest subjects for the given text and return a dict with results
76
    formatted according to Swagger spec"""
77
78
    try:
79
        project = annif.registry.get_project(project_id, min_access=Access.hidden)
80
    except ValueError:
81
        return project_not_found_error(project_id)
82
83
    try:
84
        lang = body.get("language") or project.vocab_lang
85
    except AnnifException as err:
86
        return server_error(err)
87
88
    if lang not in project.vocab.languages:
89
        return connexion.problem(
90
            status=400,
91
            title="Bad Request",
92
            detail=f'language "{lang}" not supported by vocabulary',
93
        )
94
95
    limit = body.get("limit", 10)
96
    threshold = body.get("threshold", 0.0)
97
98
    try:
99
        hit_filter = SuggestionFilter(project.subjects, limit, threshold)
100
        result = project.suggest(body["text"])
101
    except AnnifException as err:
102
        return server_error(err)
103
104
    hits = hit_filter(result).as_list()
105
    return {
106
        "results": [_suggestion_to_dict(hit, project.subjects, lang) for hit in hits]
107
    }
108
109
110
def _documents_to_corpus(documents, subject_index):
111
    corpus = [
112
        Document(
113
            text=d["text"],
114
            subject_set=SubjectSet(
115
                [subject_index.by_uri(subj["uri"]) for subj in d["subjects"]]
116
            ),
117
        )
118
        for d in documents
119
        if "text" in d and "subjects" in d
120
    ]
121
    return DocumentList(corpus)
122
123
124
def learn(project_id, body):
125
    """learn from documents and return an empty 204 response if succesful"""
126
127
    try:
128
        project = annif.registry.get_project(project_id, min_access=Access.hidden)
129
    except ValueError:
130
        return project_not_found_error(project_id)
131
132
    try:
133
        corpus = _documents_to_corpus(body, project.subjects)
134
        project.learn(corpus)
135
    except AnnifException as err:
136
        return server_error(err)
137
138
    return None, 204
139