blueprints.py 6.92 KB
Newer Older
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
1
2
#!/usr/bin/python
# -*- coding: utf-8 -*-
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
3
4
# Copyright 2014 J. Fernando Sánchez Rada - Grupo de Sistemas Inteligentes
# DIT, UPM
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
5
#
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
6
7
8
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
9
#
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
10
# http://www.apache.org/licenses/LICENSE-2.0
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
11
#
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
12
# Unless required by applicable law or agreed to in writing, software
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
13
14
15
16
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
17
18
19
"""
Blueprints for Senpy
"""
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
20
from flask import Blueprint, request, current_app, render_template
21
from .models import Error, Response, Plugins
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
22
from future.utils import iteritems
23

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
24
import json
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
25
import logging
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
26

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
27
28
logger = logging.getLogger(__name__)

29
nif_blueprint = Blueprint("NIF Sentiment Analysis Server", __name__)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
30
demo_blueprint = Blueprint("Demo of the service. It includes an HTML+Javascript playground to test senpy", __name__)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
31

32
API_PARAMS = {
33
34
35
36
37
38
39
40
    "algorithm": {
        "aliases": ["algorithm", "a", "algo"],
        "required": False,
    },
    "inHeaders": {
        "aliases": ["inHeaders", "headers"],
        "required": True,
        "default": "0"
41
42
43
44
45
46
47
    },
    "prefix": {
        "@id": "prefix",
        "aliases": ["prefix", "p"],
        "required": True,
        "default": "",
    },
48
49
}

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
BASIC_PARAMS = {
    "algorithm": {
        "aliases": ["algorithm", "a", "algo"],
        "required": False,
    },
    "inHeaders": {
        "aliases": ["inHeaders", "headers"],
        "required": True,
        "default": "0"
    },
    "input": {
        "@id": "input",
        "aliases": ["i", "input"],
        "required": True,
        "help": "Input text"
    },
    "informat": {
        "@id": "informat",
        "aliases": ["f", "informat"],
        "required": False,
        "default": "text",
        "options": ["turtle", "text"],
    },
    "intype": {
        "@id": "intype",
        "aliases": ["intype", "t"],
        "required": False,
        "default": "direct",
        "options": ["direct", "url", "file"],
    },
    "outformat": {
        "@id": "outformat",
        "aliases": ["outformat", "o"],
        "default": "json-ld",
        "required": False,
        "options": ["json-ld"],
    },
    "language": {
        "@id": "language",
        "aliases": ["language", "l"],
        "required": False,
    },
    "prefix": {
        "@id": "prefix",
        "aliases": ["prefix", "p"],
        "required": True,
        "default": "",
    },
    "urischeme": {
        "@id": "urischeme",
        "aliases": ["urischeme", "u"],
        "required": False,
        "default": "RFC5147String",
        "options": "RFC5147String"
    },
}

107
def get_params(req, params=BASIC_PARAMS):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
108
109
    if req.method == 'POST':
        indict = req.form
J. Fernando Sánchez's avatar
Oups    
J. Fernando Sánchez committed
110
    elif req.method == 'GET':
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
111
112
        indict = req.args
    else:
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
113
        raise Error(message="Invalid data")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
114
115

    outdict = {}
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
116
    wrong_params = {}
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
117
    for param, options in iteritems(params):
118
119
120
121
122
123
124
125
126
127
128
        if param[0] != "@":  # Exclude json-ld properties
            logger.debug("Param: %s - Options: %s", param, options)
            for alias in options["aliases"]:
                if alias in indict:
                    outdict[param] = indict[alias]
            if param not in outdict:
                if options.get("required", False) and "default" not in options:
                    wrong_params[param] = params[param]
                else:
                    if "default" in options:
                        outdict[param] = options["default"]
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
129
            else:
130
131
132
                if "options" in params[param] and \
                   outdict[param] not in params[param]["options"]:
                    wrong_params[param] = params[param]
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
133
    if wrong_params:
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
134
135
136
137
138
        message = Error(status=404,
                        message="Missing or invalid parameters",
                        parameters=outdict,
                        errors={param: error for param, error in
                                iteritems(wrong_params)})
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
139
        raise Error(message=message)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
140
141
    return outdict

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
142

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
143
def basic_analysis(params):
144
145
146
147
148
149
150
    response = {"@context":
                [("http://demos.gsi.dit.upm.es/"
                  "eurosentiment/static/context.jsonld"),
                 {
                    "@base": "{}#".format(request.url.encode('utf-8'))
                  }
                 ],
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
151
                "analysis": [{"@type": "marl:SentimentAnalysis"}],
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
152
153
154
155
                "entries": []
                }
    if "language" in params:
        response["language"] = params["language"]
156
    for idx, sentence in enumerate(params["input"].split(".")):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
157
        response["entries"].append({
158
            "@id": "Sentence{}".format(idx),
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
159
160
161
162
            "nif:isString": sentence
        })
    return response

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
163

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
164
@demo_blueprint.route('/')
Ignacio Corcuera's avatar
Ignacio Corcuera committed
165
166
167
168
def index():
    return render_template("index.html")


J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
169
@nif_blueprint.route('/', methods=['POST', 'GET'])
Ignacio Corcuera's avatar
Ignacio Corcuera committed
170
def api():
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
171
    try:
172
173
        params = get_params(request)
        algo = params.get("algorithm", None)
174
        specific_params = current_app.senpy.parameters(algo)
175
176
        logger.debug(
            "Specific params: %s", json.dumps(specific_params, indent=4))
177
        params.update(get_params(request, specific_params))
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
178
        response = current_app.senpy.analyse(**params)
179
        in_headers = params["inHeaders"] != "0"
180
181
        prefix = params["prefix"]
        return response.flask(in_headers=in_headers, prefix=prefix)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
182
    except Error as ex:
183
        return ex.message.flask()
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
184

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
185

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
186
@nif_blueprint.route('/plugins/', methods=['POST', 'GET'])
187
188
189
190
191
192
def plugins():
    in_headers = get_params(request, API_PARAMS)["inHeaders"] != "0"
    sp = current_app.senpy
    dic = Plugins(plugins=list(sp.plugins.values()))
    return dic.flask(in_headers=in_headers)
    
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
193
194
@nif_blueprint.route('/plugins/<plugin>/', methods=['POST', 'GET'])
@nif_blueprint.route('/plugins/<plugin>/<action>', methods=['POST', 'GET'])
195
def plugin(plugin=None, action="list"):
196
    params = get_params(request, API_PARAMS)
197
    filt = {}
198
    sp = current_app.senpy
199
200
201
202
203
204
205
206
    plugs = sp.filter_plugins(name=plugin)
    if plugin == 'default' and sp.default_plugin:
        response = sp.default_plugin
        plugin = response.name
    elif plugin in sp.plugins:
        response = sp.plugins[plugin]
    else:
        return Error(message="Plugin not found", status=404).flask()
207
    if action == "list":
208
209
210
        in_headers = params["inHeaders"] != "0"
        prefix = params['prefix']
        return response.flask(in_headers=in_headers, prefix=prefix)
211
212
213
    method = "{}_plugin".format(action)
    if(hasattr(sp, method)):
        getattr(sp, method)(plugin)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
214
        return Response(message="Ok").flask()
215
    else:
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
216
        return Error(message="action '{}' not allowed".format(action)).flask()
217

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
218
if __name__ == '__main__':
219
    import config
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
220

221
    app.register_blueprint(nif_blueprint)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
222
    app.debug = config.DEBUG
Ignacio Corcuera's avatar
Ignacio Corcuera committed
223
    app.run(host='0.0.0.0', port=5000)