kopia lustrzana https://github.com/gd3kr/BlenderGPT
added context retention, higher reliability, better User Interface
rodzic
8992498e90
commit
8d99d33801
159
__init__.py
159
__init__.py
|
@ -1,6 +1,7 @@
|
|||
import sys
|
||||
import os
|
||||
import bpy
|
||||
import bpy.props
|
||||
import re
|
||||
|
||||
bl_info = {
|
||||
|
@ -8,7 +9,7 @@ bl_info = {
|
|||
"blender": (2, 82, 0),
|
||||
"category": "Object",
|
||||
"author": "Aarya (@gd3kr)",
|
||||
"version": (1, 0, 0),
|
||||
"version": (2, 0, 0),
|
||||
"location": "3D View > UI > GPT-4 Blender Assistant",
|
||||
"description": "Generate Blender Python code using OpenAI's GPT-4 to perform various tasks.",
|
||||
"warning": "",
|
||||
|
@ -29,16 +30,16 @@ user: create 10 cubes in random locations from -10 to 10
|
|||
assistant:
|
||||
```
|
||||
import bpy
|
||||
from random import randint
|
||||
import random
|
||||
bpy.ops.mesh.primitive_cube_add()
|
||||
|
||||
#how many cubes you want to add
|
||||
count = 10
|
||||
|
||||
for c in range(0,count):
|
||||
x = randint(-10,10)
|
||||
y = randint(-10,10)
|
||||
z = randint(-10,10)
|
||||
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))
|
||||
```"""
|
||||
|
||||
|
@ -59,45 +60,44 @@ def get_api_key(context):
|
|||
|
||||
|
||||
def init_props():
|
||||
bpy.types.Scene.gpt4_natural_language_input = bpy.props.StringProperty(
|
||||
name="Command",
|
||||
description="Enter the natural language command",
|
||||
bpy.types.Scene.gpt4_chat_history = bpy.props.CollectionProperty(type=bpy.types.PropertyGroup)
|
||||
bpy.types.Scene.gpt4_chat_input = bpy.props.StringProperty(
|
||||
name="Message",
|
||||
description="Enter your message",
|
||||
default="",
|
||||
)
|
||||
bpy.types.Scene.gpt4_button_pressed = bpy.props.BoolProperty(default=False)
|
||||
|
||||
|
||||
bpy.types.PropertyGroup.type = bpy.props.StringProperty()
|
||||
bpy.types.PropertyGroup.content = bpy.props.StringProperty()
|
||||
|
||||
def clear_props():
|
||||
del bpy.types.Scene.gpt4_natural_language_input
|
||||
del bpy.types.Scene.gpt4_chat_history
|
||||
del bpy.types.Scene.gpt4_chat_input
|
||||
del bpy.types.Scene.gpt4_button_pressed
|
||||
|
||||
def generate_blender_code(prompt, chat_history):
|
||||
messages = [{"role": "system", "content": system_prompt}]
|
||||
for message in chat_history[-10:]:
|
||||
if message.type == "assistant":
|
||||
messages.append({"role": "assistant", "content": "```\n" + message.content + "\n```"})
|
||||
else:
|
||||
messages.append({"role": message.type.lower(), "content": message.content})
|
||||
|
||||
def generate_blender_code(prompt):
|
||||
|
||||
# Add the current user message
|
||||
messages.append({"role": "user", "content": "Can you please write Blender code for me that accomplishes the following task: " + prompt + "? \n. Do not respond with anything that is not Python code. Do not provide explanations"})
|
||||
|
||||
|
||||
try:
|
||||
response = openai.ChatCompletion.create(
|
||||
model="gpt-4",
|
||||
messages=[{
|
||||
"role": "system",
|
||||
"content": system_prompt
|
||||
},
|
||||
{"role": "user", "content": "Can you please write Blender code for me that accomplishes the following task: " + prompt + "? \n. Do not respond with anything that is not Python code. Do not provide explanations"}
|
||||
],
|
||||
messages=messages,
|
||||
stream=True,
|
||||
max_tokens=1500,
|
||||
)
|
||||
except Exception as e: # Use GPT-3.5 if GPT-4 is not available
|
||||
response = openai.ChatCompletion.create(
|
||||
model="gpt-3.5-turbo",
|
||||
messages=[{
|
||||
"role": "system",
|
||||
"content": system_prompt
|
||||
},
|
||||
{"role": "user", "content": "Can you please write Blender code for me that accomplishes the following task: " + prompt + "?\nDo not respond with anything that is not Python code. Do not provide explanations"}
|
||||
],
|
||||
messages=messages,
|
||||
stream=True,
|
||||
max_tokens=1500,
|
||||
)
|
||||
|
@ -118,13 +118,57 @@ def generate_blender_code(prompt):
|
|||
completion_text += event_text # append the text
|
||||
print(completion_text, flush=True, end='\r')
|
||||
completion_text = re.findall(r'```(.*?)```', completion_text, re.DOTALL)[0]
|
||||
# remove "python" if the first line has it
|
||||
completion_text = re.sub(r'^python', '', completion_text, flags=re.MULTILINE)
|
||||
|
||||
return completion_text
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def split_area_to_text_editor(context):
|
||||
area = context.area
|
||||
for region in area.regions:
|
||||
if region.type == 'WINDOW':
|
||||
override = {'area': 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'
|
||||
return new_area
|
||||
|
||||
|
||||
class GPT4_OT_ShowCode(bpy.types.Operator):
|
||||
bl_idname = "gpt4.show_code"
|
||||
bl_label = "Show Code"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
code: bpy.props.StringProperty(
|
||||
name="Code",
|
||||
description="The generated code",
|
||||
default="",
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
text_name = "GPT4_Generated_Code.py"
|
||||
text = bpy.data.texts.get(text_name)
|
||||
if text is None:
|
||||
text = bpy.data.texts.new(text_name)
|
||||
|
||||
text.clear()
|
||||
text.write(self.code)
|
||||
|
||||
text_editor_area = None
|
||||
for area in context.screen.areas:
|
||||
if area.type == 'TEXT_EDITOR':
|
||||
text_editor_area = area
|
||||
break
|
||||
|
||||
if text_editor_area is None:
|
||||
text_editor_area = split_area_to_text_editor(context)
|
||||
|
||||
text_editor_area.spaces.active.text = text
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class GPT4_PT_Panel(bpy.types.Panel):
|
||||
bl_label = "GPT-4 Blender Assistant"
|
||||
|
@ -137,22 +181,40 @@ class GPT4_PT_Panel(bpy.types.Panel):
|
|||
layout = self.layout
|
||||
column = layout.column(align=True)
|
||||
|
||||
column.label(text="Enter a natural language command:")
|
||||
|
||||
# Add the input field for natural language commands
|
||||
column.prop(context.scene, "gpt4_natural_language_input", text="")
|
||||
|
||||
# Execute the operator with the input from the user
|
||||
button_label = "Please wait...(this might take some time)" if context.scene.gpt4_button_pressed else "Execute"
|
||||
operator = column.operator("gpt4.execute", text=button_label)
|
||||
operator.natural_language_input = context.scene.gpt4_natural_language_input
|
||||
column.label(text="Chat history:")
|
||||
box = column.box()
|
||||
for message in context.scene.gpt4_chat_history:
|
||||
if message.type == 'assistant':
|
||||
row = box.row()
|
||||
row.label(text="Assistant: ")
|
||||
show_code_op = row.operator("gpt4.show_code", text="Show Code")
|
||||
show_code_op.code = message.content
|
||||
else:
|
||||
box.label(text=f"User: {message.content}")
|
||||
|
||||
column.separator()
|
||||
|
||||
column.label(text="Enter your message:")
|
||||
column.prop(context.scene, "gpt4_chat_input", text="")
|
||||
button_label = "Please wait...(this might take some time)" if context.scene.gpt4_button_pressed else "Execute"
|
||||
row = column.row(align=True)
|
||||
row.operator("gpt4.send_message", text=button_label)
|
||||
row.operator("gpt4.clear_chat", text="Clear Chat")
|
||||
|
||||
column.separator()
|
||||
|
||||
class GPT4_OT_ClearChat(bpy.types.Operator):
|
||||
bl_idname = "gpt4.clear_chat"
|
||||
bl_label = "Clear Chat"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.gpt4_chat_history.clear()
|
||||
return {'FINISHED'}
|
||||
|
||||
class GPT4_OT_Execute(bpy.types.Operator):
|
||||
bl_idname = "gpt4.execute"
|
||||
bl_label = "GPT-4 Execute"
|
||||
bl_idname = "gpt4.send_message"
|
||||
bl_label = "Send Message"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
natural_language_input: bpy.props.StringProperty(
|
||||
|
@ -171,11 +233,20 @@ class GPT4_OT_Execute(bpy.types.Operator):
|
|||
context.scene.gpt4_button_pressed = True
|
||||
bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
|
||||
|
||||
blender_code = generate_blender_code(self.natural_language_input)
|
||||
blender_code = generate_blender_code(context.scene.gpt4_chat_input, context.scene.gpt4_chat_history)
|
||||
|
||||
message = context.scene.gpt4_chat_history.add()
|
||||
message.type = 'user'
|
||||
message.content = context.scene.gpt4_chat_input
|
||||
|
||||
# Clear the chat input field
|
||||
context.scene.gpt4_chat_input = ""
|
||||
|
||||
|
||||
if blender_code:
|
||||
# Add this line to print the generated code.
|
||||
print("Generated code:", blender_code)
|
||||
message = context.scene.gpt4_chat_history.add()
|
||||
message.type = 'assistant'
|
||||
message.content = blender_code
|
||||
try:
|
||||
exec(blender_code)
|
||||
except Exception as e:
|
||||
|
@ -187,6 +258,8 @@ class GPT4_OT_Execute(bpy.types.Operator):
|
|||
context.scene.gpt4_button_pressed = False
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
|
||||
context.scene.gpt4_button_pressed = False
|
||||
return {'FINISHED'}
|
||||
|
||||
|
@ -212,6 +285,9 @@ def register():
|
|||
bpy.utils.register_class(GPT4AddonPreferences)
|
||||
bpy.utils.register_class(GPT4_OT_Execute)
|
||||
bpy.utils.register_class(GPT4_PT_Panel)
|
||||
bpy.utils.register_class(GPT4_OT_ClearChat)
|
||||
bpy.utils.register_class(GPT4_OT_ShowCode)
|
||||
|
||||
bpy.types.VIEW3D_MT_mesh_add.append(menu_func)
|
||||
init_props()
|
||||
|
||||
|
@ -220,6 +296,9 @@ def unregister():
|
|||
bpy.utils.unregister_class(GPT4AddonPreferences)
|
||||
bpy.utils.unregister_class(GPT4_OT_Execute)
|
||||
bpy.utils.unregister_class(GPT4_PT_Panel)
|
||||
bpy.utils.unregister_class(GPT4_OT_ClearChat)
|
||||
bpy.utils.register_class(GPT4_OT_ShowCode)
|
||||
|
||||
bpy.types.VIEW3D_MT_mesh_add.remove(menu_func)
|
||||
clear_props()
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue