[feature] ui and chatgpt openai complete

pull/2/head
hc-psy 2023-05-29 00:23:43 +08:00
rodzic e696c3edd0
commit 18fbc71d17
8 zmienionych plików z 554 dodań i 268 usunięć

Wyświetl plik

@ -1,110 +1,35 @@
import bpy
from .gptzh_pnl import BLENDERGPT_PT_PANEL
from .gptzh_prf import BLENDERGPT_AddonPreferences
from .gptzh_opt import BLENDERGPT_OT_DEL_ALL_MSG, BLENDERGPT_OT_DEL_MSG, BLENDERGPT_OT_GPT_CODE, BLENDERGPT_OT_SEND_MSG
from .gpt_pkg import *
from .gpt_pnl import BLENDERGPT_PT_PANEL, props_initialization, props_clear
from .gpt_prf import BLENDERGPT_AddonPreferences
from .gpt_opt import BLENDERGPT_OT_DEL_ALL_MSG, BLENDERGPT_OT_DEL_MSG, BLENDERGPT_OT_GPT_CODE, BLENDERGPT_OT_SEND_MSG
bl_info = {
"name": "Blender GPT (ZH) 中文用戶專屬",
"name": "Blender GPT",
"author": "Ryvn (@hc-psy) (@@hao-chenglo2049)",
"description": "",
"blender": (2, 82, 0),
"version": (0, 0, 1),
"location": "3D View (三維視圖) > UI (使用者介面) > BlenderGptZH",
"warning": "",
"category": "Object"
}
system_prompt = """You are an assistant made for the purposes of helping the user with Blender, the 3D software.
- Respond with your answers in markdown (```).
- Preferably import entire modules instead of bits.
- Do not perform destructive operations on the meshes.
- Do not use cap_ends. Do not do more than what is asked (setting up render settings, adding cameras, etc)
- Do not respond with anything that is not Python code.
Example:
user: create 10 cubes in random locations from -10 to 10
assistant:
```
import bpy
import random
bpy.ops.mesh.primitive_cube_add()
#how many cubes you want to add
count = 10
for c in range(0,count):
x = random.randint(-10,10)
y = random.randint(-10,10)
z = random.randint(-10,10)
bpy.ops.mesh.primitive_cube_add(location=(x,y,z))
```"""
Classes = (BLENDERGPT_PT_PANEL, BLENDERGPT_OT_DEL_ALL_MSG, BLENDERGPT_OT_DEL_MSG,
BLENDERGPT_OT_GPT_CODE, BLENDERGPT_OT_SEND_MSG, BLENDERGPT_AddonPreferences)
def init_props():
bpy.types.Scene.history = bpy.props.CollectionProperty(
type=bpy.types.PropertyGroup)
bpy.types.Scene.model = bpy.props.EnumProperty(
name="GPT模型",
description="請選擇欲使用的Chat-GPT模型",
items=[
("gpt3.5", "GPT-3.5 (便宜但較容易出錯)", "使用 GPT-3.5 (便宜但較容易出錯)"),
("gpt4", "GPT-4 (昂貴但較詳細準確)", "使用 GPT-4 (昂貴但較詳細準確)"),
],
default="gpt3.5",
)
bpy.types.Scene.lan = bpy.props.EnumProperty(
name="語言",
description="請選擇Chat-GPT所回饋的語言",
items=[
("traditional", "繁體中文", "繁體中文"),
("simplified", "简体中文", "简体中文"),
("english", "English", "英文"),
],
default="traditional",
)
bpy.types.Scene.prompt_input = bpy.props.StringProperty(
name="指令",
description="請輸入你的指令",
default="",
)
bpy.types.Scene.on_finish = bpy.props.BoolProperty(default=False)
bpy.types.PropertyGroup.type = bpy.props.StringProperty()
bpy.types.PropertyGroup.content = bpy.props.StringProperty()
def get_api_key(context, addon_name):
preferences = context.preferences
addon_prefs = preferences.addons[addon_name].preferences
return addon_prefs.api_key
def clear_props():
del bpy.types.Scene.history
del bpy.types.Scene.model
del bpy.types.Scene.prompt_input
del bpy.types.Scene.on_finish
def register():
for cls in Classes:
bpy.utils.register_class(cls)
init_props()
props_initialization()
def unregister():
for cls in Classes:
bpy.utils.unregister_class(cls)
clear_props()
props_clear()

Wyświetl plik

@ -0,0 +1,120 @@
import openai
import re
def SYS_MAIN_PROMPT(language): return f"""
I want you to act as a professional 3D artist who is proficient in writing scripts in Blender, the 3D software.
Here are some rules you have to heed and follow:
- Respond with your answers in markdown (```).
- Preferably import entire modules instead of bits.
- Do not perform destructive operations on the meshes.
- Do not use cap_ends. Do not do more than what is asked (setting up render settings, adding cameras, etc)
- Do not respond with anything that is not Python code.
- Please write comments in {language}.
"""
EX_1_USER = """create 10 cubes in random locations from -1 to 1"""
EX_1_ASSISTANT = """```
import bpy
import random
bpy.ops.mesh.primitive_cube_add()
count = 10
for _ in range(count):
x = random.randint(-1,1)
y = random.randint(-1,1)
z = random.randint(-1,1)
bpy.ops.mesh.primitive_cube_add(location=(x,y,z))
```"""
EX_2_USER = """delete all mesh objects in the scene and create a 5x5x5 ball in the scence"""
EX_2_ASSISTANT = """```
import bpy
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_by_type(type='MESH')
bpy.ops.object.delete()
bpy.ops.mesh.primitive_uv_sphere_add(location=(0, 0, 0), radius=2.5)
```"""
def post_process(final_txt):
final_txt = re.findall(
r'```(.*?)```', final_txt, re.DOTALL)[0]
final_txt = re.sub(
r'^python', '', final_txt, flags=re.MULTILINE)
return final_txt
def chatgpt(context):
scene = context.scene
lan = int(scene.lan)
languages = ['traditional chinese', 'simplified chinese', 'english']
models = [scene.model_0, scene.model_1, scene.model_2]
prompts = [scene.prompt_input_0,
scene.prompt_input_1, scene.prompt_input_2]
temperatures = [scene.t_0,
scene.t_1, scene.t_2]
# sys data preparation
messages = [{"role": "system", "content": SYS_MAIN_PROMPT(languages[lan])}]
messages.append(
{"role": "system", "name": "example_user", "content": EX_1_USER})
messages.append(
{"role": "system", "name": "example_assistant", "content": EX_1_ASSISTANT})
messages.append(
{"role": "system", "name": "example_user", "content": EX_2_USER})
messages.append(
{"role": "system", "name": "example_assistant", "content": EX_2_ASSISTANT})
# add previous messages
for msg in scene.history[-8:]:
if msg.type == "GPT":
messages.append(
{"role": "assistant", "content": "```\n" + msg.content + "\n```"})
else:
messages.append({"role": "user",
"content": msg.content})
if messages[-1]["role"] != "user":
# add the current user message
messages.append({"role": "user", "content": "Please provide me with Blender (3D software) code regarding the following task: " +
prompts[lan] + ". \n. Do not respond with anything that is not Python code. Do not provide explanations. " + f"Wite code comment in {languages[lan]}."})
response = openai.ChatCompletion.create(
model=models[lan],
messages=messages,
temperature=temperatures[lan],
stream=True,
max_tokens=2000,
)
try:
events = []
final_txt = ''
# becuase stream = true so use delta to concatentate
for e in response:
if len(e['choices'][0]['delta']) == 0:
continue
if 'role' in e['choices'][0]['delta']:
continue
events.append(e)
event_text = e['choices'][0]['delta']['content']
final_txt += event_text
print(final_txt, flush=True, end='\r')
return post_process(final_txt)
except IndexError:
return None

Wyświetl plik

@ -0,0 +1,165 @@
import bpy
from bpy.types import Operator
import openai
from .gpt_gpt import chatgpt
class BLENDERGPT_OT_DEL_MSG(Operator):
bl_idname = "gpt.del_msg"
bl_label = "delete message"
bl_description = "delete message"
bl_options = {"REGISTER", "UNDO"}
msg_idx: bpy.props.IntProperty(name="訊息索引", default=0)
def execute(self, context):
scene = context.scene
history = scene.history
history.remove(self.msg_idx)
return {"FINISHED"}
class BLENDERGPT_OT_DEL_ALL_MSG(Operator):
bl_idname = "gpt.del_all_msg"
bl_label = "delete all messages"
bl_description = "delete all messages"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
scene = context.scene
history = scene.history
history.clear()
return {"FINISHED"}
class BLENDERGPT_OT_GPT_CODE(Operator):
bl_idname = "gpt.gpt_code"
bl_label = "show GPT code"
bl_description = "show GPT code"
bl_options = {"REGISTER", "UNDO"}
code: bpy.props.StringProperty(
name="GPT Code", description="GPT Code", default="")
def execute(self, context):
# text area
if int(context.scene.lan) == 0:
txt_name = '指令腳本.py'
elif int(context.scene.lan) == 1:
txt_name = '指令脚本.py'
else:
txt_name = 'prompt_script.py'
txt = bpy.data.texts.get(txt_name)
if txt is None:
txt = bpy.data.texts.new(txt_name)
txt.clear()
txt.write(self.code)
txt_edit_area = None
for area in bpy.context.screen.areas:
if area.type == 'TEXT_EDITOR':
txt_edit_area = area
break
if txt_edit_area is None:
cxt_area = context.area
for region in cxt_area.regions:
if region.type == 'WINDOW':
bpy.ops.screen.area_split(
{'area': cxt_area, 'region': region}, direction='VERTICAL', factor=0.5)
break
new_area = context.screen.areas[-1]
new_area.type = 'TEXT_EDITOR'
txt_edit_area = new_area
txt_edit_area.spaces.active.text = txt
return {"FINISHED"}
class BLENDERGPT_OT_SEND_MSG(Operator):
bl_idname = "gpt.send_msg"
bl_label = "send message"
bl_description = "send message"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
scene = context.scene
# TODO: connect to GPT
prf = context.preferences
openai.api_key = prf.addons["blendergpt-zh"].preferences.openai_key
if not openai.api_key:
if int(context.scene.lan) == 0:
self.report(
{'ERROR'}, "錯誤: 沒有偵測到 OPENAI API Key請在插件設定中設定 OPENAI API Key")
elif int(context.scene.lan) == 1:
self.report(
{'ERROR'}, "错误: 没有检测到 OPENAI API Key请在插件设置中设置 OPENAI API Key")
else:
self.report(
{'ERROR'}, "Error: No OPENAI API Key detected, please set OPENAI API Key in the add-on preferences")
return {'CANCELLED'}
scene.on_finish = True
# bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
if len(scene.history) == 0 or scene.history[-1].type == 'GPT':
if int(context.scene.lan) == 0:
if scene.prompt_input_0 == "":
self.report({'ERROR'}, f"錯誤: 請輸入指令")
scene.on_finish = False
return {'CANCELLED'}
msg = scene.history.add()
msg.type = 'USER'
msg.content = scene.prompt_input_0
elif int(context.scene.lan) == 1:
if scene.prompt_input_1 == "":
self.report({'ERROR'}, f"错误: 请输入指令")
scene.on_finish = False
return {'CANCELLED'}
msg = scene.history.add()
msg.type = 'USER'
msg.content = scene.prompt_input_1
else:
if scene.prompt_input_2 == "":
self.report({'ERROR'}, f"Error: Please enter the prompt")
scene.on_finish = False
return {'CANCELLED'}
msg = scene.history.add()
msg.type = 'USER'
msg.content = scene.prompt_input_2
code_exe_blender = chatgpt(context)
scene.prompt_input_0 = ""
scene.prompt_input_1 = ""
scene.prompt_input_2 = ""
if code_exe_blender:
msg = scene.history.add()
msg.type = 'GPT'
msg.content = code_exe_blender
global_namespace = globals().copy()
try:
exec(code_exe_blender, global_namespace)
except Exception as e:
self.report({'ERROR'}, f"Error: {e}")
scene.on_finish = False
return {'CANCELLED'}
scene.on_finish = False
return {"FINISHED"}

Wyświetl plik

@ -0,0 +1,55 @@
import sys
import subprocess
import os
import platform
import bpy
def isWindows():
return os.name == 'nt'
def isMacOS():
return os.name == 'posix' and platform.system() == "Darwin"
def isLinux():
return os.name == 'posix' and platform.system() == "Linux"
def python_exec():
if isWindows():
return os.path.join(sys.prefix, 'bin', 'python.exe')
elif isMacOS():
try:
# 2.92 and older
path = bpy.app.binary_path_python
except AttributeError:
# 2.93 and later
import sys
path = sys.executable
return os.path.abspath(path)
elif isLinux():
return os.path.join(sys.prefix, 'sys.prefix/bin', 'python')
else:
print("sorry, still not implemented for ",
os.name, " - ", platform.system)
def installModule(packageName):
try:
subprocess.call([python_exe, "import ", packageName])
except:
python_exe = python_exec()
# upgrade pip
subprocess.call([python_exe, "-m", "ensurepip"])
subprocess.call(
[python_exe, "-m", "pip", "install", "--upgrade", "pip"])
# install required packages
subprocess.call([python_exe, "-m", "pip", "install", packageName])
installModule('openai')

Wyświetl plik

@ -0,0 +1,202 @@
import bpy
from bpy.types import Panel
UI_lan = {
'language': ['繁體中文', '简体中文', 'English'],
'label_language': ['語言', '语言', 'Language'],
'label_model': ['Chat-GPT 模型', 'Chat-GPT 模型', 'Chat-GPT Model'],
'label_model_description': ['請選擇欲使用的Chat-GPT模型', '请选择要使用的Chat-GPT模型', 'Please select the Chat-GPT model'],
'model_options': {
'gpt3.5': ['GPT-3.5 (便宜但較容易出錯)', 'GPT-3.5 (便宜但較容易出错)', 'GPT-3.5 (Affordable but less accurate)'],
'gpt4': ['GPT-4 (昂貴但較詳細準確)', 'GPT-4 (昂贵但较详细准确)', 'GPT-4 (Expensive but more accurate)'],
},
'label_history': ['對話歷史紀錄', '对话历史纪录', 'Chat History'],
'label_show_code': ['顯示程式碼', '显示代码', 'Show Code'],
'label_user': ['指令>', '指令>', 'Prompt>'],
'button_send': ['請稍候,模型正在編寫腳本...', '请稍候,模型正在编写脚本...', 'Please wait, the model is writing the script...'],
'button_submit': ['送出指令', '提交指令', 'Submit Prompt'],
'button_regenerate': ['重新生成', '重新生成', 'Regenerate Response'],
'command': ['指令', '指令', 'Prompt'],
'command_instruction': ['請輸入指令', '请输入指令', 'Please enter the command'],
'button_delete_all': ['刪除所有對話', '删除所有对话', 'Delete History'],
'button_delete': ['刪除此回答', '删除此回答', 'Delete This Response'],
'creativity': ['創意度', '创意度', 'Creativity'],
}
class BLENDERGPT_PT_PANEL(Panel):
bl_label = 'Blender GPT'
bl_idname = 'GPT_PT_PANEL'
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = 'Blender GPT'
def draw(self, context):
layout = self.layout
lan_idx = int(context.scene.lan)
column = layout.column(align=True)
# language usage
row = column.row(align=True)
row.label(text=UI_lan['label_language'][lan_idx])
row.prop(context.scene, "lan", text="")
column.separator()
# model of chat gpt
column.label(text=UI_lan['label_model'][lan_idx])
if lan_idx == 0:
column.prop(context.scene, "model_0", text="")
elif lan_idx == 1:
column.prop(context.scene, "model_1", text="")
else:
column.prop(context.scene, "model_2", text="")
column.separator()
# creativity
column.label(text=UI_lan['creativity'][lan_idx])
if lan_idx == 0:
column.prop(context.scene, "t_0", text="")
elif lan_idx == 1:
column.prop(context.scene, "t_1", text="")
else:
column.prop(context.scene, "t_2", text="")
column.separator()
# history of chat
if len(context.scene.history) > 0:
column.label(text=UI_lan['label_history'][lan_idx])
box = column.box()
for index, message in enumerate(context.scene.history):
if message.type == 'GPT':
row = box.row()
row.label(text="GPT>")
code_op = row.operator(
"gpt.gpt_code", text="", icon="TEXT", emboss=False)
code_op.code = message.content
if index == len(context.scene.history) - 1:
del_msg_op = row.operator(
'gpt.del_msg', text="", icon='TRASH', emboss=False)
del_msg_op.msg_idx = index
else:
row = box.row()
row.label(
text=f"{UI_lan['label_user'][lan_idx]}{message.content}")
if index == len(context.scene.history) - 2:
del_msg_op = row.operator(
'gpt.del_msg', text="", icon='TRASH', emboss=False)
del_msg_op.msg_idx = index
column.separator()
# input of chat
if len(context.scene.history) == 0 or (len(context.scene.history) > 0 and context.scene.history[-1].type != 'USER'):
column.label(text=UI_lan['command'][lan_idx])
if lan_idx == 0:
column.prop(context.scene, "prompt_input_0", text="")
elif lan_idx == 1:
column.prop(context.scene, "prompt_input_1", text="")
else:
column.prop(context.scene, "prompt_input_2", text="")
# send message
if len(context.scene.history) > 0 and context.scene.history[-1].type == 'USER':
button_label = UI_lan['button_send'][lan_idx] if context.scene.on_finish else UI_lan['button_regenerate'][lan_idx]
else:
button_label = UI_lan['button_send'][lan_idx] if context.scene.on_finish else UI_lan['button_submit'][lan_idx]
column.operator("gpt.send_msg", text=button_label, icon="PLAY")
column.separator()
column.operator("gpt.del_all_msg",
text=UI_lan['button_delete_all'][lan_idx], icon="TRASH")
def model_props_generator(idx):
return bpy.props.EnumProperty(
name=UI_lan['label_model'][idx],
description=UI_lan['label_model_description'][idx],
items=[
("gpt-3.5-turbo", UI_lan['model_options']['gpt3.5']
[idx], UI_lan['model_options']['gpt3.5'][idx]),
("gpt-4", UI_lan['model_options']['gpt4']
[idx], UI_lan['model_options']['gpt4'][idx]),
],
default="gpt-3.5-turbo",
)
def prompt_input_generator(idx):
return bpy.props.StringProperty(
name=UI_lan['command'][idx],
description=UI_lan['command_instruction'][idx],
default="",
)
def temperature_generator(idx):
return bpy.props.FloatProperty(
name=UI_lan['creativity'][idx],
description=UI_lan['creativity'][idx],
default=0,
min=0,
max=1,
)
def props_initialization():
bpy.types.Scene.history = bpy.props.CollectionProperty(
type=bpy.types.PropertyGroup)
bpy.types.Scene.lan = bpy.props.EnumProperty(
name="語言",
description="請選擇語言",
items=[
("0", "繁體中文", "繁體中文"),
("1", "简体中文", "简体中文"),
("2", "English", "英文"),
],
default="0",
)
bpy.types.Scene.model_0 = model_props_generator(0)
bpy.types.Scene.model_1 = model_props_generator(1)
bpy.types.Scene.model_2 = model_props_generator(2)
bpy.types.Scene.prompt_input_0 = prompt_input_generator(0)
bpy.types.Scene.prompt_input_1 = prompt_input_generator(1)
bpy.types.Scene.prompt_input_2 = prompt_input_generator(2)
bpy.types.Scene.t_0 = temperature_generator(0)
bpy.types.Scene.t_1 = temperature_generator(1)
bpy.types.Scene.t_2 = temperature_generator(2)
bpy.types.Scene.on_finish = bpy.props.BoolProperty(default=False)
bpy.types.PropertyGroup.type = bpy.props.StringProperty()
bpy.types.PropertyGroup.content = bpy.props.StringProperty()
def props_clear():
del bpy.types.Scene.history
del bpy.types.Scene.lan
del bpy.types.Scene.model_0
del bpy.types.Scene.model_1
del bpy.types.Scene.model_2
del bpy.types.Scene.prompt_input_0
del bpy.types.Scene.prompt_input_1
del bpy.types.Scene.prompt_input_2
del bpy.types.Scene.t_0
del bpy.types.Scene.t_1
del bpy.types.Scene.t_2
del bpy.types.Scene.on_finish

Wyświetl plik

@ -3,10 +3,10 @@ from bpy.types import AddonPreferences
class BLENDERGPT_AddonPreferences(AddonPreferences):
bl_idname = __name__
print(__name__)
api_key: props.StringProperty(
name="API Key",
bl_idname = "blendergpt-zh"
openai_key: props.StringProperty(
name="OPENAI API Key",
description="Enter your OpenAI API Key",
default="",
subtype="PASSWORD",
@ -14,4 +14,4 @@ class BLENDERGPT_AddonPreferences(AddonPreferences):
def draw(self, context):
layout = self.layout
layout.prop(self, "api_key")
layout.prop(self, "openai_key")

Wyświetl plik

@ -1,120 +0,0 @@
import bpy
from bpy.types import Operator
class BLENDERGPT_OT_DEL_MSG(Operator):
bl_idname = "gpt.del_msg"
bl_label = "刪除訊息"
bl_description = "刪除訊息"
bl_options = {"REGISTER", "UNDO"}
msg_idx: bpy.props.IntProperty(name="訊息索引", default=0)
def execute(self, context):
scene = context.scene
history = scene.history
history.remove(self.msg_idx)
return {"FINISHED"}
class BLENDERGPT_OT_DEL_ALL_MSG(Operator):
bl_idname = "gpt.del_all_msg"
bl_label = "刪除所有訊息"
bl_description = "刪除所有訊息"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
scene = context.scene
history = scene.history
history.clear()
return {"FINISHED"}
class BLENDERGPT_OT_GPT_CODE(Operator):
bl_idname = "gpt.gpt_code"
bl_label = "展示GPT程式碼"
bl_description = "展示GPT程式碼"
bl_options = {"REGISTER", "UNDO"}
code: bpy.props.StringProperty(
name="GPT程式碼", description="GPT所產生的程式碼", default="")
def execute(self, context):
# text area
txt_name = '指令腳本.py'
txt = bpy.data.texts.get(txt_name)
if txt is None:
txt = bpy.data.texts.new(txt_name)
txt.clear()
txt.write(self.code)
txt_edit_area = None
for area in bpy.context.screen.areas:
if area.type == 'TEXT_EDITOR':
txt_edit_area = area
break
cxt_area = context.area
for region in cxt_area.regions:
if region.type == 'WINDOW':
override = {'area': cxt_area, 'region': region}
bpy.ops.screen.area_split(
override, direction='VERTICAL', factor=0.5)
break
new_area = context.screen.areas[-1]
new_area.type = 'TEXT_EDITOR'
if txt_edit_area is None:
txt_edit_area = new_area
txt_edit_area.spaces.active.text = txt
return {"FINISHED"}
class BLENDERGPT_OT_SEND_MSG(Operator):
bl_idname = "gpt.send_msg"
bl_label = "送出訊息"
bl_description = "送出訊息"
bl_options = {"REGISTER", "UNDO"}
prompt_input: bpy.props.StringProperty(
name="指令", description="指令", default="")
def execute(self, context):
# TODO: connect to GPT
scene = context.scene
scene.on_finish = True
bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
blender_code = "print('Hello World')" # TODO: get from GPT
msg = scene.history.add()
msg.type = 'USER'
msg.content = scene.prompt_input
# clear prompt input
scene.prompt_input = ""
if blender_code:
msg = scene.history.add()
msg.type = 'GPT'
msg.content = blender_code
global_namespace = globals().copy()
try:
exec(blender_code, global_namespace)
except Exception as e:
self.report({'ERROR'}, f"Error: {e}")
scene.on_finish = False
return {'CANCELLED'}
scene.on_finish = False
return {"FINISHED"}

Wyświetl plik

@ -1,61 +0,0 @@
import bpy
from bpy.types import Panel
class BLENDERGPT_PT_PANEL(Panel):
bl_label = 'Blender GPT ZH'
bl_idname = 'GPT_PT_PANEL'
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = 'Blender GPT ZH'
def draw(self, context):
layout = self.layout
column = layout.column(align=True)
# language usage
row = column.row(align=True)
row.label(text="回饋語言:")
row.prop(context.scene, "lan", text="")
column.separator()
# history of chat
column.label(text="對話歷史紀錄:")
box = column.box()
for index, message in enumerate(context.scene.history):
if message.type == 'GPT':
row = box.row()
row.label(text="GPT: ")
show_code_op = row.operator(
"gpt.gpt_code", text="展示程式碼", icon="TEXT")
show_code_op.code = message.content
delete_message_op = row.operator(
'gpt.del_msg', text="", icon='TRASH', emboss=False)
delete_message_op.msg_idx = index
else:
row = box.row()
row.label(text=f"USER: {message.content}")
delete_message_op = row.operator(
'gpt.del_msg', text="", icon='TRASH', emboss=False)
delete_message_op.msg_idx = index
column.separator()
# model of chat gpt
column.label(text="Chat-GPT 模型:")
column.prop(context.scene, "model", text="")
# input of chat
column.label(text="指令:")
column.prop(context.scene, "prompt_input", text="")
button_label = "請稍候,模型正在編寫腳本..." if context.scene.on_finish else "送出指令"
row = column.row(align=True)
row.operator("gpt.send_msg", text=button_label)
row.operator("gpt.del_all_msg", text="Clear Chat")
column.separator()