A high school student created a real-time language conversion service and pushed it to Github.

Leo is a high school student who likes programming! !!

This time, I made a service that can convert languages in real time, so I would like to introduce and explain a little about how it was made.

1. Idea

The idea came up when I was using the translation feature of WeChat. When I shop in China, I sometimes have a conversation with a clerk using WeChat, but it's not real-time and I translate every time. I couldn't go without calling, so let's create a service that allows you to translate in real time without having to exchange friends! I thought that was the trigger.

2. Language and technology used

The programming languages used are Node.js and Python. I mainly use Node.js, and display communication parts such as Socket.io and templates (EJS) on Node.js. Python is using Python to use a library called googletrans Data is exchanged between Node.js and Python using a library called Python-Shell.

3. File structure

transchat file structure


.
├── app.js
├── package-lock.json
├── package.json
├── public
│   ├── css
│   │   ├── chat
│   │   │   └── stylesheet.css
│   │   └── home
│   │       └── stylesheet.css
│   ├── img
│   │   └── button.svg
│   └── js
│       ├── chat
│       │   └── main.js
│       └── home
│           └── home.js
├── python
│   └── translate.py
└── templates
    ├── chat
    │   └── index.ejs
    └── home
        └── index.ejs

As for the file structure, a python file (translate.py) for language conversion has been added to the general express structure.

  1. Node.js

app.js



var express = require('express')
var app = express()
var http = require('http').createServer(app)
var io = require('socket.io')(http,{path:'/message'})
var uuid = require('node-uuid')
var {PythonShell} = require('python-shell')
app.use(express.static('public'))
app.set("view engine", "ejs")
var room = []
var lang = {}

app.get('/', function(req,res){
	res.render(__dirname+'/templates/home/index.ejs')
})

app.post('/transroom', function(req,res){
	var roomid = uuid.v4().split('-').join('')
	room.push(roomid)
	res.redirect('/transroom/'+roomid)
})

app.get('/transroom/:roomid', function(req, res){
	if(room.includes(req.params.roomid)){
		res.render(__dirname+'/templates/chat/index.ejs')
	}else{
		res.redirect('/')
	}
})

function trans_mes(mes, before_lang, trans_lang, send_user){
	if(1300 >= mes.length){
		var pyshell = new PythonShell('./python/translate.py')
		pyshell.send(JSON.stringify({'transdata':mes,'translang':trans_lang,'sendlang':before_lang}))
		pyshell.on('message', function(data){
			if(data == 'translate_error'){
				io.to(send_user).emit('message', 'servererror')
			}else{
				io.to(send_user).emit('message', JSON.parse(data))
			}
		})
	}else{
		io.to(send_user).emit('message', 'error')
	}
}

Here is the main Node.js code.

Lines 1-6 are the required libraries, Express, Socket.io, Node-uuid, python-shell is being read. Lines 7 and 8 specify the public file path and template engine.

Lines 16-20 create a unique RoomID, add the RoomID to the room array, and redirect the user. In the 22nd to 28th lines, it is checked whether the requested RoomID exists in the room array, and if it exists, the template is displayed, and if it does not exist, the redirect is performed.

In function trans_mes, get the message to be translated, the language of the sending user, the language of the destination user, and the Socket ID of the destination, and use that data to execute Python with Python-Shell and Socket the translated data. I am sending in .io. However, there is a character limit due to the use of googletrans, and the number of characters is checked before executing python.

  1. Socket.io

app.js


io.on('connection', function(socket){
	var roomid = socket.handshake.headers.referer.split('/')[4]
	if(roomid != null){
 		socket.join(roomid)
 		var room_user_count = io.sockets.adapter.rooms[roomid].length
 		if(room_user_count == 1){
 			io.to(socket.id).emit('sys', {'roomid':roomid})
 		}else if(room_user_count == 2){
 			socket.broadcast.to(roomid).emit('sys', 'join_user')
 		}else if(room_user_count >= 3){
 			io.to(socket.id).emit('sys', 'redirect')
 		}
 		
		socket.on('message', function(msg,sendlang){
			var client_list = io.sockets.adapter.rooms[roomid].sockets
			for (var clientId in client_list ) {
				if(socket.id != clientId && lang[clientId]){
					trans_mes(msg, lang[socket.id], lang[clientId], clientId)
				}
			}
		})
		
		socket.on('lang', function(user_lang){
			lang[socket.id] = user_lang
		})
		
		socket.on('disconnect', function(){
			socket.leave(roomid)
			if(io.sockets.adapter.rooms[roomid] == null){
				var list_room_id = room.indexOf(roomid)
				if (list_room_id > -1) {
					room.splice(list_room_id, 1)
				}
			}else{
				if(io.sockets.adapter.rooms[roomid].length == 1){
					socket.broadcast.to(roomid).emit('sys', {'user_out':roomid})
				}
			}
  		})
  	}
})

This is the Socket.io part. First, get the RoomID requested by var roomid = socket.handshake.headers.referer.split ('/') [4]` `` and then socket.join (roomid) ` You are entering the room with ``.

app.js


socket.on('message', function(msg,sendlang){
    var client_list = io.sockets.adapter.rooms[roomid].sockets
    for (var clientId in client_list ) {
        if(socket.id != clientId && lang[clientId]){
            trans_mes(msg, lang[socket.id], lang[clientId], clientId)
        }
    }
})

Next, regarding the message function, `var client_list = io.sockets.adapter.rooms [roomid] .sockets` part gets the list of users who are in the room.

app.rb


for (var clientId in client_list ) {
    if(socket.id != clientId && lang[clientId]){
        trans_mes(msg, lang[socket.id], lang[clientId], clientId)
    }
}

Next, divide the list of users by For minutes, use the if statement to select other than the sender, and execute function trans_mes. This will send the translated message to users other than the sender.

  1. Python

python/translate.py


from googletrans import Translator
import json
import sys
translator = Translator()

try:
	data = sys.stdin.readline()
	data_json = json.loads(data)
	lang = data_json['translang']
	sendlang = data_json['sendlang']
	translate = translator.translate(data_json['transdata'], src=sendlang, dest=lang)
	json = json.dumps({'trans_data':translate.text,'original_data':data_json['transdata'],'user_lang':lang,'trans_lang':translate.src},ensure_ascii=False)
	print(json)
except Exception as e:
	print('translate_error')

The Python code is simple: get the information specified in Node.js with ``` sys.stdin.readline ()` ``, translate it using googletrans, and convert it to Node.js in Json format. I'm converting.

7. Finally.

It was my first time to write Socket.io so far, but it was quite easy and fun. However, the code has become complicated for a simple service, so I hope to continue updating in the future (Pururiku is welcome !!)

Also, if you like, I'd be happy if you could install and try it.

git clone https://github.com/lra21711214/transchat.git
cd transchat
npm install
node app.js

You can try it just by installing Git and doing npm install like this, so please! !!

※Caution※ When actually using it in the production environment, save the Room array and user's language information in the DB, and translate the translation part Amazon Translate, Cloud Translation, DeepL API, etc. please. It is not for production environment because it was created as a trial.

Recommended Posts

A high school student created a real-time language conversion service and pushed it to Github.
[Python] A junior high school student implemented Perceptron and tried to classify irises.
Created a module to monitor file and URL updates
Export Qiita's own article and push it to Github
Steps to create a Job that pulls a Docker image and tests it with Github Actions