blueprints.py 6.67 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
41
42
43
    "algorithm": {
        "aliases": ["algorithm", "a", "algo"],
        "required": False,
    },
    "inHeaders": {
        "aliases": ["inHeaders", "headers"],
        "required": True,
        "default": "0"
    }
}

44
45
46
47
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
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"
    },
}

101
def get_params(req, params=BASIC_PARAMS):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
102
103
    if req.method == 'POST':
        indict = req.form
J. Fernando Sánchez's avatar
Oups    
J. Fernando Sánchez committed
104
    elif req.method == 'GET':
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
105
106
        indict = req.args
    else:
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
107
        raise Error(message="Invalid data")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
108
109

    outdict = {}
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
110
    wrong_params = {}
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
111
    for param, options in iteritems(params):
112
113
114
115
116
117
118
119
120
121
122
        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
123
            else:
124
125
126
                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
127
    if wrong_params:
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
128
129
130
131
132
        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
133
        raise Error(message=message)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
134
135
    return outdict

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

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
137
def basic_analysis(params):
138
139
140
141
142
143
144
    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
145
                "analysis": [{"@type": "marl:SentimentAnalysis"}],
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
146
147
148
149
                "entries": []
                }
    if "language" in params:
        response["language"] = params["language"]
150
    for idx, sentence in enumerate(params["input"].split(".")):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
151
        response["entries"].append({
152
            "@id": "Sentence{}".format(idx),
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
153
154
155
156
            "nif:isString": sentence
        })
    return response

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

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
158
@demo_blueprint.route('/')
Ignacio Corcuera's avatar
Ignacio Corcuera committed
159
160
161
162
def index():
    return render_template("index.html")


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

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

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
179
@nif_blueprint.route('/plugins/', methods=['POST', 'GET'])
180
181
182
183
184
185
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
186
187
@nif_blueprint.route('/plugins/<plugin>/', methods=['POST', 'GET'])
@nif_blueprint.route('/plugins/<plugin>/<action>', methods=['POST', 'GET'])
188
def plugin(plugin=None, action="list"):
189
    filt = {}
190
    sp = current_app.senpy
191
192
193
194
195
196
197
198
    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()
199
    if action == "list":
200
201
        in_headers = get_params(request, API_PARAMS)["inHeaders"] != "0"
        return response.flask(in_headers=in_headers)
202
203
204
    method = "{}_plugin".format(action)
    if(hasattr(sp, method)):
        getattr(sp, method)(plugin)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
205
        return Response(message="Ok").flask()
206
    else:
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
207
        return Error(message="action '{}' not allowed".format(action)).flask()
208

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
209
if __name__ == '__main__':
210
    import config
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
211

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