1
0
mirror of https://github.com/gsi-upm/senpy synced 2025-09-17 03:52:22 +00:00

Compare commits

..

5 Commits

Author SHA1 Message Date
J. Fernando Sánchez
d8b59d06a4 Converted Ekman2VAD to centroids
* Changed the way modules are imported -> we can now use dotted
  notation (e.g. senpy.plugins.conversion.centroids)
* Refactored ekman2vad's plugin -> generic centroids
* Added some basic tests
2017-02-28 05:28:55 +01:00
J. Fernando Sánchez
453b9f3257 Fixed bugs in Ekman2VAD 2017-02-28 04:01:05 +01:00
J. Fernando Sánchez
5fb858f5fc Fixed error when installing dependencies 2017-02-28 02:24:49 +01:00
J. Fernando Sánchez
bd984a1437 Fix 5 2017-02-27 21:22:10 +01:00
J. Fernando Sánchez
e741b565a1 Fix 4 2017-02-27 20:44:27 +01:00
11 changed files with 123 additions and 90 deletions

View File

@@ -6,7 +6,7 @@ image: gsiupm/dockermake:latest
variables:
DOCKER_DRIVER: overlay
DOCKERFILE: Dockerfile
VERSION: $CI_BUILD_REF
IMAGENAME: $CI_REGISTRY_IMAGE
stages:
- test
@@ -43,28 +43,18 @@ push-3.5:
<<: *image_definition
variables:
PYTHON_VERSION: "3.5"
VERSION: $CI_BUILD_TAG
push-2.7:
<<: *image_definition
variables:
PYTHON_VERSION: "2.7"
VERSION: $CI_BUILD_TAG
push-main:
<<: *image_definition
variables:
PYTHON_VERSION: main
VERSION: $CI_BUILD_TAG
push-latest:
<<: *image_definition
variables:
PYTHON_VERSION: latest
VERSION: $CI_BUILD_TAG
only:
- master
- tags
- triggers
clean :

View File

@@ -41,12 +41,12 @@ build-%: version Dockerfile-%
quick_test: $(addprefix test-,$(PYMAIN))
dev-%:
@docker start $(NAME)-dev || (\
@docker start $(NAME)-dev$* || (\
$(MAKE) build-$*; \
docker run -d -w /usr/src/app/ -v $$PWD:/usr/src/app --entrypoint=/bin/bash -p 5000:5000 -ti --name $(NAME)-dev '$(IMAGEWTAG)-python$*'; \
docker run -d -w /usr/src/app/ -v $$PWD:/usr/src/app --entrypoint=/bin/bash -ti --name $(NAME)-dev$* '$(IMAGEWTAG)-python$*'; \
)\
docker exec -ti $(NAME)-dev bash
docker exec -ti $(NAME)-dev$* bash
dev: dev-$(PYMAIN)
@@ -98,12 +98,10 @@ push-latest: build-$(PYMAIN)
docker push '$(IMAGENAME)'
docker push '$(IMAGEWTAG)'
push-main: push-$(PYMAIN)
push-%: build-%
docker push $(IMAGENAME):$(VERSION)-python$*
ci:
gitlab-runner exec docker --docker-volumes /var/run/docker.sock:/var/run/docker.sock --env CI_PROJECT_NAME=$(NAME) ${action}
.PHONY: test test-% test-all build-% build test pip_test run yapf dev ci version .FORCE
.PHONY: test test-% test-all build-% build test pip_test run yapf push-main push-% dev ci version .FORCE

View File

@@ -13,10 +13,11 @@ from .api import API_PARAMS, NIF_PARAMS, parse_params
from threading import Thread
import os
import copy
import fnmatch
import inspect
import sys
import imp
import importlib
import logging
import traceback
import yaml
@@ -180,7 +181,7 @@ class Senpy(object):
newentries = []
for i in resp.entries:
if output == "full":
newemotions = i.emotions.copy()
newemotions = copy.deepcopy(i.emotions)
else:
newemotions = []
for j in i.emotions:
@@ -288,7 +289,7 @@ class Senpy(object):
def install_deps(self):
for i in self.plugins.values():
self._install_deps(i._info)
self._install_deps(i)
@classmethod
def _install_deps(cls, info=None):
@@ -302,6 +303,13 @@ class Senpy(object):
logger.info('Installing requirements: ' + str(requirements))
pip.main(pip_args)
@classmethod
def _load_module(cls, name, root):
sys.path.append(root)
tmp = importlib.import_module(name)
sys.path.remove(root)
return tmp
@classmethod
def _load_plugin_from_info(cls, info, root):
if not cls.validate_info(info):
@@ -309,11 +317,10 @@ class Senpy(object):
return None, None
module = info["module"]
name = info["name"]
sys.path.append(root)
(fp, pathname, desc) = imp.find_module(module, [root, ])
cls._install_deps(info)
tmp = imp.load_module(module, fp, pathname, desc)
sys.path.remove(root)
tmp = cls._load_module(module, root)
candidate = None
for _, obj in inspect.getmembers(tmp):
if inspect.isclass(obj) and inspect.getmodule(obj) == tmp:

View File

@@ -7,7 +7,7 @@ import pickle
import logging
import tempfile
import copy
from . import models
from .. import models
logger = logging.getLogger(__name__)

View File

View File

@@ -0,0 +1,52 @@
from senpy.plugins import EmotionConversionPlugin
from senpy.models import EmotionSet, Emotion, Error
import logging
logger = logging.getLogger(__name__)
class CentroidConversion(EmotionConversionPlugin):
def _forward_conversion(self, original):
"""Sum the VAD value of all categories found."""
res = Emotion()
for e in original.onyx__hasEmotion:
category = e.onyx__hasEmotionCategory
if category in self.centroids:
for dim, value in self.centroids[category].iteritems():
try:
res[dim] += value
except Exception:
res[dim] = value
return res
def _backwards_conversion(self, original):
"""Find the closest category"""
dimensions = list(self.centroids.values())[0]
def distance(e1, e2):
return sum((e1[k] - e2.get(self.aliases[k], 0)) for k in dimensions)
emotion = ''
mindistance = 10000000000000000000000.0
for state in self.centroids:
d = distance(self.centroids[state], original)
if d < mindistance:
mindistance = d
emotion = state
result = Emotion(onyx__hasEmotionCategory=emotion)
return result
def convert(self, emotionSet, fromModel, toModel, params):
cf, ct = self.centroids_direction
logger.debug('{}\n{}\n{}\n{}'.format(emotionSet, fromModel, toModel, params))
e = EmotionSet()
if fromModel == cf:
e.onyx__hasEmotion.append(self._forward_conversion(emotionSet))
elif fromModel == ct:
for i in emotionSet.onyx__hasEmotion:
e.onyx__hasEmotion.append(self._backwards_conversion(i))
else:
raise Error('EMOTION MODEL NOT KNOWN')
yield e

View File

@@ -1,56 +0,0 @@
from senpy.plugins import EmotionConversionPlugin
from senpy.models import EmotionSet, Emotion, Error
import logging
logger = logging.getLogger(__name__)
import math
class WNA2VAD(EmotionConversionPlugin):
def _ekman_to_vad(self, ekmanSet):
potency = 0
arousal = 0
dominance = 0
for e in ekmanSet.onyx__hasEmotion:
category = e.onyx__hasEmotionCategory
centroid = self.centroids[category]
potency += centroid['V']
arousal += centroid['A']
dominance += centroid['D']
e = Emotion({'emoml:potency': potency,
'emoml:arousal': arousal,
'emoml:dominance': dominance})
return e
def _vad_to_ekman(self, VADEmotion):
V = VADEmotion['emoml:valence']
A = VADEmotion['emoml:potency']
D = VADEmotion['emoml:dominance']
emotion = ''
value = 10000000000000000000000.0
for state in self.centroids:
valence = V - self.centroids[state]['V']
arousal = A - self.centroids[state]['A']
dominance = D - self.centroids[state]['D']
new_value = math.sqrt((valence**2) +
(arousal**2) +
(dominance**2))
if new_value < value:
value = new_value
emotion = state
result = Emotion(onyx__hasEmotionCategory=emotion)
return result
def convert(self, emotionSet, fromModel, toModel, params):
logger.debug('{}\n{}\n{}\n{}'.format(emotionSet, fromModel, toModel, params))
e = EmotionSet()
if fromModel == 'emoml:big6':
e.onyx__hasEmotion.append(self._ekman_to_vad(emotionSet))
elif fromModel == 'emoml:fsre-dimensions':
for i in emotionSet.onyx__hasEmotion:
e.onyx__hasEmotion.append(self._vad_to_ekman(e))
else:
raise Error('EMOTION MODEL NOT KNOWN')
yield e

View File

@@ -1,13 +1,13 @@
---
name: Ekman2VAD
module: ekman2vad
module: senpy.plugins.conversion.centroids
description: Plugin to convert emotion sets from Ekman to VAD
version: 0.1
onyx:doesConversion:
- onyx:conversionFrom: emoml:big6
onyx:conversionTo: emoml:fsre-dimensions
- onyx:conversionFrom: emoml:fsre-dimensions
onyx:conversionTo: wna:WNAModel
onyx:conversionTo: emoml:big6
centroids:
emoml:big6anger:
A: 6.95
@@ -29,7 +29,10 @@ centroids:
A: 5.21
D: 2.82
V: 2.21
centroids_direction:
- emoml:big6
- emoml:fsre-dimensions
aliases:
A: emoml:arousal
V: emoml:potency
V: emoml:valence
D: emoml:dominance

View File

@@ -9,4 +9,6 @@ test=pytest
ignore = E402
max-line-length = 100
[bdist_wheel]
universal=1
universal=1
[tool:pytest]
addopts = --cov=senpy --cov-report term-missing

View File

@@ -1,5 +1,6 @@
from __future__ import print_function
import os
from copy import deepcopy
import logging
try:
@@ -9,7 +10,7 @@ except ImportError:
from functools import partial
from senpy.extensions import Senpy
from senpy.models import Error
from senpy.models import Error, Results, Entry, EmotionSet, Emotion
from flask import Flask
from unittest import TestCase
@@ -52,6 +53,7 @@ class ExtensionsTest(TestCase):
assert module
import noop
dir(noop)
self.senpy.install_deps()
def test_installing(self):
""" Enabling a plugin """
@@ -120,3 +122,42 @@ class ExtensionsTest(TestCase):
def test_load_default_plugins(self):
senpy = Senpy(plugin_folder=self.dir, default_plugins=True)
assert len(senpy.plugins) > 1
def test_convert_emotions(self):
self.senpy.activate_all()
plugin = {
'id': 'imaginary',
'onyx:usesEmotionModel': 'emoml:fsre-dimensions'
}
eSet1 = EmotionSet()
eSet1['onyx:hasEmotion'].append(Emotion({
'emoml:arousal': 1,
'emoml:potency': 0,
'emoml:valence': 0
}))
response = Results({
'entries': [Entry({
'text': 'much ado about nothing',
'emotions': [eSet1]
})]
})
params = {'emotionModel': 'emoml:big6',
'conversion': 'full'}
r1 = deepcopy(response)
self.senpy.convert_emotions(r1,
plugin,
params)
assert len(r1.entries[0].emotions) == 2
params['conversion'] = 'nested'
r2 = deepcopy(response)
self.senpy.convert_emotions(r2,
plugin,
params)
assert len(r2.entries[0].emotions) == 1
assert r2.entries[0].emotions[0]['prov:wasDerivedFrom'] == eSet1
params['conversion'] = 'filtered'
r3 = deepcopy(response)
self.senpy.convert_emotions(r3,
plugin,
params)
assert len(r3.entries[0].emotions) == 1

View File

@@ -143,7 +143,3 @@ class ModelsTest(TestCase):
print(t)
g = rdflib.Graph().parse(data=t, format='turtle')
assert len(g) == len(triples)
def test_convert_emotions(self):
"""It should be possible to convert between different emotion models"""
pass