Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9309

高校生がリアルタイム言語変換のサービスを作ってGithubにPushしてみた。

$
0
0

高校生でプログラミングが好きなレオです!!

今回はリアルタイムで言語変換できるサービスを作ったので、
紹介とどのように作ったのか少し説明したいと思います。

※この記事は、Node.jsとPython,Socket.ioを使える前提で話を進めていきます。

1. アイディア

アイディアはWeChatの翻訳機能を使っていた時に思いつきました。
僕が中国でお買い物をする際に店員さんと、WeChatを使って会話をすることがあるのですが、リアルタイムではなく、毎度翻訳をかけないと行けなかったので、リアルタイムで翻訳できて、友達交換もしなくていいサービスを作ろう!と思ったのがきっかけです。

2. 使用した言語と技術

使用したプログラミング言語はNode.jsとPythonです。
主にNode.jsを使っていて、Node.js上でSocket.ioなどの通信部分やテンプレート(EJS)を表示しています。
Pythonはgoogletransというライブラリを使用するためにPythonを使用していて、
Node.jsとPythonの間はPython-Shellというライブラリを使ってデータのやりとりをしています。

3. ファイル構成

transchatのファイル構成
.
├── 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

ファイル構成は一般的なexpressの構成に言語変換用のpythonファイル(translate.py)を追加しました。

4. Node.js

app.js
varexpress=require('express')varapp=express()varhttp=require('http').createServer(app)vario=require('socket.io')(http,{path:'/message'})varuuid=require('node-uuid')var{PythonShell}=require('python-shell')app.use(express.static('public'))app.set("view engine","ejs")varroom=[]varlang={}app.get('/',function(req,res){res.render(__dirname+'/templates/home/index.ejs')})app.post('/transroom',function(req,res){varroomid=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('/')}})functiontrans_mes(mes,before_lang,trans_lang,send_user){if(1300>=mes.length){varpyshell=newPythonShell('./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')}}

これがメインのNode.jsのコードです。

1行目〜6行目は必要なライブラリ、ExpressSocket.io,Node-uuid,python-shellの読み込みを行っています。
7行目と8行目では、パブリックファイルのパス指定とテンプレートエンジンの指定を行っています。

16行目〜20行目では、ユニークのRoomIDを作成し、room配列にRoomIDを追加して、ユーザをリダイレクトしています。
22行目〜28行目では、room配列にリクエストされたRoomIDがあるか確認をして、あった場合はテンプレートを表示し、なかった場合はリダイレクトをしています。

function trans_mesでは、翻訳するメッセージ・送信したユーザの言語・送信先のユーザの言語・送信先のSocketIDを取得し、そのデータを使って、Python-ShellでPythonを実行し、翻訳されたデータをSocket.ioで送信しています。
ただ、googletransの使用上文字数制限があり、pythonを実行する前に文字数の確認を行なっています。

5. Socket.io

app.js
io.on('connection',function(socket){varroomid=socket.handshake.headers.referer.split('/')[4]if(roomid!=null){socket.join(roomid)varroom_user_count=io.sockets.adapter.rooms[roomid].lengthif(room_user_count==1){io.to(socket.id).emit('sys',{'roomid':roomid})}elseif(room_user_count==2){socket.broadcast.to(roomid).emit('sys','join_user')}elseif(room_user_count>=3){io.to(socket.id).emit('sys','redirect')}socket.on('message',function(msg,sendlang){varclient_list=io.sockets.adapter.rooms[roomid].socketsfor(varclientIdinclient_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){varlist_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})}}})}})

これが、Socket.io部分です。
まず、最初にvar roomid = socket.handshake.headers.referer.split('/')[4]でリクエストされたRoomIDを取得して、socket.join(roomid)でユーザをルームに入室しています。

app.js
socket.on('message',function(msg,sendlang){varclient_list=io.sockets.adapter.rooms[roomid].socketsfor(varclientIdinclient_list){if(socket.id!=clientId&&lang[clientId]){trans_mes(msg,lang[socket.id],lang[clientId],clientId)}}})

次にメッセージの機能ですが、var client_list = io.sockets.adapter.rooms[roomid].socketsの部分でRoomに入室しているユーザのリストを取得しています。

app.rb
for(varclientIdinclient_list){if(socket.id!=clientId&&lang[clientId]){trans_mes(msg,lang[socket.id],lang[clientId],clientId)}}

次に、ユーザのリストをFor分で分割し、if文を使って、送信者以外を選択し、function trans_mesを実行します。
これによって、送信者以外のユーザに翻訳されたメッセージが送信されます。

6. Python

python/translate.py
fromgoogletransimportTranslatorimportjsonimportsystranslator=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)exceptExceptionase:print('translate_error')

Pythonのコードは簡単で、sys.stdin.readline()でNode.jsで指定した情報を取得して、それをgoogletransを使って翻訳をし、Json形式でNode.jsに変換しています。

7. 最後に。

Socket.ioをここまでガッツリ書いたのが初めてだったのですが、結構簡単にかけて楽しかったです。
ただ、簡単なサービスな割にはコードが複雑になってしまったため、今後もアップデートを続けて行けたらなと思います(プルリク大歓迎です!!)

それと、もし良ければ、インストールして試してもらえると嬉しいです。

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

このようにGitインストールを行なってnpm installをするだけで試すことが可能なのでお願いします!!

※注意※
実際に本番環境で、使用する際は、Room配列やユーザの言語情報などをDBに保存するようにしたり、翻訳部分をAmazon TranslateCloud Translation,DeepL APIなどを使用してください。
あくまで、お試し感覚で作成したため、本番環境向けではございません。


Viewing all articles
Browse latest Browse all 9309

Trending Articles