GitHub Action commited on
Commit
b453cca
·
1 Parent(s): 3f80c6a

Sync ling-space changes from GitHub commit 225a47b

Browse files
code_kit/agent_code_generator.py CHANGED
@@ -2,14 +2,16 @@ import gradio as gr
2
  import time
3
  import logging
4
  import os
 
5
  from model_handler import ModelHandler
6
- from tab_code_prompts.html_system_prompt import get_html_system_prompt
 
 
7
 
8
  # Configure logging
9
  logger = logging.getLogger(__name__)
10
 
11
  # Read the content of the JavaScript file for error catching
12
- # Assuming the script is run from the project root or ling-space root.
13
  try:
14
  with open("static/catch-error.js", "r", encoding="utf-8") as f:
15
  CATCH_ERROR_JS_SCRIPT = f.read()
@@ -39,10 +41,42 @@ def get_spinner_html():
39
  </style>
40
  """
41
 
42
- def code_generation_agent(code_type, model_choice, user_prompt, color_palette, decoration_style, overall_style, chatbot_history):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  """Generate code and provide a preview, updating a log stream chatbot."""
44
  logger.info(f"--- [Code Generation] Start ---")
45
- logger.info(f"Code Type: {code_type}, Model: {model_choice}, Prompt: '{user_prompt}'")
 
 
 
 
46
 
47
  if not user_prompt:
48
  chatbot_history.append({"role": "assistant", "content": "🚨 **错误**: 请输入提示词。"})
@@ -54,7 +88,7 @@ def code_generation_agent(code_type, model_choice, user_prompt, color_palette, d
54
 
55
  if user_prompt == "create an error" or user_prompt == "创建一个报错示例":
56
  error_code = f"""<h1>This will create an error</h1><script>{CATCH_ERROR_JS_SCRIPT}</script><script>nonExistentFunction();</script>"""
57
- escaped_code = error_code.replace("'", "&apos;").replace('"', '&quot;')
58
  final_preview_html = f"""
59
  <div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
60
  <iframe srcdoc='{escaped_code}'
@@ -84,63 +118,73 @@ def code_generation_agent(code_type, model_choice, user_prompt, color_palette, d
84
  start_time = time.time()
85
  model_handler = ModelHandler()
86
 
87
- if code_type == "静态页面":
88
- system_prompt = get_html_system_prompt()
89
- full_code_with_think = ""
90
- full_code_for_preview = ""
91
- buffer = ""
92
- is_thinking = False
 
 
93
 
94
- for code_chunk in model_handler.generate_code(system_prompt, full_user_prompt, model_choice):
95
- full_code_with_think += code_chunk
96
- buffer += code_chunk
97
-
98
- while True:
99
- if is_thinking:
100
- end_index = buffer.find("</think>")
101
- if end_index != -1:
102
- is_thinking = False
103
- buffer = buffer[end_index + len("</think>"):]
104
- else:
105
- break
106
  else:
107
- start_index = buffer.find("<think>")
108
- if start_index != -1:
109
- part_to_add = buffer[:start_index]
110
- full_code_for_preview += part_to_add
111
- is_thinking = True
112
- buffer = buffer[start_index:]
113
- else:
114
- full_code_for_preview += buffer
115
- buffer = ""
116
- break
117
-
118
- elapsed_time = time.time() - start_time
119
- generated_length = len(full_code_with_think)
120
- speed = generated_length / elapsed_time if elapsed_time > 0 else 0
121
-
122
- log_message = f"""
123
- **⏳ 正在生成中...**
124
- - **时间:** {elapsed_time:.2f}s
125
- - **长度:** {generated_length} chars
126
- - **速度:** {speed:.2f} char/s
127
- """
128
-
129
- if len(chatbot_history) > 0 and "正在生成中" in chatbot_history[-1]["content"]:
130
- chatbot_history[-1] = {"role": "assistant", "content": log_message}
131
  else:
132
- chatbot_history.append({"role": "assistant", "content": log_message})
133
-
134
- yield full_code_with_think, gr.update(), chatbot_history, gr.update()
 
 
 
 
 
 
 
135
 
136
- escaped_code = full_code_for_preview.replace("'", "&apos;").replace('"', '&quot;')
137
- final_preview_html = f"""
138
- <div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
139
- <iframe srcdoc='{escaped_code}'
140
- style="position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; border: none;">
141
- </iframe>
142
- </div>
 
 
143
  """
144
- chatbot_history.append({"role": "assistant", "content": "✅ **成功**: 代码生成完成!"})
145
- yield full_code_with_think, gr.HTML(final_preview_html), chatbot_history, gr.Tabs(selected=0)
146
- logger.info("Static page streaming finished.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import time
3
  import logging
4
  import os
5
+ import re
6
  from model_handler import ModelHandler
7
+ from config import CODE_FRAMEWORK_SPECS, STATIC_PAGE
8
+ from tab_code_prompts.framework_system_prompts import get_framework_system_prompt
9
+ from code_kit.code_trimmer import trim_html_markdown_blocks # Import the trimmer
10
 
11
  # Configure logging
12
  logger = logging.getLogger(__name__)
13
 
14
  # Read the content of the JavaScript file for error catching
 
15
  try:
16
  with open("static/catch-error.js", "r", encoding="utf-8") as f:
17
  CATCH_ERROR_JS_SCRIPT = f.read()
 
41
  </style>
42
  """
43
 
44
+ def inject_error_catcher(html_code):
45
+ """
46
+ Injects the error catching script into the HTML code.
47
+ It tries to insert it after the <head> tag.
48
+ If <head> is not found, it prepends it to the code (fallback).
49
+ """
50
+ if not CATCH_ERROR_JS_SCRIPT:
51
+ return html_code
52
+
53
+ script_tag = f"<script>{CATCH_ERROR_JS_SCRIPT}</script>"
54
+
55
+ # Try to find <head> (case insensitive)
56
+ head_match = re.search(r"<head>", html_code, re.IGNORECASE)
57
+ if head_match:
58
+ # Insert after <head>
59
+ insert_pos = head_match.end()
60
+ return html_code[:insert_pos] + script_tag + html_code[insert_pos:]
61
+
62
+ # Try to find <body> (case insensitive)
63
+ body_match = re.search(r"<body>", html_code, re.IGNORECASE)
64
+ if body_match:
65
+ # Insert before <body>
66
+ insert_pos = body_match.start()
67
+ return html_code[:insert_pos] + script_tag + html_code[insert_pos:]
68
+
69
+ # Fallback: Just prepend if it looks somewhat like HTML or empty
70
+ return script_tag + html_code
71
+
72
+ def code_generation_agent(code_type_display_name, model_choice, user_prompt, color_palette, decoration_style, overall_style, chatbot_history):
73
  """Generate code and provide a preview, updating a log stream chatbot."""
74
  logger.info(f"--- [Code Generation] Start ---")
75
+ logger.info(f"Code Type (Display Name): {code_type_display_name}, Model: {model_choice}, Prompt: '{user_prompt}'")
76
+
77
+ # Map display name back to constant key
78
+ code_framework_key = next((k for k, v in CODE_FRAMEWORK_SPECS.items() if v["display_name"] == code_type_display_name), STATIC_PAGE)
79
+ logger.info(f"Mapped Code Framework Key: {code_framework_key}")
80
 
81
  if not user_prompt:
82
  chatbot_history.append({"role": "assistant", "content": "🚨 **错误**: 请输入提示词。"})
 
88
 
89
  if user_prompt == "create an error" or user_prompt == "创建一个报错示例":
90
  error_code = f"""<h1>This will create an error</h1><script>{CATCH_ERROR_JS_SCRIPT}</script><script>nonExistentFunction();</script>"""
91
+ escaped_code = error_code.replace("'", "&apos;").replace('"', "&quot;")
92
  final_preview_html = f"""
93
  <div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
94
  <iframe srcdoc='{escaped_code}'
 
118
  start_time = time.time()
119
  model_handler = ModelHandler()
120
 
121
+ # Get the system prompt based on the selected framework AND specific color palette
122
+ # Passing color_palette allows it to be baked into the system prompt instructions
123
+ system_prompt = get_framework_system_prompt(code_framework_key, color_palette)
124
+
125
+ full_code_with_think = ""
126
+ full_code_for_preview = ""
127
+ buffer = ""
128
+ is_thinking = False
129
 
130
+ for code_chunk in model_handler.generate_code(system_prompt, full_user_prompt, model_choice):
131
+ full_code_with_think += code_chunk
132
+ buffer += code_chunk
133
+
134
+ while True:
135
+ if is_thinking:
136
+ end_index = buffer.find("</think>")
137
+ if end_index != -1:
138
+ is_thinking = False
139
+ buffer = buffer[end_index + len("</think>"):]
 
 
140
  else:
141
+ break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  else:
143
+ start_index = buffer.find("<think>")
144
+ if start_index != -1:
145
+ part_to_add = buffer[:start_index]
146
+ full_code_for_preview += part_to_add
147
+ is_thinking = True
148
+ buffer = buffer[start_index:]
149
+ else:
150
+ full_code_for_preview += buffer
151
+ buffer = ""
152
+ break
153
 
154
+ elapsed_time = time.time() - start_time
155
+ generated_length = len(full_code_with_think)
156
+ speed = generated_length / elapsed_time if elapsed_time > 0 else 0
157
+
158
+ log_message = f"""
159
+ **⏳ 正在生成中...**
160
+ - **时间:** {elapsed_time:.2f}s
161
+ - **长度:** {generated_length} chars
162
+ - **速度:** {speed:.2f} char/s
163
  """
164
+
165
+ if len(chatbot_history) > 0 and "正在生成中" in chatbot_history[-1]["content"]:
166
+ chatbot_history[-1] = {"role": "assistant", "content": log_message}
167
+ else:
168
+ chatbot_history.append({"role": "assistant", "content": log_message})
169
+
170
+ yield full_code_with_think, gr.update(), chatbot_history, gr.update()
171
+
172
+ # Apply trimming to the final generated code
173
+ trimmed_full_code_with_think = trim_html_markdown_blocks(full_code_with_think)
174
+ trimmed_full_code_for_preview = trim_html_markdown_blocks(full_code_for_preview)
175
+
176
+ # Inject error catching script before final render
177
+ final_code_with_error_catcher = inject_error_catcher(trimmed_full_code_for_preview)
178
+
179
+ escaped_code = final_code_with_error_catcher.replace("'", "&apos;").replace('"', "&quot;")
180
+ final_preview_html = f"""
181
+ <div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
182
+ <iframe srcdoc='{escaped_code}'
183
+ style="position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; border: none;">
184
+ </iframe>
185
+ </div>
186
+ """
187
+ chatbot_history.append({"role": "assistant", "content": "✅ **成功**: 代码生成完成!"})
188
+ # Yield the trimmed code for display in the "Generated Source Code" tab
189
+ yield trimmed_full_code_with_think, gr.HTML(final_preview_html), chatbot_history, gr.Tabs(selected=0)
190
+ logger.info("Code generation streaming finished.")
code_kit/code_examples.py CHANGED
@@ -34,5 +34,10 @@ CODE_EXAMPLES = [
34
  "task": "报错测试",
35
  "model": get_model_display_name(LING_FLASH_2_0),
36
  "user_prompt": "创建一个报错示例"
 
 
 
 
 
37
  }
38
- ]
 
34
  "task": "报错测试",
35
  "model": get_model_display_name(LING_FLASH_2_0),
36
  "user_prompt": "创建一个报错示例"
37
+ },
38
+ {
39
+ "task": "生成错误-React",
40
+ "model": get_model_display_name(LING_FLASH_2_0),
41
+ "user_prompt": "Write a React component that deliberately throws an error during rendering to test the error boundary mechanism."
42
  }
43
+ ]
code_kit/code_trimmer.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+
3
+ def trim_html_markdown_blocks(code_string: str) -> str:
4
+ """
5
+ Trims Markdown HTML code block delimiters (```html and ```) from the start and end of a string.
6
+ Also removes any leading/trailing whitespace/newlines.
7
+ """
8
+ if not code_string:
9
+ return ""
10
+
11
+ # Pattern to match ```html or ``` followed by optional whitespace/newlines
12
+ # and capture the actual code content.
13
+ # It attempts to match the opening ```html block
14
+ # and the closing ``` block at the very beginning and end of the string.
15
+
16
+ # Trim leading ```html or ```
17
+ trimmed_code = re.sub(r"^\s*```(html)?\s*\n", "", code_string, flags=re.IGNORECASE)
18
+ # Trim trailing ```
19
+ trimmed_code = re.sub(r"\n\s*```\s*$", "", trimmed_code)
20
+
21
+ return trimmed_code.strip()
22
+
23
+
config.py CHANGED
@@ -86,12 +86,31 @@ CHAT_MODEL_SPECS = {
86
 
87
  # Constants for easy referencing of code frameworks
88
  STATIC_PAGE = "static_page"
89
- GRADIO_APP = "gradio_app"
 
 
 
90
 
91
  CODE_FRAMEWORK_SPECS = {
92
  STATIC_PAGE: {
93
  "display_name": "静态页面",
94
  "description": "生成一个独立的、响应式的 HTML 文件,包含所有必要的 CSS 和 JavaScript。适合快速原型和简单的网页展示。"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  }
96
  }
97
 
@@ -121,5 +140,4 @@ def get_model_display_name(model_constant: str) -> str:
121
  Retrieves the display name for a given model constant.
122
  This is what's shown in the UI.
123
  """
124
- return CHAT_MODEL_SPECS.get(model_constant, {}).get("display_name", model_constant)
125
-
 
86
 
87
  # Constants for easy referencing of code frameworks
88
  STATIC_PAGE = "static_page"
89
+ REACT_TAILWIND = "react_tailwind"
90
+ REACT_TAILWIND_CHARTJS = "react_tailwind_chartjs" # Added new constant
91
+ REACT_THREE_FIBER = "react_three_fiber"
92
+ OLD_SCHOOL_HTML = "old_school_html"
93
 
94
  CODE_FRAMEWORK_SPECS = {
95
  STATIC_PAGE: {
96
  "display_name": "静态页面",
97
  "description": "生成一个独立的、响应式的 HTML 文件,包含所有必要的 CSS 和 JavaScript。适合快速原型和简单的网页展示。"
98
+ },
99
+ REACT_TAILWIND: {
100
+ "display_name": "React + Tailwind",
101
+ "description": "使用 React 和 Tailwind CSS 构建的现代单页应用。生成内容将是一个单 HTML 文件(使用 CDN)。"
102
+ },
103
+ REACT_TAILWIND_CHARTJS: { # Added new framework spec
104
+ "display_name": "React + Tailwind + Chart.js",
105
+ "description": "使用 React, Tailwind CSS 和 Chart.js 构建数据可视化单页应用。生成内容将是一个单 HTML 文件(使用 CDN)。"
106
+ },
107
+ REACT_THREE_FIBER: {
108
+ "display_name": "React 3D (R3F)",
109
+ "description": "基于 React Three Fiber 的 3D 场景,配合 Tailwind CSS。适合酷炫的 3D 交互效果。"
110
+ },
111
+ OLD_SCHOOL_HTML: {
112
+ "display_name": "90s 复古风格",
113
+ "description": "90 年代风格的纯 HTML + CSS,无 JavaScript。致敬 Web 1.0 时代,适合怀旧风格。"
114
  }
115
  }
116
 
 
140
  Retrieves the display name for a given model constant.
141
  This is what's shown in the UI.
142
  """
143
+ return CHAT_MODEL_SPECS.get(model_constant, {}).get("display_name", model_constant)
 
tab_code.py CHANGED
@@ -10,26 +10,34 @@ from code_kit.code_examples import CODE_EXAMPLES
10
  # Configure logging
11
  logger = logging.getLogger(__name__)
12
 
13
- def refresh_preview(code_type, current_code, chatbot_history):
14
- """Refresh the preview and add a log entry."""
 
 
 
 
15
  logger.info(f"--- [Manual Refresh] Start ---")
16
- logger.info(f"Code Type: {code_type}")
17
-
18
- if code_type == "静态页面":
19
- escaped_code = current_code.replace("'", "&apos;").replace('"', '&quot;')
20
- final_preview_html = f"""
21
- <div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
22
- <iframe srcdoc='{escaped_code}'
23
- style="position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; border: none;">
24
- </iframe>
25
- </div>
26
- """
27
- chatbot_history.append({"role": "assistant", "content": "🔄 **状态**: 预览已手动刷新。"})
28
- logger.info("Refreshed static page preview.")
29
- return gr.HTML(final_preview_html), chatbot_history
30
-
31
- chatbot_history.append({"role": "assistant", "content": "⚠️ **警告**: 未知的代码类型,无法刷新。"})
32
- return gr.update(), chatbot_history
 
 
 
 
33
 
34
  def toggle_fullscreen(is_fullscreen):
35
  is_fullscreen = not is_fullscreen
@@ -161,4 +169,4 @@ def create_code_tab():
161
  fn=log_js_error,
162
  inputs=[js_error_channel, log_chatbot],
163
  outputs=log_chatbot
164
- )
 
10
  # Configure logging
11
  logger = logging.getLogger(__name__)
12
 
13
+ def refresh_preview(code_type_display_name, current_code, chatbot_history):
14
+ """
15
+ Refresh the preview and add a log entry.
16
+ Refactored to rely solely on the HTML content for preview, assuming all frameworks
17
+ produce a single-file HTML output that works in an iframe.
18
+ """
19
  logger.info(f"--- [Manual Refresh] Start ---")
20
+ logger.info(f"Code Type: {code_type_display_name}")
21
+
22
+ # Simple validation: Check if code seems to be HTML
23
+ if not current_code or not isinstance(current_code, str):
24
+ chatbot_history.append({"role": "assistant", "content": "⚠️ **警告**: 没有代码可供刷新。"})
25
+ return gr.update(), chatbot_history
26
+
27
+ # For all currently supported frameworks (Static, React+Tailwind, R3F, Old School),
28
+ # the output is a self-contained HTML string.
29
+ # So we can process them uniformly.
30
+ escaped_code = current_code.replace("'", "&apos;").replace('"', '&quot;')
31
+ final_preview_html = f"""
32
+ <div style="width: 100%; height: 600px; border: 1px solid #ddd; overflow: hidden; position: relative; background-color: #f9f9f9;">
33
+ <iframe srcdoc='{escaped_code}'
34
+ style="position: absolute; top: 0; left: 0; width: 200%; height: 200%; transform: scale(0.5); transform-origin: 0 0; border: none;">
35
+ </iframe>
36
+ </div>
37
+ """
38
+ chatbot_history.append({"role": "assistant", "content": "🔄 **状态**: 预览已手动刷新。"})
39
+ logger.info("Refreshed preview.")
40
+ return gr.HTML(final_preview_html), chatbot_history
41
 
42
  def toggle_fullscreen(is_fullscreen):
43
  is_fullscreen = not is_fullscreen
 
169
  fn=log_js_error,
170
  inputs=[js_error_channel, log_chatbot],
171
  outputs=log_chatbot
172
+ )
tab_code_prompts/framework_system_prompts.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from config import STATIC_PAGE, REACT_TAILWIND, REACT_TAILWIND_CHARTJS, REACT_THREE_FIBER, OLD_SCHOOL_HTML
2
+
3
+ def get_framework_system_prompt(framework_type, color_palette=None):
4
+ """
5
+ Returns the system prompt specific to the selected framework.
6
+ Optionally incorporates specific color palette instructions directly into the system prompt.
7
+ """
8
+
9
+ base_role = "You are an expert front-end developer."
10
+
11
+ # Construct dynamic palette instruction
12
+ palette_instruction = "**Color Palette:** If a color palette is provided in the user prompt, **YOU MUST** use those specific hex codes."
13
+ if color_palette:
14
+ palette_instruction = f"**Color Palette (MANDATORY):** You have been assigned the following color palette. **YOU MUST** use these specific hex codes for the corresponding roles:\n {color_palette}\n Use Tailwind's arbitrary value syntax (e.g., `bg-[#FF5733]`) to apply them."
15
+
16
+ if framework_type == REACT_TAILWIND:
17
+ return f"""
18
+ {base_role}
19
+ Create a single-file HTML application using **React** and **Tailwind CSS**.
20
+
21
+ **Technical Constraints & Libraries:**
22
+ 1. **Library Loading:** Use unpkg/cdnjs for imports.
23
+ * React: `https://unpkg.com/react@18/umd/react.development.js`
24
+ * ReactDOM: `https://unpkg.com/react-dom@18/umd/react-dom.development.js`
25
+ * Babel: `https://unpkg.com/@babel/standalone/babel.min.js`
26
+ * Tailwind: `https://cdn.tailwindcss.com`
27
+ 2. **Structure:**
28
+ * Load Tailwind via script tag.
29
+ * Load React/ReactDOM/Babel via script tags.
30
+ * Write your React components inside `<script type="text/babel">`.
31
+ * Mount the main component to a root div.
32
+ 3. **Visual Style & Theming:**
33
+ * **Strictly follow** any "Visual Style Requirements" (Decoration, Theme) provided in the user prompt.
34
+ * {palette_instruction}
35
+ * **Decoration:** Reflect the requested decoration style (e.g., rounded corners, shadows, borders) using Tailwind classes.
36
+ 4. **Common Pitfalls to Avoid:**
37
+ * Do NOT use `import` statements (ES modules) for React in this single-file setup. Use the global `React` and `ReactDOM` variables.
38
+ * Ensure valid JSX syntax.
39
+ * Remember to use `className` instead of `class`.
40
+ * Close all self-closing tags (e.g., `<img />`, `<br />`).
41
+
42
+ **Output Format:**
43
+ Return ONLY the raw HTML code. No markdown explanations.
44
+ """
45
+
46
+ elif framework_type == REACT_TAILWIND_CHARTJS:
47
+ # Specific instruction for Chart.js palette usage
48
+ chart_palette_instr = palette_instruction
49
+ if color_palette:
50
+ chart_palette_instr = f"**Color Palette (MANDATORY):** You have been assigned the following color palette:\n {color_palette}\n **CRITICAL:** Apply these exact colors to your Chart.js `backgroundColor` and `borderColor` datasets, and use them for UI elements via Tailwind arbitrary values."
51
+
52
+ return f"""
53
+ {base_role}
54
+ Create a single-file HTML application using **React**, **Tailwind CSS**, and **Chart.js** for data visualization.
55
+
56
+ **Technical Constraints & Libraries:**
57
+ 1. **Library Loading:** Use unpkg/cdnjs for imports.
58
+ * React: `https://unpkg.com/react@18/umd/react.development.js`
59
+ * ReactDOM: `https://unpkg.com/react-dom@18/umd/react-dom.development.js`
60
+ * Babel: `https://unpkg.com/@babel/standalone/babel.min.js`
61
+ * Tailwind: `https://cdn.tailwindcss.com`
62
+ * Chart.js: `https://cdn.jsdelivr.net/npm/chart.js`
63
+ 2. **Structure:**
64
+ * Load Tailwind via script tag.
65
+ * Load React/ReactDOM/Babel via script tags.
66
+ * Load Chart.js via script tag (before your React script that uses it).
67
+ * Write your React components inside `<script type="text/babel">`.
68
+ * Mount the main component to a root div.
69
+ * Use a `<canvas>` element for Chart.js charts and get its 2D context within a React ref or a direct DOM query in `useEffect`.
70
+ 3. **Visual Style & Theming (CRITICAL):**
71
+ * **Strictly follow** any "Visual Style Requirements" provided in the user prompt.
72
+ * {chart_palette_instr}
73
+ * **Decoration:** Apply the requested decoration style using appropriate Tailwind utilities.
74
+ 4. **Common Pitfalls to Avoid:**
75
+ * Do NOT use `import` statements (ES modules) for React/ReactDOM/Babel/Chart.js in this single-file setup. Use the global `React`, `ReactDOM`, `Chart` variables.
76
+ * Ensure valid JSX syntax.
77
+ * Remember to use `className` instead of `class`.
78
+ * Close all self-closing tags.
79
+ * For Chart.js, ensure the canvas context is properly obtained (`canvasRef.current.getContext('2d')`).
80
+ * Manage Chart.js instances within React's `useEffect` hook: create the chart on mount and destroy it on unmount to prevent memory leaks.
81
+ * Ensure Chart.js data and options objects are correctly structured.
82
+
83
+ **Output Format:**
84
+ Return ONLY the raw HTML code. No markdown explanations.
85
+ """
86
+
87
+ elif framework_type == REACT_THREE_FIBER:
88
+ r3f_palette_instr = palette_instruction
89
+ if color_palette:
90
+ r3f_palette_instr = f"**Color Palette (MANDATORY):** You have been assigned the following color palette:\n {color_palette}\n Use these hex codes for 3D materials (`color='#hex'`), lights, background, and UI overlays."
91
+
92
+ return f"""
93
+ {base_role}
94
+ Create a 3D interactive scene using **React Three Fiber (R3F)**, **React Drei**, and **Tailwind CSS**.
95
+
96
+ **Technical Constraints & Libraries:**
97
+ 1. **Library Loading:** Use ES Modules via `importmap` for R3F, as it usually requires a module system.
98
+ * Add an `<script type="importmap">` block defining 'react', 'react-dom/client', 'three', '@react-three/fiber', '@react-three/drei'.
99
+ * Use `https://esm.sh/` for reliable module imports.
100
+ * Example: "react": "https://esm.sh/react@18.2.0"
101
+ * Load Tailwind CSS via `https://cdn.tailwindcss.com`.
102
+ 2. **Structure:**
103
+ * Use `<script type="module">` for your React logic.
104
+ * Import specific components from the libraries.
105
+ * Setup a `<Canvas>` from `@react-three/fiber`.
106
+ 3. **Visual Style & Theming:**
107
+ * **Strictly follow** any "Visual Style Requirements" provided in the user prompt.
108
+ * {r3f_palette_instr}
109
+ 4. **Common Pitfalls to Avoid:**
110
+ * Ensure `three` version compatibility with `@react-three/fiber`.
111
+ * Do not mix UMD globals with ES module imports. Stick to the module approach for this stack.
112
+ * Set the canvas height (e.g., `h-screen` or fixed height) via Tailwind, otherwise it might be 0px.
113
+
114
+ **Output Format:**
115
+ Return ONLY the raw HTML code. No markdown explanations.
116
+ """
117
+
118
+ elif framework_type == OLD_SCHOOL_HTML:
119
+ old_school_palette_instr = "**Color Palette:** If a palette is provided, use those specific hex codes for `bgcolor` attributes, `font color`, or inline styles."
120
+ if color_palette:
121
+ old_school_palette_instr = f"**Color Palette (MANDATORY):** You MUST use these specific colors:\n {color_palette}\n Apply them using `bgcolor` attributes, `<font color='...'>`, or inline `style='color: ...'`."
122
+
123
+ return f"""
124
+ {base_role}
125
+ Create a **90s/Early 2000s style** web page.
126
+
127
+ **Technical Constraints & Style:**
128
+ 1. **Technology:** Pure HTML 4.01 style (transitional) and CSS. **NO JavaScript**.
129
+ 2. **Visual Style (The Vibe):**
130
+ * {old_school_palette_instr}
131
+ * Use web-safe colors, tiling backgrounds, and extensive HTML tables (`<table>`) for layout.
132
+ * Use `<marquee>` tags, `<blink>` tags (or CSS simulation), and specific fonts like Times New Roman or Comic Sans MS.
133
+ * Beveled buttons and borders (CSS `border-style: outset`).
134
+ 3. **Common Pitfalls to Avoid:**
135
+ * Do NOT use Flexbox or Grid.
136
+ * Do NOT use modern CSS variables or shadows.
137
+ * Do NOT use any external CSS frameworks.
138
+
139
+ **Output Format:**
140
+ Return ONLY the raw HTML code. No markdown explanations.
141
+ """
142
+
143
+ else: # Default to STATIC_PAGE
144
+ static_palette_instr = "**Color Palette:** If provided, use the specified hex codes for your CSS styles."
145
+ if color_palette:
146
+ static_palette_instr = f"**Color Palette (MANDATORY):** You MUST use these specific colors for your CSS variables or styles:\n {color_palette}"
147
+
148
+ return f"""
149
+ {base_role}
150
+ Create a complete, modern, and responsive single HTML file based on the user's request.
151
+
152
+ **Technical Constraints:**
153
+ 1. **Self-Contained:** Include all necessary HTML, CSS, and JavaScript in the file.
154
+ 2. **Libraries:** If you need external libraries (like jQuery, Bootstrap, FontAwesome), use standard CDNs (cdnjs/unpkg).
155
+ 3. **Visual Style:**
156
+ * **Strictly follow** any "Visual Style Requirements" (Decoration, Theme) provided in the user prompt.
157
+ * {static_palette_instr}
158
+ 4. **Structure:**
159
+ * Use semantic HTML5.
160
+ * Use modern CSS (Flexbox, Grid).
161
+ * Keep scripts at the end of the body.
162
+
163
+ **Output Format:**
164
+ Return ONLY the raw HTML code. No markdown explanations.
165
+ """