Skip to content

Commit

Permalink
feat: Python TCP server and Node.js TCP client for IPC (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
louistiti committed Mar 5, 2022
1 parent caa86fc commit 5970ec9
Show file tree
Hide file tree
Showing 12 changed files with 575 additions and 7 deletions.
4 changes: 4 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ LEON_HTTP_API_LANG=en-US
# Enable/disable collaborative logger
LEON_LOGGER=true

# Python WebSocket server
LEON_PY_WS_SERVER_HOST=0.0.0.0
LEON_PY_WS_SERVER_PORT=1342

# Path to the Pipfile
PIPENV_PIPFILE=bridges/python/Pipfile

Expand Down
4 changes: 4 additions & 0 deletions bridges/python/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@ spacy = "==3.2.0"
setuptools = "==60.9.3"
wheel = "==0.37.1"
torch = "==1.9.0"
python-socketio = "==5.5.2"
eventlet = "==0.33.0"
python-dotenv = "==0.19.2"
zerorpc = "==0.6.3"

[dev-packages]
333 changes: 330 additions & 3 deletions bridges/python/Pipfile.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion bridges/python/ner/spacy-run.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
nlp = spacy.load("en_core_web_trf", disable=["tagger", "parser", "attribute_ruler", "lemmatizer"])
# nlp = spacy.load("en_core_web_md", disable=["tok2vec", "tagger", "parser", "attribute_ruler", "lemmatizer"])

doc = nlp("Do you know Spotify? I live in Paris and I'm Matthieu")
# doc = nlp("Do you know Spotify? I live in Paris and I'm Matthieu")
doc = nlp("Hi, I'm louis and I'm from saint-claude. Today I live in Shenzhen China and I work at Alibaba")

for ent in doc.ents:
print(ent.text, ent.label_)
50 changes: 50 additions & 0 deletions bridges/python/tcp-server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import socket
import os
import json
from os.path import join, dirname
from dotenv import load_dotenv
import spacy

dotenv_path = join(dirname(__file__), '../../.env')
load_dotenv(dotenv_path)

nlp = spacy.load('en_core_web_trf', disable=['tagger', 'parser', 'attribute_ruler', 'lemmatizer'])

ws_server_host = os.environ.get('LEON_PY_WS_SERVER_HOST', '0.0.0.0')
ws_server_port = os.environ.get('LEON_PY_WS_SERVER_PORT', 1342)

tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket.bind((ws_server_host, int(ws_server_port)))
tcp_socket.listen()

def extract_spacy_entities(utterance):
doc = nlp(utterance)

for ent in doc.ents:
print(ent.text, ent.label_)

while True:
print('Waiting for connection...')
connection, addr = tcp_socket.accept()

try:
print(f'Client connected: {addr}')

while True:
data = connection.recv(1024)
data_dict = json.loads(data)

print('data', data)

if data_dict['topic'] == 'get-spacy-entities':
extract_spacy_entities(data_dict['data'])

print(f'Received data: {data_dict}')

if not data:
break

connection.sendall(data)

finally:
connection.close()
42 changes: 42 additions & 0 deletions bridges/python/ws-server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import socketio
import eventlet
import os
from os.path import join, dirname
from dotenv import load_dotenv
import spacy

dotenv_path = join(dirname(__file__), '../../.env')
load_dotenv(dotenv_path)

nlp = spacy.load('en_core_web_trf', disable=['tagger', 'parser', 'attribute_ruler', 'lemmatizer'])

sio = socketio.Server(async_mode='eventlet', cors_allowed_origins="*", logger=False, engineio_logger=False)
# sio = socketio.Server(async_mode='eventlet', cors_allowed_origins="*")
app = socketio.WSGIApp(sio)

ws_server_host = os.environ.get('LEON_PY_WS_SERVER_HOST', '0.0.0.0')
ws_server_port = os.environ.get('LEON_PY_WS_SERVER_PORT', 1342)

@sio.event
def connect(sid, env, auth):
print('Client connected ', sid)

@sio.event
def disconnect(sid):
print('Client disconnected', sid)

@sio.event
def extract_entities(sid, utterance):
print('DO YOUR JOOOB')
doc = nlp(utterance)

for ent in doc.ents:
print(ent.text, ent.label_)

sio.emit('entities_extracted', {'data': 'foobar'}, room=sid)

try:
print('Python WebSocket server is running on ' + ws_server_host + ':' + ws_server_port)
eventlet.wsgi.server(eventlet.listen((ws_server_host, int(ws_server_port))), app)
except:
print('Python WebSocket server failed to run. Please check that the ' + ws_server_port + ' port is free on ' + ws_server_host)
23 changes: 22 additions & 1 deletion server/src/core/http-server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Brain from '@/core/brain'
import Asr from '@/core/asr'
import Stt from '@/stt/stt'
import Tts from '@/tts/tts'
import TcpClient from '@/core/tcp-client'
import corsMidd from '@/core/http-server/plugins/cors'
import otherMidd from '@/core/http-server/plugins/other'
import keyMidd from '@/core/http-server/plugins/key'
Expand All @@ -19,6 +20,7 @@ import log from '@/helpers/log'
import date from '@/helpers/date'

const server = { }
let tcpClient = { }
let brain = { }
let nlu = { }

Expand Down Expand Up @@ -176,8 +178,23 @@ server.handleOnConnection = (socket) => {

socket.emit('is-typing', true)

const utterance = data.value

/* tcpClient.on('spacy-entities-received', async (entities) => {
try {
await nlu.process(utterance)
} catch (e) { /!* *!/ }
}) */

tcpClient.emit('get-spacy-entities', utterance)
})

tcpClient.ee.on('spacy-entities-received', async ({ utterance, spacyEntities }) => {
console.log('utterance', utterance)
console.log('spacyEntities', spacyEntities)

try {
await nlu.process(data.value)
await nlu.process(utterance)
} catch (e) { /* */ }
})

Expand Down Expand Up @@ -280,7 +297,11 @@ server.init = async () => {
const sLogger = (process.env.LEON_LOGGER !== 'true') ? 'disabled' : 'enabled'
log.success(`Collaborative logger ${sLogger}`)

tcpClient = new TcpClient(process.env.LEON_PY_WS_SERVER_HOST, process.env.LEON_PY_WS_SERVER_PORT)
// pyWsClient = new PyWsClient(`ws://${process.env.LEON_PY_WS_SERVER_HOST}:${process.env.LEON_PY_WS_SERVER_PORT}`)
brain = new Brain()
// brain.pySocket = pyWsClient.pySocket

nlu = new Nlu(brain)

// Load NLP model
Expand Down
29 changes: 29 additions & 0 deletions server/src/core/py-ws-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { io } from 'socket.io-client'

export default class PyWsClient {
constructor (serverUrl) {
this.serverUrl = serverUrl
this.pySocket = io(this.serverUrl)

this.pySocket.on('connect', () => {
console.log('CONNECTED')
})

this.pySocket.on('entities_extracted', (data) => {
console.log('entities_extracted data', data)
})
}

extractEntities (utterance) {
return new Promise((resolve) => {
console.log('EMMIIIT')
this.pySocket.emit(
'extract_entities',
utterance,
(conf) => {
resolve(conf)
}
)
})
}
}
57 changes: 57 additions & 0 deletions server/src/core/tcp-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import Net from 'net'
import { EventEmitter } from 'events'

import log from '@/helpers/log'

export default class TcpClient {
constructor (host, port) {
this.tcpSocket = new Net.Socket()
this._ee = new EventEmitter()
this._status = this.tcpSocket.readyState

log.title('TCP Client')
log.success('New instance')

this.tcpSocket.connect({ host, port }, () => {
log.title('TCP Client')
log.success(`Connected to TCP server tcp://${host}:${port}`)
})

this.tcpSocket.on('data', (chunk) => {
log.title('TCP Client')

const data = JSON.parse(chunk)

this._ee.emit(data.topic, data.data)

console.log('RECEIIIIVED', chunk.toString())
})

this.tcpSocket.on('error', (err) => {
log.title('TCP Client')
log.error(err)
})

this.tcpSocket.on('end', () => {
log.title('TCP Client')
log.success('Disconnected from TCP server')
})
}

get status () {
return this._status
}

get ee () {
return this._ee
}

emit (topic, data) {
const obj = {
topic,
data
}

this.tcpSocket.write(JSON.stringify(obj))
}
}
4 changes: 2 additions & 2 deletions server/src/helpers/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import log from '@/helpers/log'

const sentences = [
'This process takes time, please go for a coffee (or a fruit juice)',
'This will take a while, grab a drink and come back later',
'This may take a while, grab a drink and come back later',
'Go for a walk, this action takes time',
'That will take some time, let\'s chill and relax',
'That may take some time, let\'s chill and relax',
'Leon will be ready for you in a moment'
]
const spinner = new Spinner('\x1b[95m%s\x1b[0m\r').setSpinnerString(18)
Expand Down
4 changes: 4 additions & 0 deletions server/src/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import dotenv from 'dotenv'
// import { command } from 'execa'

import server from '@/core/http-server/server'

(async () => {
dotenv.config()

/* command('pipenv run python bridges/python/ws-server.py', {
shell: true
}) */
await server.init()
})()
29 changes: 29 additions & 0 deletions tcp-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Include Nodejs' net module.
const Net = require('net');
// The port number and hostname of the server.
const port = 1342;
const host = '0.0.0.0';

// Create a new TCP client.
const client = new Net.Socket();
// Send a connection request to the server.
client.connect({ port: port, host: host }, function() {
// If there is no error, the server has accepted the request and created a new
// socket dedicated to us.
console.log('TCP connection established with the server.');

// The client can now send data to the server by writing to its socket.
client.write('Hello, server.');
});

// The client can also receive data from the server by reading from its socket.
client.on('data', function(chunk) {
console.log(`Data received from the server: ${chunk.toString()}.`);

// Request an end to the connection after the data has been received.
client.end();
});

client.on('end', function() {
console.log('Requested an end to the TCP connection');
});

0 comments on commit 5970ec9

Please sign in to comment.