Merge pull request #1 from hc-psy/dev

[feature] init and panel
pull/7/head
Hao-Cheng Lo 2023-05-27 15:27:29 +08:00 zatwierdzone przez GitHub
commit d68d43d947
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
5 zmienionych plików z 311 dodań i 0 usunięć

3
.gitignore vendored
Wyświetl plik

@ -6,6 +6,9 @@ __pycache__/
# C extensions
*.so
.DS_Store/
.DS_Store
# Distribution / packaging
.Python
build/

Wyświetl plik

@ -0,0 +1,110 @@
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
bl_info = {
"name": "Blender GPT (ZH) 中文用戶專屬",
"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()
def unregister():
for cls in Classes:
bpy.utils.unregister_class(cls)
clear_props()

Wyświetl plik

@ -0,0 +1,120 @@
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

@ -0,0 +1,61 @@
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()

Wyświetl plik

@ -0,0 +1,17 @@
from bpy import props
from bpy.types import AddonPreferences
class BLENDERGPT_AddonPreferences(AddonPreferences):
bl_idname = __name__
print(__name__)
api_key: props.StringProperty(
name="API Key",
description="Enter your OpenAI API Key",
default="",
subtype="PASSWORD",
)
def draw(self, context):
layout = self.layout
layout.prop(self, "api_key")