Spaces:
Build error
Build error
Commit ·
d00747b
1
Parent(s): a2217b9
code updated in app and synth
Browse files- app.py +41 -20
- translator/synth.py +47 -22
app.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
import os
|
| 2 |
import gradio as gr
|
| 3 |
from translator.agent import TranslationAgent
|
|
|
|
| 4 |
|
| 5 |
agent = TranslationAgent()
|
| 6 |
|
|
@@ -9,26 +10,31 @@ description = "Paste a Unity C# script and get Unreal C++ (.h/.cpp) + Unreal Blu
|
|
| 9 |
|
| 10 |
|
| 11 |
def extract_class_name(csharp_code: str) -> str:
|
| 12 |
-
|
| 13 |
match = re.search(r"class\s+(\w+)", csharp_code)
|
| 14 |
return match.group(1) if match else "MyActor"
|
| 15 |
|
| 16 |
|
| 17 |
def split_cpp_code(full_cpp_code: str):
|
| 18 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
if not full_cpp_code:
|
| 20 |
return "", ""
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
|
|
|
| 32 |
|
| 33 |
|
| 34 |
def do_translate(csharp_code, target_format, model_choice):
|
|
@@ -41,15 +47,17 @@ def do_translate(csharp_code, target_format, model_choice):
|
|
| 41 |
# Split .h / .cpp parts if present
|
| 42 |
header_code, cpp_code_only = split_cpp_code(cpp_code)
|
| 43 |
|
| 44 |
-
# Save files
|
| 45 |
h_filename = f"{class_name}.h"
|
| 46 |
cpp_filename = f"{class_name}.cpp"
|
|
|
|
| 47 |
with open(h_filename, "w", encoding="utf-8") as h:
|
| 48 |
h.write(header_code or "// No header generated")
|
|
|
|
| 49 |
with open(cpp_filename, "w", encoding="utf-8") as c:
|
| 50 |
c.write(cpp_code_only or "// No cpp generated")
|
| 51 |
|
| 52 |
-
# Split blueprint output into main and
|
| 53 |
blueprint_parts = blueprint_code.split("###")
|
| 54 |
main_script = blueprint_parts[0].strip()
|
| 55 |
extra_info = blueprint_parts[1].strip() if len(blueprint_parts) > 1 else ""
|
|
@@ -57,6 +65,7 @@ def do_translate(csharp_code, target_format, model_choice):
|
|
| 57 |
return header_code, cpp_code_only, main_script, extra_info, h_filename, cpp_filename
|
| 58 |
|
| 59 |
|
|
|
|
| 60 |
with gr.Blocks(title=title) as demo:
|
| 61 |
gr.Markdown(f"### 🧠 {title}")
|
| 62 |
gr.Markdown(description)
|
|
@@ -69,12 +78,20 @@ with gr.Blocks(title=title) as demo:
|
|
| 69 |
)
|
| 70 |
|
| 71 |
with gr.Row():
|
| 72 |
-
target_format = gr.Radio(
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
translate_btn = gr.Button("🔁 Translate")
|
| 76 |
|
| 77 |
-
#
|
| 78 |
with gr.Tab("C++ Output"):
|
| 79 |
with gr.Row():
|
| 80 |
header_box = gr.Code(label=".h (Header File)", language="cpp")
|
|
@@ -83,12 +100,16 @@ with gr.Blocks(title=title) as demo:
|
|
| 83 |
download_h = gr.File(label="Download .h")
|
| 84 |
download_cpp = gr.File(label="Download .cpp")
|
| 85 |
|
|
|
|
| 86 |
with gr.Tab("Blueprint Output"):
|
| 87 |
with gr.Row():
|
| 88 |
blueprint_main = gr.Textbox(label="Blueprint Python Script", lines=15)
|
| 89 |
with gr.Row():
|
| 90 |
-
blueprint_notes = gr.Textbox(
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
translate_btn.click(
|
| 94 |
do_translate,
|
|
|
|
| 1 |
import os
|
| 2 |
import gradio as gr
|
| 3 |
from translator.agent import TranslationAgent
|
| 4 |
+
import re
|
| 5 |
|
| 6 |
agent = TranslationAgent()
|
| 7 |
|
|
|
|
| 10 |
|
| 11 |
|
| 12 |
def extract_class_name(csharp_code: str) -> str:
|
| 13 |
+
"""Extracts Unity class name for file naming."""
|
| 14 |
match = re.search(r"class\s+(\w+)", csharp_code)
|
| 15 |
return match.group(1) if match else "MyActor"
|
| 16 |
|
| 17 |
|
| 18 |
def split_cpp_code(full_cpp_code: str):
|
| 19 |
+
"""
|
| 20 |
+
Split model output into .h and .cpp parts using file markers like:
|
| 21 |
+
---FILE: MyActor.h---
|
| 22 |
+
---FILE: MyActor.cpp---
|
| 23 |
+
"""
|
| 24 |
if not full_cpp_code:
|
| 25 |
return "", ""
|
| 26 |
+
|
| 27 |
+
header_match = re.search(r"---FILE:\s*.*?\.h---([\s\S]*?)(?=---FILE:|$)", full_cpp_code)
|
| 28 |
+
cpp_match = re.search(r"---FILE:\s*.*?\.cpp---([\s\S]*?)(?=---FILE:|$)", full_cpp_code)
|
| 29 |
+
|
| 30 |
+
header_code = header_match.group(1).strip() if header_match else ""
|
| 31 |
+
cpp_code = cpp_match.group(1).strip() if cpp_match else full_cpp_code.strip()
|
| 32 |
+
|
| 33 |
+
# Cleanup any ``` fences if the model wrapped code blocks
|
| 34 |
+
header_code = re.sub(r"^```[a-zA-Z]*|```$", "", header_code, flags=re.MULTILINE).strip()
|
| 35 |
+
cpp_code = re.sub(r"^```[a-zA-Z]*|```$", "", cpp_code, flags=re.MULTILINE).strip()
|
| 36 |
+
|
| 37 |
+
return header_code, cpp_code
|
| 38 |
|
| 39 |
|
| 40 |
def do_translate(csharp_code, target_format, model_choice):
|
|
|
|
| 47 |
# Split .h / .cpp parts if present
|
| 48 |
header_code, cpp_code_only = split_cpp_code(cpp_code)
|
| 49 |
|
| 50 |
+
# Save to temporary files for download
|
| 51 |
h_filename = f"{class_name}.h"
|
| 52 |
cpp_filename = f"{class_name}.cpp"
|
| 53 |
+
|
| 54 |
with open(h_filename, "w", encoding="utf-8") as h:
|
| 55 |
h.write(header_code or "// No header generated")
|
| 56 |
+
|
| 57 |
with open(cpp_filename, "w", encoding="utf-8") as c:
|
| 58 |
c.write(cpp_code_only or "// No cpp generated")
|
| 59 |
|
| 60 |
+
# Split blueprint output into main and extra sections if available
|
| 61 |
blueprint_parts = blueprint_code.split("###")
|
| 62 |
main_script = blueprint_parts[0].strip()
|
| 63 |
extra_info = blueprint_parts[1].strip() if len(blueprint_parts) > 1 else ""
|
|
|
|
| 65 |
return header_code, cpp_code_only, main_script, extra_info, h_filename, cpp_filename
|
| 66 |
|
| 67 |
|
| 68 |
+
# Gradio UI
|
| 69 |
with gr.Blocks(title=title) as demo:
|
| 70 |
gr.Markdown(f"### 🧠 {title}")
|
| 71 |
gr.Markdown(description)
|
|
|
|
| 78 |
)
|
| 79 |
|
| 80 |
with gr.Row():
|
| 81 |
+
target_format = gr.Radio(
|
| 82 |
+
["cpp", "blueprint", "both"],
|
| 83 |
+
value="both",
|
| 84 |
+
label="Target Format"
|
| 85 |
+
)
|
| 86 |
+
model_choice = gr.Radio(
|
| 87 |
+
["hf", "openai"],
|
| 88 |
+
value="hf",
|
| 89 |
+
label="Model Backend"
|
| 90 |
+
)
|
| 91 |
|
| 92 |
translate_btn = gr.Button("🔁 Translate")
|
| 93 |
|
| 94 |
+
# C++ output tab
|
| 95 |
with gr.Tab("C++ Output"):
|
| 96 |
with gr.Row():
|
| 97 |
header_box = gr.Code(label=".h (Header File)", language="cpp")
|
|
|
|
| 100 |
download_h = gr.File(label="Download .h")
|
| 101 |
download_cpp = gr.File(label="Download .cpp")
|
| 102 |
|
| 103 |
+
# Blueprint output tab
|
| 104 |
with gr.Tab("Blueprint Output"):
|
| 105 |
with gr.Row():
|
| 106 |
blueprint_main = gr.Textbox(label="Blueprint Python Script", lines=15)
|
| 107 |
with gr.Row():
|
| 108 |
+
blueprint_notes = gr.Textbox(
|
| 109 |
+
label="Blueprint Hints / Logs",
|
| 110 |
+
lines=10,
|
| 111 |
+
placeholder="Any additional output, logs, or notes will appear here."
|
| 112 |
+
)
|
| 113 |
|
| 114 |
translate_btn.click(
|
| 115 |
do_translate,
|
translator/synth.py
CHANGED
|
@@ -3,47 +3,72 @@ from .llm_client import generate_with_hf, generate_with_openai
|
|
| 3 |
def synthesize_cpp(parsed: dict, mapping: dict, prompt_context: str = "", model_backend="hf") -> str:
|
| 4 |
"""
|
| 5 |
Converts Unity C# parsed structure into Unreal Engine C++ (header + source).
|
|
|
|
|
|
|
|
|
|
| 6 |
"""
|
|
|
|
|
|
|
| 7 |
prompt = f"""
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
|
| 18 |
-
Be concise, compile-ready, and use UPROPERTY/UFUNCTION macros where suitable.
|
| 19 |
{prompt_context}
|
| 20 |
"""
|
| 21 |
|
| 22 |
if model_backend == "openai":
|
| 23 |
-
from .llm_client import generate_with_openai
|
| 24 |
return generate_with_openai(prompt, model="gpt-4o-mini")
|
| 25 |
else:
|
| 26 |
-
from .llm_client import generate_with_hf
|
| 27 |
return generate_with_hf(prompt, model="mistralai/Mistral-7B-Instruct-v0.3")
|
| 28 |
|
| 29 |
|
| 30 |
def synthesize_blueprint_python(parsed: dict, mapping: dict, model_backend="hf") -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
prompt = f"""
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
- A float property 'RotationSpeed' exposed to Blueprints
|
| 36 |
-
- A Tick override that rotates actor by RotationSpeed * DeltaTime
|
| 37 |
|
| 38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
-
Parsed
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
| 42 |
"""
|
| 43 |
|
| 44 |
if model_backend == "openai":
|
| 45 |
-
from .llm_client import generate_with_openai
|
| 46 |
return generate_with_openai(prompt, model="gpt-4o-mini")
|
| 47 |
else:
|
| 48 |
-
|
| 49 |
-
return generate_with_hf(prompt, model="mistralai/Mistral-7B-Instruct-v0.3")
|
|
|
|
| 3 |
def synthesize_cpp(parsed: dict, mapping: dict, prompt_context: str = "", model_backend="hf") -> str:
|
| 4 |
"""
|
| 5 |
Converts Unity C# parsed structure into Unreal Engine C++ (header + source).
|
| 6 |
+
Always returns code with clear file markers:
|
| 7 |
+
---FILE: ClassName.h---
|
| 8 |
+
---FILE: ClassName.cpp---
|
| 9 |
"""
|
| 10 |
+
class_name = parsed.get("classes", [{}])[0].get("name", "MyActor")
|
| 11 |
+
|
| 12 |
prompt = f"""
|
| 13 |
+
You are an expert Unreal Engine C++ developer.
|
| 14 |
+
Translate the following Unity C# class into idiomatic Unreal C++.
|
| 15 |
+
|
| 16 |
+
✅ Follow these rules:
|
| 17 |
+
- Create TWO files with exact markers:
|
| 18 |
+
---FILE: {class_name}.h---
|
| 19 |
+
(Header file)
|
| 20 |
+
---FILE: {class_name}.cpp---
|
| 21 |
+
(Implementation file)
|
| 22 |
+
- Use Unreal macros like UCLASS(), UPROPERTY(), and UFUNCTION() appropriately.
|
| 23 |
+
- Include necessary Unreal headers.
|
| 24 |
+
- Ensure code compiles cleanly.
|
| 25 |
+
- Use PascalCase for class and method names.
|
| 26 |
+
- Avoid Unity-specific APIs; map them via given rules.
|
| 27 |
|
| 28 |
+
Mapping rules:
|
| 29 |
+
{mapping}
|
| 30 |
+
|
| 31 |
+
Parsed structure:
|
| 32 |
+
{parsed}
|
| 33 |
|
|
|
|
| 34 |
{prompt_context}
|
| 35 |
"""
|
| 36 |
|
| 37 |
if model_backend == "openai":
|
|
|
|
| 38 |
return generate_with_openai(prompt, model="gpt-4o-mini")
|
| 39 |
else:
|
|
|
|
| 40 |
return generate_with_hf(prompt, model="mistralai/Mistral-7B-Instruct-v0.3")
|
| 41 |
|
| 42 |
|
| 43 |
def synthesize_blueprint_python(parsed: dict, mapping: dict, model_backend="hf") -> str:
|
| 44 |
+
"""
|
| 45 |
+
Generates Unreal Python Editor script that creates a Blueprint equivalent
|
| 46 |
+
of the Unity class (BP_<ClassName>).
|
| 47 |
+
"""
|
| 48 |
+
class_name = parsed.get("classes", [{}])[0].get("name", "MyActor")
|
| 49 |
+
|
| 50 |
prompt = f"""
|
| 51 |
+
You are an Unreal Engine Python scripting expert.
|
| 52 |
+
Convert the given Unity C# class into an Unreal Python Editor script
|
| 53 |
+
that generates a Blueprint Actor named BP_{class_name}.
|
|
|
|
|
|
|
| 54 |
|
| 55 |
+
Requirements:
|
| 56 |
+
- Use Unreal Python API (unreal module).
|
| 57 |
+
- Create Blueprint under /Game/Blueprints/BP_{class_name}.
|
| 58 |
+
- Add StaticMeshComponent as root.
|
| 59 |
+
- Add float property 'RotationSpeed' exposed to Blueprint.
|
| 60 |
+
- Implement a Tick method to rotate actor: RotationSpeed * DeltaTime.
|
| 61 |
+
- Include import statements and comments for clarity.
|
| 62 |
+
- Output only the full Python script (no explanations).
|
| 63 |
|
| 64 |
+
Parsed structure:
|
| 65 |
+
{parsed}
|
| 66 |
+
|
| 67 |
+
Mapping rules:
|
| 68 |
+
{mapping}
|
| 69 |
"""
|
| 70 |
|
| 71 |
if model_backend == "openai":
|
|
|
|
| 72 |
return generate_with_openai(prompt, model="gpt-4o-mini")
|
| 73 |
else:
|
| 74 |
+
return generate_with_hf(prompt, model="mistralai/Mistral-7B-Instruct-v0.3")
|
|
|