みんなの「作ってみた」

悟空語ジェネレーターをぺぇそん(Python)でも作ってみたぞ!えーぴーえぇ(API)化もしたぞ!

2019/02/21

shonansurvivors
shonansurvivors

(2019/2/23更新 PyPIに登録し、pip installで使えるようになりました)

まとめ

Pythonモジュール版について

使い方

ぺぇぴーえぇ(PyPI)に登録済みなので、pip installで使えます。

(venv) $ pip install gokulang

なお、

  • 形態素解析モジュールであるjanome
  • 日本語をローマ字に変換するモジュールであるpykakasi
  • その他semidbm, six

に依存していますので一緒にインストールされます。

(venv) $ pip list
Package    Version
---------- -------
gokulang   1.0.1  
Janome     0.3.7  
pip        10.0.1 
pykakasi   0.94   
semidbm    0.5.1  
setuptools 39.1.0 
six        1.12.0 

無事インストールされたら、gokulang.pyからGokuLangクラスをimportし、インスタンス化の上、translateメソッドに日本語文章を渡してください。

(venv) $ python
>>> from gokulang.gokulang import GokuLang
>>> g = GokuLang()
>>> g.translate('FF外から失礼します')
'FFげぇからしつれぇすっぞ'

以下環境で動作確認しています。

  • Python 3.6.6
  • Janome 0.3.7
  • pykakasi 0.94
  • semidbm 0.5.1
  • six 1.12.0

Web API版について

使い方

パラメータtextに日本語文章を入れてください。

レスポンスの

  • originalには入力値であるtextそのまま
  • translatedには変換後の文章

が入ります。

GETの場合

$ curl https://gokulang.herokuapp.com/api/?text=お願いします
{"original": "お願いします", "translated": "おねげぇすっぞ"}

POSTの場合

$ curl https://gokulang.herokuapp.com/api/ -X POST -d 'text=もう帰ります'
{"original": "もう帰ります", "translated": "もうけぇっぞ"}

なお、API側にデータベースなどは持っていませんので、POSTを実行しても何かが更新されるようなことはありません。

変換処理の大まかな流れ

考え方は悟空語ジェネレーターとほぼ同じです。

  1. janomeで形態素解析を行い、各単語とその読み、品詞を取得
  2. 各単語をpykakasiでローマ字に変換
  3. ローマ字を悟空独特の言い回しに変換 e.g.) a + i => e + e
  4. 変化のあったローマ字をRomanKanaTable ジェネレーターを参考に平仮名に戻す。変化の無かった語は、当初の内容に戻す。

ただ、悟空語ジェネレーターのソースを解析して作ったわけではないので、変換結果は大なり小なり差はあるかと思います。

また、悟空語ジェネレーターに存在した以下仕様には現時点では対応はしていません。

  • 一人称をおら、二人称をおめぇに変換
  • 悟空語なまりの強さを選択可能

今回の個人開発で学んだこと

1. テストコードの重要性

2019年2月現在、私はコードを全く書くことの無い仕事をしており、恥ずかしながら今回の個人開発で初めてテストコードを書きました。

悟空語変換ロジックを作り上げる過程では、ロジックの追加・修正の都度、従来上手く行っていた変換がおかしくなることがありました。

>>> g.translate('登録したぞ')
'登録すっぞぞ'

頻発するデグレートの発見と再修正を効率良く行う上で、テストコードは不可欠でした。

test_gokulang.py
import unittest
from gokulang import GokuLang


class GokuLangTest(unittest.TestCase):
    def setUp(self):
        self.G = GokuLang()

    def tearDown(self):
        pass

    def test_ai_ae(self):
        q = '最初の試合は緊張するだろうけど、今のお前なら大丈夫だ'
        a = 'せぇしょのしえぇは緊張するだろうけど、今のおめぇならでぇじょうぶだ'
        self.assertEqual(a, self.G.translate(q))

    def test_ei_ae_oi(self):
        q = '冷静に考えろ、奴は強いぞ'
        a = 'れぇせぇにかんげぇろ、奴はつえぇぞ'
        self.assertEqual(a, self.G.translate(q))

    def test_oe(self):
        q = 'ここを越えるよ'
        a = 'ここをけぇるよ'
        self.assertEqual(a, self.G.translate(q))

    def test_kaeru(self):
        q = 'もう帰ります'
        a = 'もうけぇっぞ'
        self.assertEqual(a, self.G.translate(q))

    def test_non_reading_shimasu(self):
        q = 'FF外から失礼します'
        a = 'FFげぇからしつれぇすっぞ'
        self.assertEqual(a, self.G.translate(q))

    def test_ta(self):
        # 見送っぞ にならないことのテスト
        q = '見送った'
        a = '見送った'
        self.assertEqual(a, self.G.translate(q))

    def test_ta2(self):
        # 登録すっぞぞ にならないことのテスト
        q = '登録したぞ'
        a = '登録したぞ'
        self.assertEqual(a, self.G.translate(q))

    def test_nai(self):
        # みえっぞ にならないことのテスト
        q = '見えない'
        a = '見えねぇ'
        self.assertEqual(a, self.G.translate(q))

    def test_da(self):
        # あそっぞ や あそぶぞ にならないことのテスト
        q = '遊んだ'
        a = '遊んだ'
        self.assertEqual(a, self.G.translate(q))

    def test_dekami(self):
        q = 'ぱいぱいでか美'
        a = 'ぺぇぺぇでか美'
        self.assertEqual(a, self.G.translate(q))


if __name__ == '__main__':
    unittest.main()

2. Web API化

Web APIを作るのも初めてで、Djangoにて手探りで作ってみました。
APIとしての考え方やお作法など、何か間違っている点があればご指摘いただけると幸いです。

api/views.py
import json

from django.views.generic import View, TemplateView
from django.http.response import HttpResponse

from .gokulang.gokulang import GokuLang


class GokuLangView(View):

    def get(self, request):

        text = request.GET.get('text') if request.GET.get('text') else ''

        g = GokuLang()
        translated = g.translate(text)

        response = {'original': text, 'translated': translated}

        return HttpResponse(json.dumps(response, ensure_ascii=False), content_type='application/json')

    def post(self, request):

        text = request.POST.get('text') if request.POST.get('text') else ''

        g = GokuLang()
        translated = g.translate(text)

        response = {'original': text, 'translated': translated}

        return HttpResponse(json.dumps(response, ensure_ascii=False), content_type='application/json')

# ...

def getdef postもやっていることがほぼ同じなので、コードが冗長ですね・・・。

参考