diff --git a/CHANGELOG.md b/CHANGELOG.md index e0f0583..536392d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [1.0.1] +### Added +* License headers +* Description for PyPI (setup.py) + +### Changed +* The evaluation tab shows datasets inline, and a tooltip shows the number of instances +* The docs should be clearer now +## [1.0.0] ### Fixed * Restored hash changing function in `main.js` diff --git a/docs/Quickstart-30minutes.ipynb b/docs/Advanced.ipynb similarity index 90% rename from docs/Quickstart-30minutes.ipynb rename to docs/Advanced.ipynb index d733d48..d376794 100644 --- a/docs/Quickstart-30minutes.ipynb +++ b/docs/Advanced.ipynb @@ -4,20 +4,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Senpy in 30 minutes" + "# Advanced features" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This tutorial takes up where the [10 minute tutorial](Quickstart-10minutes.ipynb) left off.\n", + "This tutorial takes up where the [basic tutorial](Quickstart.ipynb) left off.\n", "\n", "It covers more advanced tasks such as:\n", "\n", - "* Asking for specific emotion models (automatic model conversion)\n", "* Listing available services in an endpoint\n", - "* Transforming the results\n", + "* Transforming the results of a service\n", "* Calling multiple services in the same request (Pipelines)\n", "* Running your own Senpy instance" ] @@ -47,25 +46,22 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import requests\n", - "try:\n", - " from IPython.display import Code\n", - " def pretty(txt, language='json-ld'):\n", - " return Code(txt, language=language)\n", - "except ImportError:\n", - " def pretty(txt, **kwargs):\n", - " print(txt)" + "from IPython.display import Code\n", + " \n", + "def query(endpoint, raw=False, **kwargs):\n", + " '''Query a given Senpy endpoint with specific parameters, and prettify the output'''\n", + " res = requests.get(endpoint,\n", + " params=kwargs)\n", + " if raw:\n", + " return res\n", + " return Code(res.text, language=kwargs.get('outformat', 'json-ld'))" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, { "cell_type": "markdown", "metadata": {}, @@ -87,137 +83,7 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[\"Senpy is a wonderful service\"]\n" - ] - } - ], - "source": [ - "res = requests.get(f'{endpoint}/sentiment140',\n", - " params={\"input\": \"Senpy is a wonderful service\",\n", - " \"fields\": 'entries[].\"nif:isString\"'})\n", - "print(res.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or we could get both the text and the polarity of the text (assuming there is only one opinion per entry) with a slightly more complicated query:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[\"Senpy is a service. Wonderful service.\", \"marl:Neutral\"]\n" - ] - } - ], - "source": [ - "res = requests.get(f'{endpoint}/sentiment140',\n", - " params={\"input\": \"Senpy is a service. Wonderful service.\",\n", - " \"delimiter\": \"sentence\",\n", - " \"fields\": 'entries[0].[\"nif:isString\", \"marl:hasOpinion\"[0].\"marl:hasPolarity\"]'})\n", - "print(res.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "jmespath is rather extensive for this tutorial. We will cover only the most simple cases, so you do not need to learn much about the notation.\n", - "\n", - "For more complicated transformations, check out [jmespath](http://jmespath.org).\n", - "In addition to a fairly complete documentation, they have a live environment you can use to test your queries." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Emotion conversion" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If the model used by a plugin is not right for your application, you can ask for a specific emotion model in your request.\n", - "\n", - "Senpy ships with emotion conversion capabilities, and it will try to automatically convert the results.\n", - "\n", - "For example, the `emotion-anew` plugin uses the dimensional `pad` (or VAD, valence-arousal-dominance) model, as we can see here:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQj\",\n", - " \"@type\": \"Results\",\n", - " \"entries\": [\n", - " {\n", - " \"@id\": \"prefix:\",\n", - " \"@type\": \"Entry\",\n", - " \"marl:hasOpinion\": [],\n", - " \"nif:isString\": \"Senpy is a wonderful service and I love it\",\n", - " \"onyx:hasEmotionSet\": [\n", - " {\n", - " \"@id\": \"Emotions0\",\n", - " \"@type\": \"EmotionSet\",\n", - " \"onyx:hasEmotion\": [\n", - " {\n", - " \"@id\": \"Emotion0\",\n", - " \"@type\": \"Emotion\",\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal\": 6.44,\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance\": 7.11,\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence\": 8.72,\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382982.775705\"\n", - " }\n", - " ],\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382982.775705\"\n", - " }\n", - " ]\n", - " }\n", - " ]\n", - "}\n" - ] - } - ], - "source": [ - "res = requests.get(f'{endpoint}/emotion-anew',\n", - " params={\"input\": \"Senpy is a wonderful service and I love it\"})\n", - "print(res.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we need a category level, we can ask for the equivalent results in the `big6` model:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -291,163 +157,39 @@ ".output_html .vg { color: #19177C } /* Name.Variable.Global */\n", ".output_html .vi { color: #19177C } /* Name.Variable.Instance */\n", ".output_html .vm { color: #19177C } /* Name.Variable.Magic */\n", - ".output_html .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
-       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbi1tb2RlbD1lbW9tbCUzQWJpZzYj",\n",
-       "  "@type": "Results",\n",
-       "  "entries": [\n",
-       "    {\n",
-       "      "@id": "prefix:",\n",
-       "      "@type": "Entry",\n",
-       "      "marl:hasOpinion": [],\n",
-       "      "nif:isString": "Senpy is a wonderful service and I love it",\n",
-       "      "onyx:hasEmotionSet": [\n",
-       "        {\n",
-       "          "@id": "Emotions0",\n",
-       "          "@type": "EmotionSet",\n",
-       "          "onyx:hasEmotion": [\n",
-       "            {\n",
-       "              "@id": "Emotion0",\n",
-       "              "@type": "Emotion",\n",
-       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal": 6.44,\n",
-       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance": 7.11,\n",
-       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence": 8.72,\n",
-       "              "prov:wasGeneratedBy": "prefix:Analysis_1554382982.8068626"\n",
-       "            }\n",
-       "          ],\n",
-       "          "prov:wasGeneratedBy": "prefix:Analysis_1554382982.8068626"\n",
-       "        },\n",
-       "        {\n",
-       "          "@type": "EmotionSet",\n",
-       "          "onyx:hasEmotion": [\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:algorithmConfidence": 7.449999999999999,\n",
-       "              "onyx:hasEmotionCategory": "emoml:big6fear"\n",
-       "            }\n",
-       "          ],\n",
-       "          "prov:wasGeneratedBy": "prefix:Analysis_1554382982.8106468"\n",
-       "        }\n",
-       "      ]\n",
-       "    }\n",
-       "  ]\n",
-       "}\n",
+       ".output_html .il { color: #666666 } /* Literal.Number.Integer.Long */
["Senpy is a wonderful service"]\n",
        "
\n" ], "text/latex": [ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbi1tb2RlbD1lbW9tbCUzQWJpZzYj\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service and I love it\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotions0\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion0\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}arousal\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{6.44}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}dominance\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{7.11}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}valence\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{8.72}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382982.8068626\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382982.8068626\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:algorithmConfidence\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{7.449999999999999}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}emoml:big6fear\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382982.8106468\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - "\\PY{p}{\\PYZcb{}}\n", + "\\PY{p}{[}\\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service\\PYZdq{}}\\PY{p}{]}\n", "\\end{Verbatim}\n" ], "text/plain": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbi1tb2RlbD1lbW9tbCUzQWJpZzYj\",\n", - " \"@type\": \"Results\",\n", - " \"entries\": [\n", - " {\n", - " \"@id\": \"prefix:\",\n", - " \"@type\": \"Entry\",\n", - " \"marl:hasOpinion\": [],\n", - " \"nif:isString\": \"Senpy is a wonderful service and I love it\",\n", - " \"onyx:hasEmotionSet\": [\n", - " {\n", - " \"@id\": \"Emotions0\",\n", - " \"@type\": \"EmotionSet\",\n", - " \"onyx:hasEmotion\": [\n", - " {\n", - " \"@id\": \"Emotion0\",\n", - " \"@type\": \"Emotion\",\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal\": 6.44,\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance\": 7.11,\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence\": 8.72,\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382982.8068626\"\n", - " }\n", - " ],\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382982.8068626\"\n", - " },\n", - " {\n", - " \"@type\": \"EmotionSet\",\n", - " \"onyx:hasEmotion\": [\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:algorithmConfidence\": 7.449999999999999,\n", - " \"onyx:hasEmotionCategory\": \"emoml:big6fear\"\n", - " }\n", - " ],\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382982.8106468\"\n", - " }\n", - " ]\n", - " }\n", - " ]\n", - "}" + "[\"Senpy is a wonderful service\"]" ] }, - "execution_count": 14, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/emotion-anew',\n", - " params={\"input\": \"Senpy is a wonderful service and I love it\",\n", - " \"emotion-model\": \"emoml:big6\"})\n", - "pretty(res.text)" + "query(f'{endpoint}/sentiment140',\n", + " input=\"Senpy is a wonderful service\",\n", + " fields='entries[].\"nif:isString\"')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Because we don't usually care about the original emotion, the conversion can be presented in three ways:\n", - "\n", - "* full: the original and converted emotions are included at the same level\n", - "* filtered: the original emotion is replaced by the converted emotion\n", - "* nested: the original emotion is replaced, but the converted emotion points to it\n", - "\n", - "For example, here's how the `nested` structure would look like:" + "Or we could get both the text and the polarity of the text (assuming there is only one opinion per entry) with a slightly more complicated query:" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -521,158 +263,57 @@ ".output_html .vg { color: #19177C } /* Name.Variable.Global */\n", ".output_html .vi { color: #19177C } /* Name.Variable.Instance */\n", ".output_html .vm { color: #19177C } /* Name.Variable.Magic */\n", - ".output_html .il { color: #666666 } /* Literal.Number.Integer.Long */
{\n",
-       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbi1tb2RlbD1lbW9tbCUzQWJpZzYmY29udmVyc2lvbj1uZXN0ZWQj",\n",
-       "  "@type": "Results",\n",
-       "  "entries": [\n",
-       "    {\n",
-       "      "@id": "prefix:",\n",
-       "      "@type": "Entry",\n",
-       "      "marl:hasOpinion": [],\n",
-       "      "nif:isString": "Senpy is a wonderful service and I love it",\n",
-       "      "onyx:hasEmotionSet": [\n",
-       "        {\n",
-       "          "@type": "EmotionSet",\n",
-       "          "onyx:hasEmotion": [\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:algorithmConfidence": 7.449999999999999,\n",
-       "              "onyx:hasEmotionCategory": "emoml:big6fear"\n",
-       "            }\n",
-       "          ],\n",
-       "          "prov:wasDerivedFrom": {\n",
-       "            "@id": "Emotions0",\n",
-       "            "@type": "EmotionSet",\n",
-       "            "onyx:hasEmotion": [\n",
-       "              {\n",
-       "                "@id": "Emotion0",\n",
-       "                "@type": "Emotion",\n",
-       "                "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal": 6.44,\n",
-       "                "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance": 7.11,\n",
-       "                "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence": 8.72,\n",
-       "                "prov:wasGeneratedBy": "prefix:Analysis_1554382982.8948743"\n",
-       "              }\n",
-       "            ],\n",
-       "            "prov:wasGeneratedBy": "prefix:Analysis_1554382982.8948743"\n",
-       "          },\n",
-       "          "prov:wasGeneratedBy": "prefix:Analysis_1554382982.8985674"\n",
-       "        }\n",
-       "      ]\n",
-       "    }\n",
-       "  ]\n",
-       "}\n",
+       ".output_html .il { color: #666666 } /* Literal.Number.Integer.Long */
["Senpy is a service. Wonderful service.", "marl:Neutral"]\n",
        "
\n" ], "text/latex": [ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbi1tb2RlbD1lbW9tbCUzQWJpZzYmY29udmVyc2lvbj1uZXN0ZWQj\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service and I love it\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:algorithmConfidence\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{7.449999999999999}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}emoml:big6fear\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasDerivedFrom\\PYZdq{}}\\PY{p}{:} \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotions0\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion0\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}arousal\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{6.44}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}dominance\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{7.11}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}valence\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{8.72}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382982.8948743\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382982.8948743\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382982.8985674\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - "\\PY{p}{\\PYZcb{}}\n", + "\\PY{p}{[}\\PY{l+s+s2}{\\PYZdq{}Senpy is a service. Wonderful service.\\PYZdq{}}\\PY{p}{,} \\PY{l+s+s2}{\\PYZdq{}marl:Neutral\\PYZdq{}}\\PY{p}{]}\n", "\\end{Verbatim}\n" ], "text/plain": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbi1tb2RlbD1lbW9tbCUzQWJpZzYmY29udmVyc2lvbj1uZXN0ZWQj\",\n", - " \"@type\": \"Results\",\n", - " \"entries\": [\n", - " {\n", - " \"@id\": \"prefix:\",\n", - " \"@type\": \"Entry\",\n", - " \"marl:hasOpinion\": [],\n", - " \"nif:isString\": \"Senpy is a wonderful service and I love it\",\n", - " \"onyx:hasEmotionSet\": [\n", - " {\n", - " \"@type\": \"EmotionSet\",\n", - " \"onyx:hasEmotion\": [\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:algorithmConfidence\": 7.449999999999999,\n", - " \"onyx:hasEmotionCategory\": \"emoml:big6fear\"\n", - " }\n", - " ],\n", - " \"prov:wasDerivedFrom\": {\n", - " \"@id\": \"Emotions0\",\n", - " \"@type\": \"EmotionSet\",\n", - " \"onyx:hasEmotion\": [\n", - " {\n", - " \"@id\": \"Emotion0\",\n", - " \"@type\": \"Emotion\",\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal\": 6.44,\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance\": 7.11,\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence\": 8.72,\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382982.8948743\"\n", - " }\n", - " ],\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382982.8948743\"\n", - " },\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382982.8985674\"\n", - " }\n", - " ]\n", - " }\n", - " ]\n", - "}" + "[\"Senpy is a service. Wonderful service.\", \"marl:Neutral\"]" ] }, - "execution_count": 15, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/emotion-anew',\n", - " params={\"input\": \"Senpy is a wonderful service and I love it\",\n", - " \"emotion-model\": \"emoml:big6\",\n", - " \"conversion\": \"nested\"})\n", - "pretty(res.text)" + "query(f'{endpoint}/sentiment140',\n", + " input=\"Senpy is a service. Wonderful service.\",\n", + " delimiter=\"sentence\",\n", + " fields='entries[0].[\"nif:isString\", \"marl:hasOpinion\"[0].\"marl:hasPolarity\"]')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "jmespath is rather extensive for this tutorial. We will cover only the most simple cases, so you do not need to learn much about the notation.\n", + "\n", + "For more complicated transformations, check out [jmespath](http://jmespath.org).\n", + "In addition to a fairly complete documentation, they have a live environment you can use to test your queries." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Emotion conversion with field selection" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Again, for completion, we could get only the label with the `fields` parameter:" + "We could mix emotion conversion with field selection to only get the label of an emotion analysis that has been automatically converted:" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -746,30 +387,29 @@ ".output_html .vg { color: #19177C } /* Name.Variable.Global */\n", ".output_html .vi { color: #19177C } /* Name.Variable.Instance */\n", ".output_html .vm { color: #19177C } /* Name.Variable.Magic */\n", - ".output_html .il { color: #666666 } /* Literal.Number.Integer.Long */
[["Senpy is a wonderful service and I love it", "emoml:big6fear"]]\n",
+       ".output_html .il { color: #666666 } /* Literal.Number.Integer.Long */
[["Senpy is a wonderful service and I love it"]]\n",
        "
\n" ], "text/latex": [ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{p}{[}\\PY{p}{[}\\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service and I love it\\PYZdq{}}\\PY{p}{,} \\PY{l+s+s2}{\\PYZdq{}emoml:big6fear\\PYZdq{}}\\PY{p}{]}\\PY{p}{]}\n", + "\\PY{p}{[}\\PY{p}{[}\\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service and I love it\\PYZdq{}}\\PY{p}{]}\\PY{p}{]}\n", "\\end{Verbatim}\n" ], "text/plain": [ - "[[\"Senpy is a wonderful service and I love it\", \"emoml:big6fear\"]]" + "[[\"Senpy is a wonderful service and I love it\"]]" ] }, - "execution_count": 16, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/emotion-anew',\n", - " params={\"input\": \"Senpy is a wonderful service and I love it\",\n", - " \"emotion-model\": \"emoml:big6\",\n", - " \"fields\": 'entries[].[[\"nif:isString\",\"onyx:hasEmotionSet\"[].\"onyx:hasEmotion\"[].\"onyx:hasEmotionCategory\"][]][]',\n", - " \"conversion\": \"filtered\"})\n", - "pretty(res.text)" + "query(f'{endpoint}/emotion-anew',\n", + " input=\"Senpy is a wonderful service and I love it\",\n", + " emotionmodel=\"emoml:big6\",\n", + " fields='entries[].[[\"nif:isString\",\"onyx:hasEmotionSet\"[].\"onyx:hasEmotion\"[].\"onyx:hasEmotionCategory\"][]][]',\n", + " conversion=\"filtered\")" ] }, { @@ -793,7 +433,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -878,7 +518,7 @@ " {\n", " "@type": "Sentiment",\n", " "marl:hasPolarity": "marl:Neutral",\n", - " "prov:wasGeneratedBy": "prefix:Analysis_1554382983.2991712"\n", + " "prov:wasGeneratedBy": "prefix:Analysis_1563369539.5176148"\n", " }\n", " ],\n", " "nif:isString": "Senpy is a wonderful service",\n", @@ -927,7 +567,7 @@ " "onyx:hasEmotionIntensity": 0.09950234435617733\n", " }\n", " ],\n", - " "prov:wasGeneratedBy": "prefix:Analysis_1554382983.3010163"\n", + " "prov:wasGeneratedBy": "prefix:Analysis_1563369539.5185866"\n", " }\n", " ]\n", " }\n", @@ -948,7 +588,7 @@ " \\PY{p}{\\PYZob{}}\n", " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Neutral\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382983.2991712\\PYZdq{}}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563369539.5176148\\PYZdq{}}\n", " \\PY{p}{\\PYZcb{}}\n", " \\PY{p}{]}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service\\PYZdq{}}\\PY{p}{,}\n", @@ -997,7 +637,7 @@ " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.09950234435617733}\n", " \\PY{p}{\\PYZcb{}}\n", " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382983.3010163\\PYZdq{}}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563369539.5185866\\PYZdq{}}\n", " \\PY{p}{\\PYZcb{}}\n", " \\PY{p}{]}\n", " \\PY{p}{\\PYZcb{}}\n", @@ -1017,7 +657,7 @@ " {\n", " \"@type\": \"Sentiment\",\n", " \"marl:hasPolarity\": \"marl:Neutral\",\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382983.2991712\"\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563369539.5176148\"\n", " }\n", " ],\n", " \"nif:isString\": \"Senpy is a wonderful service\",\n", @@ -1066,7 +706,7 @@ " \"onyx:hasEmotionIntensity\": 0.09950234435617733\n", " }\n", " ],\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382983.3010163\"\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563369539.5185866\"\n", " }\n", " ]\n", " }\n", @@ -1074,15 +714,14 @@ "}" ] }, - "execution_count": 17, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/sentiment140/emotion-depechemood',\n", - " params={\"input\": \"Senpy is a wonderful service\"})\n", - "pretty(res.text)" + "query(f'{endpoint}/sentiment140/emotion-depechemood',\n", + " input=\"Senpy is a wonderful service\")" ] }, { @@ -1102,7 +741,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -1187,7 +826,7 @@ " {\n", " "@type": "Sentiment",\n", " "marl:hasPolarity": "marl:Positive",\n", - " "prov:wasGeneratedBy": "prefix:Analysis_1554382983.5748618"\n", + " "prov:wasGeneratedBy": "prefix:Analysis_1563369539.7878842"\n", " }\n", " ],\n", " "nif:isString": "Senpy is awesome. And services are composable.",\n", @@ -1200,7 +839,7 @@ " {\n", " "@type": "Sentiment",\n", " "marl:hasPolarity": "marl:Positive",\n", - " "prov:wasGeneratedBy": "prefix:Analysis_1554382983.5748618"\n", + " "prov:wasGeneratedBy": "prefix:Analysis_1563369539.7878842"\n", " }\n", " ],\n", " "nif:isString": "Senpy is awesome.",\n", @@ -1213,7 +852,7 @@ " {\n", " "@type": "Sentiment",\n", " "marl:hasPolarity": "marl:Neutral",\n", - " "prov:wasGeneratedBy": "prefix:Analysis_1554382983.5748618"\n", + " "prov:wasGeneratedBy": "prefix:Analysis_1563369539.7878842"\n", " }\n", " ],\n", " "nif:isString": "And services are composable.",\n", @@ -1236,7 +875,7 @@ " \\PY{p}{\\PYZob{}}\n", " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Positive\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382983.5748618\\PYZdq{}}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563369539.7878842\\PYZdq{}}\n", " \\PY{p}{\\PYZcb{}}\n", " \\PY{p}{]}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is awesome. And services are composable.\\PYZdq{}}\\PY{p}{,}\n", @@ -1249,7 +888,7 @@ " \\PY{p}{\\PYZob{}}\n", " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Positive\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382983.5748618\\PYZdq{}}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563369539.7878842\\PYZdq{}}\n", " \\PY{p}{\\PYZcb{}}\n", " \\PY{p}{]}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is awesome.\\PYZdq{}}\\PY{p}{,}\n", @@ -1262,7 +901,7 @@ " \\PY{p}{\\PYZob{}}\n", " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Neutral\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382983.5748618\\PYZdq{}}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563369539.7878842\\PYZdq{}}\n", " \\PY{p}{\\PYZcb{}}\n", " \\PY{p}{]}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}And services are composable.\\PYZdq{}}\\PY{p}{,}\n", @@ -1284,7 +923,7 @@ " {\n", " \"@type\": \"Sentiment\",\n", " \"marl:hasPolarity\": \"marl:Positive\",\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382983.5748618\"\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563369539.7878842\"\n", " }\n", " ],\n", " \"nif:isString\": \"Senpy is awesome. And services are composable.\",\n", @@ -1297,7 +936,7 @@ " {\n", " \"@type\": \"Sentiment\",\n", " \"marl:hasPolarity\": \"marl:Positive\",\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382983.5748618\"\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563369539.7878842\"\n", " }\n", " ],\n", " \"nif:isString\": \"Senpy is awesome.\",\n", @@ -1310,7 +949,7 @@ " {\n", " \"@type\": \"Sentiment\",\n", " \"marl:hasPolarity\": \"marl:Neutral\",\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382983.5748618\"\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563369539.7878842\"\n", " }\n", " ],\n", " \"nif:isString\": \"And services are composable.\",\n", @@ -1320,18 +959,17 @@ "}" ] }, - "execution_count": 18, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/split/sentiment140',\n", - " params={\"input\": \"Senpy is awesome. And services are composable.\", \n", - " \"delimiter\": \"sentence\",\n", - " \"language\": \"en\",\n", - " \"outformat\": \"json-ld\"})\n", - "pretty(res.text)" + "query(f'{endpoint}/split/sentiment140',\n", + " input=\"Senpy is awesome. And services are composable.\", \n", + " delimiter=\"sentence\",\n", + " language=\"en\",\n", + " outformat=\"json-ld\")" ] }, { @@ -1350,7 +988,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -1436,19 +1074,18 @@ "[[\"Senpy is awesome. And services are composable.\", \"marl:Positive\"], [\"Senpy is awesome.\", \"marl:Positive\"], [\"And services are composable.\", \"marl:Neutral\"]]" ] }, - "execution_count": 19, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/split/sentiment140',\n", - " params={\"input\": \"Senpy is awesome. And services are composable.\", \n", - " \"delimiter\": \"sentence\",\n", - " \"fields\": 'entries[].[[\"nif:isString\",\"marl:hasOpinion\"[].\"marl:hasPolarity\"][]][]',\n", - " \"language\": \"en\",\n", - " \"outformat\": \"json-ld\"})\n", - "pretty(res.text)" + "query(f'{endpoint}/split/sentiment140',\n", + " input=\"Senpy is awesome. And services are composable.\", \n", + " delimiter=\"sentence\",\n", + " fields='entries[].[[\"nif:isString\",\"marl:hasOpinion\"[].\"marl:hasPolarity\"][]][]',\n", + " language=\"en\",\n", + " outformat=\"json-ld\")" ] }, { @@ -1467,7 +1104,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 9, "metadata": { "scrolled": true }, @@ -2323,14 +1960,13 @@ "}" ] }, - "execution_count": 20, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/plugins')\n", - "pretty(res.text)" + "query(f'{endpoint}/plugins')" ] }, { @@ -2343,7 +1979,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -2852,14 +2488,14 @@ "}" ] }, - "execution_count": 21, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/plugins', params={\"plugin_type\": \"SentimentPlugin\"})\n", - "pretty(res.text)" + "query(f'{endpoint}/plugins',\n", + " plugin_type=\"SentimentPlugin\")" ] }, { @@ -2871,7 +2507,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -2957,14 +2593,14 @@ "[[\"endpoint:plugins/emotion-anew_0.5.1\", \"EmotionPlugin\"], [\"endpoint:plugins/emotion-depechemood_0.1\", \"EmotionPlugin\"], [\"endpoint:plugins/emotion-wnaffect_0.2\", \"EmotionPlugin\"], [\"endpoint:plugins/example-plugin_0.1\", \"Plugin\"], [\"endpoint:plugins/sentiment-basic_0.1.1\", \"SentimentPlugin\"], [\"endpoint:plugins/sentiment-meaningcloud_1.1\", \"SentimentPlugin\"], [\"endpoint:plugins/sentiment-vader_0.1.1\", \"SentimentPlugin\"], [\"endpoint:plugins/sentiment140_0.2\", \"SentimentPlugin\"], [\"endpoint:plugins/split_0.3\", \"Plugin\"]]" ] }, - "execution_count": 22, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/plugins', params={\"fields\": 'plugins[].[\"@id\",\"@type\"]'})\n", - "pretty(res.text)" + "query(f'{endpoint}/plugins',\n", + " fields='plugins[].[\"@id\",\"@type\"]')" ] }, { @@ -2974,34 +2610,6 @@ "Alternatively:" ] }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "EmotionPlugin -> endpoint:plugins/emotion-anew_0.5.1\n", - "EmotionPlugin -> endpoint:plugins/emotion-depechemood_0.1\n", - "EmotionPlugin -> endpoint:plugins/emotion-wnaffect_0.2\n", - "Plugin -> endpoint:plugins/example-plugin_0.1\n", - "SentimentPlugin -> endpoint:plugins/sentiment-basic_0.1.1\n", - "SentimentPlugin -> endpoint:plugins/sentiment-meaningcloud_1.1\n", - "SentimentPlugin -> endpoint:plugins/sentiment-vader_0.1.1\n", - "SentimentPlugin -> endpoint:plugins/sentiment140_0.2\n", - "Plugin -> endpoint:plugins/split_0.3\n" - ] - } - ], - "source": [ - "for pid, ptype in res.json():\n", - " print('{:20s} -> {}'.format(ptype, pid))" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -3020,7 +2628,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -3331,18 +2939,16 @@ "}" ] }, - "execution_count": 24, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "res = requests.get(f'{endpoint}/evaluate',\n", - " params={\"algo\": \"sentiment-vader\",\n", - " \"dataset\": \"vader,sts\",\n", - " 'outformat': 'json-ld'\n", - " })\n", - "pretty(res.text)" + "query(f'{endpoint}/evaluate',\n", + " algo=\"sentiment-vader\",\n", + " dataset=\"vader,sts\",\n", + " outformat='json-ld')" ] }, { @@ -3419,8 +3025,10 @@ }, { "cell_type": "code", - "execution_count": 25, - "metadata": {}, + "execution_count": 13, + "metadata": { + "scrolled": true + }, "outputs": [ { "data": { @@ -3498,7 +3106,7 @@ " "@type": "Results",\n", " "activities": [\n", " {\n", - " "@id": "prefix:Analysis_1554382985.03282",\n", + " "@id": "prefix:Analysis_1563369541.408701",\n", " "@type": "Analysis",\n", " "marl:maxPolarityValue": 1,\n", " "marl:minPolarityValue": 0,\n", @@ -3590,7 +3198,7 @@ " {\n", " "@type": "Sentiment",\n", " "marl:hasPolarity": "marl:Positive",\n", - " "prov:wasGeneratedBy": "prefix:Analysis_1554382985.03282"\n", + " "prov:wasGeneratedBy": "prefix:Analysis_1563369541.408701"\n", " }\n", " ],\n", " "nif:isString": "Senpy is the best framework for semantic sentiment analysis, and very easy to use",\n", @@ -3607,7 +3215,7 @@ " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}activities\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382985.03282\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563369541.408701\\PYZdq{}}\\PY{p}{,}\n", " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Analysis\\PYZdq{}}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}marl:maxPolarityValue\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mi}{1}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}marl:minPolarityValue\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mi}{0}\\PY{p}{,}\n", @@ -3699,7 +3307,7 @@ " \\PY{p}{\\PYZob{}}\n", " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Positive\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382985.03282\\PYZdq{}}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563369541.408701\\PYZdq{}}\n", " \\PY{p}{\\PYZcb{}}\n", " \\PY{p}{]}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is the best framework for semantic sentiment analysis, and very easy to use\\PYZdq{}}\\PY{p}{,}\n", @@ -3715,7 +3323,7 @@ " \"@type\": \"Results\",\n", " \"activities\": [\n", " {\n", - " \"@id\": \"prefix:Analysis_1554382985.03282\",\n", + " \"@id\": \"prefix:Analysis_1563369541.408701\",\n", " \"@type\": \"Analysis\",\n", " \"marl:maxPolarityValue\": 1,\n", " \"marl:minPolarityValue\": 0,\n", @@ -3807,7 +3415,7 @@ " {\n", " \"@type\": \"Sentiment\",\n", " \"marl:hasPolarity\": \"marl:Positive\",\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382985.03282\"\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563369541.408701\"\n", " }\n", " ],\n", " \"nif:isString\": \"Senpy is the best framework for semantic sentiment analysis, and very easy to use\",\n", @@ -3817,18 +3425,15 @@ "}" ] }, - "execution_count": 25, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "import requests\n", - "res = requests.get(f'{endpoint}/sentiment140',\n", - " params={\n", - " \"input\": \"Senpy is the best framework for semantic sentiment analysis, and very easy to use\",\n", - " \"verbose\": True}).text\n", - "pretty(res)" + "query(f'{endpoint}/sentiment140',\n", + " input=\"Senpy is the best framework for semantic sentiment analysis, and very easy to use\",\n", + " verbose=True)" ] }, { @@ -3840,7 +3445,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -4553,17 +4158,14 @@ "}" ] }, - "execution_count": 26, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "import requests\n", - "res = requests.get(f'{endpoint}/',\n", - " params={\n", - " \"help\": True}).text\n", - "pretty(res)" + "query(f'{endpoint}/',\n", + " help=True)" ] }, { @@ -4575,7 +4177,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -4668,10 +4270,10 @@ " "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal": 4.22,\n", " "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance": 5.17,\n", " "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence": 5.2,\n", - " "prov:wasGeneratedBy": "prefix:Analysis_1554382985.2021937"\n", + " "prov:wasGeneratedBy": "prefix:Analysis_1563369541.631805"\n", " }\n", " ],\n", - " "prov:wasGeneratedBy": "prefix:Analysis_1554382985.2021937"\n", + " "prov:wasGeneratedBy": "prefix:Analysis_1563369541.631805"\n", " }\n", " ]\n", " }\n", @@ -4700,10 +4302,10 @@ " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}arousal\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{4.22}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}dominance\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{5.17}\\PY{p}{,}\n", " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}valence\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{5.2}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382985.2021937\\PYZdq{}}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563369541.631805\\PYZdq{}}\n", " \\PY{p}{\\PYZcb{}}\n", " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554382985.2021937\\PYZdq{}}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563369541.631805\\PYZdq{}}\n", " \\PY{p}{\\PYZcb{}}\n", " \\PY{p}{]}\n", " \\PY{p}{\\PYZcb{}}\n", @@ -4731,10 +4333,10 @@ " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal\": 4.22,\n", " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance\": 5.17,\n", " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence\": 5.2,\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382985.2021937\"\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563369541.631805\"\n", " }\n", " ],\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554382985.2021937\"\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563369541.631805\"\n", " }\n", " ]\n", " }\n", @@ -4742,18 +4344,15 @@ "}" ] }, - "execution_count": 27, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "import requests\n", - "res = requests.get(f'{endpoint}/',\n", - " params={\n", - " \"input\": \"This will tell senpy to only include the context in the headers\",\n", - " \"inheaders\": True})\n", - "pretty(res.text)" + "query(f'{endpoint}/',\n", + " input=\"This will tell senpy to only include the context in the headers\",\n", + " inheaders=True)" ] }, { @@ -4765,7 +4364,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -4777,15 +4376,12 @@ } ], "source": [ + "# We first repeat the query, to get the raw requests response using raw=True\n", + "res = query(f'{endpoint}/', input=\"This will tell senpy to only include the context in the headers\", inheaders=True, raw=True)\n", + "\n", + "# The URI of the context is in the headers:\n", "print(res.headers['Link'])" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/docs/Evaluation.ipynb b/docs/Evaluation.ipynb new file mode 100644 index 0000000..712e08f --- /dev/null +++ b/docs/Evaluation.ipynb @@ -0,0 +1,592 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Evaluating Services" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sentiment analysis plugins can also be evaluated on a series of pre-defined datasets.\n", + "This can be done in three ways: through the Web UI (playground), through the web API and programmatically.\n", + "\n", + "Regardless of the way you perform the evaluation, you will need to specify a plugin (service) that you want to evaluate, and a series of datasets on which it should be evaluated.\n", + "\n", + "to evaluate a plugin on a dataset, senpy use the plugin to predict the sentiment in each entry in the dataset.\n", + "These predictions are compared with the expected values to produce several metrics, such as: accuracy, precision and f1-score.\n", + "\n", + "**note**: the evaluation process might take long for plugins that use external services, such as `sentiment140`.\n", + "\n", + "**note**: plugins are assumed to be pre-trained and invariant. i.e., the prediction for an entry should " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Web UI (Playground)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The playground should contain a tab for Evaluation, where you can select any plugin that can be evaluated, and the set of datasets that you want to test the plugin on.\n", + "\n", + "For example, the image below shows the results of the `sentiment-vader` plugin on the `vader` and `sts` datasets:\n", + "\n", + "\n", + "![](eval_table.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Web API" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The api exposes an endpoint (`/evaluate`), which accents the plugin and the set of datasets on which it should be evaluated." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following code is not necessary, but it will display the results better:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is a simple call using the requests library:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
{\n",
+       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2V2YWx1YXRlLz9hbGdvPXNlbnRpbWVudC12YWRlciZkYXRhc2V0PXZhZGVyJTJDc3RzJm91dGZvcm1hdD1qc29uLWxkIw%3D%3D",\n",
+       "  "@type": "AggregatedEvaluation",\n",
+       "  "senpy:evaluations": [\n",
+       "    {\n",
+       "      "@type": "Evaluation",\n",
+       "      "evaluates": "endpoint:plugins/sentiment-vader_0.1.1__vader",\n",
+       "      "evaluatesOn": "vader",\n",
+       "      "metrics": [\n",
+       "        {\n",
+       "          "@type": "Accuracy",\n",
+       "          "value": 0.6907142857142857\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "Precision_macro",\n",
+       "          "value": 0.34535714285714286\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "Recall_macro",\n",
+       "          "value": 0.5\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "F1_macro",\n",
+       "          "value": 0.40853400929446554\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "F1_weighted",\n",
+       "          "value": 0.5643605528396403\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "F1_micro",\n",
+       "          "value": 0.6907142857142857\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "F1_macro",\n",
+       "          "value": 0.40853400929446554\n",
+       "        }\n",
+       "      ]\n",
+       "    },\n",
+       "    {\n",
+       "      "@type": "Evaluation",\n",
+       "      "evaluates": "endpoint:plugins/sentiment-vader_0.1.1__sts",\n",
+       "      "evaluatesOn": "sts",\n",
+       "      "metrics": [\n",
+       "        {\n",
+       "          "@type": "Accuracy",\n",
+       "          "value": 0.3107177974434612\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "Precision_macro",\n",
+       "          "value": 0.1553588987217306\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "Recall_macro",\n",
+       "          "value": 0.5\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "F1_macro",\n",
+       "          "value": 0.23705926481620407\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "F1_weighted",\n",
+       "          "value": 0.14731706525451424\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "F1_micro",\n",
+       "          "value": 0.3107177974434612\n",
+       "        },\n",
+       "        {\n",
+       "          "@type": "F1_macro",\n",
+       "          "value": 0.23705926481620407\n",
+       "        }\n",
+       "      ]\n",
+       "    }\n",
+       "  ]\n",
+       "}\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2V2YWx1YXRlLz9hbGdvPXNlbnRpbWVudC12YWRlciZkYXRhc2V0PXZhZGVyJTJDc3RzJm91dGZvcm1hdD1qc29uLWxkIw\\PYZpc{}3D\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}AggregatedEvaluation\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}senpy:evaluations\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Evaluation\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}evaluates\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}endpoint:plugins/sentiment\\PYZhy{}vader\\PYZus{}0.1.1\\PYZus{}\\PYZus{}vader\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}evaluatesOn\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}vader\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}metrics\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Accuracy\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.6907142857142857}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Precision\\PYZus{}macro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.34535714285714286}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Recall\\PYZus{}macro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.5}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}F1\\PYZus{}macro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.40853400929446554}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}F1\\PYZus{}weighted\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.5643605528396403}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}F1\\PYZus{}micro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.6907142857142857}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}F1\\PYZus{}macro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.40853400929446554}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Evaluation\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}evaluates\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}endpoint:plugins/sentiment\\PYZhy{}vader\\PYZus{}0.1.1\\PYZus{}\\PYZus{}sts\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}evaluatesOn\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}sts\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}metrics\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Accuracy\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.3107177974434612}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Precision\\PYZus{}macro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.1553588987217306}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Recall\\PYZus{}macro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.5}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}F1\\PYZus{}macro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.23705926481620407}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}F1\\PYZus{}weighted\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.14731706525451424}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}F1\\PYZus{}micro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.3107177974434612}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nt}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}F1\\PYZus{}macro\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}value\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.23705926481620407}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + "\\PY{p}{\\PYZcb{}}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "{\n", + " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2V2YWx1YXRlLz9hbGdvPXNlbnRpbWVudC12YWRlciZkYXRhc2V0PXZhZGVyJTJDc3RzJm91dGZvcm1hdD1qc29uLWxkIw%3D%3D\",\n", + " \"@type\": \"AggregatedEvaluation\",\n", + " \"senpy:evaluations\": [\n", + " {\n", + " \"@type\": \"Evaluation\",\n", + " \"evaluates\": \"endpoint:plugins/sentiment-vader_0.1.1__vader\",\n", + " \"evaluatesOn\": \"vader\",\n", + " \"metrics\": [\n", + " {\n", + " \"@type\": \"Accuracy\",\n", + " \"value\": 0.6907142857142857\n", + " },\n", + " {\n", + " \"@type\": \"Precision_macro\",\n", + " \"value\": 0.34535714285714286\n", + " },\n", + " {\n", + " \"@type\": \"Recall_macro\",\n", + " \"value\": 0.5\n", + " },\n", + " {\n", + " \"@type\": \"F1_macro\",\n", + " \"value\": 0.40853400929446554\n", + " },\n", + " {\n", + " \"@type\": \"F1_weighted\",\n", + " \"value\": 0.5643605528396403\n", + " },\n", + " {\n", + " \"@type\": \"F1_micro\",\n", + " \"value\": 0.6907142857142857\n", + " },\n", + " {\n", + " \"@type\": \"F1_macro\",\n", + " \"value\": 0.40853400929446554\n", + " }\n", + " ]\n", + " },\n", + " {\n", + " \"@type\": \"Evaluation\",\n", + " \"evaluates\": \"endpoint:plugins/sentiment-vader_0.1.1__sts\",\n", + " \"evaluatesOn\": \"sts\",\n", + " \"metrics\": [\n", + " {\n", + " \"@type\": \"Accuracy\",\n", + " \"value\": 0.3107177974434612\n", + " },\n", + " {\n", + " \"@type\": \"Precision_macro\",\n", + " \"value\": 0.1553588987217306\n", + " },\n", + " {\n", + " \"@type\": \"Recall_macro\",\n", + " \"value\": 0.5\n", + " },\n", + " {\n", + " \"@type\": \"F1_macro\",\n", + " \"value\": 0.23705926481620407\n", + " },\n", + " {\n", + " \"@type\": \"F1_weighted\",\n", + " \"value\": 0.14731706525451424\n", + " },\n", + " {\n", + " \"@type\": \"F1_micro\",\n", + " \"value\": 0.3107177974434612\n", + " },\n", + " {\n", + " \"@type\": \"F1_macro\",\n", + " \"value\": 0.23705926481620407\n", + " }\n", + " ]\n", + " }\n", + " ]\n", + "}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import requests\n", + "from IPython.display import Code\n", + "\n", + "endpoint = 'http://senpy.gsi.upm.es/api'\n", + "res = requests.get(f'{endpoint}/evaluate',\n", + " params={\"algo\": \"sentiment-vader\",\n", + " \"dataset\": \"vader,sts\",\n", + " 'outformat': 'json-ld'\n", + " })\n", + "Code(res.text, language='json')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Programmatically (expert)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A third option is to evaluate plugins manually without launching the server.\n", + "\n", + "This option is particularly interesting for advanced users that want faster iterations and evaluation results, and for automation.\n", + "\n", + "We would first need an instance of a plugin.\n", + "In this example we will use the Sentiment140 plugin that is included in every senpy installation:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "from senpy.plugins.sentiment import sentiment140_plugin" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "s140 = sentiment140_plugin.Sentiment140()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we need to know what datasets are available.\n", + "We can list all datasets and basic stats (e.g., number of instances and labels used) like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "vader {'instances': 4200, 'labels': [1, -1]}\n", + "sts {'instances': 4200, 'labels': [1, -1]}\n", + "imdb_unsup {'instances': 50000, 'labels': [1, -1]}\n", + "imdb {'instances': 50000, 'labels': [1, -1]}\n", + "sst {'instances': 11855, 'labels': [1, -1]}\n", + "multidomain {'instances': 38548, 'labels': [1, -1]}\n", + "sentiment140 {'instances': 1600000, 'labels': [1, -1]}\n", + "semeval07 {'instances': 'None', 'labels': [1, -1]}\n", + "semeval14 {'instances': 7838, 'labels': [1, -1]}\n", + "pl04 {'instances': 4000, 'labels': [1, -1]}\n", + "pl05 {'instances': 10662, 'labels': [1, -1]}\n", + "semeval13 {'instances': 6259, 'labels': [1, -1]}\n" + ] + } + ], + "source": [ + "from senpy.gsitk_compat import datasets\n", + "for k, d in datasets.items():\n", + " print(k, d['stats'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we will evaluate our plugin in one of the smallest datasets, `sts`:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[{\n", + " \"@type\": \"Evaluation\",\n", + " \"evaluates\": \"endpoint:plugins/sentiment140_0.2\",\n", + " \"evaluatesOn\": \"sts\",\n", + " \"metrics\": [\n", + " {\n", + " \"@type\": \"Accuracy\",\n", + " \"value\": 0.872173058013766\n", + " },\n", + " {\n", + " \"@type\": \"Precision_macro\",\n", + " \"value\": 0.9035254323131467\n", + " },\n", + " {\n", + " \"@type\": \"Recall_macro\",\n", + " \"value\": 0.8021249029415483\n", + " },\n", + " {\n", + " \"@type\": \"F1_macro\",\n", + " \"value\": 0.8320673712021136\n", + " },\n", + " {\n", + " \"@type\": \"F1_weighted\",\n", + " \"value\": 0.8631351567604358\n", + " },\n", + " {\n", + " \"@type\": \"F1_micro\",\n", + " \"value\": 0.872173058013766\n", + " },\n", + " {\n", + " \"@type\": \"F1_macro\",\n", + " \"value\": 0.8320673712021136\n", + " }\n", + " ]\n", + " }]" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s140.evaluate(['sts', ])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + }, + "toc": { + "colors": { + "hover_highlight": "#DAA520", + "running_highlight": "#FF0000", + "selected_highlight": "#FFD700" + }, + "moveMenuLeft": true, + "nav_menu": { + "height": "68px", + "width": "252px" + }, + "navigate_menu": true, + "number_sections": true, + "sideBar": true, + "threshold": 4, + "toc_cell": false, + "toc_section_display": "block", + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/docs/Quickstart-10minutes.ipynb b/docs/Quickstart-10minutes.ipynb deleted file mode 100644 index ad85a42..0000000 --- a/docs/Quickstart-10minutes.ipynb +++ /dev/null @@ -1,1513 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Senpy in 10 minutes\n", - "\n", - "This tutorial assumes you have completed the [1 minute tutorial](Quickstart-1minute.ipynb) and you know how to access the API.\n", - "\n", - "It covers:\n", - "\n", - "* Annotating entiment with a sentiment analysis service\n", - "* Annotating emotions\n", - "* Interoperability of services\n", - "* Using other semantic formats (RDF)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Requirements" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Once again, we will use the demo server at http://senpy.gsi.upm.es.\n", - "This time, we will use the requests library.\n", - "\n", - "We will use a variable for our endpoint, so you can try this examples on a different senpy instance:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "endpoint = 'http://senpy.gsi.upm.es/api'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will also add a function to get syntax highlighting for the JSON-LD/Turtle results:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "try:\n", - " from IPython.display import Code\n", - " def pretty(txt, language='json-ld'):\n", - " return Code(txt, language=language)\n", - "except ImportError:\n", - " def pretty(txt, **kwargs):\n", - " print(txt)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Sentiment Analysis of Text" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To start, let us analyse the sentiment in the following sentence: *senpy is awesome*.\n", - "\n", - "For now, we will use the [sentiment140](http://www.sentiment140.com/) service, through the sentiment140 plugin.\n", - "We will later cover how to use a different service.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
{\n",
-       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D",\n",
-       "  "@type": "Results",\n",
-       "  "entries": [\n",
-       "    {\n",
-       "      "@id": "prefix:",\n",
-       "      "@type": "Entry",\n",
-       "      "marl:hasOpinion": [\n",
-       "        {\n",
-       "          "@type": "Sentiment",\n",
-       "          "marl:hasPolarity": "marl:Positive",\n",
-       "          "prov:wasGeneratedBy": "prefix:Analysis_1554396807.629645"\n",
-       "        }\n",
-       "      ],\n",
-       "      "nif:isString": "Senpy is awesome",\n",
-       "      "onyx:hasEmotionSet": []\n",
-       "    }\n",
-       "  ]\n",
-       "}\n",
-       "
\n" - ], - "text/latex": [ - "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw\\PYZpc{}3D\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Positive\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554396807.629645\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is awesome\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - "\\PY{p}{\\PYZcb{}}\n", - "\\end{Verbatim}\n" - ], - "text/plain": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D\",\n", - " \"@type\": \"Results\",\n", - " \"entries\": [\n", - " {\n", - " \"@id\": \"prefix:\",\n", - " \"@type\": \"Entry\",\n", - " \"marl:hasOpinion\": [\n", - " {\n", - " \"@type\": \"Sentiment\",\n", - " \"marl:hasPolarity\": \"marl:Positive\",\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554396807.629645\"\n", - " }\n", - " ],\n", - " \"nif:isString\": \"Senpy is awesome\",\n", - " \"onyx:hasEmotionSet\": []\n", - " }\n", - " ]\n", - "}" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import requests\n", - "res = requests.get(f'{endpoint}/sentiment140',\n", - " params={\"input\": \"Senpy is awesome\",})\n", - "pretty(res.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Senpy services always return an object of type `senpy:Results`, with a list of entries.\n", - "You can think of an entry as a self-contained textual context (`nif:Context` and `senpy:Entry`).\n", - "Entries can be as short as a sentence, or as long as a news article.\n", - "\n", - "Each entry has a `nif:isString` property that contains the original text of the entry, and several other properties that are provided by the plugins.\n", - "\n", - "For instance, sentiment annotations are provided through `marl:hasOpinion`.\n", - "\n", - "The annotations are semantic.\n", - "We can ask Senpy for the expanded JSON-LD output to reveal the full URIs of each property and entity:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
{\n",
-       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lJmV4cGFuZGVkPVRydWUj",\n",
-       "  "@type": [\n",
-       "    "http://www.gsi.upm.es/onto/senpy/ns#Results"\n",
-       "  ],\n",
-       "  "http://www.w3.org/ns/prov#used": [\n",
-       "    {\n",
-       "      "@id": "http://senpy.invalid/",\n",
-       "      "@type": [\n",
-       "        "http://www.gsi.upm.es/onto/senpy/ns#Entry"\n",
-       "      ],\n",
-       "      "http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#isString": [\n",
-       "        {\n",
-       "          "@value": "Senpy is awesome"\n",
-       "        }\n",
-       "      ],\n",
-       "      "http://www.gsi.dit.upm.es/ontologies/marl/ns#hasOpinion": [\n",
-       "        {\n",
-       "          "@type": [\n",
-       "            "http://www.gsi.upm.es/onto/senpy/ns#Sentiment"\n",
-       "          ],\n",
-       "          "http://www.gsi.dit.upm.es/ontologies/marl/ns#hasPolarity": [\n",
-       "            {\n",
-       "              "@value": "marl:Positive"\n",
-       "            }\n",
-       "          ],\n",
-       "          "http://www.w3.org/ns/prov#wasGeneratedBy": [\n",
-       "            {\n",
-       "              "@id": "http://senpy.invalid/Analysis_1554389672.269198"\n",
-       "            }\n",
-       "          ]\n",
-       "        }\n",
-       "      ],\n",
-       "      "http://www.gsi.dit.upm.es/ontologies/onyx/ns#hasEmotionSet": []\n",
-       "    }\n",
-       "  ]\n",
-       "}\n",
-       "
\n" - ], - "text/latex": [ - "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lJmV4cGFuZGVkPVRydWUj\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{l+s+s2}{\\PYZdq{}http://www.gsi.upm.es/onto/senpy/ns\\PYZsh{}Results\\PYZdq{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.w3.org/ns/prov\\PYZsh{}used\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.invalid/\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{l+s+s2}{\\PYZdq{}http://www.gsi.upm.es/onto/senpy/ns\\PYZsh{}Entry\\PYZdq{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://persistence.uni\\PYZhy{}leipzig.org/nlp2rdf/ontologies/nif\\PYZhy{}core\\PYZsh{}isString\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@value\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is awesome\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/marl/ns\\PYZsh{}hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{l+s+s2}{\\PYZdq{}http://www.gsi.upm.es/onto/senpy/ns\\PYZsh{}Sentiment\\PYZdq{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/marl/ns\\PYZsh{}hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@value\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Positive\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.w3.org/ns/prov\\PYZsh{}wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.invalid/Analysis\\PYZus{}1554389672.269198\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/ns\\PYZsh{}hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - "\\PY{p}{\\PYZcb{}}\n", - "\\end{Verbatim}\n" - ], - "text/plain": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lJmV4cGFuZGVkPVRydWUj\",\n", - " \"@type\": [\n", - " \"http://www.gsi.upm.es/onto/senpy/ns#Results\"\n", - " ],\n", - " \"http://www.w3.org/ns/prov#used\": [\n", - " {\n", - " \"@id\": \"http://senpy.invalid/\",\n", - " \"@type\": [\n", - " \"http://www.gsi.upm.es/onto/senpy/ns#Entry\"\n", - " ],\n", - " \"http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#isString\": [\n", - " {\n", - " \"@value\": \"Senpy is awesome\"\n", - " }\n", - " ],\n", - " \"http://www.gsi.dit.upm.es/ontologies/marl/ns#hasOpinion\": [\n", - " {\n", - " \"@type\": [\n", - " \"http://www.gsi.upm.es/onto/senpy/ns#Sentiment\"\n", - " ],\n", - " \"http://www.gsi.dit.upm.es/ontologies/marl/ns#hasPolarity\": [\n", - " {\n", - " \"@value\": \"marl:Positive\"\n", - " }\n", - " ],\n", - " \"http://www.w3.org/ns/prov#wasGeneratedBy\": [\n", - " {\n", - " \"@id\": \"http://senpy.invalid/Analysis_1554389672.269198\"\n", - " }\n", - " ]\n", - " }\n", - " ],\n", - " \"http://www.gsi.dit.upm.es/ontologies/onyx/ns#hasEmotionSet\": []\n", - " }\n", - " ]\n", - "}" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import requests\n", - "res = requests.get(f'{endpoint}/sentiment140',\n", - " params={\"input\": \"Senpy is awesome\",\n", - " \"expanded\": True})\n", - "pretty(res.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Service interoperability" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "All senpy plugins use the same API, which makes moving from one service to another a breeze.\n", - "\n", - "Let us go back to our simple example, which uses the `sentiment140` service." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
{\n",
-       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D",\n",
-       "  "@type": "Results",\n",
-       "  "entries": [\n",
-       "    {\n",
-       "      "@id": "prefix:",\n",
-       "      "@type": "Entry",\n",
-       "      "marl:hasOpinion": [\n",
-       "        {\n",
-       "          "@type": "Sentiment",\n",
-       "          "marl:hasPolarity": "marl:Positive",\n",
-       "          "prov:wasGeneratedBy": "prefix:Analysis_1554389675.2303865"\n",
-       "        }\n",
-       "      ],\n",
-       "      "nif:isString": "Senpy is awesome",\n",
-       "      "onyx:hasEmotionSet": []\n",
-       "    }\n",
-       "  ]\n",
-       "}\n",
-       "
\n" - ], - "text/latex": [ - "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw\\PYZpc{}3D\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Positive\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554389675.2303865\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is awesome\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - "\\PY{p}{\\PYZcb{}}\n", - "\\end{Verbatim}\n" - ], - "text/plain": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D\",\n", - " \"@type\": \"Results\",\n", - " \"entries\": [\n", - " {\n", - " \"@id\": \"prefix:\",\n", - " \"@type\": \"Entry\",\n", - " \"marl:hasOpinion\": [\n", - " {\n", - " \"@type\": \"Sentiment\",\n", - " \"marl:hasPolarity\": \"marl:Positive\",\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554389675.2303865\"\n", - " }\n", - " ],\n", - " \"nif:isString\": \"Senpy is awesome\",\n", - " \"onyx:hasEmotionSet\": []\n", - " }\n", - " ]\n", - "}" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import requests\n", - "res = requests.get(f'{endpoint}/sentiment140',\n", - " params={\"input\": \"Senpy is awesome\"})\n", - "pretty(res.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we wanted to use a different service (e.g. the `sentiment-basic` plugin), we can do it just by changing the URL of the service:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
{\n",
-       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudC1iYXNpYz9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D",\n",
-       "  "@type": "Results",\n",
-       "  "entries": [\n",
-       "    {\n",
-       "      "@id": "prefix:",\n",
-       "      "@type": "Entry",\n",
-       "      "marl:hasOpinion": [\n",
-       "        {\n",
-       "          "@type": "Sentiment",\n",
-       "          "marl:hasPolarity": "marl:Neutral",\n",
-       "          "prov:wasGeneratedBy": "prefix:Analysis_1554389675.9911203"\n",
-       "        }\n",
-       "      ],\n",
-       "      "nif:isString": "Senpy is awesome",\n",
-       "      "onyx:hasEmotionSet": []\n",
-       "    }\n",
-       "  ]\n",
-       "}\n",
-       "
\n" - ], - "text/latex": [ - "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudC1iYXNpYz9pbnB1dD1TZW5weStpcythd2Vzb21lIw\\PYZpc{}3D\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Neutral\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554389675.9911203\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is awesome\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - "\\PY{p}{\\PYZcb{}}\n", - "\\end{Verbatim}\n" - ], - "text/plain": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudC1iYXNpYz9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D\",\n", - " \"@type\": \"Results\",\n", - " \"entries\": [\n", - " {\n", - " \"@id\": \"prefix:\",\n", - " \"@type\": \"Entry\",\n", - " \"marl:hasOpinion\": [\n", - " {\n", - " \"@type\": \"Sentiment\",\n", - " \"marl:hasPolarity\": \"marl:Neutral\",\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554389675.9911203\"\n", - " }\n", - " ],\n", - " \"nif:isString\": \"Senpy is awesome\",\n", - " \"onyx:hasEmotionSet\": []\n", - " }\n", - " ]\n", - "}" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import requests\n", - "res = requests.get(f'{endpoint}/sentiment-basic',\n", - " params={\"input\": \"Senpy is awesome\"})\n", - "pretty(res.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you can see, the structure and annotation schema of the response is the same.\n", - "This makes it very easy to compare and migrate to different services.\n", - "\n", - "Service interoperability is not only useful for users.\n", - "It is also key for other features such as [automated evaluation](#Evaluation).\n", - "This is a compelling reason to adapt existing services to use the Senpy API.\n", - "In fact, the `sentiment140` senpy service is proxy to the public [Sentiment 140 service](http://www.sentiment140.com/)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Emotion analysis" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "Senpy uses the `onyx` vocabulary to represent emotions, which incorporates the notion of `EmotionSet`'s, an emotion that is composed of several emotions.\n", - "In a nutshell, an `Entry` is linked to one or more `EmotionSet`, which in turn is made up of one or more `Emotion`.\n", - "\n", - "Let's illustrate it with an example, using the `emotion-depechemood` plugin." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
{\n",
-       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q_aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrdGhhdCtzZXJ2aWNlIw%3D%3D",\n",
-       "  "@type": "Results",\n",
-       "  "entries": [\n",
-       "    {\n",
-       "      "@id": "prefix:",\n",
-       "      "@type": "Entry",\n",
-       "      "marl:hasOpinion": [],\n",
-       "      "nif:isString": "Senpy is a wonderful that service",\n",
-       "      "onyx:hasEmotionSet": [\n",
-       "        {\n",
-       "          "@type": "EmotionSet",\n",
-       "          "onyx:hasEmotion": [\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:hasEmotionCategory": "wna:negative-fear",\n",
-       "              "onyx:hasEmotionIntensity": 0.06258366271018097\n",
-       "            },\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:hasEmotionCategory": "wna:amusement",\n",
-       "              "onyx:hasEmotionIntensity": 0.15784834034155437\n",
-       "            },\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:hasEmotionCategory": "wna:anger",\n",
-       "              "onyx:hasEmotionIntensity": 0.08728815135373413\n",
-       "            },\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:hasEmotionCategory": "wna:annoyance",\n",
-       "              "onyx:hasEmotionIntensity": 0.12184635680460143\n",
-       "            },\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:hasEmotionCategory": "wna:indifference",\n",
-       "              "onyx:hasEmotionIntensity": 0.1374081151031531\n",
-       "            },\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:hasEmotionCategory": "wna:joy",\n",
-       "              "onyx:hasEmotionIntensity": 0.12267040802346799\n",
-       "            },\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:hasEmotionCategory": "wna:awe",\n",
-       "              "onyx:hasEmotionIntensity": 0.21085262130713067\n",
-       "            },\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:hasEmotionCategory": "wna:sadness",\n",
-       "              "onyx:hasEmotionIntensity": 0.09950234435617733\n",
-       "            }\n",
-       "          ],\n",
-       "          "prov:wasGeneratedBy": "prefix:Analysis_1554389679.0535374"\n",
-       "        }\n",
-       "      ]\n",
-       "    }\n",
-       "  ]\n",
-       "}\n",
-       "
\n" - ], - "text/latex": [ - "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q\\PYZus{}aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrdGhhdCtzZXJ2aWNlIw\\PYZpc{}3D\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful that service\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:negative\\PYZhy{}fear\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.06258366271018097}\n", - " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:amusement\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.15784834034155437}\n", - " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:anger\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.08728815135373413}\n", - " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:annoyance\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.12184635680460143}\n", - " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:indifference\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.1374081151031531}\n", - " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:joy\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.12267040802346799}\n", - " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:awe\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.21085262130713067}\n", - " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:sadness\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.09950234435617733}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554389679.0535374\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - "\\PY{p}{\\PYZcb{}}\n", - "\\end{Verbatim}\n" - ], - "text/plain": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q_aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrdGhhdCtzZXJ2aWNlIw%3D%3D\",\n", - " \"@type\": \"Results\",\n", - " \"entries\": [\n", - " {\n", - " \"@id\": \"prefix:\",\n", - " \"@type\": \"Entry\",\n", - " \"marl:hasOpinion\": [],\n", - " \"nif:isString\": \"Senpy is a wonderful that service\",\n", - " \"onyx:hasEmotionSet\": [\n", - " {\n", - " \"@type\": \"EmotionSet\",\n", - " \"onyx:hasEmotion\": [\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:hasEmotionCategory\": \"wna:negative-fear\",\n", - " \"onyx:hasEmotionIntensity\": 0.06258366271018097\n", - " },\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:hasEmotionCategory\": \"wna:amusement\",\n", - " \"onyx:hasEmotionIntensity\": 0.15784834034155437\n", - " },\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:hasEmotionCategory\": \"wna:anger\",\n", - " \"onyx:hasEmotionIntensity\": 0.08728815135373413\n", - " },\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:hasEmotionCategory\": \"wna:annoyance\",\n", - " \"onyx:hasEmotionIntensity\": 0.12184635680460143\n", - " },\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:hasEmotionCategory\": \"wna:indifference\",\n", - " \"onyx:hasEmotionIntensity\": 0.1374081151031531\n", - " },\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:hasEmotionCategory\": \"wna:joy\",\n", - " \"onyx:hasEmotionIntensity\": 0.12267040802346799\n", - " },\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:hasEmotionCategory\": \"wna:awe\",\n", - " \"onyx:hasEmotionIntensity\": 0.21085262130713067\n", - " },\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:hasEmotionCategory\": \"wna:sadness\",\n", - " \"onyx:hasEmotionIntensity\": 0.09950234435617733\n", - " }\n", - " ],\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554389679.0535374\"\n", - " }\n", - " ]\n", - " }\n", - " ]\n", - "}" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "res = requests.get(f'{endpoint}/emotion-depechemood',\n", - " params={\"input\": \"Senpy is a wonderful that service\"})\n", - "pretty(res.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you have probably noticed, there are several emotions in this result, each with a different intensity.\n", - "\n", - "We can also tell senpy to only return the emotion with the maximum intensity using the `maxemotion` parameter:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
{\n",
-       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q_aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrc2VydmljZSZtYXhlbW90aW9uPVRydWUj",\n",
-       "  "@type": "Results",\n",
-       "  "entries": [\n",
-       "    {\n",
-       "      "@id": "prefix:",\n",
-       "      "@type": "Entry",\n",
-       "      "marl:hasOpinion": [],\n",
-       "      "nif:isString": "Senpy is a wonderful service",\n",
-       "      "onyx:hasEmotionSet": [\n",
-       "        {\n",
-       "          "@type": "EmotionSet",\n",
-       "          "onyx:hasEmotion": [\n",
-       "            {\n",
-       "              "@type": "Emotion",\n",
-       "              "onyx:hasEmotionCategory": "wna:awe",\n",
-       "              "onyx:hasEmotionIntensity": 0.21085262130713067\n",
-       "            }\n",
-       "          ],\n",
-       "          "prov:wasGeneratedBy": "prefix:Analysis_1554389681.1941268"\n",
-       "        }\n",
-       "      ]\n",
-       "    }\n",
-       "  ]\n",
-       "}\n",
-       "
\n" - ], - "text/latex": [ - "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q\\PYZus{}aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrc2VydmljZSZtYXhlbW90aW9uPVRydWUj\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", - " \\PY{p}{\\PYZob{}}\n", - " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:awe\\PYZdq{}}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.21085262130713067}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\\PY{p}{,}\n", - " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1554389681.1941268\\PYZdq{}}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - " \\PY{p}{\\PYZcb{}}\n", - " \\PY{p}{]}\n", - "\\PY{p}{\\PYZcb{}}\n", - "\\end{Verbatim}\n" - ], - "text/plain": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q_aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrc2VydmljZSZtYXhlbW90aW9uPVRydWUj\",\n", - " \"@type\": \"Results\",\n", - " \"entries\": [\n", - " {\n", - " \"@id\": \"prefix:\",\n", - " \"@type\": \"Entry\",\n", - " \"marl:hasOpinion\": [],\n", - " \"nif:isString\": \"Senpy is a wonderful service\",\n", - " \"onyx:hasEmotionSet\": [\n", - " {\n", - " \"@type\": \"EmotionSet\",\n", - " \"onyx:hasEmotion\": [\n", - " {\n", - " \"@type\": \"Emotion\",\n", - " \"onyx:hasEmotionCategory\": \"wna:awe\",\n", - " \"onyx:hasEmotionIntensity\": 0.21085262130713067\n", - " }\n", - " ],\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554389681.1941268\"\n", - " }\n", - " ]\n", - " }\n", - " ]\n", - "}" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "res = requests.get(f'{endpoint}/emotion-depechemood',\n", - " params={\"input\": \"Senpy is a wonderful service\",\n", - " \"maxemotion\": True})\n", - "pretty(res.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Other output formats" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Senpy supports several semantic formats, like turtle and xml-RDF.\n", - "You can select the format of the output with the `outformat` parameter:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
@prefix : <http://www.gsi.upm.es/onto/senpy/ns#> .\n",
-       "@prefix dc: <http://dublincore.org/2012/06/14/dcelements#> .\n",
-       "@prefix emoml: <http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/emotionml/ns#> .\n",
-       "@prefix endpoint: <http://senpy.gsi.upm.es/api/> .\n",
-       "@prefix fam: <http://vocab.fusepool.info/fam#> .\n",
-       "@prefix marl: <http://www.gsi.dit.upm.es/ontologies/marl/ns#> .\n",
-       "@prefix nif: <http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#> .\n",
-       "@prefix onyx: <http://www.gsi.dit.upm.es/ontologies/onyx/ns#> .\n",
-       "@prefix prefix: <http://senpy.invalid/> .\n",
-       "@prefix prov: <http://www.w3.org/ns/prov#> .\n",
-       "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n",
-       "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n",
-       "@prefix senpy: <http://www.gsi.upm.es/onto/senpy/ns#> .\n",
-       "@prefix wna: <http://www.gsi.dit.upm.es/ontologies/wnaffect/ns#> .\n",
-       "@prefix xml: <http://www.w3.org/XML/1998/namespace> .\n",
-       "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n",
-       "\n",
-       "prefix: a senpy:Entry ;\n",
-       "    nif:isString "Senpy is the best framework for semantic sentiment analysis, and very easy to use" ;\n",
-       "    marl:hasOpinion [ a senpy:Sentiment ;\n",
-       "            marl:hasPolarity "marl:Positive" ;\n",
-       "            prov:wasGeneratedBy prefix:Analysis_1554389682.350598 ] .\n",
-       "\n",
-       "[] a senpy:Results ;\n",
-       "    prov:used prefix: .\n",
-       "
\n" - ], - "text/latex": [ - "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.upm.es/onto/senpy/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{dc:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://dublincore.org/2012/06/14/dcelements\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{emoml:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/emotionml/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{endpoint:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://senpy.gsi.upm.es/api/\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{fam:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://vocab.fusepool.info/fam\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{marl:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.dit.upm.es/ontologies/marl/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{nif:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://persistence.uni\\PYZhy{}leipzig.org/nlp2rdf/ontologies/nif\\PYZhy{}core\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{onyx:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.dit.upm.es/ontologies/onyx/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{prefix:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://senpy.invalid/\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{prov:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/ns/prov\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{rdf:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/1999/02/22\\PYZhy{}rdf\\PYZhy{}syntax\\PYZhy{}ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{rdfs:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/2000/01/rdf\\PYZhy{}schema\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{senpy:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.upm.es/onto/senpy/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{wna:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.dit.upm.es/ontologies/wnaffect/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{xml:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/XML/1998/namespace\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{xsd:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/2001/XMLSchema\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", - "\n", - "\\PY{err}{p}\\PY{err}{r}\\PY{err}{e}\\PY{err}{f}\\PY{err}{i}\\PY{err}{x}\\PY{p}{:}\\PY{+w}{ }\\PY{k+kt}{a}\\PY{+w}{ }\\PY{n+nn}{senpy:}\\PY{n+nt}{Entry}\\PY{+w}{ }\\PY{p}{;}\n", - "\\PY{+w}{ }\\PY{n+nn}{nif:}\\PY{n+nt}{isString}\\PY{+w}{ }\\PY{l+s}{\\PYZdq{}}\\PY{l+s}{Senpy is the best framework for semantic sentiment analysis, and very easy to use}\\PY{l+s}{\\PYZdq{}}\\PY{+w}{ }\\PY{p}{;}\n", - "\\PY{+w}{ }\\PY{n+nn}{marl:}\\PY{n+nt}{hasOpinion}\\PY{+w}{ }\\PY{p}{[}\\PY{+w}{ }\\PY{k+kt}{a}\\PY{+w}{ }\\PY{n+nn}{senpy:}\\PY{n+nt}{Sentiment}\\PY{+w}{ }\\PY{p}{;}\n", - "\\PY{+w}{ }\\PY{n+nn}{marl:}\\PY{n+nt}{hasPolarity}\\PY{+w}{ }\\PY{l+s}{\\PYZdq{}}\\PY{l+s}{marl:Positive}\\PY{l+s}{\\PYZdq{}}\\PY{+w}{ }\\PY{p}{;}\n", - "\\PY{+w}{ }\\PY{n+nn}{prov:}\\PY{n+nt}{wasGeneratedBy}\\PY{+w}{ }\\PY{n+nn}{prefix:}\\PY{n+nt}{Analysis\\PYZus{}1554389682}\\PY{l+m+mf}{.350598}\\PY{+w}{ }\\PY{p}{]}\\PY{+w}{ }\\PY{p}{.}\n", - "\n", - "\\PY{p}{[}\\PY{p}{]}\\PY{+w}{ }\\PY{k+kt}{a}\\PY{+w}{ }\\PY{n+nn}{senpy:}\\PY{n+nt}{Results}\\PY{+w}{ }\\PY{p}{;}\n", - "\\PY{+w}{ }\\PY{n+nn}{prov:}\\PY{n+nt}{used}\\PY{+w}{ }\\PY{err}{p}\\PY{err}{r}\\PY{err}{e}\\PY{err}{f}\\PY{err}{i}\\PY{err}{x}\\PY{p}{:}\\PY{+w}{ }\\PY{p}{.}\n", - "\\end{Verbatim}\n" - ], - "text/plain": [ - "@prefix : .\n", - "@prefix dc: .\n", - "@prefix emoml: .\n", - "@prefix endpoint: .\n", - "@prefix fam: .\n", - "@prefix marl: .\n", - "@prefix nif: .\n", - "@prefix onyx: .\n", - "@prefix prefix: .\n", - "@prefix prov: .\n", - "@prefix rdf: .\n", - "@prefix rdfs: .\n", - "@prefix senpy: .\n", - "@prefix wna: .\n", - "@prefix xml: .\n", - "@prefix xsd: .\n", - "\n", - "prefix: a senpy:Entry ;\n", - " nif:isString \"Senpy is the best framework for semantic sentiment analysis, and very easy to use\" ;\n", - " marl:hasOpinion [ a senpy:Sentiment ;\n", - " marl:hasPolarity \"marl:Positive\" ;\n", - " prov:wasGeneratedBy prefix:Analysis_1554389682.350598 ] .\n", - "\n", - "[] a senpy:Results ;\n", - " prov:used prefix: .\n" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "res = requests.get(f'{endpoint}/sentiment140',\n", - " params={\"input\": \"Senpy is the best framework for semantic sentiment analysis, and very easy to use\",\n", - " \"outformat\": \"turtle\"})\n", - "pretty(res.text, language='turtle')" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - }, - "toc": { - "colors": { - "hover_highlight": "#DAA520", - "running_highlight": "#FF0000", - "selected_highlight": "#FFD700" - }, - "moveMenuLeft": true, - "nav_menu": { - "height": "68px", - "width": "252px" - }, - "navigate_menu": true, - "number_sections": true, - "sideBar": true, - "threshold": 4, - "toc_cell": false, - "toc_section_display": "block", - "toc_window_display": false - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/docs/Quickstart-1minute.ipynb b/docs/Quickstart-1minute.ipynb deleted file mode 100644 index a4e4edb..0000000 --- a/docs/Quickstart-1minute.ipynb +++ /dev/null @@ -1,152 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Senpy in 1 minute\n", - "\n", - "This mini-tutorial only shows how to annotate with a service.\n", - "We will use the [demo server](http://senpy.gsi.upm.es), which runs some open source plugins for sentiment and emotion analysis." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Annotating with senpy is as simple as issuing an HTTP request to the API using your favourite tool.\n", - "This is just an example using curl:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\r\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD8j\",\r\n", - " \"@type\": \"Results\",\r\n", - " \"entries\": [\r\n", - " {\r\n", - " \"@id\": \"prefix:\",\r\n", - " \"@type\": \"Entry\",\r\n", - " \"marl:hasOpinion\": [\r\n", - " {\r\n", - " \"@type\": \"Sentiment\",\r\n", - " \"marl:hasPolarity\": \"marl:Positive\",\r\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554389334.6431913\"\r\n", - " }\r\n", - " ],\r\n", - " \"nif:isString\": \"Senpy is awesome\",\r\n", - " \"onyx:hasEmotionSet\": []\r\n", - " }\r\n", - " ]\r\n", - "}" - ] - } - ], - "source": [ - "!curl \"http://senpy.gsi.upm.es/api/sentiment140\" --data-urlencode \"input=Senpy is awesome\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Congratulations**, you've used your first senpy service!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here is the equivalent using the `requests` library:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D\",\n", - " \"@type\": \"Results\",\n", - " \"entries\": [\n", - " {\n", - " \"@id\": \"prefix:\",\n", - " \"@type\": \"Entry\",\n", - " \"marl:hasOpinion\": [\n", - " {\n", - " \"@type\": \"Sentiment\",\n", - " \"marl:hasPolarity\": \"marl:Positive\",\n", - " \"prov:wasGeneratedBy\": \"prefix:Analysis_1554389335.9803226\"\n", - " }\n", - " ],\n", - " \"nif:isString\": \"Senpy is awesome\",\n", - " \"onyx:hasEmotionSet\": []\n", - " }\n", - " ]\n", - "}\n" - ] - } - ], - "source": [ - "import requests\n", - "res = requests.get('http://senpy.gsi.upm.es/api/sentiment140',\n", - " params={\"input\": \"Senpy is awesome\",})\n", - "print(res.text)" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - }, - "toc": { - "colors": { - "hover_highlight": "#DAA520", - "running_highlight": "#FF0000", - "selected_highlight": "#FFD700" - }, - "moveMenuLeft": true, - "nav_menu": { - "height": "68px", - "width": "252px" - }, - "navigate_menu": true, - "number_sections": true, - "sideBar": true, - "threshold": 4, - "toc_cell": false, - "toc_section_display": "block", - "toc_window_display": false - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/docs/Quickstart.ipynb b/docs/Quickstart.ipynb index fbd89bb..1680aaf 100644 --- a/docs/Quickstart.ipynb +++ b/docs/Quickstart.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Quickstart\n", + "# Tutorial\n", "\n", "This short tutorial will teach you how to consume senpy services for several tasks, and how to take advantage of the features of the framework.\n", "\n", @@ -13,32 +13,1664 @@ "* Annotating text with sentiment and emotion using interoperable services\n", "* Switching to different services (service interoperability)\n", "* Getting results in different formats (Turtle, XML, text...)\n", - "* Asking for specific emotion models (automatic model conversion)\n", - "* Listing available services in an endpoint\n", - "* Calling multiple services in the same request (Pipelines)\n", + "* Asking for specific emotion models (automatic model conversion)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Requirements" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will use the demo server at http://senpy.gsi.upm.es abd the requests library.\n", "\n", - "These topics are split into two separate tutorials.\n", + "We will use a variable for our endpoint so you can try these examples on other instances:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "endpoint = 'http://senpy.gsi.upm.es/api'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will also add a little helper function (`query`) to simplify our queries and pretty-print the results with syntax highlighting:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "from IPython.display import Code\n", + " \n", + "def query(endpoint, **kwargs):\n", + " '''Query a given Senpy endpoint with specific parameters, and prettify the output'''\n", + " res = requests.get(endpoint,\n", + " params=kwargs)\n", + " if res.status_code != 200:\n", + " raise Exception(res)\n", + " return Code(res.text, language=kwargs.get('outformat', 'json-ld'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sentiment Analysis of Text" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To start, let us analyse the sentiment in the following sentence: *senpy is awesome*.\n", "\n", - "Reading all the sections is not necessary, although it is encouraged in order to get a glimpse of all the features." + "For now, we will use the [sentiment140](http://www.sentiment140.com/) service, through the sentiment140 plugin.\n", + "We will later cover how to use a different service.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
{\n",
+       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D",\n",
+       "  "@type": "Results",\n",
+       "  "entries": [\n",
+       "    {\n",
+       "      "@id": "prefix:",\n",
+       "      "@type": "Entry",\n",
+       "      "marl:hasOpinion": [\n",
+       "        {\n",
+       "          "@type": "Sentiment",\n",
+       "          "marl:hasPolarity": "marl:Positive",\n",
+       "          "prov:wasGeneratedBy": "prefix:Analysis_1563372853.439696"\n",
+       "        }\n",
+       "      ],\n",
+       "      "nif:isString": "Senpy is awesome",\n",
+       "      "onyx:hasEmotionSet": []\n",
+       "    }\n",
+       "  ]\n",
+       "}\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw\\PYZpc{}3D\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Positive\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372853.439696\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is awesome\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + "\\PY{p}{\\PYZcb{}}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "{\n", + " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D\",\n", + " \"@type\": \"Results\",\n", + " \"entries\": [\n", + " {\n", + " \"@id\": \"prefix:\",\n", + " \"@type\": \"Entry\",\n", + " \"marl:hasOpinion\": [\n", + " {\n", + " \"@type\": \"Sentiment\",\n", + " \"marl:hasPolarity\": \"marl:Positive\",\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372853.439696\"\n", + " }\n", + " ],\n", + " \"nif:isString\": \"Senpy is awesome\",\n", + " \"onyx:hasEmotionSet\": []\n", + " }\n", + " ]\n", + "}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query(f'{endpoint}/sentiment140', input=\"Senpy is awesome\")" ] }, { "cell_type": "markdown", - "metadata": { - "nbsphinx-toctree": { - "maxdepth": 2 + "metadata": {}, + "source": [ + "Senpy services always return an object of type `senpy:Results`, with a list of entries.\n", + "You can think of an entry as a self-contained textual context (`nif:Context` and `senpy:Entry`).\n", + "Entries can be as short as a sentence, or as long as a news article.\n", + "\n", + "Each entry has a `nif:isString` property that contains the original text of the entry, and several other properties that are provided by the plugins.\n", + "\n", + "For instance, sentiment annotations are provided through `marl:hasOpinion`.\n", + "\n", + "The annotations are semantic.\n", + "This is clear if we request a different semantic format, such as `turtle`.\n", + "The output format is controlled with the `outformat` parameter:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
@prefix : <http://www.gsi.upm.es/onto/senpy/ns#> .\n",
+       "@prefix dc: <http://dublincore.org/2012/06/14/dcelements#> .\n",
+       "@prefix emoml: <http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/emotionml/ns#> .\n",
+       "@prefix endpoint: <http://senpy.gsi.upm.es/api/> .\n",
+       "@prefix fam: <http://vocab.fusepool.info/fam#> .\n",
+       "@prefix marl: <http://www.gsi.dit.upm.es/ontologies/marl/ns#> .\n",
+       "@prefix nif: <http://persistence.uni-leipzig.org/nlp2rdf/ontologies/nif-core#> .\n",
+       "@prefix onyx: <http://www.gsi.dit.upm.es/ontologies/onyx/ns#> .\n",
+       "@prefix prefix: <http://senpy.invalid/> .\n",
+       "@prefix prov: <http://www.w3.org/ns/prov#> .\n",
+       "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n",
+       "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n",
+       "@prefix senpy: <http://www.gsi.upm.es/onto/senpy/ns#> .\n",
+       "@prefix wna: <http://www.gsi.dit.upm.es/ontologies/wnaffect/ns#> .\n",
+       "@prefix xml: <http://www.w3.org/XML/1998/namespace> .\n",
+       "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n",
+       "\n",
+       "prefix: a senpy:Entry ;\n",
+       "    nif:isString "Senpy is awesome" ;\n",
+       "    marl:hasOpinion [ a senpy:Sentiment ;\n",
+       "            marl:hasPolarity "marl:Positive" ;\n",
+       "            prov:wasGeneratedBy prefix:Analysis_1563372853.6874764 ] .\n",
+       "\n",
+       "[] a senpy:Results ;\n",
+       "    prov:used prefix: .\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.upm.es/onto/senpy/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{dc:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://dublincore.org/2012/06/14/dcelements\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{emoml:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/emotionml/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{endpoint:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://senpy.gsi.upm.es/api/\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{fam:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://vocab.fusepool.info/fam\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{marl:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.dit.upm.es/ontologies/marl/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{nif:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://persistence.uni\\PYZhy{}leipzig.org/nlp2rdf/ontologies/nif\\PYZhy{}core\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{onyx:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.dit.upm.es/ontologies/onyx/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{prefix:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://senpy.invalid/\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{prov:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/ns/prov\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{rdf:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/1999/02/22\\PYZhy{}rdf\\PYZhy{}syntax\\PYZhy{}ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{rdfs:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/2000/01/rdf\\PYZhy{}schema\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{senpy:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.upm.es/onto/senpy/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{wna:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.gsi.dit.upm.es/ontologies/wnaffect/ns\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{xml:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/XML/1998/namespace\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\\PY{k}{@prefix}\\PY{+w}{ }\\PY{n+nn}{xsd:}\\PY{+w}{ }\\PY{n+nv}{\\PYZlt{}http://www.w3.org/2001/XMLSchema\\PYZsh{}\\PYZgt{}}\\PY{+w}{ }\\PY{p}{.}\n", + "\n", + "\\PY{err}{p}\\PY{err}{r}\\PY{err}{e}\\PY{err}{f}\\PY{err}{i}\\PY{err}{x}\\PY{p}{:}\\PY{+w}{ }\\PY{k+kt}{a}\\PY{+w}{ }\\PY{n+nn}{senpy:}\\PY{n+nt}{Entry}\\PY{+w}{ }\\PY{p}{;}\n", + "\\PY{+w}{ }\\PY{n+nn}{nif:}\\PY{n+nt}{isString}\\PY{+w}{ }\\PY{l+s}{\\PYZdq{}}\\PY{l+s}{Senpy is awesome}\\PY{l+s}{\\PYZdq{}}\\PY{+w}{ }\\PY{p}{;}\n", + "\\PY{+w}{ }\\PY{n+nn}{marl:}\\PY{n+nt}{hasOpinion}\\PY{+w}{ }\\PY{p}{[}\\PY{+w}{ }\\PY{k+kt}{a}\\PY{+w}{ }\\PY{n+nn}{senpy:}\\PY{n+nt}{Sentiment}\\PY{+w}{ }\\PY{p}{;}\n", + "\\PY{+w}{ }\\PY{n+nn}{marl:}\\PY{n+nt}{hasPolarity}\\PY{+w}{ }\\PY{l+s}{\\PYZdq{}}\\PY{l+s}{marl:Positive}\\PY{l+s}{\\PYZdq{}}\\PY{+w}{ }\\PY{p}{;}\n", + "\\PY{+w}{ }\\PY{n+nn}{prov:}\\PY{n+nt}{wasGeneratedBy}\\PY{+w}{ }\\PY{n+nn}{prefix:}\\PY{n+nt}{Analysis\\PYZus{}1563372853}\\PY{l+m+mf}{.6874764}\\PY{+w}{ }\\PY{p}{]}\\PY{+w}{ }\\PY{p}{.}\n", + "\n", + "\\PY{p}{[}\\PY{p}{]}\\PY{+w}{ }\\PY{k+kt}{a}\\PY{+w}{ }\\PY{n+nn}{senpy:}\\PY{n+nt}{Results}\\PY{+w}{ }\\PY{p}{;}\n", + "\\PY{+w}{ }\\PY{n+nn}{prov:}\\PY{n+nt}{used}\\PY{+w}{ }\\PY{err}{p}\\PY{err}{r}\\PY{err}{e}\\PY{err}{f}\\PY{err}{i}\\PY{err}{x}\\PY{p}{:}\\PY{+w}{ }\\PY{p}{.}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "@prefix : .\n", + "@prefix dc: .\n", + "@prefix emoml: .\n", + "@prefix endpoint: .\n", + "@prefix fam: .\n", + "@prefix marl: .\n", + "@prefix nif: .\n", + "@prefix onyx: .\n", + "@prefix prefix: .\n", + "@prefix prov: .\n", + "@prefix rdf: .\n", + "@prefix rdfs: .\n", + "@prefix senpy: .\n", + "@prefix wna: .\n", + "@prefix xml: .\n", + "@prefix xsd: .\n", + "\n", + "prefix: a senpy:Entry ;\n", + " nif:isString \"Senpy is awesome\" ;\n", + " marl:hasOpinion [ a senpy:Sentiment ;\n", + " marl:hasPolarity \"marl:Positive\" ;\n", + " prov:wasGeneratedBy prefix:Analysis_1563372853.6874764 ] .\n", + "\n", + "[] a senpy:Results ;\n", + " prov:used prefix: .\n" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" } + ], + "source": [ + "query(f'{endpoint}/sentiment140',\n", + " input=\"Senpy is awesome\",\n", + " outformat=\"turtle\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Moving to a different service" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All senpy plugins use the same API, which makes moving from one service to another a breeze.\n", + "\n", + "Let us modify the earlier example, which uses the `sentiment140` service, to use a different service (e.g. the `sentiment-basic` plugin).\n", + "We can do it just by changing the URL of the service:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "scrolled": false }, + "outputs": [ + { + "data": { + "text/html": [ + "
{\n",
+       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudC1iYXNpYz9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D",\n",
+       "  "@type": "Results",\n",
+       "  "entries": [\n",
+       "    {\n",
+       "      "@id": "prefix:",\n",
+       "      "@type": "Entry",\n",
+       "      "marl:hasOpinion": [\n",
+       "        {\n",
+       "          "@type": "Sentiment",\n",
+       "          "marl:hasPolarity": "marl:Neutral",\n",
+       "          "prov:wasGeneratedBy": "prefix:Analysis_1563372853.8034046"\n",
+       "        }\n",
+       "      ],\n",
+       "      "nif:isString": "Senpy is awesome",\n",
+       "      "onyx:hasEmotionSet": []\n",
+       "    }\n",
+       "  ]\n",
+       "}\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudC1iYXNpYz9pbnB1dD1TZW5weStpcythd2Vzb21lIw\\PYZpc{}3D\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Sentiment\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}marl:hasPolarity\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}marl:Neutral\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372853.8034046\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is awesome\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + "\\PY{p}{\\PYZcb{}}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "{\n", + " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudC1iYXNpYz9pbnB1dD1TZW5weStpcythd2Vzb21lIw%3D%3D\",\n", + " \"@type\": \"Results\",\n", + " \"entries\": [\n", + " {\n", + " \"@id\": \"prefix:\",\n", + " \"@type\": \"Entry\",\n", + " \"marl:hasOpinion\": [\n", + " {\n", + " \"@type\": \"Sentiment\",\n", + " \"marl:hasPolarity\": \"marl:Neutral\",\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372853.8034046\"\n", + " }\n", + " ],\n", + " \"nif:isString\": \"Senpy is awesome\",\n", + " \"onyx:hasEmotionSet\": []\n", + " }\n", + " ]\n", + "}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query(f'{endpoint}/sentiment-basic',\n", + " input=\"Senpy is awesome\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "* [Senpy in 1 minute](./Quickstart-1minute.ipynb) shows how to query the API.\n", - "* [Senpy in 10 minutes](./Quickstart-10minutes.ipynb) introduces basic sentiment and emotion analysis.\n", - "* [Senpy in 30 minutes](./Quickstart-30minutes.ipynb) builds on the previous and adds more advanced functionalities, such as emotion conversion, field selection and pipelines." + "As you can see, the structure and annotation schema of the response is the same.\n", + "This makes it very easy to compare and migrate to different services.\n", + "\n", + "Service interoperability is not only useful for users.\n", + "It is also key for other features such as [automated evaluation](http://senpy.readthedocs.io/Evaluation.html).\n", + "This is a compelling reason to adapt existing services to use the Senpy API.\n", + "In fact, the `sentiment140` senpy service is proxy to the public [Sentiment 140 service](http://www.sentiment140.com/)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Emotion analysis" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Senpy uses the `onyx` vocabulary to represent emotions, which incorporates the notion of `EmotionSet`'s, an emotion that is composed of several emotions.\n", + "In a nutshell, an `Entry` is linked to one or more `EmotionSet`, which in turn is made up of one or more `Emotion`.\n", + "\n", + "Let's illustrate it with an example, using the `emotion-depechemood` plugin." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
{\n",
+       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q_aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrdGhhdCtzZXJ2aWNlIw%3D%3D",\n",
+       "  "@type": "Results",\n",
+       "  "entries": [\n",
+       "    {\n",
+       "      "@id": "prefix:",\n",
+       "      "@type": "Entry",\n",
+       "      "marl:hasOpinion": [],\n",
+       "      "nif:isString": "Senpy is a wonderful that service",\n",
+       "      "onyx:hasEmotionSet": [\n",
+       "        {\n",
+       "          "@type": "EmotionSet",\n",
+       "          "onyx:hasEmotion": [\n",
+       "            {\n",
+       "              "@type": "Emotion",\n",
+       "              "onyx:hasEmotionCategory": "wna:negative-fear",\n",
+       "              "onyx:hasEmotionIntensity": 0.06258366271018097\n",
+       "            },\n",
+       "            {\n",
+       "              "@type": "Emotion",\n",
+       "              "onyx:hasEmotionCategory": "wna:amusement",\n",
+       "              "onyx:hasEmotionIntensity": 0.15784834034155437\n",
+       "            },\n",
+       "            {\n",
+       "              "@type": "Emotion",\n",
+       "              "onyx:hasEmotionCategory": "wna:anger",\n",
+       "              "onyx:hasEmotionIntensity": 0.08728815135373413\n",
+       "            },\n",
+       "            {\n",
+       "              "@type": "Emotion",\n",
+       "              "onyx:hasEmotionCategory": "wna:annoyance",\n",
+       "              "onyx:hasEmotionIntensity": 0.12184635680460143\n",
+       "            },\n",
+       "            {\n",
+       "              "@type": "Emotion",\n",
+       "              "onyx:hasEmotionCategory": "wna:indifference",\n",
+       "              "onyx:hasEmotionIntensity": 0.1374081151031531\n",
+       "            },\n",
+       "            {\n",
+       "              "@type": "Emotion",\n",
+       "              "onyx:hasEmotionCategory": "wna:joy",\n",
+       "              "onyx:hasEmotionIntensity": 0.12267040802346799\n",
+       "            },\n",
+       "            {\n",
+       "              "@type": "Emotion",\n",
+       "              "onyx:hasEmotionCategory": "wna:awe",\n",
+       "              "onyx:hasEmotionIntensity": 0.21085262130713067\n",
+       "            },\n",
+       "            {\n",
+       "              "@type": "Emotion",\n",
+       "              "onyx:hasEmotionCategory": "wna:sadness",\n",
+       "              "onyx:hasEmotionIntensity": 0.09950234435617733\n",
+       "            }\n",
+       "          ],\n",
+       "          "prov:wasGeneratedBy": "prefix:Analysis_1563372853.9469151"\n",
+       "        }\n",
+       "      ]\n",
+       "    }\n",
+       "  ]\n",
+       "}\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q\\PYZus{}aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrdGhhdCtzZXJ2aWNlIw\\PYZpc{}3D\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful that service\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:negative\\PYZhy{}fear\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.06258366271018097}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:amusement\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.15784834034155437}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:anger\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.08728815135373413}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:annoyance\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.12184635680460143}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:indifference\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.1374081151031531}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:joy\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.12267040802346799}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:awe\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.21085262130713067}\n", + " \\PY{p}{\\PYZcb{}}\\PY{p}{,}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:sadness\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.09950234435617733}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372853.9469151\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + "\\PY{p}{\\PYZcb{}}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "{\n", + " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q_aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrdGhhdCtzZXJ2aWNlIw%3D%3D\",\n", + " \"@type\": \"Results\",\n", + " \"entries\": [\n", + " {\n", + " \"@id\": \"prefix:\",\n", + " \"@type\": \"Entry\",\n", + " \"marl:hasOpinion\": [],\n", + " \"nif:isString\": \"Senpy is a wonderful that service\",\n", + " \"onyx:hasEmotionSet\": [\n", + " {\n", + " \"@type\": \"EmotionSet\",\n", + " \"onyx:hasEmotion\": [\n", + " {\n", + " \"@type\": \"Emotion\",\n", + " \"onyx:hasEmotionCategory\": \"wna:negative-fear\",\n", + " \"onyx:hasEmotionIntensity\": 0.06258366271018097\n", + " },\n", + " {\n", + " \"@type\": \"Emotion\",\n", + " \"onyx:hasEmotionCategory\": \"wna:amusement\",\n", + " \"onyx:hasEmotionIntensity\": 0.15784834034155437\n", + " },\n", + " {\n", + " \"@type\": \"Emotion\",\n", + " \"onyx:hasEmotionCategory\": \"wna:anger\",\n", + " \"onyx:hasEmotionIntensity\": 0.08728815135373413\n", + " },\n", + " {\n", + " \"@type\": \"Emotion\",\n", + " \"onyx:hasEmotionCategory\": \"wna:annoyance\",\n", + " \"onyx:hasEmotionIntensity\": 0.12184635680460143\n", + " },\n", + " {\n", + " \"@type\": \"Emotion\",\n", + " \"onyx:hasEmotionCategory\": \"wna:indifference\",\n", + " \"onyx:hasEmotionIntensity\": 0.1374081151031531\n", + " },\n", + " {\n", + " \"@type\": \"Emotion\",\n", + " \"onyx:hasEmotionCategory\": \"wna:joy\",\n", + " \"onyx:hasEmotionIntensity\": 0.12267040802346799\n", + " },\n", + " {\n", + " \"@type\": \"Emotion\",\n", + " \"onyx:hasEmotionCategory\": \"wna:awe\",\n", + " \"onyx:hasEmotionIntensity\": 0.21085262130713067\n", + " },\n", + " {\n", + " \"@type\": \"Emotion\",\n", + " \"onyx:hasEmotionCategory\": \"wna:sadness\",\n", + " \"onyx:hasEmotionIntensity\": 0.09950234435617733\n", + " }\n", + " ],\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372853.9469151\"\n", + " }\n", + " ]\n", + " }\n", + " ]\n", + "}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query(f'{endpoint}/emotion-depechemood',\n", + " input=\"Senpy is a wonderful that service\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you have probably noticed, there are several emotions in this result, each with a different intensity.\n", + "\n", + "We can also tell senpy to only return the emotion with the maximum intensity using the `maxemotion` parameter:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
{\n",
+       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q_aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrc2VydmljZSZtYXhlbW90aW9uPVRydWUj",\n",
+       "  "@type": "Results",\n",
+       "  "entries": [\n",
+       "    {\n",
+       "      "@id": "prefix:",\n",
+       "      "@type": "Entry",\n",
+       "      "marl:hasOpinion": [],\n",
+       "      "nif:isString": "Senpy is a wonderful service",\n",
+       "      "onyx:hasEmotionSet": [\n",
+       "        {\n",
+       "          "@type": "EmotionSet",\n",
+       "          "onyx:hasEmotion": [\n",
+       "            {\n",
+       "              "@type": "Emotion",\n",
+       "              "onyx:hasEmotionCategory": "wna:awe",\n",
+       "              "onyx:hasEmotionIntensity": 0.21085262130713067\n",
+       "            }\n",
+       "          ],\n",
+       "          "prov:wasGeneratedBy": "prefix:Analysis_1563372854.0490181"\n",
+       "        }\n",
+       "      ]\n",
+       "    }\n",
+       "  ]\n",
+       "}\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q\\PYZus{}aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrc2VydmljZSZtYXhlbW90aW9uPVRydWUj\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionCategory\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}wna:awe\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionIntensity\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{0.21085262130713067}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372854.0490181\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + "\\PY{p}{\\PYZcb{}}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "{\n", + " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tZGVwZWNoZW1vb2Q_aW5wdXQ9U2VucHkraXMrYSt3b25kZXJmdWwrc2VydmljZSZtYXhlbW90aW9uPVRydWUj\",\n", + " \"@type\": \"Results\",\n", + " \"entries\": [\n", + " {\n", + " \"@id\": \"prefix:\",\n", + " \"@type\": \"Entry\",\n", + " \"marl:hasOpinion\": [],\n", + " \"nif:isString\": \"Senpy is a wonderful service\",\n", + " \"onyx:hasEmotionSet\": [\n", + " {\n", + " \"@type\": \"EmotionSet\",\n", + " \"onyx:hasEmotion\": [\n", + " {\n", + " \"@type\": \"Emotion\",\n", + " \"onyx:hasEmotionCategory\": \"wna:awe\",\n", + " \"onyx:hasEmotionIntensity\": 0.21085262130713067\n", + " }\n", + " ],\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372854.0490181\"\n", + " }\n", + " ]\n", + " }\n", + " ]\n", + "}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query(f'{endpoint}/emotion-depechemood',\n", + " input=\"Senpy is a wonderful service\",\n", + " maxemotion=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Emotion conversion\n", + "\n", + "Sometimes the model used by a plugin is not right for your application. Senpy ships with emotion conversion capabilities: you can ask for a specific emotion model in your request and the service will try to automatically convert the results.\n", + "\n", + "For example, the `emotion-anew` plugin uses the dimensional `pad` (or VAD, valence-arousal-dominance) model, as we can see here:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
{\n",
+       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQj",\n",
+       "  "@type": "Results",\n",
+       "  "entries": [\n",
+       "    {\n",
+       "      "@id": "prefix:",\n",
+       "      "@type": "Entry",\n",
+       "      "marl:hasOpinion": [],\n",
+       "      "nif:isString": "Senpy is a wonderful service and I love it",\n",
+       "      "onyx:hasEmotionSet": [\n",
+       "        {\n",
+       "          "@id": "Emotions0",\n",
+       "          "@type": "EmotionSet",\n",
+       "          "onyx:hasEmotion": [\n",
+       "            {\n",
+       "              "@id": "Emotion0",\n",
+       "              "@type": "Emotion",\n",
+       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal": 6.44,\n",
+       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance": 7.11,\n",
+       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence": 8.72,\n",
+       "              "prov:wasGeneratedBy": "prefix:Analysis_1563372854.2822595"\n",
+       "            }\n",
+       "          ],\n",
+       "          "prov:wasGeneratedBy": "prefix:Analysis_1563372854.2822595"\n",
+       "        }\n",
+       "      ]\n",
+       "    }\n",
+       "  ]\n",
+       "}\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQj\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service and I love it\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotions0\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion0\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}arousal\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{6.44}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}dominance\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{7.11}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}valence\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{8.72}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372854.2822595\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372854.2822595\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + "\\PY{p}{\\PYZcb{}}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "{\n", + " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQj\",\n", + " \"@type\": \"Results\",\n", + " \"entries\": [\n", + " {\n", + " \"@id\": \"prefix:\",\n", + " \"@type\": \"Entry\",\n", + " \"marl:hasOpinion\": [],\n", + " \"nif:isString\": \"Senpy is a wonderful service and I love it\",\n", + " \"onyx:hasEmotionSet\": [\n", + " {\n", + " \"@id\": \"Emotions0\",\n", + " \"@type\": \"EmotionSet\",\n", + " \"onyx:hasEmotion\": [\n", + " {\n", + " \"@id\": \"Emotion0\",\n", + " \"@type\": \"Emotion\",\n", + " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal\": 6.44,\n", + " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance\": 7.11,\n", + " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence\": 8.72,\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372854.2822595\"\n", + " }\n", + " ],\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372854.2822595\"\n", + " }\n", + " ]\n", + " }\n", + " ]\n", + "}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query(f'{endpoint}/emotion-anew',\n", + " input=\"Senpy is a wonderful service and I love it\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we need a category level, we can ask for the equivalent results in the `big6` model:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
{\n",
+       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbm1vZGVsPWVtb21sJTNBYmlnNiM%3D",\n",
+       "  "@type": "Results",\n",
+       "  "entries": [\n",
+       "    {\n",
+       "      "@id": "prefix:",\n",
+       "      "@type": "Entry",\n",
+       "      "marl:hasOpinion": [],\n",
+       "      "nif:isString": "Senpy is a wonderful service and I love it",\n",
+       "      "onyx:hasEmotionSet": [\n",
+       "        {\n",
+       "          "@id": "Emotions0",\n",
+       "          "@type": "EmotionSet",\n",
+       "          "onyx:hasEmotion": [\n",
+       "            {\n",
+       "              "@id": "Emotion0",\n",
+       "              "@type": "Emotion",\n",
+       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal": 6.44,\n",
+       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance": 7.11,\n",
+       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence": 8.72,\n",
+       "              "prov:wasGeneratedBy": "prefix:Analysis_1563372854.3354168"\n",
+       "            }\n",
+       "          ],\n",
+       "          "prov:wasGeneratedBy": "prefix:Analysis_1563372854.3354168"\n",
+       "        }\n",
+       "      ]\n",
+       "    }\n",
+       "  ]\n",
+       "}\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbm1vZGVsPWVtb21sJTNBYmlnNiM\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service and I love it\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotions0\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion0\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}arousal\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{6.44}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}dominance\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{7.11}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}valence\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{8.72}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372854.3354168\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372854.3354168\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + "\\PY{p}{\\PYZcb{}}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "{\n", + " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbm1vZGVsPWVtb21sJTNBYmlnNiM%3D\",\n", + " \"@type\": \"Results\",\n", + " \"entries\": [\n", + " {\n", + " \"@id\": \"prefix:\",\n", + " \"@type\": \"Entry\",\n", + " \"marl:hasOpinion\": [],\n", + " \"nif:isString\": \"Senpy is a wonderful service and I love it\",\n", + " \"onyx:hasEmotionSet\": [\n", + " {\n", + " \"@id\": \"Emotions0\",\n", + " \"@type\": \"EmotionSet\",\n", + " \"onyx:hasEmotion\": [\n", + " {\n", + " \"@id\": \"Emotion0\",\n", + " \"@type\": \"Emotion\",\n", + " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal\": 6.44,\n", + " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance\": 7.11,\n", + " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence\": 8.72,\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372854.3354168\"\n", + " }\n", + " ],\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372854.3354168\"\n", + " }\n", + " ]\n", + " }\n", + " ]\n", + "}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query(f'{endpoint}/emotion-anew',\n", + " input=\"Senpy is a wonderful service and I love it\",\n", + " emotionmodel=\"emoml:big6\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Because we don't usually care about the original emotion, the conversion can be presented in three ways:\n", + "\n", + "* full: the original and converted emotions are included at the same level\n", + "* filtered: the original emotion is replaced by the converted emotion\n", + "* nested: the original emotion is replaced, but the converted emotion points to it\n", + "\n", + "For example, here's how the `nested` structure would look like:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
{\n",
+       "  "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbm1vZGVsPWVtb21sJTNBYmlnNiZjb252ZXJzaW9uPW5lc3RlZCM%3D",\n",
+       "  "@type": "Results",\n",
+       "  "entries": [\n",
+       "    {\n",
+       "      "@id": "prefix:",\n",
+       "      "@type": "Entry",\n",
+       "      "marl:hasOpinion": [],\n",
+       "      "nif:isString": "Senpy is a wonderful service and I love it",\n",
+       "      "onyx:hasEmotionSet": [\n",
+       "        {\n",
+       "          "@id": "Emotions0",\n",
+       "          "@type": "EmotionSet",\n",
+       "          "onyx:hasEmotion": [\n",
+       "            {\n",
+       "              "@id": "Emotion0",\n",
+       "              "@type": "Emotion",\n",
+       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal": 6.44,\n",
+       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance": 7.11,\n",
+       "              "http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence": 8.72,\n",
+       "              "prov:wasGeneratedBy": "prefix:Analysis_1563372854.3876536"\n",
+       "            }\n",
+       "          ],\n",
+       "          "prov:wasGeneratedBy": "prefix:Analysis_1563372854.3876536"\n",
+       "        }\n",
+       "      ]\n",
+       "    }\n",
+       "  ]\n",
+       "}\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@context\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbm1vZGVsPWVtb21sJTNBYmlnNiZjb252ZXJzaW9uPW5lc3RlZCM\\PYZpc{}3D\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Results\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}entries\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Entry\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}marl:hasOpinion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}nif:isString\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Senpy is a wonderful service and I love it\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotionSet\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotions0\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}EmotionSet\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}onyx:hasEmotion\\PYZdq{}}\\PY{p}{:} \\PY{p}{[}\n", + " \\PY{p}{\\PYZob{}}\n", + " \\PY{n+nd}{\\PYZdq{}@id\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion0\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nd}{\\PYZdq{}@type\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}Emotion\\PYZdq{}}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}arousal\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{6.44}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}dominance\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{7.11}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns\\PYZsh{}valence\\PYZdq{}}\\PY{p}{:} \\PY{l+m+mf}{8.72}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372854.3876536\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\\PY{p}{,}\n", + " \\PY{n+nt}{\\PYZdq{}prov:wasGeneratedBy\\PYZdq{}}\\PY{p}{:} \\PY{l+s+s2}{\\PYZdq{}prefix:Analysis\\PYZus{}1563372854.3876536\\PYZdq{}}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + " \\PY{p}{\\PYZcb{}}\n", + " \\PY{p}{]}\n", + "\\PY{p}{\\PYZcb{}}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "{\n", + " \"@context\": \"http://senpy.gsi.upm.es/api/contexts/YXBpL2Vtb3Rpb24tYW5ldz9pbnB1dD1TZW5weStpcythK3dvbmRlcmZ1bCtzZXJ2aWNlK2FuZCtJK2xvdmUraXQmZW1vdGlvbm1vZGVsPWVtb21sJTNBYmlnNiZjb252ZXJzaW9uPW5lc3RlZCM%3D\",\n", + " \"@type\": \"Results\",\n", + " \"entries\": [\n", + " {\n", + " \"@id\": \"prefix:\",\n", + " \"@type\": \"Entry\",\n", + " \"marl:hasOpinion\": [],\n", + " \"nif:isString\": \"Senpy is a wonderful service and I love it\",\n", + " \"onyx:hasEmotionSet\": [\n", + " {\n", + " \"@id\": \"Emotions0\",\n", + " \"@type\": \"EmotionSet\",\n", + " \"onyx:hasEmotion\": [\n", + " {\n", + " \"@id\": \"Emotion0\",\n", + " \"@type\": \"Emotion\",\n", + " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#arousal\": 6.44,\n", + " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#dominance\": 7.11,\n", + " \"http://www.gsi.dit.upm.es/ontologies/onyx/vocabularies/anew/ns#valence\": 8.72,\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372854.3876536\"\n", + " }\n", + " ],\n", + " \"prov:wasGeneratedBy\": \"prefix:Analysis_1563372854.3876536\"\n", + " }\n", + " ]\n", + " }\n", + " ]\n", + "}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query(f'{endpoint}/emotion-anew',\n", + " input=\"Senpy is a wonderful service and I love it\",\n", + " emotionmodel=\"emoml:big6\",\n", + " conversion=\"nested\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Learn more\n", + "\n", + "[A separate notebook](Advanced.ipynb) covers advanced topics such as listing all plugins available in an endpoint, or creating analysis pipelines that chain several analysis services." ] } ], "metadata": { "anaconda-cloud": {}, - "celltoolbar": "Edit Metadata", "kernelspec": { "display_name": "Python 3", "language": "python", diff --git a/docs/advanced.rst b/docs/advanced.rst deleted file mode 100644 index b07c218..0000000 --- a/docs/advanced.rst +++ /dev/null @@ -1,10 +0,0 @@ -Advanced usage --------------- - -.. toctree:: - :maxdepth: 1 - - server-cli - conversion - commandline - development diff --git a/docs/commandline.rst b/docs/commandline.rst deleted file mode 100644 index 47582a7..0000000 --- a/docs/commandline.rst +++ /dev/null @@ -1,10 +0,0 @@ -Command line -============ - -Although the main use of senpy is to publish services, the tool can also be used locally to analyze text in the command line. -This is a short video demonstration: - -.. image:: https://asciinema.org/a/9uwef1ghkjk062cw2t4mhzpyk.png - :width: 100% - :target: https://asciinema.org/a/9uwef1ghkjk062cw2t4mhzpyk - :alt: CLI demo diff --git a/docs/conf.py b/docs/conf.py index 1b1d06f..914ff4c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -130,6 +130,7 @@ html_theme_options = { 'github_user': 'gsi-upm', 'github_repo': 'senpy', 'github_banner': True, + 'sidebar_collapse': True, } diff --git a/docs/conversion.rst b/docs/conversion.rst index c761148..e287066 100644 --- a/docs/conversion.rst +++ b/docs/conversion.rst @@ -1,93 +1,152 @@ -Conversion ----------- +Automatic Model Conversion +-------------------------- -Senpy includes experimental support for emotion/sentiment conversion plugins. +Senpy includes support for emotion and sentiment conversion. +When a user requests a specific model, senpy will choose a strategy to convert the model that the service usually outputs and the model requested by the user. + +Out of the box, senpy can convert from the `emotionml:pad` (pleasure-arousal-dominance) dimensional model to `emoml:big6` (Ekman's big-6) categories, and vice versa. +This specific conversion uses a series of dimensional centroids (`emotionml:pad`) for each emotion category (`emotionml:big6`). +A dimensional value is converted to a category by looking for the nearest centroid. +The centroids are calculated according to this article: + +.. code-block:: text + + Kim, S. M., Valitutti, A., & Calvo, R. A. (2010, June). + Evaluation of unsupervised emotion models to textual affect recognition. + In Proceedings of the NAACL HLT 2010 Workshop on Computational Approaches to Analysis and Generation of Emotion in Text (pp. 62-70). + Association for Computational Linguistics. + + + +It is possible to add new conversion strategies by `Developing a conversion plugin`_. Use === -Consider the original query: http://127.0.0.1:5000/api/?i=hello&algo=emotion-random +Consider the following query to an emotion service: http://senpy.gsi.upm.es/api/emotion-anew?i=good -The requested plugin (emotion-random) returns emotions using Ekman's model (or big6 in EmotionML): +The requested plugin (emotion-random) returns emotions using the VAD space (FSRE dimensions in EmotionML): .. code:: json - ... rest of the document ... - { - "@type": "emotionSet", - "onyx:hasEmotion": { - "@type": "emotion", - "onyx:hasEmotionCategory": "emoml:big6anger" - }, - "prov:wasGeneratedBy": "plugins/emotion-random_0.1" - } + [ + { + "@type": "EmotionSet", + "onyx:hasEmotion": [ + { + "@type": "Emotion", + "emoml:pad-dimensions_arousal": 5.43, + "emoml:pad-dimensions_dominance": 6.41, + "emoml:pad-dimensions_pleasure": 7.47, + "prov:wasGeneratedBy": "prefix:Analysis_1562744784.8789825" + } + ], + "prov:wasGeneratedBy": "prefix:Analysis_1562744784.8789825" + } + ] + -To get these emotions in VAD space (FSRE dimensions in EmotionML), we'd do this: +To get the equivalent of these emotions in Ekman's categories (i.e., Ekman's Big 6 in EmotionML), we'd do this: -http://127.0.0.1:5000/api/?i=hello&algo=emotion-random&emotionModel=emoml:fsre-dimensions +http://senpy.gsi.upm.es/api/emotion-anew?i=good&emotion-model=emoml:big6 This call, provided there is a valid conversion plugin from Ekman's to VAD, would return something like this: .. code:: json - - ... rest of the document ... + [ + { + "@type": "EmotionSet", + "onyx:hasEmotion": [ { - "@type": "emotionSet", - "onyx:hasEmotion": { - "@type": "emotion", - "onyx:hasEmotionCategory": "emoml:big6anger" - }, - "prov:wasGeneratedBy": "plugins/emotion-random.1" - }, { - "@type": "emotionSet", - "onyx:hasEmotion": { - "@type": "emotion", - "A": 7.22, - "D": 6.28, - "V": 8.6 - }, - "prov:wasGeneratedBy": "plugins/Ekman2VAD_0.1" - + "@type": "Emotion", + "onyx:algorithmConfidence": 4.4979, + "onyx:hasEmotionCategory": "emoml:big6happiness" } + ], + "prov:wasDerivedFrom": { + "@id": "Emotions0", + "@type": "EmotionSet", + "onyx:hasEmotion": [ + { + "@id": "Emotion0", + "@type": "Emotion", + "emoml:pad-dimensions_arousal": 5.43, + "emoml:pad-dimensions_dominance": 6.41, + "emoml:pad-dimensions_pleasure": 7.47, + "prov:wasGeneratedBy": "prefix:Analysis_1562745220.1553965" + } + ], + "prov:wasGeneratedBy": "prefix:Analysis_1562745220.1553965" + }, + "prov:wasGeneratedBy": "prefix:Analysis_1562745220.1570725" + } + ] That is called a *full* response, as it simply adds the converted emotion alongside. It is also possible to get the original emotion nested within the new converted emotion, using the `conversion=nested` parameter: +http://senpy.gsi.upm.es/api/emotion-anew?i=good&emotion-model=emoml:big6&conversion=nested + .. code:: json + [ + { + "@type": "EmotionSet", + "onyx:hasEmotion": [ + { + "@type": "Emotion", + "onyx:algorithmConfidence": 4.4979, + "onyx:hasEmotionCategory": "emoml:big6happiness" + } + ], + "prov:wasDerivedFrom": { + "@id": "Emotions0", + "@type": "EmotionSet", + "onyx:hasEmotion": [ + { + "@id": "Emotion0", + "@type": "Emotion", + "emoml:pad-dimensions_arousal": 5.43, + "emoml:pad-dimensions_dominance": 6.41, + "emoml:pad-dimensions_pleasure": 7.47, + "prov:wasGeneratedBy": "prefix:Analysis_1562744962.896306" + } + ], + "prov:wasGeneratedBy": "prefix:Analysis_1562744962.896306" + }, + "prov:wasGeneratedBy": "prefix:Analysis_1562744962.8978968" + } + ] - ... rest of the document ... - { - "@type": "emotionSet", - "onyx:hasEmotion": { - "@type": "emotion", - "onyx:hasEmotionCategory": "emoml:big6anger" - }, - "prov:wasGeneratedBy": "plugins/emotion-random.1" - "onyx:wasDerivedFrom": { - "@type": "emotionSet", - "onyx:hasEmotion": { - "@type": "emotion", - "A": 7.22, - "D": 6.28, - "V": 8.6 - }, - "prov:wasGeneratedBy": "plugins/Ekman2VAD_0.1" - } - - } Lastly, `conversion=filtered` would only return the converted emotions. + +.. code:: json + + [ + { + "@type": "EmotionSet", + "onyx:hasEmotion": [ + { + "@type": "Emotion", + "onyx:algorithmConfidence": 4.4979, + "onyx:hasEmotionCategory": "emoml:big6happiness" + } + ], + "prov:wasGeneratedBy": "prefix:Analysis_1562744925.7322266" + } + ] + Developing a conversion plugin -================================ +============================== Conversion plugins are discovered by the server just like any other plugin. The difference is the slightly different API, and the need to specify the `source` and `target` of the conversion. @@ -106,7 +165,6 @@ For instance, an emotion conversion plugin needs the following: - .. code:: python @@ -114,3 +172,6 @@ For instance, an emotion conversion plugin needs the following: def convert(self, emotionSet, fromModel, toModel, params): pass + + +More implementation details are shown in the `centroids plugin `_. diff --git a/docs/demo.rst b/docs/demo.rst index 96ceea7..b645c09 100644 --- a/docs/demo.rst +++ b/docs/demo.rst @@ -2,7 +2,7 @@ Demo ---- There is a demo available on http://senpy.gsi.upm.es/, where you can test a live instance of Senpy, with several open source plugins. -You can use the playground (a web interface) or make HTTP requests to the service API. +You can use the playground (a web interface) or the HTTP API. .. image:: playground-0.20.png :target: http://senpy.gsi.upm.es diff --git a/docs/development.rst b/docs/development.rst index 5def52e..3b0c1ab 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -19,6 +19,7 @@ Sharing your sentiment analysis with the world has never been easier! .. toctree:: :maxdepth: 1 + server-cli plugins-quickstart plugins-faq plugins-definition diff --git a/docs/eval_table.png b/docs/eval_table.png new file mode 100644 index 0000000..a7e7570 Binary files /dev/null and b/docs/eval_table.png differ diff --git a/docs/index.rst b/docs/index.rst index 04432d5..bbd00b4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,24 +12,97 @@ Welcome to Senpy's documentation! .. image:: https://img.shields.io/pypi/l/requests.svg :target: https://lab.gsi.upm.es/senpy/senpy/ +Senpy is a framework to build sentiment and emotion analysis services. +It provides functionalities for: -Senpy is a framework for sentiment and emotion analysis services. -Senpy services are interchangeable and easy to use because they share a common semantic :doc:`apischema`. +- developing sentiment and emotion classifier and exposing them as an HTTP service +- requesting sentiment and emotion analysis from different providers (i.e. Vader, Sentimet140, ...) using the same interface (:doc:`apischema`). In this way, applications do not depend on the API offered for these services. +- combining services that use different sentiment model (e.g. polarity between [-1, 1] or [0,1] or emotion models (e.g. Ekkman or VAD) +- evaluating sentiment algorithms with well known datasets -If you interested in consuming Senpy services, read :doc:`Quickstart`. + +Using senpy services is as simple as sending an HTTP request with your favourite tool or library. +Let's analyze the sentiment of the text "Senpy is awesome". + +We can call the `Sentiment140 `_ service with an HTTP request using curl: + + +.. code:: shell + :emphasize-lines: 14,18 + + $ curl "http://senpy.gsi.upm.es/api/sentiment140" \ + --data-urlencode "input=Senpy is awesome" + + { + "@context": "http://senpy.gsi.upm.es/api/contexts/YXBpL3NlbnRpbWVudDE0MD8j", + "@type": "Results", + "entries": [ + { + "@id": "prefix:", + "@type": "Entry", + "marl:hasOpinion": [ + { + "@type": "Sentiment", + "marl:hasPolarity": "marl:Positive", + "prov:wasGeneratedBy": "prefix:Analysis_1554389334.6431913" + } + ], + "nif:isString": "Senpy is awesome", + "onyx:hasEmotionSet": [] + } + ] + } + + +Congratulations, you’ve used your first senpy service! +You can observe the result: the polarity is positive (marl:Positive). The reason of this prefix is that Senpy follows a linked data approach. + +You can analyze the same sentence using a different sentiment service (e.g. Vader) and requesting a different format (e.g. turtle): + + + +.. code:: shell + + $ curl "http://senpy.gsi.upm.es/api/sentiment-vader" \ + --data-urlencode "input=Senpy is awesome" \ + --data-urlencode "outformat=turtle" + + @prefix : . + @prefix endpoint: . + @prefix marl: . + @prefix nif: . + @prefix prefix: . + @prefix prov: . + @prefix senpy: . + + prefix: a senpy:Entry ; + nif:isString "Senpy is awesome" ; + marl:hasOpinion [ a senpy:Sentiment ; + marl:hasPolarity "marl:Positive" ; + marl:polarityValue 6.72e-01 ; + prov:wasGeneratedBy prefix:Analysis_1562668175.9808676 ] . + + [] a senpy:Results ; + prov:used prefix: . + +As you see, Vader returns also the polarity value (0.67) in addition to the category (positive). + +If you are interested in consuming Senpy services, read :doc:`Quickstart`. To get familiar with the concepts behind Senpy, and what it can offer for service developers, check out :doc:`development`. :doc:`apischema` contains information about the semantic models and vocabularies used by Senpy. - .. toctree:: :caption: Learn more about senpy: :maxdepth: 2 + :hidden: senpy demo Quickstart.ipynb installation + conversion + Evaluation.ipynb apischema - advanced + development publications - + projects diff --git a/docs/installation.rst b/docs/installation.rst index e81d1f6..7aadd88 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -17,18 +17,20 @@ Through PIP .. code:: bash - pip install --user senpy + pip install senpy + + # Or with --user if you get permission errors: + pip install --user senpy -Alternatively, you can use the development version: - -.. code:: bash +.. + Alternatively, you can use the development version: - git clone git@github.com:gsi-upm/senpy - cd senpy - pip install --user . + .. code:: bash -If you want to install senpy globally, use sudo instead of the ``--user`` flag. + git clone git@github.com:gsi-upm/senpy + cd senpy + pip install --user . Docker Image ************ diff --git a/docs/plugins-definition.rst b/docs/plugins-definition.rst index bec02a8..a078b3a 100644 --- a/docs/plugins-definition.rst +++ b/docs/plugins-definition.rst @@ -9,20 +9,21 @@ Lastly, it is also possible to add new plugins programmatically. .. contents:: :local: -What is a plugin? -================= +.. + What is a plugin? + ================= -A plugin is a program that, given a text, will add annotations to it. -In practice, a plugin consists of at least two files: + A plugin is a program that, given a text, will add annotations to it. + In practice, a plugin consists of at least two files: -- Definition file: a `.senpy` file that describes the plugin (e.g. what input parameters it accepts, what emotion model it uses). -- Python module: the actual code that will add annotations to each input. + - Definition file: a `.senpy` file that describes the plugin (e.g. what input parameters it accepts, what emotion model it uses). + - Python module: the actual code that will add annotations to each input. -This separation allows us to deploy plugins that use the same code but employ different parameters. -For instance, one could use the same classifier and processing in several plugins, but train with different datasets. -This scenario is particularly useful for evaluation purposes. + This separation allows us to deploy plugins that use the same code but employ different parameters. + For instance, one could use the same classifier and processing in several plugins, but train with different datasets. + This scenario is particularly useful for evaluation purposes. -The only limitation is that the name of each plugin needs to be unique. + The only limitation is that the name of each plugin needs to be unique. Definition files ================ @@ -109,5 +110,3 @@ Now, in a file named ``helloworld.py``: sentiment['marl:hasPolarity'] = 'marl:Negative' entry.sentiments.append(sentiment) yield entry - -The complete code of the example plugin is available `here `__. diff --git a/docs/plugins-faq.rst b/docs/plugins-faq.rst index bfc5967..6f55168 100644 --- a/docs/plugins-faq.rst +++ b/docs/plugins-faq.rst @@ -23,7 +23,7 @@ In practice, this is what a plugin looks like, tests included: .. literalinclude:: ../example-plugins/rand_plugin.py - :emphasize-lines: 5-11 + :emphasize-lines: 21-28 :language: python diff --git a/docs/plugins-quickstart.rst b/docs/plugins-quickstart.rst index a55a4f3..0577a6e 100644 --- a/docs/plugins-quickstart.rst +++ b/docs/plugins-quickstart.rst @@ -37,7 +37,8 @@ The framework consists of two main modules: Senpy core, which is the building bl What is a plugin? ################# -A plugin is a python object that can process entries. Given an entry, it will modify it, add annotations to it, or generate new entries. +A plugin is a python object that can process entries. +Given an entry, it will modify it, add annotations to it, or generate new entries. What is an entry? diff --git a/docs/projects.rst b/docs/projects.rst new file mode 100644 index 0000000..7664ad0 --- /dev/null +++ b/docs/projects.rst @@ -0,0 +1,49 @@ +Projects using Senpy +-------------------- + +Are you using Senpy in your work?, we would love to hear from you! +Here is a list of on-going and past projects that have benefited from senpy: + + +MixedEmotions +,,,,,,,,,,,,, + +`MixedEmotions `_ develops innovative multilingual multi-modal Big Data analytics applications. +The analytics relies on a common toolbox for multi-modal sentiment and emotion analysis. +The NLP parts of the toolbox are based on senpy and its API. + +The toolbox is featured in this publication: + +.. code-block:: text + + Buitelaar, P., Wood, I. D., Arcan, M., McCrae, J. P., Abele, A., Robin, C., … Tummarello, G. (2018). + MixedEmotions: An Open-Source Toolbox for Multi-Modal Emotion Analysis. + IEEE Transactions on Multimedia. + +EuroSentiment +,,,,,,,,,,,,, + +The aim of the EUROSENTIMENT project was to create a pool for multilingual language resources and services for Sentiment Analysis. + +The EuroSentiment project was the main motivation behind the development of Senpy, and some early versions were used: + +.. code-block:: text + + Sánchez-Rada, J. F., Vulcu, G., Iglesias, C. A., & Buitelaar, P. (2014). + EUROSENTIMENT: Linked Data Sentiment Analysis. + Proceedings of the ISWC 2014 Posters & Demonstrations Track + 13th International Semantic Web Conference (ISWC 2014) (Vol. 1272, pp. 145–148). + + +SoMeDi +,,,,,, +`SoMeDi `_ is an ITEA3 project to research machine learning and artificial intelligence techniques that can be used to turn digital interaction data into Digital Interaction Intelligence and approaches that can be used to effectively enter and act in social media, and to automate this process. +SoMeDi exploits senpy's interoperability of services in their customizable data enrichment and NLP workflows. + +TRIVALENT +,,,,,,,,, + +`TRIVALENT `_ is an EU funded project which aims to a better understanding of root causes of the phenomenon of violent radicalisation in Europe in order to develop appropriate countermeasures, ranging from early detection methodologies to techniques of counter-narrative. + +In addition to sentiment and emotion analysis services, trivalent provides other types of senpy services such as radicalism and writing style analysis. + diff --git a/docs/publications.rst b/docs/publications.rst index edd646c..a3cb4ea 100644 --- a/docs/publications.rst +++ b/docs/publications.rst @@ -2,7 +2,7 @@ Publications ============ -If you use Senpy in your research, please cite `Senpy: A Pragmatic Linked Sentiment Analysis Framework `__ (`BibTex `__): +And if you use Senpy in your research, please cite `Senpy: A Pragmatic Linked Sentiment Analysis Framework `__ (`BibTex `__): .. code-block:: text @@ -12,7 +12,6 @@ If you use Senpy in your research, please cite `Senpy: A Pragmatic Linked Sentim 2016 IEEE International Conference on (pp. 735-742). IEEE. - Senpy uses Onyx for emotion representation, first introduced in: .. code-block:: text @@ -28,19 +27,10 @@ Senpy uses Marl for sentiment representation, which was presented in: Westerski, A., Iglesias Fernandez, C. A., & Tapia Rico, F. (2011). Linked opinions: Describing sentiments on the structured web of data. - -Senpy has been used extensively in the toolbox of the MixedEmotions project: - -.. code-block:: text - - Buitelaar, P., Wood, I. D., Arcan, M., McCrae, J. P., Abele, A., Robin, C., … Tummarello, G. (2018). - MixedEmotions: An Open-Source Toolbox for Multi-Modal Emotion Analysis. - IEEE Transactions on Multimedia. - The representation models, formats and challenges are partially covered in a chapter of the book Sentiment Analysis in Social Networks: .. code-block:: text Iglesias, C. A., Sánchez-Rada, J. F., Vulcu, G., & Buitelaar, P. (2017). Linked Data Models for Sentiment and Emotion Analysis in Social Networks. - In Sentiment Analysis in Social Networks (pp. 49-69). \ No newline at end of file + In Sentiment Analysis in Social Networks (pp. 49-69). diff --git a/docs/server-cli.rst b/docs/server-cli.rst index 1bd4d5e..11135f2 100644 --- a/docs/server-cli.rst +++ b/docs/server-cli.rst @@ -1,5 +1,8 @@ -Server -====== +Command line tool +================= + +Basic usage +----------- The senpy server is launched via the `senpy` command: @@ -70,3 +73,14 @@ For instance, to accept connections on port 6000 on any interface: senpy --host 0.0.0.0 --port 6000 For more options, see the `--help` page. + +Sentiment analysis in the command line +-------------------------------------- + +Although the main use of senpy is to publish services, the tool can also be used locally to analyze text in the command line. +This is a short video demonstration: + +.. image:: https://asciinema.org/a/9uwef1ghkjk062cw2t4mhzpyk.png + :width: 100% + :target: https://asciinema.org/a/9uwef1ghkjk062cw2t4mhzpyk + :alt: CLI demo diff --git a/example-plugins/async_plugin.py b/example-plugins/async_plugin.py index dd628f1..3bc008a 100644 --- a/example-plugins/async_plugin.py +++ b/example-plugins/async_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy import AnalysisPlugin import multiprocessing diff --git a/example-plugins/basic.py b/example-plugins/basic.py index 1c0c78f..93aaaad 100644 --- a/example-plugins/basic.py +++ b/example-plugins/basic.py @@ -1,5 +1,21 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + emoticons = { 'pos': [':)', ':]', '=)', ':D'], diff --git a/example-plugins/basic_analyse_entry_plugin.py b/example-plugins/basic_analyse_entry_plugin.py index b0b28bc..3ec042d 100644 --- a/example-plugins/basic_analyse_entry_plugin.py +++ b/example-plugins/basic_analyse_entry_plugin.py @@ -1,5 +1,20 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# from senpy import easy_test, models, plugins diff --git a/example-plugins/basic_box_plugin.py b/example-plugins/basic_box_plugin.py index fa7d111..2bf6c09 100644 --- a/example-plugins/basic_box_plugin.py +++ b/example-plugins/basic_box_plugin.py @@ -1,5 +1,20 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# from senpy import easy_test, SentimentBox diff --git a/example-plugins/basic_plugin.py b/example-plugins/basic_plugin.py index 0f62f4e..6debd0a 100644 --- a/example-plugins/basic_plugin.py +++ b/example-plugins/basic_plugin.py @@ -1,5 +1,21 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy import easy_test, SentimentBox diff --git a/example-plugins/configurable_plugin.py b/example-plugins/configurable_plugin.py index fcdd22b..c61dcef 100644 --- a/example-plugins/configurable_plugin.py +++ b/example-plugins/configurable_plugin.py @@ -1,5 +1,21 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy import easy_test, models, plugins diff --git a/example-plugins/dummy_plugin.py b/example-plugins/dummy_plugin.py index 7ee2754..640b336 100644 --- a/example-plugins/dummy_plugin.py +++ b/example-plugins/dummy_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy import AnalysisPlugin, easy diff --git a/example-plugins/dummy_required_plugin.py b/example-plugins/dummy_required_plugin.py index 237d7ba..def98a2 100644 --- a/example-plugins/dummy_required_plugin.py +++ b/example-plugins/dummy_required_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy import AnalysisPlugin, easy diff --git a/example-plugins/emorand_plugin.py b/example-plugins/emorand_plugin.py index 42283cb..0ed1e22 100644 --- a/example-plugins/emorand_plugin.py +++ b/example-plugins/emorand_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import random from senpy.plugins import EmotionPlugin diff --git a/example-plugins/mynoop.py b/example-plugins/mynoop.py index 98b05b7..0f443d0 100644 --- a/example-plugins/mynoop.py +++ b/example-plugins/mynoop.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import noop from senpy.plugins import SentimentPlugin diff --git a/example-plugins/parameterized_plugin.py b/example-plugins/parameterized_plugin.py index f915d38..87c8176 100644 --- a/example-plugins/parameterized_plugin.py +++ b/example-plugins/parameterized_plugin.py @@ -1,5 +1,21 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy import easy_test, models, plugins diff --git a/example-plugins/rand_plugin.py b/example-plugins/rand_plugin.py index 0c9363a..b3d1d87 100644 --- a/example-plugins/rand_plugin.py +++ b/example-plugins/rand_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import random from senpy import SentimentPlugin, Sentiment, Entry diff --git a/example-plugins/sklearn/mydata.py b/example-plugins/sklearn/mydata.py index 7368842..6786430 100644 --- a/example-plugins/sklearn/mydata.py +++ b/example-plugins/sklearn/mydata.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + ''' Create a dummy dataset. Messages with a happy emoticon are labelled positive diff --git a/example-plugins/sklearn/mypipeline.py b/example-plugins/sklearn/mypipeline.py index 0394e1e..45f6eab 100644 --- a/example-plugins/sklearn/mypipeline.py +++ b/example-plugins/sklearn/mypipeline.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from sklearn.pipeline import Pipeline from sklearn.feature_extraction.text import CountVectorizer from sklearn.model_selection import train_test_split diff --git a/example-plugins/sklearn/pipeline_plugin.py b/example-plugins/sklearn/pipeline_plugin.py index a4d4b52..64d7bb9 100644 --- a/example-plugins/sklearn/pipeline_plugin.py +++ b/example-plugins/sklearn/pipeline_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy import SentimentBox, easy_test from mypipeline import pipeline diff --git a/example-plugins/sleep_plugin.py b/example-plugins/sleep_plugin.py index 95d4381..38c00fe 100644 --- a/example-plugins/sleep_plugin.py +++ b/example-plugins/sleep_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy.plugins import AnalysisPlugin from time import sleep diff --git a/senpy/__init__.py b/senpy/__init__.py index 035c097..f0d31a3 100644 --- a/senpy/__init__.py +++ b/senpy/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright 2014 J. Fernando Sánchez Rada - Grupo de Sistemas Inteligentes -# DIT, UPM +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,6 +14,7 @@ # 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. +# """ Sentiment analysis server in Python """ diff --git a/senpy/__main__.py b/senpy/__main__.py index 640b5ad..bb5d1d1 100644 --- a/senpy/__main__.py +++ b/senpy/__main__.py @@ -1,7 +1,6 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright 2014 J. Fernando Sánchez Rada - Grupo de Sistemas Inteligentes -# DIT, UPM +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/senpy/api.py b/senpy/api.py index 8e0503e..b11e162 100644 --- a/senpy/api.py +++ b/senpy/api.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from future.utils import iteritems from .models import Error, Results, Entry, from_string import logging diff --git a/senpy/blueprints.py b/senpy/blueprints.py index a3b4f0a..34b5f7e 100644 --- a/senpy/blueprints.py +++ b/senpy/blueprints.py @@ -1,19 +1,20 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright 2014 J. Fernando Sánchez Rada - Grupo de Sistemas Inteligentes -# DIT, UPM # -# 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 +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 # -# Unless required by applicable law or agreed to in writing, software +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software # 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. +# """ Blueprints for Senpy """ @@ -24,7 +25,7 @@ from . import api from .version import __version__ from functools import wraps -from .gsitk_compat import GSITK_AVAILABLE +from .gsitk_compat import GSITK_AVAILABLE, datasets import logging import json @@ -272,8 +273,6 @@ def plugin(plugin): @api_blueprint.route('/datasets/', methods=['POST', 'GET']) @basic_api -def datasets(): - sp = current_app.senpy - datasets = sp.datasets +def get_datasets(): dic = Datasets(datasets=list(datasets.values())) return dic diff --git a/senpy/cli.py b/senpy/cli.py index e0ee796..7bf203d 100644 --- a/senpy/cli.py +++ b/senpy/cli.py @@ -1,3 +1,18 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# from __future__ import print_function import sys diff --git a/senpy/client.py b/senpy/client.py index dfe0579..2805f5b 100644 --- a/senpy/client.py +++ b/senpy/client.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import requests import logging from . import models diff --git a/senpy/extensions.py b/senpy/extensions.py index 2f5f6a6..04c42d6 100644 --- a/senpy/extensions.py +++ b/senpy/extensions.py @@ -1,3 +1,18 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# """ Main class for Senpy. It orchestrates plugin (de)activation and analysis. @@ -274,36 +289,16 @@ class Senpy(object): return response def _get_datasets(self, request): - if not self.datasets: - raise Error( - status=404, - message=("No datasets found." - " Please verify DatasetManager")) datasets_name = request.parameters.get('dataset', None).split(',') for dataset in datasets_name: - if dataset not in self.datasets: + if dataset not in gsitk_compat.datasets: logger.debug(("The dataset '{}' is not valid\n" "Valid datasets: {}").format( - dataset, self.datasets.keys())) + dataset, gsitk_compat.datasets.keys())) raise Error( status=404, message="The dataset '{}' is not valid".format(dataset)) - dm = gsitk_compat.DatasetManager() - datasets = dm.prepare_datasets(datasets_name) - return datasets - - @property - def datasets(self): - self._dataset_list = {} - dm = gsitk_compat.DatasetManager() - for item in dm.get_datasets(): - for key in item: - if key in self._dataset_list: - continue - properties = item[key] - properties['@id'] = key - self._dataset_list[key] = properties - return self._dataset_list + return datasets_name def evaluate(self, params): logger.debug("evaluating request: {}".format(params)) diff --git a/senpy/gsitk_compat.py b/senpy/gsitk_compat.py index c91c1d7..1d46e09 100644 --- a/senpy/gsitk_compat.py +++ b/senpy/gsitk_compat.py @@ -1,4 +1,21 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import logging +import os from pkg_resources import parse_version, get_distribution, DistributionNotFound @@ -17,15 +34,34 @@ try: gsitk_distro = get_distribution("gsitk") GSITK_VERSION = parse_version(gsitk_distro.version) + if not os.environ.get('DATA_PATH'): + os.environ['DATA_PATH'] = os.environ.get('SENPY_DATA', 'senpy_data') + from gsitk.datasets.datasets import DatasetManager from gsitk.evaluation.evaluation import Evaluation as Eval # noqa: F401 from gsitk.evaluation.evaluation import EvalPipeline # noqa: F401 from sklearn.pipeline import Pipeline modules = locals() GSITK_AVAILABLE = True + datasets = {} + manager = DatasetManager() + + for item in manager.get_datasets(): + for key in item: + if key in datasets: + continue + properties = item[key] + properties['@id'] = key + datasets[key] = properties + + def prepare(ds, *args, **kwargs): + return manager.prepare_datasets(ds, *args, **kwargs) + + except (DistributionNotFound, ImportError) as err: logger.debug('Error importing GSITK: {}'.format(err)) logger.warning(IMPORTMSG) GSITK_AVAILABLE = False GSITK_VERSION = () - DatasetManager = Eval = Pipeline = raise_exception + DatasetManager = Eval = Pipeline = prepare = raise_exception + datasets = {} diff --git a/senpy/meta.py b/senpy/meta.py index a8a5b6b..4f69931 100644 --- a/senpy/meta.py +++ b/senpy/meta.py @@ -1,3 +1,18 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# ''' Meta-programming for the models. ''' diff --git a/senpy/models.py b/senpy/models.py index 447568e..5b42b86 100644 --- a/senpy/models.py +++ b/senpy/models.py @@ -1,3 +1,18 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# ''' Senpy Models. diff --git a/senpy/plugins/__init__.py b/senpy/plugins/__init__.py index 06c8172..962488f 100644 --- a/senpy/plugins/__init__.py +++ b/senpy/plugins/__init__.py @@ -1,5 +1,21 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from future import standard_library standard_library.install_aliases() @@ -45,7 +61,7 @@ class PluginMeta(models.BaseMeta): plugin_type.add(name) alias = attrs.get('name', name).lower() attrs['_plugin_type'] = plugin_type - logger.debug('Adding new plugin class', name, bases, attrs, plugin_type) + logger.debug('Adding new plugin class: %s %s %s %s', name, bases, attrs, plugin_type) attrs['name'] = alias if 'description' not in attrs: doc = attrs.get('__doc__', None) @@ -94,7 +110,7 @@ class Plugin(with_metaclass(PluginMeta, models.Plugin)): Provides a canonical name for plugins and serves as base for other kinds of plugins. """ - logger.debug("Initialising {}".format(info)) + logger.debug("Initialising %s", info) super(Plugin, self).__init__(**kwargs) if info: self.update(info) @@ -164,8 +180,7 @@ class Plugin(with_metaclass(PluginMeta, models.Plugin)): def process_entries(self, entries, activity): for entry in entries: - self.log.debug('Processing entry with plugin {}: {}'.format( - self, entry)) + self.log.debug('Processing entry with plugin %s: %s', self, entry) results = self.process_entry(entry, activity) if inspect.isgenerator(results): for result in results: @@ -347,6 +362,9 @@ class Evaluable(Plugin): def evaluate_func(self, X, activity=None): raise Exception('Implement the evaluate_func function') + def evaluate(self, *args, **kwargs): + return evaluate([self], *args, **kwargs) + class SentimentPlugin(Analyser, Evaluable, models.SentimentPlugin): ''' @@ -831,6 +849,9 @@ def evaluate(plugins, datasets, **kwargs): if not hasattr(plug, 'as_pipe'): raise models.Error('Plugin {} cannot be evaluated'.format(plug.name)) + if not isinstance(datasets, dict): + datasets = gsitk_compat.prepare(datasets, download=True) + tuples = list(product(plugins, datasets)) missing = [] for (p, d) in tuples: @@ -844,12 +865,12 @@ def evaluate(plugins, datasets, **kwargs): new_ev = evaluations_to_JSONLD(results, **kwargs) for ev in new_ev: dataset = ev.evaluatesOn - model = ev.evaluates.rstrip('__' + dataset) + model = ev.evaluates cached_evs[(model, dataset)] = ev evaluations = [] - print(tuples, 'Cached evs', cached_evs) + logger.debug('%s. Cached evs: %s', tuples, cached_evs) for (p, d) in tuples: - print('Adding', d, p) + logger.debug('Adding %s, %s', d, p) evaluations.append(cached_evs[(p.id, d)]) return evaluations @@ -868,7 +889,7 @@ def evaluations_to_JSONLD(results, flatten=False): if row.get('CV', True): evaluation['@type'] = ['StaticCV', 'Evaluation'] evaluation.evaluatesOn = row['Dataset'] - evaluation.evaluates = row['Model'] + evaluation.evaluates = row['Model'].rstrip('__' + row['Dataset']) i = 0 if flatten: metric = models.Metric() diff --git a/senpy/plugins/misc/split_plugin.py b/senpy/plugins/misc/split_plugin.py index af13d65..faabb2a 100644 --- a/senpy/plugins/misc/split_plugin.py +++ b/senpy/plugins/misc/split_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy.plugins import Transformation from senpy.models import Entry from nltk.tokenize.punkt import PunktSentenceTokenizer diff --git a/senpy/plugins/postprocessing/emotion/centroids.py b/senpy/plugins/postprocessing/emotion/centroids.py index 492b389..14ccfa7 100644 --- a/senpy/plugins/postprocessing/emotion/centroids.py +++ b/senpy/plugins/postprocessing/emotion/centroids.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy.plugins import EmotionConversionPlugin from senpy.models import EmotionSet, Emotion, Error @@ -85,7 +101,13 @@ class CentroidConversion(EmotionConversionPlugin): def distance(centroid): return sum(distance_k(centroid, original, k) for k in dimensions) - emotion = min(centroids, key=lambda x: distance(centroids[x])) + distances = {k: distance(centroids[k]) for k in centroids} + + logger.debug('Converting %s', original) + logger.debug('Centroids: %s', centroids) + logger.debug('Distances: %s', distances) + + emotion = min(distances, key=lambda x: distances[x]) result = Emotion(onyx__hasEmotionCategory=emotion) result.onyx__algorithmConfidence = distance(centroids[emotion]) diff --git a/senpy/plugins/postprocessing/emotion/ekman2vad.senpy b/senpy/plugins/postprocessing/emotion/ekman2vad.senpy index d089a41..a08938d 100644 --- a/senpy/plugins/postprocessing/emotion/ekman2vad.senpy +++ b/senpy/plugins/postprocessing/emotion/ekman2vad.senpy @@ -9,30 +9,30 @@ centroids: anger: A: 6.95 D: 5.1 - V: 2.7 + P: 2.7 disgust: A: 5.3 D: 8.05 - V: 2.7 + P: 2.7 fear: A: 6.5 D: 3.6 - V: 3.2 + P: 3.2 happiness: A: 7.22 D: 6.28 - V: 8.6 + P: 8.6 sadness: A: 5.21 D: 2.82 - V: 2.21 + P: 2.21 centroids_direction: - emoml:big6 - - emoml:pad + - emoml:pad-dimensions aliases: # These are aliases for any key in the centroid, to avoid repeating a long name several times - A: emoml:pad-dimensions:arousal - V: emoml:pad-dimensions:valence - D: emoml:pad-dimensions:dominance + P: emoml:pad-dimensions_pleasure + A: emoml:pad-dimensions_arousal + D: emoml:pad-dimensions_dominance anger: emoml:big6anger disgust: emoml:big6disgust fear: emoml:big6fear diff --git a/senpy/plugins/postprocessing/emotion/maxEmotion_plugin.py b/senpy/plugins/postprocessing/emotion/maxEmotion_plugin.py index a024d55..80d74f0 100644 --- a/senpy/plugins/postprocessing/emotion/maxEmotion_plugin.py +++ b/senpy/plugins/postprocessing/emotion/maxEmotion_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from senpy import PostProcessing, easy_test diff --git a/senpy/plugins/sentiment/sentiment140/sentiment140_plugin.py b/senpy/plugins/sentiment/sentiment140_plugin.py similarity index 75% rename from senpy/plugins/sentiment/sentiment140/sentiment140_plugin.py rename to senpy/plugins/sentiment/sentiment140_plugin.py index 1b7c5ce..a0a391b 100644 --- a/senpy/plugins/sentiment/sentiment140/sentiment140_plugin.py +++ b/senpy/plugins/sentiment/sentiment140_plugin.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import requests import json diff --git a/senpy/static/js/main.js b/senpy/static/js/main.js index 23af15c..0951bc2 100644 --- a/senpy/static/js/main.js +++ b/senpy/static/js/main.js @@ -174,10 +174,18 @@ function add_plugin_pipeline(){ function draw_datasets(){ html = ""; - repeated_html = ""+datasets[dataset]["@id"]; - html += "
" + ds = datasets[dataset] + + // html += repeated_html+datasets[dataset]["@id"]+"\">"+datasets[dataset]["@id"]; + html += ` + +
+ + +
+
+` } document.getElementById("datasets").innerHTML = html; } diff --git a/senpy/templates/index.html b/senpy/templates/index.html index a1cd8f4..055620e 100755 --- a/senpy/templates/index.html +++ b/senpy/templates/index.html @@ -233,28 +233,43 @@ In Data Science and Advanced Analytics (DSAA),
+

Automatically evaluate the classification performance of your plugin in several public datasets, and compare it with other plugins.

+

The datasets will be automatically downloaded if they are not already available locally. Depending on the size of the dataset and the speed of the plugin, the evaluation may take a long time.

-
-

Automatically evaluate the classification performance of your plugin in several public datasets, and compare it with other plugins.

-

The datasets will be automatically downloaded if they are not already available locally. Depending on the size of the dataset and the speed of the plugin, the evaluation may take a long time.

- - +
+
+
+ Select the plugin. +
+
+
+ +
-
- -
- + +
+
+
+ Select the dataset. +
+
+
+
+
- - -
+ + +
+
+ +
- +
- - - - - - - - - - - - - - - - -
PluginDatasetAccuracyPrecision_macroRecall_macroF1_macroF1_weightedF1_microF1
+
+ + + + + + + + + + + + + + + + +
PluginDatasetAccuracyPrecision_macroRecall_macroF1_macroF1_weightedF1_microF1
+
diff --git a/senpy/testing.py b/senpy/testing.py index 6777a0d..420e90c 100644 --- a/senpy/testing.py +++ b/senpy/testing.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from past.builtins import basestring import os diff --git a/senpy/utils.py b/senpy/utils.py index d7756b8..ba771f9 100644 --- a/senpy/utils.py +++ b/senpy/utils.py @@ -1,3 +1,18 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# from . import models, __version__ from collections import MutableMapping import pprint diff --git a/senpy/version.py b/senpy/version.py index c517050..b9dd463 100644 --- a/senpy/version.py +++ b/senpy/version.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import os import logging @@ -13,7 +29,7 @@ def read_version(versionfile=DEFAULT_FILE): return f.read().strip() except IOError: # pragma: no cover logger.error('Running an unknown version of senpy. Be careful!.') - return '0.0' + return 'devel' __version__ = read_version() diff --git a/setup.py b/setup.py index 42e23e0..f8f37da 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,29 @@ +''' +Copyright 2014 GSI DIT UPM + +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 + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +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. +''' + from setuptools import setup +from os import path -with open('senpy/VERSION') as f: - __version__ = f.read().strip() - assert __version__ +try: + with open('senpy/VERSION') as f: + __version__ = f.read().strip() + assert __version__ +except IOError: # pragma: no cover + print('Installing a development version of senpy. Proceed with caution!') + __version__ = 'devel' def parse_requirements(filename): @@ -12,6 +33,11 @@ def parse_requirements(filename): return [line for line in lineiter if line and not line.startswith("#")] +this_directory = path.abspath(path.dirname(__file__)) +with open(path.join(this_directory, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + + install_reqs = parse_requirements("requirements.txt") test_reqs = parse_requirements("test-requirements.txt") extra_reqs = parse_requirements("extra-requirements.txt") @@ -25,6 +51,8 @@ setup( description=('A sentiment analysis server implementation. ' 'Designed to be extensible, so new algorithms ' 'and sources can be used.'), + long_description=long_description, + long_description_content_type='text/x-rst', author='J. Fernando Sanchez', author_email='balkian@gmail.com', url='https://github.com/gsi-upm/senpy', # use the URL to the github repo diff --git a/tests/test_api.py b/tests/test_api.py index e558046..aabf226 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import logging logger = logging.getLogger(__name__) diff --git a/tests/test_blueprints.py b/tests/test_blueprints.py index 1e33515..4b5144b 100644 --- a/tests/test_blueprints.py +++ b/tests/test_blueprints.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import os import logging diff --git a/tests/test_cli.py b/tests/test_cli.py index bb1000d..fadf137 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import logging from functools import partial diff --git a/tests/test_client.py b/tests/test_client.py index 88bea6e..7ac74fe 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from unittest import TestCase from senpy.testing import patch_requests diff --git a/tests/test_extensions.py b/tests/test_extensions.py index 1107996..02e805e 100644 --- a/tests/test_extensions.py +++ b/tests/test_extensions.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from __future__ import print_function import os from copy import deepcopy diff --git a/tests/test_models.py b/tests/test_models.py index d6c59b6..5583cf7 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import logging import jsonschema diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 3281573..6fa98b6 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -1,5 +1,21 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + import os import pickle diff --git a/tests/test_schemas.py b/tests/test_schemas.py index 5cb1ee4..6a3a340 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from __future__ import print_function import json diff --git a/tests/test_semantics.py b/tests/test_semantics.py index 580a7b8..9fb90d3 100644 --- a/tests/test_semantics.py +++ b/tests/test_semantics.py @@ -1,5 +1,21 @@ #!/usr/local/bin/python # -*- coding: utf-8 -*- +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from future.standard_library import install_aliases install_aliases() diff --git a/tests/test_test.py b/tests/test_test.py index 41360cc..e560d6b 100644 --- a/tests/test_test.py +++ b/tests/test_test.py @@ -1,3 +1,19 @@ +# +# Copyright 2014 Grupo de Sistemas Inteligentes (GSI) DIT, UPM +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# 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. +# + from unittest import TestCase import requests