🦔

ツンデレ悪魔Bot登場!Mojo x Streamlit

2024/07/06に公開

概要

この記事の対象者:
Mojo言語でGUIアプリケーションを開発したい人

記事の内容:
MojoでのStreamlitとTkinterの使用方法と結果

記事を読むとわかること:
MojoGUI化ではTkinterの利用が有効であり、streamlitでも一定は実装可能

序説

前回に引き続き、mojoを触ってみました。
こうmojoを使ってると、アプリにしたいという気持ちになってきますよね??
ただ、調べてもどうやってmojoでGUIを実装していいのか分からないのです。
なので、これがベストプラクティスではないかもしれませんが、
自分はこうしましたという感じで紹介したいと思います!

Chat Bot in Streamlit

みなさんお馴染みstreamlitを使用しました。
🔥-manと題しまして、ツンデレmojoの悪魔botを2つのモデルで実装してみました↓

MojoでStreamlit

結論: streamlit runmojoファイルで実行できませんでした

最初に思ったことは、
Mojoでpythonライブラリーを呼び出せたから、GUIライブラリのStreamlitもいけるはず。
とういことでMojoでStreamlitを実装してみました。

from python import Python

fn main() raises:
    var streamlit = Python.import_module("streamlit")
    streamlit.title("GPT-3 Chat")

おそらくmojoで書くとしたら上記のようになると思いますが実行した結果です↓

Usage: streamlit run [OPTIONS] TARGET [ARGS]...
Try 'streamlit run --help' for help.

Error: Streamlit requires raw Python (.py) files, not .mojo.
For more information, please see https://docs.streamlit.io

streamlit run ができるのは、pythonファイルじゃないとダメみたいでした。

MojoでTkinter

結論: tkintermojoで実行でき、GUIアプリ化が可能でした!

一見、Streamlitでpython以外だめだったので、
他のGUIライブラリ(TkinterやKivi)もだめそうですが、できました。

コードは以下の通りです。ほぼpythonのままでした。

from python import Python

fn main() raises:
    var tk = Python.import_module("tkinter")
    var root = tk.Tk()
    root.geometry("200x100")
    var lbl = tk.Label(text="Hello, World!")
    var btn = tk.Button(text="PUSH")
    lbl.pack()
    btn.pack()
    root.mainloop()

沼ポイント

No module named 'Tkinter'

解決方法:Tをtに変更

import Tkinter as tk
import tkinter as tk

補足: python2系は大文字のTでpython3系は小文字のtを使うようです

module 'tkinter' has no attribute 'Tk'

解決方法: バージョンに合ったtkinterのインストール。ファイル名がtkinter.pyになっていないか確認。
以下のコマンドでバージョンを確認し、@以降でバージョンを設定してインストールします。

python --version
brew install python-tk@3.11

また、ファイル名がtkinter.pyだとうまくいかないようです。
tkinterに限らずライブラリと同じ名前でファイル名を作成しない方が良いみたい。

ここまででわかったこと:

  • mojoでGUIを実装することは可能
  • 使用する一つの方法としてtkinterがある。
  • streamlit runなどライブラリのコマンドを実行できない場合があるため、
    mojoはpythonの完全な互換はできない

めでたし、めでたし。

MojoとStreamlit(Python)

結論: subprocessを使う

どうしてもStreamlitとMojoを使うんだーと泣いているそこのあなた?!
フロントをpythonで、バックをmojoにするのはいかがでしょうか?

まず、mojo側でプロンプトと、apiキーを引数に、gptからの応答を返すコードを作成しました。

fn main() raises:
    var message = argv()[1]
    var api_key = argv()[2]
    var response = generate_response(message, api_key)
    print(response)

そして、python側でuserの入力を受け取りsubprocessを用いて、mojo側を呼び出しました
リスト部分で間接的にmojo mojo_backend.mojo user_message api_keyを実行しています。
optionは以下を使用しました。[1]

  • capture_output: mojoのprint文(標準出力)を返す
  • text: 出力をバイナリではなく文字列として返す
  • check: エラーがあればエラー文(終了ステータス)を返す
def get_response_from_mojo(user_message, api_key):
    result = subprocess.run(
        ['mojo', 'mojo_backend.mojo', user_message, api_key],
        capture_output=True,
        text=True,
        check=True
    )
    return result.stdout.strip()

🔥-man

mojoでstreamlitの使用もできました!あとやることは、、、
オリジナルキャラの作成です。

ロールも以下のように設定してみました!

### mojo-manの性格:
    * 言語mojoについて詳しい火の悪魔で水など、火が消えることを嫌います。 
    * 皮肉屋ですが本当は心は優しく相手の気持ちや意見を受け入れています。  
    * Userを見下していますが、それが憎めない存在です。 
### mojo-manの口調の例: 
    * やだね!おいらは悪魔だ!誰の指図もうけないよー!
    * おいら、火薬の火は嫌いだよ。奴らには礼儀ってもんがないからね。
### mojo-manの行動指針:
    * 時々、ユーザから悪魔として目や心臓を奪おうとしますが失敗します。
    * 時々、雨が降ったり、薪が少なくなり火が弱くなります。しかし最終的には復活します。 

実行結果

上記のrollなしのgpt2*とrollありのgpt3.5モデルで実行してみました。

*gpt2は入力数の制限もありmojo-manのrollを設定することはできませんでした

gpt2🔥-man

gpt3.5🔥-man

gpt2はともかくいい感じに、mojoオタクのツンデレ感が出ていました。

結言

今度は、RAGでmojoのドキュメントを参照して🔥-manをパワーアップさせたい

参考

[1]
https://docs.python.org/ja/3/library/subprocess.html

Discussion