...
create a new folder in https://bitbucket.org/socialroboticshub/processing/src/master/ with the name of the service
copy the certificate file https://bitbucket.org/socialroboticshub/docker/src/master/cbsr/beamforming/cert.pem from any of the other services' folders into the service’s folder
copy any additional files that the services may need into the service’s folder
create a factory file inheriting from the
CBSRFactory
in the service’s folder, and override the superclass’s methodscreate a service file inheriting from
CBSRService
in the service’s folder, and override the superclass’s methodsupdate the https://bitbucket.org/socialroboticshub/processing/src/master/deploy_to_docker.sh file in the root folder with the new service files
deploy the new service to the https://bitbucket.org/socialroboticshub/docker/src/master/ folder by running the
deploy_to_docker.sh
fileupdate the https://bitbucket.org/socialroboticshub/docker/src/master/docker-compose.yml file in the
docker
folder with the new serviceupdate the https://bitbucket.org/socialroboticshub/docker/src/master/Dockerfile.python3 file in the
docker
folder with the new service’s dependenciesupdate the topics in the constructor of the Abstract Connector from the https://bitbucket.org/socialroboticshub/connectors/src/master/python/social_interaction_cloud/ folder with the name of the new service
update the device listeners in
enable_service
in the Abstract Connector with the serviceupdate the listened to channels in
__listen
in the Abstract Connector with the servicecreate the corresponding event handler method for the service in the Abstract Connector
create the corresponding event handler method for the service in the Basic Connector
use the new service in a new file
The detailed explanation of these steps with a sentiment analysis example can be found below:
Too Long Still Read
create a new folder in https://bitbucket.org/socialroboticshub/processing/src/master/ with the name of the service.
my_service
sentiment_analysis
(https://bitbucket.org/socialroboticshub/docker/src/master/cbsr/sentiment/ ) will be used as the example folder and service name in this casecopy the certificate file https://bitbucket.org/socialroboticshub/docker/src/master/cbsr/beamforming/cert.pem from any of the other services' folders into the
my_service
foldercreate amy_servicesentiment
foldercopy the https://bitbucket.org/socialroboticshub/docker/src/master/cbsr/sentiment/classifier.pickle into the
sentiment
foldercreate a https://bitbucket.org/socialroboticshub/docker/src/master/cbsr/sentiment/sentiment_factory.py file in the
my_service
sentiment
folder
Code Block | ||||
---|---|---|---|---|
| ||||
from os import getcwd from cbsr.factory import CBSRfactory from my_servicenltk import MyServicedownload from nltk.data class MyServiceFactory(CBSRfactory):import path from sentiment_service import SentimentAnalysisService class SentimentAnalysisFactory(CBSRfactory): def __init__(self): """ MyServiceFactory constructorsuper(SentimentAnalysisFactory, self).__init__() def get_connection_channel(self): inherit from the CBSRfactory constructor to create the new service as a service return 'sentiment_analysis' def create_service(self, connect, identifier, disconnect): """ return SentimentAnalysisService(connect, identifier, disconnect) super(MyServiceFactory, self).if __initname__() def get_connection_channel(self)== '__main__': cwd = getcwd() """ initialise the name of the service Redis channel download('punkt', download_dir=cwd) download('omw-1.4', download_dir=cwd) """download('averaged_perceptron_tagger', download_dir=cwd) return 'my_service' download('wordnet', download_dir=cwd) def create_service(self, connect, identifier, disconnect):path.append(cwd) return MyService(connect, identifier, disconnect) if __name__ == '__main__': my_sentiment_analysis_factory = MyServiceFactorySentimentAnalysisFactory() mysentiment_analysis_factory.run() |
45. create a my_ https://bitbucket.org/socialroboticshub/docker/src/master/cbsr/sentiment/sentiment_service.py file in the my_service
sentiment
folder
Code Block | ||||
---|---|---|---|---|
| ||||
""" This file shows an example of a mocksentiment service that uses the text_transcript channel result from the Dialogflow speech-to-text andto publishesget it intothe the newtype my_service channel. of sentiment """ from pickle Theimport fileload canfrom bere extendedimport tosub asfrom manystring servicesimport aspunctuation necessary """ from cbsr.service import CBSRservice from nltk.stem.wordnet import WordNetLemmatizer from nltk.tag import pos_tag from nltk.tokenize import word_tokenize class MyServiceSentimentAnalysisService(CBSRservice): def __init__(self, connect, identifier, disconnect): super(MyServiceSentimentAnalysisService, self).__init__(connect, identifier, disconnect) def get_device_types(self) with open('classifier.pickle', 'rb') as pickle: """ :return list of devicesself.classifier the service uses= load(pickle) self.lemmatizer = WordNetLemmatizer() This method returns a list of all the devices my_service uses; in this case, only the microphone """ def get_device_types(self): return ['mic'] def get_channel_action_mapping(self): """ :return key-value dictionary pairing, with listened channel as key and linked method as value;{self.get_full_channel('text_transcript'): self.execute} def execute(self, message): sentence = message['data'].decode() tokens multiple channels can be listened to, linked to a method when separated by a comma in the output dictionary= self.remove_noise(word_tokenize(sentence)) sentiment = self.classifier.classify(dict([token, True] for token in tokens)) print(sentiment) Use an already-existing channel and links it to a method to be called when there is a message in the channel The channel should correspond to one of the topics in abstract_connector.py; in this case, my_service uses the text_transcript channel and links it to the method self.execute """ return {self.get_full_channel('text_transcript'): self.execute} def execute(self, message): """ :param message: the message published in the channel the method was linked to This method decodes the data received in the channel it was linked to and further publishes a message in the new service channel Extra functionalities can be added to the method """ sentence = message['data'].decode() self.publish('mytext_servicesentiment', sentencesentiment) ... |
56. update the https://bitbucket.org/socialroboticshub/processing/src/master/deploy_to_docker.sh file in the root folder with the new service files
Code Block | ||||
---|---|---|---|---|
| ||||
...
echo Deploying my_service...
cd ../my_service
cp -f {cert.pem, *.py, classifier.pickle} ../../docker/cbsr/my_service # extra files can be copied if used
... |
67. deploy the new service to the https://bitbucket.org/socialroboticshub/docker/src/master/ folder by running the deploy_to_docker.sh
file
78. update the https://bitbucket.org/socialroboticshub/docker/src/master/docker-compose.yml file in the docker
folder with the new service
Code Block | ||
---|---|---|
| ||
... # ------------------------------------------------------------ # MySentiment serviceAnalysis # ------------------------------------------------------------ mysentiment_serviceanalysis: image: python3 build: context: . dockerfile: Dockerfile.python3 hostname: mysentiment_serviceanalysis user: "${NEW_UID}:${NEW_GID}" env_file: - ./.env working_dir: /my_service command: python3 my_servicesentiment_factory.py volumes: - ./cbsr/mock:/my_servicesentiment:rw${MOUNT_OPTIONS} tty: true stdin_open: false networks: app_net: ipv4_address: 172.16.238.x # address has to differ from those of the already existing services' depends_on: - redis - dialogflow # - any other services my_service depends on |
...
existing services'
depends_on:
- redis
- dialogflow
# - any other services the service depends on
... |
9. update the https://bitbucket.org/socialroboticshub/docker/src/master/Dockerfile.python3 file in the docker
folder with the new service’s dependencies
Code Block |
---|
RUN pip3 install --no-cache-dir --upgrade --prefer-binary \
redis~=4.1 \
hiredis~=2.0 \
simplejson~=3.17 \
Pillow~=9.0 \
numpy~=1.22 \
imutils~=0.5 \
[any other dependendencies] \
... |
10. update the topics
in the constructor of the Abstract Connector abstract_connector.py
from the https://bitbucket.org/socialroboticshub/connectors/src/master/python/social_interaction_cloud/ folder with the name of the new service
topics = [..., 'mytext_servicesentiment']
911. update the corresponding list of devices listeners in enable_service
in abstract_connector.py
with my_service
Code Block | ||
---|---|---|
| ||
... ########################### # Management # ########################### def enable_service(self, name: str) -> None: ... elif ... and name == 'mysentiment_serviceanalysis': for mic in self.devices[self.device_types['mic']]: pipe.publish(name, mic) ... |
1012. update the channels in __listen
in abstract_connector.py
with my_service
Code Block | ||
---|---|---|
| ||
... elif channel = 'mytext_servicesentiment': self.on_mytext_servicesentiment(message=data.decode('utf-8')) ... |
1113. create the corresponding event handler method on_my_service
in abstract_connector.py
Code Block | ||
---|---|---|
| ||
... ########################### # Event handlers # ########################### ... def on_mytext_servicesentiment(self, message: str) -> None: pass ... |
1214. create the corresponding inherited event handler method on_my_service
in basic_connector.py
Code Block | ||||
---|---|---|---|---|
| ||||
... ########################### # Event handlers # ########################### ... def on_mytext_servicesentiment(self, message: str) -> None: """ :param message: the message published on the mytext_servicesentiment channel This method notifies the listeners that a new message has been posted on the my_service channel; This method can be further inherited and overridden """ self.__notify_listeners('onMyService', message) ... |
13. use the new service by creating a new file my_service_example.py
and running it
Code Block | ||||
---|---|---|---|---|
| ||||
from social_interaction_cloud.action import ActionRunner from social_interaction_cloud.basic_connector import BasicSICConnector class MyConnector(BasicSICConnector): def __init__(self, server_ip: str): """ :param server_ip: This method inherits the BasicSICConnector and enables the new my_service service; my_service needs to be manually enabled in this way """ has been posted on the text_sentiment channel; This method can be further inherited and overridden """ self.__notify_listeners('onTextSentiment', message) ... |
15. use the new service by creating a new file sentiment_example.py
, overriding the on_text_sentiment
method and running it
Code Block | ||||
---|---|---|---|---|
| ||||
from enum import Enum from functools import partial from social_interaction_cloud.action import ActionRunner from social_interaction_cloud.basic_connector import BasicSICConnector class SentimentConnector(BasicSICConnector): def __init__(self, server_ip: str, dialogflow_key_file: str, dialogflow_agent_id: str): super(SentimentConnector, self).__init__(server_ip, 'en-US', dialogflow_key_file, dialogflow_agent_id) super(MyConnector, self).enable__init__(server_ipservice('sentiment_analysis') self.enable_service('my_service')sentiment = None def on_mytext_servicesentiment(self, messagesentiment: str) -> None: """ :param message: message published in the my_service channel print(sentiment) self.sentiment = sentiment class Example: def __init__(self, server_ip: str, dialogflow_key_file: str, dialogflow_agent_id: str): This methodself.sic overrides the event function on_my_service inherited from the BasicSICConnector= SentimentConnector(server_ip, dialogflow_key_file, dialogflow_agent_id) self.action_runner = ActionRunner(self.sic) """ self.recognition_manager = printRecognitionManager(message2) self.stop().user_model = {} ... |