7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ChatGPT API を使用してMayaを(Pythonスクリプトで)操作してもらう

Last updated at Posted at 2023-03-04

はじめに

ChatGPTのAPIがリリースされたのでMaya上で動作させてみました。ただ会話するだけではつまらないので、Pythonスクリプトを書いてもらってそのまま実行するUIを作成してみます。

テスト環境

  • Maya 2023 (Python 3.9.7)
  • openai 0.27.0

Mayaにopenaiを入れる

まずはMayaのPythonからopenaiモジュールを呼び出せないといけないので、以下の方法でインストールしました。

  1. Anaconda3で仮想環境を作成。Mayaと同じバージョンのPythonを入れる
  2. 仮想環境にopenaiを入れる
  3. PYTHONPATHに仮想環境のパッケージフォルダ~\site-packagesを追加し、Maya起動
conda create -n maya2023 python=3.9.7
conda activate maya2023
pip install openai
@echo off
set PYTHONPATH=%UserProfile%\Anaconda3\envs\maya2023\Lib\site-packages
start "" "%ProgramFiles%\Autodesk\Maya2023\bin\maya.exe"
exit

mayapyとpipでMayaのインストールフォルダに直接パッケージを入れる方法もありますが、Maya本体には手を入れたくないためこのような方法を取っています。

実装

APIコールを行う関数を準備

import os
import openai

openai.api_key = os.getenv("OPENAI_API_KEY")

def completion(new_message_text:str, settings_text:str = '', past_messages:list = []):
    if len(past_messages) == 0 and len(settings_text) != 0:
        system = {"role": "system", "content": settings_text}
        past_messages.append(system)

    new_message = {"role": "user", "content": new_message_text}
    past_messages.append(new_message)

    result = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=past_messages
    )
    message_text = result.choices[0].message.content
    response_message = {"role": "assistant", "content": message_text}
    past_messages.append(response_message)
    
    return message_text, past_messages

こちらは以下の記事を大いに参考にさせていただいてます。(ほぼコピペですが...)

返答をPythonコードとその他の部分に分解

reモジュールを使って```python~```で囲まれた部分とそれ以外の部分を切り出します。

import re

def decompose_response(txt):
    pattern = r"```python([\s\S]*?)```"
    
    code_list = re.findall(pattern, txt)
    for i in range(int(len(code_list))):
        code_list[i] = re.sub('\A[\r?\n]', '', code_list[i])
        code_list[i] = re.sub('[\r?\n]\Z', '', code_list[i])
    
    comment = re.sub(pattern, '', txt)
    comment = re.sub('[\r?\n]+', '\n', comment)
    comment = re.sub('[\r?\n]\Z', '', comment)
    
    return comment, code_list

例えば返答がこんな感じだった場合、

ああああああああああああ。
```python
import os
```
いいいいいいいいいいいいいいい。
```python
import maya.cmds as cmds
```
うううううううううううううううううう。

戻り値はこうなります。

comment, code_list = decompose_response(txt)

comment
# Result: ああああああああああああ。
# いいいいいいいいいいいいいいい。
# うううううううううううううううううう。

code_list
# Result: ['import os', 'import maya.cmds as cmds']

UI作成

いよいよMayaでUIを作成します。
かなり即席です。ChatGPTがコードブロックを複数書いてきた場合2つ目以降は消えてなくなります(汗

from maya import cmds

class ChatGPT_Maya(object):

    def __init__(self):
        self.system_settings = "質問に対して、MayaのPythonスクリプトを書いてください。スクリプト以外の文章は短めにまとめてください。"
        self.message_log = []
        self.at_first = True
        self.create_window()

    def reset_session(self, *args):
        self.message_log = []
        self.at_first = True
        cmds.scrollField(self.input_field, e=True, tx='')
        cmds.scrollField(self.ai_comment, e=True, tx='')
        cmds.cmdScrollFieldExecuter(self.script_field, e=True, t='')

    def call(self, *args):
        user_input = cmds.scrollField(self.input_field, q=True, tx=True)
        
        # APIコール
        if self.at_first:
            message_text, self.message_log = completion(user_input, self.system_settings, [])
            self.at_first = False
        else:
            message_text, self.message_log = completion(user_input, '', self.message_log)
            
        # 返答を分解
        comment, code_list = decompose_response(message_text)
        
        # Pythonコード以外の部分をai_commentに表示
        cmds.scrollField(self.ai_comment, e=True, tx=comment)

        # Pythonコードの1つ目をscript_fieldに表示。2つ目以降は無視(汗
        if code_list:
            cmds.cmdScrollFieldExecuter(self.script_field, e=True, t=code_list[0])
            # 実行
            if cmds.checkBox(self.script_exec, q=True, v=True):
                cmds.cmdScrollFieldExecuter(self.script_field, e=True, executeAll=True)
        else:
            cmds.cmdScrollFieldExecuter(self.script_field, e=True, t='')
    
    # UI作成
    def create_window(self, *args):
        cmds.window(title=u'ChatGPTがPythonスクリプトを書くよ!', width=600, sizeable=True)
        
        cmds.columnLayout(adj=True, cat=['both',5], rs=5)
        self.reset_button = cmds.button(label='Reset', c=self.reset_session) #セッションのリセット
        self.input_field = cmds.scrollField(h=50, ed=True, ww=True, tx='', ec=self.call) #テンキーのEnterで送信
        self.script_exec = cmds.checkBox(label=u'実行もする', align='left', v=True) #Checkが入っていたら返答と同時にスクリプトを実行
        cmds.separator(h=10, st='in')
        self.ai_comment = cmds.scrollField(h=100, ed=False, ww=True, tx='') #コードブロック以外の部分を表示する場所
        cmds.text(l='Script:', align='left')
        self.script_field = cmds.cmdScrollFieldExecuter(st='python', h=200) #Pythonコードを表示・実行する場所
        cmds.setParent('..')

        cmds.showWindow()

こんなかんじのUIが出来ました!ウィンドウを閉じるかResetボタンを押すまでは、直前までの会話を記憶した状態になります。
chatgpt_maya_ui


【2023/3/6 追記】少しだけ改良したものをGithubにアップしたのでリンクを記載しました。
【2023/4/18 追記】アップデートが進んでしまったので、執筆時点のコミットへリンクを差し替えました。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?