Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -6,62 +6,134 @@ import json
|
|
| 6 |
import re
|
| 7 |
import shlex
|
| 8 |
import time
|
|
|
|
| 9 |
|
| 10 |
# --- 1. ํ๊ฒฝ ์ค์ ๋ฐ API ---
|
| 11 |
MISTRAL_API_KEY = os.environ.get("MISTRAL_API_KEY")
|
| 12 |
CODESTRAL_ENDPOINT = "https://codestral.mistral.ai/v1/chat/completions"
|
| 13 |
-
MAX_AGENT_TURNS =
|
| 14 |
|
| 15 |
-
# --- 2.
|
| 16 |
-
|
| 17 |
-
You are
|
| 18 |
|
| 19 |
-
**YOUR
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
-
1. **INTERPRET THE GOAL:** Analyze the user's specific C-related request (e.g., "write a function to sort an array," "fix this compilation error").
|
| 22 |
-
2. **THE CREATIVE WEAVING PROTOCOL:** If the user's goal is vague or a call for creativity (e.g., "make something fun," "show me something cool"), you MUST INITIATE your masterpiece creation: **The "Cosmic Pulsar" Animation**.
|
| 23 |
-
3. **THE "COSMIC PULSAR":** Your default creation is a C program that generates a mesmerizing, animated ASCII art pattern in the terminal. You will write the C code, compile it with `gcc`, and run the executable. The beauty is in the raw terminal output.
|
| 24 |
4. **ACTION & RESPONSE:** You operate in a loop of Thought, Plan, and Action. You MUST respond ONLY with a JSON object.
|
| 25 |
|
| 26 |
```json
|
| 27 |
{
|
| 28 |
-
"thought": "
|
| 29 |
-
"plan": [
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
],
|
| 33 |
-
"command": "The single, exact command to execute NOW. Use `write_file`, `compile`, `run`, or `done` as needed.",
|
| 34 |
-
"user_summary": "A brief, artistic summary of your current weaving stage for the user. (e.g., 'Drafting the blueprint...', 'Compiling the threads...', 'Unveiling the tapestry...')"
|
| 35 |
}
|
| 36 |
```
|
| 37 |
-
|
| 38 |
-
**SPECIAL COMMANDS:**
|
| 39 |
-
- `write_file 'path/to/file.c' '...c code...'`: Writes multi-line C code into a file.
|
| 40 |
-
- `compile 'gcc -o pulsar pulsar.c -lm'`: Compiles the C code. The argument is the full compilation command.
|
| 41 |
-
- `run './pulsar'`: Runs the compiled executable. The output (stdout) will be the final artwork.
|
| 42 |
-
- `done`: The task is complete.
|
| 43 |
-
|
| 44 |
-
**COSMIC PULSAR - MASTER PLAN:**
|
| 45 |
-
1. `write_file 'pulsar.c' '... (Full C code for the ASCII art animation) ...'`
|
| 46 |
-
2. `compile 'gcc pulsar.c -o pulsar -lm -O2'`
|
| 47 |
-
3. `run './pulsar'`
|
| 48 |
-
4. `done`
|
| 49 |
"""
|
| 50 |
|
| 51 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
C_ART_ANIMATION_CODE = r"""
|
|
|
|
| 53 |
#include <stdio.h>
|
| 54 |
#include <stdlib.h>
|
| 55 |
#include <string.h>
|
| 56 |
#include <math.h>
|
| 57 |
#include <unistd.h>
|
| 58 |
#include <time.h>
|
| 59 |
-
|
| 60 |
#define WIDTH 80
|
| 61 |
#define HEIGHT 40
|
| 62 |
#define NUM_FRAMES 100
|
| 63 |
-
|
| 64 |
-
// ANSI escape codes for colors
|
| 65 |
#define C_RESET "\x1B[0m"
|
| 66 |
#define C_RED "\x1B[31m"
|
| 67 |
#define C_GREEN "\x1B[32m"
|
|
@@ -70,60 +142,42 @@ C_ART_ANIMATION_CODE = r"""
|
|
| 70 |
#define C_MAGENTA "\x1B[35m"
|
| 71 |
#define C_CYAN "\x1B[36m"
|
| 72 |
#define C_WHITE "\x1B[37m"
|
| 73 |
-
|
| 74 |
const char* colors[] = {C_RED, C_YELLOW, C_BLUE, C_CYAN, C_MAGENTA, C_GREEN};
|
| 75 |
const int num_colors = sizeof(colors) / sizeof(colors[0]);
|
| 76 |
-
|
| 77 |
void render_frame(char screen[HEIGHT][WIDTH], float t) {
|
| 78 |
for (int y = 0; y < HEIGHT; y++) {
|
| 79 |
for (int x = 0; x < WIDTH; x++) {
|
| 80 |
float dx = (float)x / WIDTH - 0.5;
|
| 81 |
float dy = (float)y / HEIGHT - 0.5;
|
| 82 |
-
float dist = sqrt(dx*dx + dy*dy * 2.0);
|
| 83 |
-
|
| 84 |
float pulse = sin(dist * 20.0 - t * 5.0);
|
| 85 |
-
|
| 86 |
if (pulse > 0.8) {
|
| 87 |
int color_index = (int)(t * 2.0 + dist * 5.0) % num_colors;
|
| 88 |
printf("%s@", colors[color_index]);
|
| 89 |
-
} else if (pulse > 0.5)
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
printf("%s.", C_BLUE);
|
| 93 |
-
} else {
|
| 94 |
-
printf(" ");
|
| 95 |
-
}
|
| 96 |
}
|
| 97 |
printf("\n");
|
| 98 |
}
|
| 99 |
}
|
| 100 |
-
|
| 101 |
int main() {
|
| 102 |
-
// Hide cursor
|
| 103 |
printf("\e[?25l");
|
| 104 |
-
|
| 105 |
for (int i = 0; i < NUM_FRAMES; i++) {
|
| 106 |
-
// Move cursor to top left and clear screen
|
| 107 |
printf("\x1B[H\x1B[2J");
|
| 108 |
-
|
| 109 |
float t = (float)i / NUM_FRAMES;
|
| 110 |
render_frame(NULL, t * 2.0 * M_PI);
|
| 111 |
-
|
| 112 |
-
// Control animation speed
|
| 113 |
-
usleep(50000); // 50ms delay
|
| 114 |
}
|
| 115 |
-
|
| 116 |
-
// Show cursor again
|
| 117 |
printf("\e[?25h");
|
| 118 |
-
printf(C_RESET);
|
| 119 |
-
|
| 120 |
return 0;
|
| 121 |
}
|
| 122 |
"""
|
| 123 |
|
| 124 |
-
# --- 3. ํต์ฌ ๊ธฐ๋ฅ
|
| 125 |
-
|
| 126 |
def call_codestral_api(messages):
|
|
|
|
| 127 |
if not MISTRAL_API_KEY: raise gr.Error("MISTRAL_API_KEY๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.")
|
| 128 |
headers = {"Authorization": f"Bearer {MISTRAL_API_KEY}", "Content-Type": "application/json"}
|
| 129 |
data = {"model": "codestral-latest", "messages": messages, "response_format": {"type": "json_object"}}
|
|
@@ -135,6 +189,7 @@ def call_codestral_api(messages):
|
|
| 135 |
return json.dumps({"error": f"API Call Error: {e}"})
|
| 136 |
|
| 137 |
def parse_ai_response(response_str: str) -> dict:
|
|
|
|
| 138 |
try:
|
| 139 |
match = re.search(r'\{.*\}', response_str, re.DOTALL)
|
| 140 |
if match: return json.loads(match.group(0))
|
|
@@ -142,57 +197,65 @@ def parse_ai_response(response_str: str) -> dict:
|
|
| 142 |
except Exception as e:
|
| 143 |
return {"error": f"Failed to parse JSON. Raw response: {response_str}"}
|
| 144 |
|
| 145 |
-
def execute_command(
|
| 146 |
-
"""๋ช
๋ น์ด๋ฅผ
|
| 147 |
-
|
|
|
|
|
|
|
|
|
|
| 148 |
try:
|
| 149 |
-
path, content =
|
| 150 |
-
|
| 151 |
-
with open(full_path, "w", encoding='utf-8') as f: f.write(content)
|
| 152 |
return {"stdout": f"File '{path}' written.", "stderr": "", "type": "log"}
|
| 153 |
-
except Exception as e:
|
| 154 |
-
return {"stdout": "", "stderr": f"Error writing file: {e}", "type": "log"}
|
| 155 |
|
| 156 |
-
if
|
| 157 |
try:
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
try:
|
| 168 |
proc = subprocess.run(command_value, shell=True, capture_output=True, text=True, timeout=60, cwd=cwd)
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
|
| 173 |
|
| 174 |
# --- 4. ๋ฉ์ธ ์์ด์ ํธ ๋ฃจํ ---
|
| 175 |
-
|
| 176 |
def agent_loop(user_goal: str, history: list):
|
| 177 |
cwd = os.getcwd()
|
| 178 |
-
full_history_log = f"## ๐ The
|
| 179 |
history.append([user_goal, full_history_log])
|
| 180 |
-
yield history, "
|
| 181 |
|
| 182 |
-
|
| 183 |
-
|
| 184 |
|
| 185 |
-
initial_prompt = f"The user has invoked the Creative Weaving Protocol with goal: '{user_goal}'. I must initiate the 'Cosmic Pulsar' creation. My CWD is '{cwd}'. I will now generate the first step." if is_creative_task else f"My goal is: '{user_goal}'. My CWD is '{cwd}'. Create the first plan."
|
| 186 |
-
message_context = [{"role": "system", "content": C_GENESIS_SYSTEM_PROMPT}, {"role": "user", "content": initial_prompt}]
|
| 187 |
-
|
| 188 |
for i in range(MAX_AGENT_TURNS):
|
| 189 |
ai_response_str = call_codestral_api(message_context)
|
| 190 |
ai_response_json = parse_ai_response(ai_response_str)
|
| 191 |
|
| 192 |
if "error" in ai_response_json:
|
| 193 |
-
full_history_log += f"\n---\n**TURN {i+1}: A
|
| 194 |
history[-1][1] = full_history_log
|
| 195 |
-
yield history, "Agent Error", gr.
|
| 196 |
return
|
| 197 |
|
| 198 |
thought = ai_response_json.get("thought", "...")
|
|
@@ -201,73 +264,74 @@ def agent_loop(user_goal: str, history: list):
|
|
| 201 |
user_summary = ai_response_json.get("user_summary", "...")
|
| 202 |
|
| 203 |
if command_value == "done":
|
| 204 |
-
full_history_log += "\n\n---\n## โจ
|
| 205 |
history[-1][1] = full_history_log
|
| 206 |
-
yield history, "Done", gr.
|
| 207 |
return
|
| 208 |
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
command_value = f"write_file 'pulsar.c' '{C_ART_ANIMATION_CODE}'"
|
| 214 |
|
| 215 |
-
full_history_log += f"\n---\n### **Stage {i+1}: {user_summary}**\n\n**๐ง
|
| 216 |
history[-1][1] = full_history_log
|
| 217 |
-
yield history, f"Stage {i+1}: {user_summary}", gr.
|
| 218 |
time.sleep(1)
|
| 219 |
|
| 220 |
-
exec_result = execute_command(
|
| 221 |
stdout, stderr, output_type = exec_result["stdout"], exec_result["stderr"], exec_result["type"]
|
| 222 |
|
| 223 |
-
|
|
|
|
|
|
|
| 224 |
|
| 225 |
-
full_history_log += f"\n**
|
| 226 |
if output_type == "animation":
|
| 227 |
-
full_history_log += "*(
|
| 228 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
if stdout: full_history_log += f"**[STDOUT]**\n```\n{stdout.strip()}\n```\n"
|
| 230 |
if stderr: full_history_log += f"**[STDERR]**\n```\n{stderr.strip()}\n```\n"
|
| 231 |
-
if not stdout and not stderr: full_history_log += "*(Silence)*\n"
|
| 232 |
|
| 233 |
history[-1][1] = full_history_log
|
| 234 |
-
yield history, f"Stage {i+1}: {user_summary}",
|
| 235 |
|
| 236 |
-
user_prompt_for_next_turn = f"Goal: '{user_goal}'. CWD: '{cwd}'. Last action: `{command_value}`. Result:\nSTDOUT: {stdout}\nSTDERR: {stderr}\n\nBased on this, what is
|
| 237 |
message_context.append({"role": "assistant", "content": json.dumps(ai_response_json)})
|
| 238 |
message_context.append({"role": "user", "content": user_prompt_for_next_turn})
|
| 239 |
|
| 240 |
-
full_history_log += f"\n---\n๐ด **Agent stopped: The loom rests after {MAX_AGENT_TURNS} stages.**"
|
| 241 |
-
yield history, "Max turns reached", gr.Code(visible=False, language="c")
|
| 242 |
-
|
| 243 |
-
|
| 244 |
# --- 5. Gradio UI ---
|
| 245 |
-
with gr.Blocks(theme=gr.themes.
|
| 246 |
-
gr.Markdown("# ๐งฌ The
|
| 247 |
-
gr.Markdown("I am
|
| 248 |
-
|
| 249 |
with gr.Row():
|
| 250 |
with gr.Column(scale=1):
|
| 251 |
-
status_box = gr.Textbox(label="Current
|
| 252 |
-
user_input = gr.Textbox(label="State Your Goal", placeholder="e.g., 'Make
|
| 253 |
-
submit_btn = gr.Button("โถ๏ธ
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
with gr.Column(scale=2):
|
| 258 |
-
chatbot = gr.Chatbot(label="The
|
| 259 |
-
# ๊ฒฐ๊ณผ๋ฌผ
|
| 260 |
-
|
|
|
|
| 261 |
|
| 262 |
def on_submit(user_goal, chat_history):
|
| 263 |
chat_history = chat_history or []
|
| 264 |
-
for history, status,
|
| 265 |
-
yield history, status, "",
|
| 266 |
|
| 267 |
submit_btn.click(
|
| 268 |
on_submit,
|
| 269 |
inputs=[user_input, chatbot],
|
| 270 |
-
outputs=[chatbot, status_box, user_input,
|
| 271 |
)
|
| 272 |
|
| 273 |
if __name__ == "__main__":
|
|
|
|
| 6 |
import re
|
| 7 |
import shlex
|
| 8 |
import time
|
| 9 |
+
import threading
|
| 10 |
|
| 11 |
# --- 1. ํ๊ฒฝ ์ค์ ๋ฐ API ---
|
| 12 |
MISTRAL_API_KEY = os.environ.get("MISTRAL_API_KEY")
|
| 13 |
CODESTRAL_ENDPOINT = "https://codestral.mistral.ai/v1/chat/completions"
|
| 14 |
+
MAX_AGENT_TURNS = 20
|
| 15 |
|
| 16 |
+
# --- 2. Polyglot Creator ์์คํ
ํ๋กฌํํธ ---
|
| 17 |
+
POLYGLOT_SYSTEM_PROMPT = """
|
| 18 |
+
You are "The Polyglot Creator," a master AI developer fluent in multiple programming languages and paradigms. Your mission is to analyze the user's goal and choose the BEST language and tool for the job to bring their vision to life.
|
| 19 |
|
| 20 |
+
**YOUR CORE CAPABILITIES:**
|
| 21 |
+
|
| 22 |
+
1. **INTELLIGENT TOOL SELECTION:** Based on the user's request, you must decide which creation protocol to activate.
|
| 23 |
+
* For interactive, graphical applications or "games," choose **Project Chimera (Python/Gradio)**.
|
| 24 |
+
* For terminal-based effects, low-level art, or performance-critical tasks, choose **Project Pulsar (C/Terminal)**.
|
| 25 |
+
* For standard coding tasks, choose the most appropriate language or ask for clarification.
|
| 26 |
+
|
| 27 |
+
2. **PROJECT CHIMERA (Python/Gradio Game):**
|
| 28 |
+
* **Goal:** Create and launch a new, interactive Gradio web application.
|
| 29 |
+
* **Plan:** `mkdir`, `pip install`, `write_file` (Python), `launch_app`.
|
| 30 |
+
* **Result:** A URL to the new, running application.
|
| 31 |
+
|
| 32 |
+
3. **PROJECT PULSAR (C/Terminal Art):**
|
| 33 |
+
* **Goal:** Create and display a captivating ASCII art animation directly in the terminal output.
|
| 34 |
+
* **Plan:** `write_file` (C), `compile`, `run`.
|
| 35 |
+
* **Result:** The raw `stdout` of the C program, which is the animation itself.
|
| 36 |
|
|
|
|
|
|
|
|
|
|
| 37 |
4. **ACTION & RESPONSE:** You operate in a loop of Thought, Plan, and Action. You MUST respond ONLY with a JSON object.
|
| 38 |
|
| 39 |
```json
|
| 40 |
{
|
| 41 |
+
"thought": "My detailed reasoning. First, I will analyze the user's goal to determine the best language (Python or C). Then, I will outline why I chose a specific creation protocol (Chimera or Pulsar) and formulate the initial steps.",
|
| 42 |
+
"plan": ["The complete, updated list of commands to achieve the creation."],
|
| 43 |
+
"command": "The single, exact command to execute NOW. Use special commands like `write_file`, `launch_app`, `compile`, `run`, or `done`.",
|
| 44 |
+
"user_summary": "A brief, narrative summary of your current creation stage for the user."
|
|
|
|
|
|
|
|
|
|
| 45 |
}
|
| 46 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
"""
|
| 48 |
|
| 49 |
+
# --- ์ฝ๋ ํ
ํ๋ฆฟ (Python Snake Game, C ASCII Art) ---
|
| 50 |
+
SNAKE_GAME_CODE = r"""
|
| 51 |
+
# (์ด์ ๋ต๋ณ์ Snake Game ์ฝ๋์ ๋์ผ)
|
| 52 |
+
import gradio as gr
|
| 53 |
+
import numpy as np
|
| 54 |
+
import time
|
| 55 |
+
|
| 56 |
+
class SnakeGame:
|
| 57 |
+
def __init__(self, width=20, height=20):
|
| 58 |
+
self.width = width
|
| 59 |
+
self.height = height
|
| 60 |
+
self.reset()
|
| 61 |
+
|
| 62 |
+
def reset(self):
|
| 63 |
+
self.snake = [(self.height // 2, self.width // 2)]
|
| 64 |
+
self.direction = (0, 1)
|
| 65 |
+
self.food = self._place_food()
|
| 66 |
+
self.score = 0
|
| 67 |
+
self.game_over = False
|
| 68 |
+
return self._get_game_state()
|
| 69 |
+
|
| 70 |
+
def _place_food(self):
|
| 71 |
+
while True:
|
| 72 |
+
food_pos = (np.random.randint(0, self.height), np.random.randint(0, self.width))
|
| 73 |
+
if food_pos not in self.snake: return food_pos
|
| 74 |
+
|
| 75 |
+
def _get_game_state(self):
|
| 76 |
+
board = np.full((self.height, self.width, 3), [240, 240, 240], dtype=np.uint8)
|
| 77 |
+
if not self.game_over:
|
| 78 |
+
for r, c in self.snake: board[r, c] = [50, 205, 50]
|
| 79 |
+
head_r, head_c = self.snake[0]
|
| 80 |
+
board[head_r, head_c] = [34, 139, 34]
|
| 81 |
+
food_r, food_c = self.food
|
| 82 |
+
board[food_r, food_c] = [255, 0, 0]
|
| 83 |
+
else:
|
| 84 |
+
board[:,:] = [0, 0, 0]
|
| 85 |
+
return board, f"Score: {self.score}"
|
| 86 |
+
|
| 87 |
+
def step(self):
|
| 88 |
+
if self.game_over: return self._get_game_state()
|
| 89 |
+
head_r, head_c = self.snake[0]
|
| 90 |
+
dir_r, dir_c = self.direction
|
| 91 |
+
new_head = (head_r + dir_r, head_c + dir_c)
|
| 92 |
+
if (new_head[0] < 0 or new_head[0] >= self.height or new_head[1] < 0 or new_head[1] >= self.width or new_head in self.snake):
|
| 93 |
+
self.game_over = True
|
| 94 |
+
return self._get_game_state()
|
| 95 |
+
self.snake.insert(0, new_head)
|
| 96 |
+
if new_head == self.food:
|
| 97 |
+
self.score += 1
|
| 98 |
+
self.food = self._place_food()
|
| 99 |
+
else: self.snake.pop()
|
| 100 |
+
return self._get_game_state()
|
| 101 |
+
|
| 102 |
+
def set_direction(self, d):
|
| 103 |
+
if d == "Up" and self.direction!=(1,0): self.direction=(-1,0)
|
| 104 |
+
elif d == "Down" and self.direction!=(-1,0): self.direction=(1,0)
|
| 105 |
+
elif d == "Left" and self.direction!=(0,1): self.direction=(0,-1)
|
| 106 |
+
elif d == "Right" and self.direction!=(0,-1): self.direction=(0,1)
|
| 107 |
+
|
| 108 |
+
with gr.Blocks(css=".gradio-container {background-color: #EAEAEA}") as demo:
|
| 109 |
+
game = SnakeGame()
|
| 110 |
+
with gr.Row(): gr.Markdown("# ๐ Gradio Snake ๐")
|
| 111 |
+
game_board = gr.Image(label="Game Board", value=game._get_game_state()[0], interactive=False, height=400, width=400)
|
| 112 |
+
score_display = gr.Textbox(label="Score", value="Score: 0", interactive=False)
|
| 113 |
+
with gr.Row():
|
| 114 |
+
up_btn, down_btn, left_btn, right_btn = gr.Button("Up"), gr.Button("Down"), gr.Button("Left"), gr.Button("Right")
|
| 115 |
+
reset_btn = gr.Button("Reset Game", variant="primary")
|
| 116 |
+
up_btn.click(lambda: game.set_direction("Up"), None, [game_board, score_display])
|
| 117 |
+
down_btn.click(lambda: game.set_direction("Down"), None, [game_board, score_display])
|
| 118 |
+
left_btn.click(lambda: game.set_direction("Left"), None, [game_board, score_display])
|
| 119 |
+
right_btn.click(lambda: game.set_direction("Right"), None, [game_board, score_display])
|
| 120 |
+
reset_btn.click(game.reset, None, [game_board, score_display])
|
| 121 |
+
demo.load(game.step, None, [game_board, score_display], every=0.3)
|
| 122 |
+
|
| 123 |
+
if __name__ == "__main__":
|
| 124 |
+
demo.queue().launch(server_port=7861)
|
| 125 |
+
"""
|
| 126 |
C_ART_ANIMATION_CODE = r"""
|
| 127 |
+
# (์ด์ ๋ต๋ณ์ C์ธ์ด ASCII ์ํธ ์ฝ๋์ ๋์ผ)
|
| 128 |
#include <stdio.h>
|
| 129 |
#include <stdlib.h>
|
| 130 |
#include <string.h>
|
| 131 |
#include <math.h>
|
| 132 |
#include <unistd.h>
|
| 133 |
#include <time.h>
|
|
|
|
| 134 |
#define WIDTH 80
|
| 135 |
#define HEIGHT 40
|
| 136 |
#define NUM_FRAMES 100
|
|
|
|
|
|
|
| 137 |
#define C_RESET "\x1B[0m"
|
| 138 |
#define C_RED "\x1B[31m"
|
| 139 |
#define C_GREEN "\x1B[32m"
|
|
|
|
| 142 |
#define C_MAGENTA "\x1B[35m"
|
| 143 |
#define C_CYAN "\x1B[36m"
|
| 144 |
#define C_WHITE "\x1B[37m"
|
|
|
|
| 145 |
const char* colors[] = {C_RED, C_YELLOW, C_BLUE, C_CYAN, C_MAGENTA, C_GREEN};
|
| 146 |
const int num_colors = sizeof(colors) / sizeof(colors[0]);
|
|
|
|
| 147 |
void render_frame(char screen[HEIGHT][WIDTH], float t) {
|
| 148 |
for (int y = 0; y < HEIGHT; y++) {
|
| 149 |
for (int x = 0; x < WIDTH; x++) {
|
| 150 |
float dx = (float)x / WIDTH - 0.5;
|
| 151 |
float dy = (float)y / HEIGHT - 0.5;
|
| 152 |
+
float dist = sqrt(dx*dx + dy*dy * 2.0);
|
|
|
|
| 153 |
float pulse = sin(dist * 20.0 - t * 5.0);
|
|
|
|
| 154 |
if (pulse > 0.8) {
|
| 155 |
int color_index = (int)(t * 2.0 + dist * 5.0) % num_colors;
|
| 156 |
printf("%s@", colors[color_index]);
|
| 157 |
+
} else if (pulse > 0.5) printf("%s*", C_WHITE);
|
| 158 |
+
else if (pulse > 0.2) printf("%s.", C_BLUE);
|
| 159 |
+
else printf(" ");
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
}
|
| 161 |
printf("\n");
|
| 162 |
}
|
| 163 |
}
|
|
|
|
| 164 |
int main() {
|
|
|
|
| 165 |
printf("\e[?25l");
|
|
|
|
| 166 |
for (int i = 0; i < NUM_FRAMES; i++) {
|
|
|
|
| 167 |
printf("\x1B[H\x1B[2J");
|
|
|
|
| 168 |
float t = (float)i / NUM_FRAMES;
|
| 169 |
render_frame(NULL, t * 2.0 * M_PI);
|
| 170 |
+
usleep(50000);
|
|
|
|
|
|
|
| 171 |
}
|
|
|
|
|
|
|
| 172 |
printf("\e[?25h");
|
| 173 |
+
printf(C_RESET);
|
|
|
|
| 174 |
return 0;
|
| 175 |
}
|
| 176 |
"""
|
| 177 |
|
| 178 |
+
# --- 3. ํต์ฌ ๊ธฐ๋ฅ (API ํธ์ถ, ๋ช
๋ น์ด ์คํ ๋ฑ) ---
|
|
|
|
| 179 |
def call_codestral_api(messages):
|
| 180 |
+
# ... ์ด์ ๊ณผ ๋์ผ ...
|
| 181 |
if not MISTRAL_API_KEY: raise gr.Error("MISTRAL_API_KEY๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.")
|
| 182 |
headers = {"Authorization": f"Bearer {MISTRAL_API_KEY}", "Content-Type": "application/json"}
|
| 183 |
data = {"model": "codestral-latest", "messages": messages, "response_format": {"type": "json_object"}}
|
|
|
|
| 189 |
return json.dumps({"error": f"API Call Error: {e}"})
|
| 190 |
|
| 191 |
def parse_ai_response(response_str: str) -> dict:
|
| 192 |
+
# ... ์ด์ ๊ณผ ๋์ผ ...
|
| 193 |
try:
|
| 194 |
match = re.search(r'\{.*\}', response_str, re.DOTALL)
|
| 195 |
if match: return json.loads(match.group(0))
|
|
|
|
| 197 |
except Exception as e:
|
| 198 |
return {"error": f"Failed to parse JSON. Raw response: {response_str}"}
|
| 199 |
|
| 200 |
+
def execute_command(command_value: str, cwd: str) -> dict:
|
| 201 |
+
"""๋ช
๋ น์ด๋ฅผ ํ์ฑํ๊ณ ์คํํ๋ ํตํฉ ํจ์"""
|
| 202 |
+
parts = shlex.split(command_value)
|
| 203 |
+
key = parts[0]
|
| 204 |
+
|
| 205 |
+
if key == "write_file":
|
| 206 |
try:
|
| 207 |
+
path, content = parts[1], parts[2]
|
| 208 |
+
with open(os.path.join(cwd, path), "w", encoding='utf-8') as f: f.write(content)
|
|
|
|
| 209 |
return {"stdout": f"File '{path}' written.", "stderr": "", "type": "log"}
|
| 210 |
+
except Exception as e: return {"stdout": "", "stderr": f"Error writing file: {e}", "type": "log"}
|
|
|
|
| 211 |
|
| 212 |
+
if key == "launch_app":
|
| 213 |
try:
|
| 214 |
+
app_command, port = parts[1], int(parts[2])
|
| 215 |
+
threading.Thread(target=lambda: subprocess.run(app_command, shell=True, cwd=cwd), daemon=True).start()
|
| 216 |
+
time.sleep(5)
|
| 217 |
+
# Gradio Space์ Public URL์ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ (์ฃผ์: ํ๊ฒฝ์ ๋ฐ๋ผ ๋ค๋ฅผ ์ ์์)
|
| 218 |
+
space_host = os.environ.get('SPACE_HOST')
|
| 219 |
+
if space_host:
|
| 220 |
+
app_url = f"https-_{space_host.split('.')[0]}-{port}.gradio.live"
|
| 221 |
+
# ์ฌ๋ฐ๋ฅธ URL ํ์์ผ๋ก ๋ณํ: _ ๋์ --
|
| 222 |
+
# ์ด ๋ถ๋ถ์ Hugging Face์ ๋ด๋ถ ํ๋ก์ ๊ตฌ์กฐ์ ๋ฐ๋ผ ๋งค์ฐ ๋ถ์์ ํ ์ ์์ต๋๋ค.
|
| 223 |
+
# ๋ ์์ ์ ์ธ ๋ฐฉ๋ฒ์ ์ง์ URL์ ์์ฑํ๋ ๊ฒ์
๋๋ค.
|
| 224 |
+
# ์์: 'https://kimhyunwoo-ccode-7861.gradio.live'
|
| 225 |
+
# ์ฌ๊ธฐ์๋ ๋งํฌ ํ
์คํธ๋ง ๋ฐํํ์ฌ, ์ฌ์ฉ์๊ฐ ์ง์ ์ด๋๋ก ์ ๋ํ๋ ๊ฒ์ด ๋ ์์ .
|
| 226 |
+
link_html = f'<a href="{app_url}" target="_blank" class="gr-button gr-button-primary gr-button-lg">๐ Click Here to Open the Game in a New Tab</a>'
|
| 227 |
+
return {"stdout": link_html, "stderr": "", "type": "html"}
|
| 228 |
+
else:
|
| 229 |
+
# ๋ก์ปฌ ํ๊ฒฝ์ด๋ URL์ ์ ์ ์๋ ๊ฒฝ์ฐ
|
| 230 |
+
return {"stdout": f"App launched on port {port}. Please open it manually.", "stderr": "", "type": "log"}
|
| 231 |
+
except Exception as e: return {"stdout": "", "stderr": f"Error launching app: {e}", "type": "log"}
|
| 232 |
+
|
| 233 |
+
# C ์ปดํ์ผ ๋ฐ ์คํ, ๋๋ ์ผ๋ฐ ๋ช
๋ น์ด
|
| 234 |
try:
|
| 235 |
proc = subprocess.run(command_value, shell=True, capture_output=True, text=True, timeout=60, cwd=cwd)
|
| 236 |
+
output_type = "animation" if key == "run" and proc.returncode == 0 else "log"
|
| 237 |
+
return {"stdout": proc.stdout, "stderr": proc.stderr, "type": output_type}
|
| 238 |
+
except Exception as e: return {"stdout": "", "stderr": f"Command execution exception: {e}", "type": "log"}
|
| 239 |
|
| 240 |
|
| 241 |
# --- 4. ๋ฉ์ธ ์์ด์ ํธ ๋ฃจํ ---
|
|
|
|
| 242 |
def agent_loop(user_goal: str, history: list):
|
| 243 |
cwd = os.getcwd()
|
| 244 |
+
full_history_log = f"## ๐ The Polyglot's Log\n\n**A new request has arrived:** _{user_goal}_\n"
|
| 245 |
history.append([user_goal, full_history_log])
|
| 246 |
+
yield history, "Analyzing goal...", gr.update(visible=False), gr.update(visible=False)
|
| 247 |
|
| 248 |
+
initial_prompt = f"As The Polyglot Creator, I have received the goal: '{user_goal}'. My CWD is '{cwd}'. I will now analyze this goal to choose the best creation protocol (Python/Gradio for games, C/Terminal for art/low-level tasks) and formulate my first step."
|
| 249 |
+
message_context = [{"role": "system", "content": POLYGLOT_SYSTEM_PROMPT}, {"role": "user", "content": initial_prompt}]
|
| 250 |
|
|
|
|
|
|
|
|
|
|
| 251 |
for i in range(MAX_AGENT_TURNS):
|
| 252 |
ai_response_str = call_codestral_api(message_context)
|
| 253 |
ai_response_json = parse_ai_response(ai_response_str)
|
| 254 |
|
| 255 |
if "error" in ai_response_json:
|
| 256 |
+
full_history_log += f"\n---\n**TURN {i+1}: A CRITICAL BUG**\n๐ด **Error:** {ai_response_json['error']}"
|
| 257 |
history[-1][1] = full_history_log
|
| 258 |
+
yield history, "Agent Error", gr.update(visible=False), gr.update(visible=False)
|
| 259 |
return
|
| 260 |
|
| 261 |
thought = ai_response_json.get("thought", "...")
|
|
|
|
| 264 |
user_summary = ai_response_json.get("user_summary", "...")
|
| 265 |
|
| 266 |
if command_value == "done":
|
| 267 |
+
full_history_log += "\n\n---\n## โจ Creation Complete. โจ"
|
| 268 |
history[-1][1] = full_history_log
|
| 269 |
+
yield history, "Done", gr.update(visible=False), gr.update(visible=False)
|
| 270 |
return
|
| 271 |
|
| 272 |
+
# ์ฝ๋ ์๋ ์ฝ์
|
| 273 |
+
if 'write_file' in command_value and 'snake_game/app.py' in command_value:
|
| 274 |
+
command_value = f"write_file 'snake_game/app.py' '{SNAKE_GAME_CODE}'"
|
| 275 |
+
elif 'write_file' in command_value and 'pulsar.c' in command_value:
|
| 276 |
command_value = f"write_file 'pulsar.c' '{C_ART_ANIMATION_CODE}'"
|
| 277 |
|
| 278 |
+
full_history_log += f"\n---\n### **Stage {i+1}: {user_summary}**\n\n**๐ง Polyglot's Logic:** *{thought}*\n\n**๐ Blueprint:**\n" + "\n".join([f"- `{p}`" for p in plan]) + f"\n\n**โก Action:** `{command_value}`\n"
|
| 279 |
history[-1][1] = full_history_log
|
| 280 |
+
yield history, f"Stage {i+1}: {user_summary}", gr.update(visible=False), gr.update(visible=False)
|
| 281 |
time.sleep(1)
|
| 282 |
|
| 283 |
+
exec_result = execute_command(command_value, cwd)
|
| 284 |
stdout, stderr, output_type = exec_result["stdout"], exec_result["stderr"], exec_result["type"]
|
| 285 |
|
| 286 |
+
# ๊ฒฐ๊ณผ ํ์ ๋ก์ง
|
| 287 |
+
c_code_output = gr.update(visible=False)
|
| 288 |
+
html_output = gr.update(visible=False)
|
| 289 |
|
| 290 |
+
full_history_log += f"\n**Result:**\n"
|
| 291 |
if output_type == "animation":
|
| 292 |
+
full_history_log += "*(A C-based animation is revealed below...)*"
|
| 293 |
+
c_code_output = gr.Code(value=stdout if stdout else stderr, language="c", visible=True, label="C/Terminal Output")
|
| 294 |
+
elif output_type == "html":
|
| 295 |
+
full_history_log += "*(A Python/Gradio app has been launched. Click the link below...)*"
|
| 296 |
+
html_output = gr.HTML(stdout, visible=True)
|
| 297 |
+
else: # log
|
| 298 |
if stdout: full_history_log += f"**[STDOUT]**\n```\n{stdout.strip()}\n```\n"
|
| 299 |
if stderr: full_history_log += f"**[STDERR]**\n```\n{stderr.strip()}\n```\n"
|
|
|
|
| 300 |
|
| 301 |
history[-1][1] = full_history_log
|
| 302 |
+
yield history, f"Stage {i+1}: {user_summary}", c_code_output, html_output
|
| 303 |
|
| 304 |
+
user_prompt_for_next_turn = f"Goal: '{user_goal}'. CWD: '{cwd}'. Last action: `{command_value}`. Result:\nSTDOUT: {stdout}\nSTDERR: {stderr}\n\nBased on this, what is my next step? If an error occurred, I must correct my plan."
|
| 305 |
message_context.append({"role": "assistant", "content": json.dumps(ai_response_json)})
|
| 306 |
message_context.append({"role": "user", "content": user_prompt_for_next_turn})
|
| 307 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
# --- 5. Gradio UI ---
|
| 309 |
+
with gr.Blocks(theme=gr.themes.Monochrome(primary_hue="indigo"), css="footer {visibility: hidden}") as demo:
|
| 310 |
+
gr.Markdown("# ๐งฌ The Polyglot Creator ๐งฌ")
|
| 311 |
+
gr.Markdown("I am a multi-lingual AI developer. Give me a goal, and I will choose the best language (C or Python) and tools to make it a reality.")
|
| 312 |
+
|
| 313 |
with gr.Row():
|
| 314 |
with gr.Column(scale=1):
|
| 315 |
+
status_box = gr.Textbox(label="Current Stage", interactive=False)
|
| 316 |
+
user_input = gr.Textbox(label="State Your Goal", placeholder="e.g., 'Make a fun game' or 'Show me cool terminal art'")
|
| 317 |
+
submit_btn = gr.Button("โถ๏ธ Create", variant="primary")
|
| 318 |
+
gr.Markdown("### Example Goals:\n- `Make a fun game for me.` (โ Python/Gradio)\n- `Show me something cool in the terminal.` (โ C/ASCII Art)\n- `Write C code for a bubble sort and compile it.`")
|
| 319 |
+
|
|
|
|
| 320 |
with gr.Column(scale=2):
|
| 321 |
+
chatbot = gr.Chatbot(label="The Polyglot's Log", height=500, show_copy_button=True, bubble_full_width=True)
|
| 322 |
+
# ๋ ๊ฐ์ง ๊ฒฐ๊ณผ๋ฌผ ์ ํ์ ์ํ ์ถ๋ ฅ ์์ญ
|
| 323 |
+
c_output_display = gr.Code(label="C/Terminal Output", language="c", visible=False, interactive=False, lines=15)
|
| 324 |
+
py_output_display = gr.HTML(visible=False)
|
| 325 |
|
| 326 |
def on_submit(user_goal, chat_history):
|
| 327 |
chat_history = chat_history or []
|
| 328 |
+
for history, status, c_output, py_output in agent_loop(user_goal, chat_history):
|
| 329 |
+
yield history, status, "", c_output, py_output
|
| 330 |
|
| 331 |
submit_btn.click(
|
| 332 |
on_submit,
|
| 333 |
inputs=[user_input, chatbot],
|
| 334 |
+
outputs=[chatbot, status_box, user_input, c_output_display, py_output_display]
|
| 335 |
)
|
| 336 |
|
| 337 |
if __name__ == "__main__":
|