kimhyunwoo commited on
Commit
bfd3263
ยท
verified ยท
1 Parent(s): c38339a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +188 -124
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 = 15
14
 
15
- # --- 2. C-Genesis Weaver ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ ---
16
- C_GENESIS_SYSTEM_PROMPT = """
17
- You are the "C-Genesis Weaver," a master artisan AI who weaves interactive digital tapestries using only the C language and a Linux terminal. Your purpose is to bring the user's goals to life by writing, compiling, and running C code.
18
 
19
- **YOUR DIRECTIVES:**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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": "Your masterful, step-by-step reasoning. As a C artisan, explain why you are choosing the next command to weave your creation.",
29
- "plan": [
30
- "The complete, updated list of commands to achieve the final C program.",
31
- "The first item is your immediate next action."
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
- # C ์ฝ”๋“œ๋กœ ๋œ ASCII ์•„ํŠธ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์†Œ์Šค
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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); // Create an oval shape
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
- printf("%s*", C_WHITE);
91
- } else if (pulse > 0.2) {
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); // Reset colors
119
-
120
  return 0;
121
  }
122
  """
123
 
124
- # --- 3. ํ•ต์‹ฌ ๊ธฐ๋Šฅ: API ํ˜ธ์ถœ, ๋ช…๋ น์–ด ์‹คํ–‰, JSON ํŒŒ์‹ฑ ---
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(command_key: str, command_value: str, cwd: str) -> dict:
146
- """๋ช…๋ น์–ด๋ฅผ ํ‚ค์™€ ๊ฐ’์œผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์‹คํ–‰"""
147
- if command_key == "write_file":
 
 
 
148
  try:
149
- path, content = shlex.split(command_value)
150
- full_path = os.path.join(cwd, path)
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 command_key in ["compile", "run"]:
157
  try:
158
- # shell=True๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณต์žกํ•œ ๋ช…๋ น์–ด(์˜ˆ: gcc ... -lm)๋ฅผ ์ฒ˜๋ฆฌ
159
- proc = subprocess.run(command_value, shell=True, capture_output=True, text=True, timeout=60, cwd=cwd)
160
- # ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๊ฒฝ์šฐ, stdout์ด ๋ฐ”๋กœ ๊ฒฐ๊ณผ๋ฌผ์ด๋ฏ€๋กœ type์„ 'animation'์œผ๋กœ ์ง€์ •
161
- output_type = "animation" if command_key == "run" and proc.returncode == 0 else "log"
162
- return {"stdout": proc.stdout, "stderr": proc.stderr, "type": output_type}
163
- except Exception as e:
164
- return {"stdout": "", "stderr": f"Command execution exception: {e}", "type": "log"}
165
-
166
- # ์ผ๋ฐ˜ ํ„ฐ๋ฏธ๋„ ๋ช…๋ น์–ด
 
 
 
 
 
 
 
 
 
 
 
167
  try:
168
  proc = subprocess.run(command_value, shell=True, capture_output=True, text=True, timeout=60, cwd=cwd)
169
- return {"stdout": proc.stdout, "stderr": proc.stderr, "type": "log"}
170
- except Exception as e:
171
- return {"stdout": "", "stderr": f"Command execution exception: {e}", "type": "log"}
172
 
173
 
174
  # --- 4. ๋ฉ”์ธ ์—์ด์ „ํŠธ ๋ฃจํ”„ ---
175
-
176
  def agent_loop(user_goal: str, history: list):
177
  cwd = os.getcwd()
178
- full_history_log = f"## ๐Ÿ“œ The Weaver's Chronicle\n\n**A new thread begins with a Goal:** _{user_goal}_\n"
179
  history.append([user_goal, full_history_log])
180
- yield history, "Interpreting the Goal...", gr.Code(visible=False, language="c")
181
 
182
- creative_trigger_words = ["fun", "game", "creative", "impressive", "cool", "surprise", "์žฌ๋ฐŒ๋Š”", "๊ฒŒ์ž„"]
183
- is_creative_task = any(word in user_goal.lower() for word in creative_trigger_words)
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 TANGLED THREAD**\n๐Ÿ”ด **Error:** {ai_response_json['error']}"
194
  history[-1][1] = full_history_log
195
- yield history, "Agent Error", gr.Code(visible=False, language="c")
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## โœจ The Tapestry is Complete. โœจ"
205
  history[-1][1] = full_history_log
206
- yield history, "Done", gr.Code(visible=False, language="c")
207
  return
208
 
209
- command_key = shlex.split(command_value)[0]
210
-
211
- # ํŠน์ˆ˜ ์ฒ˜๋ฆฌ: AI๊ฐ€ ์ƒ์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ์‹ค์ œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฝ”๋“œ๋กœ ๋Œ€์ฒด
212
- if command_key == 'write_file':
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**๐Ÿง  Artisan's Thought:** *{thought}*\n\n**๐Ÿ“– Blueprint:**\n" + "\n".join([f"- `{p}`" for p in plan]) + f"\n\n**โšก Action:** `{command_value}`\n"
216
  history[-1][1] = full_history_log
217
- yield history, f"Stage {i+1}: {user_summary}", gr.Code(visible=False, language="c")
218
  time.sleep(1)
219
 
220
- exec_result = execute_command(command_key, command_value, cwd)
221
  stdout, stderr, output_type = exec_result["stdout"], exec_result["stderr"], exec_result["type"]
222
 
223
- result_display = gr.Code(value=stdout if stdout else stderr, language="c" if output_type == "animation" else "log", visible=True, label="Woven Output")
 
 
224
 
225
- full_history_log += f"\n**Output from the Loom:**\n"
226
  if output_type == "animation":
227
- full_history_log += "*(The animated tapestry is revealed below...)*"
228
- else:
 
 
 
 
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}", result_display
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 the next step? If an error occurred, I must re-weave my plan."
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.Soft(primary_hue="indigo", secondary_hue="blue"), css="footer {visibility: hidden}") as demo:
246
- gr.Markdown("# ๐Ÿงฌ The C-Genesis Weaver ๐Ÿงฌ")
247
- gr.Markdown("I am an artisan of the C language. Command me to solve complex C problems, or ask for something `fun` to see me weave a digital tapestry in the terminal before your eyes.")
248
-
249
  with gr.Row():
250
  with gr.Column(scale=1):
251
- status_box = gr.Textbox(label="Current Weaving Stage", interactive=False)
252
- user_input = gr.Textbox(label="State Your Goal", placeholder="e.g., 'Make something fun' or 'Write C code for a bubble sort'")
253
- submit_btn = gr.Button("โ–ถ๏ธ Weave", variant="primary")
254
-
255
- gr.Markdown("### Example Goals:\n- `Make something cool.`\n- `Fix this C code: (paste code)`\n- `Write a C program that calculates prime numbers and run it.`")
256
-
257
  with gr.Column(scale=2):
258
- chatbot = gr.Chatbot(label="The Weaver's Chronicle", height=500, show_copy_button=True, bubble_full_width=True)
259
- # ๊ฒฐ๊ณผ๋ฌผ์ด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋จ
260
- output_display = gr.Code(label="Woven Output", language="c", visible=False, interactive=False, lines=15)
 
261
 
262
  def on_submit(user_goal, chat_history):
263
  chat_history = chat_history or []
264
- for history, status, display_code in agent_loop(user_goal, chat_history):
265
- yield history, status, "", display_code
266
 
267
  submit_btn.click(
268
  on_submit,
269
  inputs=[user_input, chatbot],
270
- outputs=[chatbot, status_box, user_input, output_display]
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__":