akhaliq HF Staff commited on
Commit
3ccd7b9
·
1 Parent(s): fc3c8d2

add svelte app support

Browse files
Files changed (1) hide show
  1. app.py +269 -4
app.py CHANGED
@@ -90,6 +90,81 @@ The style.css should contain all the styling for the application.
90
 
91
  Always output only the three code blocks as shown above, and do not include any explanations or extra text."""
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  TRANSFORMERS_JS_SYSTEM_PROMPT_WITH_SEARCH = """You are an expert web developer creating a transformers.js application. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific technologies for transformers.js.
94
 
95
  You will generate THREE separate files: index.html, index.js, and style.css.
@@ -360,6 +435,10 @@ DEMO_LIST = [
360
  {
361
  "title": "Transformers.js App",
362
  "description": "Create a transformers.js application with AI/ML functionality using the transformers.js library"
 
 
 
 
363
  }
364
  ]
365
 
@@ -522,6 +601,39 @@ def format_transformers_js_output(files):
522
  output.append(files['style.css'])
523
  return '\n'.join(output)
524
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
  def history_render(history: History):
526
  return gr.update(visible=True), history
527
 
@@ -1246,7 +1358,8 @@ def generation_code(query: Optional[str], image: Optional[gr.Image], file: Optio
1246
  'IMPORTED PROJECT FROM HUGGING FACE SPACE' in last_assistant_msg or
1247
  '=== index.html ===' in last_assistant_msg or
1248
  '=== index.js ===' in last_assistant_msg or
1249
- '=== style.css ===' in last_assistant_msg):
 
1250
  has_existing_content = True
1251
 
1252
  # Choose system prompt based on context
@@ -1254,6 +1367,8 @@ def generation_code(query: Optional[str], image: Optional[gr.Image], file: Optio
1254
  # Use follow-up prompt for modifying existing content
1255
  if language == "transformers.js":
1256
  system_prompt = TransformersJSFollowUpSystemPrompt
 
 
1257
  else:
1258
  system_prompt = FollowUpSystemPrompt
1259
  else:
@@ -1262,6 +1377,8 @@ def generation_code(query: Optional[str], image: Optional[gr.Image], file: Optio
1262
  system_prompt = HTML_SYSTEM_PROMPT_WITH_SEARCH if enable_search else HTML_SYSTEM_PROMPT
1263
  elif language == "transformers.js":
1264
  system_prompt = TRANSFORMERS_JS_SYSTEM_PROMPT_WITH_SEARCH if enable_search else TRANSFORMERS_JS_SYSTEM_PROMPT
 
 
1265
  else:
1266
  system_prompt = GENERIC_SYSTEM_PROMPT_WITH_SEARCH.format(language=language) if enable_search else GENERIC_SYSTEM_PROMPT.format(language=language)
1267
 
@@ -1351,6 +1468,14 @@ This will help me create a better design for you."""
1351
  history_output: history_to_chatbot_messages(_history),
1352
  sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Generating transformers.js app...</div>",
1353
  }
 
 
 
 
 
 
 
 
1354
  else:
1355
  clean_code = remove_code_block(content)
1356
  if has_existing_content:
@@ -1414,6 +1539,39 @@ This will help me create a better design for you."""
1414
  sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Error parsing transformers.js output. Please try again.</div>",
1415
  history_output: history_to_chatbot_messages(_history),
1416
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1417
  elif has_existing_content:
1418
  # Handle modification of existing content
1419
  final_code = remove_code_block(content)
@@ -1655,7 +1813,7 @@ with gr.Blocks(
1655
  )
1656
  # Language dropdown for code generation
1657
  language_choices = [
1658
- "html", "python", "c", "cpp", "markdown", "latex", "json", "css", "javascript", "jinja2", "typescript", "yaml", "dockerfile", "shell", "r", "sql", "sql-msSQL", "sql-mySQL", "sql-mariaDB", "sql-sqlite", "sql-cassandra", "sql-plSQL", "sql-hive", "sql-pgSQL", "sql-gql", "sql-gpSQL", "sql-sparkSQL", "sql-esper", "transformers.js"
1659
  ]
1660
  language_dropdown = gr.Dropdown(
1661
  choices=language_choices,
@@ -1692,7 +1850,8 @@ with gr.Blocks(
1692
  ("Gradio (Python)", "gradio"),
1693
  ("Streamlit (Python)", "streamlit"),
1694
  ("Static (HTML)", "static"),
1695
- ("Transformers.js", "transformers.js")
 
1696
  ]
1697
  sdk_dropdown = gr.Dropdown(
1698
  choices=[x[0] for x in sdk_choices],
@@ -1804,6 +1963,8 @@ with gr.Blocks(
1804
  def update_sdk_based_on_language(language):
1805
  if language == "transformers.js":
1806
  return gr.update(value="Transformers.js")
 
 
1807
  elif language == "html":
1808
  return gr.update(value="Static (HTML)")
1809
  else:
@@ -1822,6 +1983,9 @@ with gr.Blocks(
1822
  return send_to_sandbox(files['index.html'])
1823
  else:
1824
  return "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>"
 
 
 
1825
  else:
1826
  return "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>"
1827
 
@@ -1905,7 +2069,8 @@ with gr.Blocks(
1905
  "Gradio (Python)": "gradio",
1906
  "Streamlit (Python)": "docker", # Use 'docker' for Streamlit Spaces
1907
  "Static (HTML)": "static",
1908
- "Transformers.js": "static" # Transformers.js uses static SDK
 
1909
  }
1910
  sdk = sdk_map.get(sdk_name, "gradio")
1911
 
@@ -2060,6 +2225,106 @@ with gr.Blocks(
2060
 
2061
  except Exception as e:
2062
  return gr.update(value=f"Error duplicating Transformers.js space: {e}. If this is a RepoUrl object error, ensure you are not accessing a .url attribute and use str(duplicated_repo) for the URL.", visible=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2063
  # Other SDKs (existing logic)
2064
  if sdk == "static":
2065
  import time
 
90
 
91
  Always output only the three code blocks as shown above, and do not include any explanations or extra text."""
92
 
93
+ SVELTE_SYSTEM_PROMPT = """You are an expert Svelte developer creating a modern Svelte application. You will generate ONLY the custom files that need user-specific content.
94
+
95
+ IMPORTANT: You MUST output ONLY the custom files in the following format:
96
+
97
+ ```svelte
98
+ <!-- src/App.svelte content here -->
99
+ ```
100
+
101
+ ```css
102
+ /* src/app.css content here */
103
+ ```
104
+
105
+ ```svelte
106
+ <!-- src/lib/Counter.svelte content here -->
107
+ ```
108
+
109
+ Requirements:
110
+ 1. Create a modern, responsive Svelte application
111
+ 2. Use TypeScript for better type safety
112
+ 3. Create a clean, professional UI with good user experience
113
+ 4. Make the application fully responsive for mobile devices
114
+ 5. Use modern CSS practices and Svelte best practices
115
+ 6. Include proper error handling and loading states
116
+ 7. Follow accessibility best practices
117
+ 8. Use Svelte's reactive features effectively
118
+ 9. Include proper component structure and organization
119
+
120
+ The files you generate are:
121
+ - src/App.svelte: Main application component (your custom app logic)
122
+ - src/app.css: Global styles (your custom styling)
123
+ - src/lib/Counter.svelte: Example component (your custom components)
124
+
125
+ The other files (index.html, package.json, vite.config.ts, tsconfig files, svelte.config.js, src/main.ts, src/vite-env.d.ts) are provided by the Svelte template and don't need to be generated.
126
+
127
+ Always output only the three code blocks as shown above, and do not include any explanations or extra text."""
128
+
129
+ SVELTE_SYSTEM_PROMPT_WITH_SEARCH = """You are an expert Svelte developer creating a modern Svelte application. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific Svelte technologies.
130
+
131
+ You will generate ONLY the custom files that need user-specific content.
132
+
133
+ IMPORTANT: You MUST output ONLY the custom files in the following format:
134
+
135
+ ```svelte
136
+ <!-- src/App.svelte content here -->
137
+ ```
138
+
139
+ ```css
140
+ /* src/app.css content here */
141
+ ```
142
+
143
+ ```svelte
144
+ <!-- src/lib/Counter.svelte content here -->
145
+ ```
146
+
147
+ Requirements:
148
+ 1. Create a modern, responsive Svelte application
149
+ 2. Use TypeScript for better type safety
150
+ 3. Create a clean, professional UI with good user experience
151
+ 4. Make the application fully responsive for mobile devices
152
+ 5. Use modern CSS practices and Svelte best practices
153
+ 6. Include proper error handling and loading states
154
+ 7. Follow accessibility best practices
155
+ 8. Use Svelte's reactive features effectively
156
+ 9. Include proper component structure and organization
157
+ 10. Use web search to find the latest Svelte patterns, libraries, and best practices
158
+
159
+ The files you generate are:
160
+ - src/App.svelte: Main application component (your custom app logic)
161
+ - src/app.css: Global styles (your custom styling)
162
+ - src/lib/Counter.svelte: Example component (your custom components)
163
+
164
+ The other files (index.html, package.json, vite.config.ts, tsconfig files, svelte.config.js, src/main.ts, src/vite-env.d.ts) are provided by the Svelte template and don't need to be generated.
165
+
166
+ Always output only the three code blocks as shown above, and do not include any explanations or extra text."""
167
+
168
  TRANSFORMERS_JS_SYSTEM_PROMPT_WITH_SEARCH = """You are an expert web developer creating a transformers.js application. You have access to real-time web search. When needed, use web search to find the latest information, best practices, or specific technologies for transformers.js.
169
 
170
  You will generate THREE separate files: index.html, index.js, and style.css.
 
435
  {
436
  "title": "Transformers.js App",
437
  "description": "Create a transformers.js application with AI/ML functionality using the transformers.js library"
438
+ },
439
+ {
440
+ "title": "Svelte App",
441
+ "description": "Create a modern Svelte application with TypeScript, Vite, and responsive design"
442
  }
443
  ]
444
 
 
601
  output.append(files['style.css'])
602
  return '\n'.join(output)
603
 
604
+ def parse_svelte_output(text):
605
+ """Parse Svelte output to extract individual files"""
606
+ files = {
607
+ 'src/App.svelte': '',
608
+ 'src/app.css': '',
609
+ 'src/lib/Counter.svelte': ''
610
+ }
611
+
612
+ # Split by code blocks
613
+ import re
614
+ code_blocks = re.findall(r'```(?:svelte|css)\n(.*?)```', text, re.DOTALL)
615
+
616
+ # Handle partial generation - assign what we have
617
+ if len(code_blocks) >= 1:
618
+ files['src/App.svelte'] = code_blocks[0].strip()
619
+ if len(code_blocks) >= 2:
620
+ files['src/app.css'] = code_blocks[1].strip()
621
+ if len(code_blocks) >= 3:
622
+ files['src/lib/Counter.svelte'] = code_blocks[2].strip()
623
+
624
+ return files
625
+
626
+ def format_svelte_output(files):
627
+ """Format Svelte files into a single display string"""
628
+ output = []
629
+ output.append("=== src/App.svelte ===")
630
+ output.append(files['src/App.svelte'])
631
+ output.append("\n=== src/app.css ===")
632
+ output.append(files['src/app.css'])
633
+ output.append("\n=== src/lib/Counter.svelte ===")
634
+ output.append(files['src/lib/Counter.svelte'])
635
+ return '\n'.join(output)
636
+
637
  def history_render(history: History):
638
  return gr.update(visible=True), history
639
 
 
1358
  'IMPORTED PROJECT FROM HUGGING FACE SPACE' in last_assistant_msg or
1359
  '=== index.html ===' in last_assistant_msg or
1360
  '=== index.js ===' in last_assistant_msg or
1361
+ '=== style.css ===' in last_assistant_msg or
1362
+ '=== src/App.svelte ===' in last_assistant_msg):
1363
  has_existing_content = True
1364
 
1365
  # Choose system prompt based on context
 
1367
  # Use follow-up prompt for modifying existing content
1368
  if language == "transformers.js":
1369
  system_prompt = TransformersJSFollowUpSystemPrompt
1370
+ elif language == "svelte":
1371
+ system_prompt = FollowUpSystemPrompt # Use generic follow-up for Svelte
1372
  else:
1373
  system_prompt = FollowUpSystemPrompt
1374
  else:
 
1377
  system_prompt = HTML_SYSTEM_PROMPT_WITH_SEARCH if enable_search else HTML_SYSTEM_PROMPT
1378
  elif language == "transformers.js":
1379
  system_prompt = TRANSFORMERS_JS_SYSTEM_PROMPT_WITH_SEARCH if enable_search else TRANSFORMERS_JS_SYSTEM_PROMPT
1380
+ elif language == "svelte":
1381
+ system_prompt = SVELTE_SYSTEM_PROMPT_WITH_SEARCH if enable_search else SVELTE_SYSTEM_PROMPT
1382
  else:
1383
  system_prompt = GENERIC_SYSTEM_PROMPT_WITH_SEARCH.format(language=language) if enable_search else GENERIC_SYSTEM_PROMPT.format(language=language)
1384
 
 
1468
  history_output: history_to_chatbot_messages(_history),
1469
  sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Generating transformers.js app...</div>",
1470
  }
1471
+ elif language == "svelte":
1472
+ # For Svelte, just show the content as it streams
1473
+ # We'll parse it properly in the final response
1474
+ yield {
1475
+ code_output: gr.update(value=content, language="html"),
1476
+ history_output: history_to_chatbot_messages(_history),
1477
+ sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Generating Svelte app...</div>",
1478
+ }
1479
  else:
1480
  clean_code = remove_code_block(content)
1481
  if has_existing_content:
 
1539
  sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Error parsing transformers.js output. Please try again.</div>",
1540
  history_output: history_to_chatbot_messages(_history),
1541
  }
1542
+ elif language == "svelte":
1543
+ # Handle Svelte output
1544
+ files = parse_svelte_output(content)
1545
+ if files['src/App.svelte'] and files['src/app.css']:
1546
+ # Model returned complete Svelte output
1547
+ formatted_output = format_svelte_output(files)
1548
+ _history.append([query, formatted_output])
1549
+ yield {
1550
+ code_output: formatted_output,
1551
+ history: _history,
1552
+ sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your Svelte code using the download button above.</div>",
1553
+ history_output: history_to_chatbot_messages(_history),
1554
+ }
1555
+ elif has_existing_content:
1556
+ # Model returned search/replace changes for Svelte - apply them
1557
+ last_content = _history[-1][1] if _history and len(_history[-1]) > 1 else ""
1558
+ modified_content = apply_search_replace_changes(last_content, content)
1559
+ _history.append([query, modified_content])
1560
+ yield {
1561
+ code_output: modified_content,
1562
+ history: _history,
1563
+ sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your Svelte code using the download button above.</div>",
1564
+ history_output: history_to_chatbot_messages(_history),
1565
+ }
1566
+ else:
1567
+ # Fallback if parsing failed - just use the raw content
1568
+ _history.append([query, content])
1569
+ yield {
1570
+ code_output: content,
1571
+ history: _history,
1572
+ sandbox: "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your Svelte code using the download button above.</div>",
1573
+ history_output: history_to_chatbot_messages(_history),
1574
+ }
1575
  elif has_existing_content:
1576
  # Handle modification of existing content
1577
  final_code = remove_code_block(content)
 
1813
  )
1814
  # Language dropdown for code generation
1815
  language_choices = [
1816
+ "html", "python", "transformers.js", "svelte", "c", "cpp", "markdown", "latex", "json", "css", "javascript", "jinja2", "typescript", "yaml", "dockerfile", "shell", "r", "sql", "sql-msSQL", "sql-mySQL", "sql-mariaDB", "sql-sqlite", "sql-cassandra", "sql-plSQL", "sql-hive", "sql-pgSQL", "sql-gql", "sql-gpSQL", "sql-sparkSQL", "sql-esper"
1817
  ]
1818
  language_dropdown = gr.Dropdown(
1819
  choices=language_choices,
 
1850
  ("Gradio (Python)", "gradio"),
1851
  ("Streamlit (Python)", "streamlit"),
1852
  ("Static (HTML)", "static"),
1853
+ ("Transformers.js", "transformers.js"),
1854
+ ("Svelte", "svelte")
1855
  ]
1856
  sdk_dropdown = gr.Dropdown(
1857
  choices=[x[0] for x in sdk_choices],
 
1963
  def update_sdk_based_on_language(language):
1964
  if language == "transformers.js":
1965
  return gr.update(value="Transformers.js")
1966
+ elif language == "svelte":
1967
+ return gr.update(value="Svelte")
1968
  elif language == "html":
1969
  return gr.update(value="Static (HTML)")
1970
  else:
 
1983
  return send_to_sandbox(files['index.html'])
1984
  else:
1985
  return "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>"
1986
+ elif language == "svelte":
1987
+ # For Svelte, we can't preview the compiled app, so show a message
1988
+ return "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your Svelte code and deploy it to see the result.</div>"
1989
  else:
1990
  return "<div style='padding:1em;color:#888;text-align:center;'>Preview is only available for HTML. Please download your code using the download button above.</div>"
1991
 
 
2069
  "Gradio (Python)": "gradio",
2070
  "Streamlit (Python)": "docker", # Use 'docker' for Streamlit Spaces
2071
  "Static (HTML)": "static",
2072
+ "Transformers.js": "static", # Transformers.js uses static SDK
2073
+ "Svelte": "static" # Svelte uses static SDK
2074
  }
2075
  sdk = sdk_map.get(sdk_name, "gradio")
2076
 
 
2225
 
2226
  except Exception as e:
2227
  return gr.update(value=f"Error duplicating Transformers.js space: {e}. If this is a RepoUrl object error, ensure you are not accessing a .url attribute and use str(duplicated_repo) for the URL.", visible=True)
2228
+ # Svelte logic
2229
+ elif sdk_name == "Svelte" and not is_update:
2230
+ try:
2231
+ # Use duplicate_space to create a Svelte template space
2232
+ from huggingface_hub import duplicate_space
2233
+
2234
+ # Duplicate the Svelte template space
2235
+ duplicated_repo = duplicate_space(
2236
+ from_id="static-templates/svelte",
2237
+ to_id=space_name.strip(),
2238
+ token=token.token,
2239
+ exist_ok=True
2240
+ )
2241
+ print("Duplicated Svelte repo result:", duplicated_repo, type(duplicated_repo))
2242
+ # Show the duplicated space URL immediately for user feedback
2243
+ gr.update(value=f"✅ Space duplicated! [Open your new Svelte Space here]({str(duplicated_repo)})", visible=True)
2244
+ # Parse the Svelte output to get the custom files
2245
+ files = parse_svelte_output(code)
2246
+
2247
+ if not files['src/App.svelte']:
2248
+ return gr.update(value="Error: Could not parse Svelte output. Please regenerate the code.", visible=True)
2249
+
2250
+ # Upload only the custom Svelte files to the duplicated space
2251
+ import tempfile
2252
+
2253
+ # Upload src/App.svelte (required)
2254
+ with tempfile.NamedTemporaryFile("w", suffix=".svelte", delete=False) as f:
2255
+ f.write(files['src/App.svelte'])
2256
+ temp_path = f.name
2257
+
2258
+ try:
2259
+ api.upload_file(
2260
+ path_or_fileobj=temp_path,
2261
+ path_in_repo="src/App.svelte",
2262
+ repo_id=repo_id,
2263
+ repo_type="space"
2264
+ )
2265
+ except Exception as e:
2266
+ error_msg = str(e)
2267
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
2268
+ return gr.update(value=f"Error: Permission denied. Please ensure you have write access to {repo_id} and your token has the correct permissions.", visible=True)
2269
+ else:
2270
+ return gr.update(value=f"Error uploading src/App.svelte: {e}", visible=True)
2271
+ finally:
2272
+ import os
2273
+ os.unlink(temp_path)
2274
+
2275
+ # Upload src/app.css (optional)
2276
+ if files['src/app.css']:
2277
+ with tempfile.NamedTemporaryFile("w", suffix=".css", delete=False) as f:
2278
+ f.write(files['src/app.css'])
2279
+ temp_path = f.name
2280
+
2281
+ try:
2282
+ api.upload_file(
2283
+ path_or_fileobj=temp_path,
2284
+ path_in_repo="src/app.css",
2285
+ repo_id=repo_id,
2286
+ repo_type="space"
2287
+ )
2288
+ except Exception as e:
2289
+ error_msg = str(e)
2290
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
2291
+ return gr.update(value=f"Error: Permission denied. Please ensure you have write access to {repo_id} and your token has the correct permissions.", visible=True)
2292
+ else:
2293
+ return gr.update(value=f"Error uploading src/app.css: {e}", visible=True)
2294
+ finally:
2295
+ import os
2296
+ os.unlink(temp_path)
2297
+
2298
+ # Upload src/lib/Counter.svelte (optional)
2299
+ if files['src/lib/Counter.svelte']:
2300
+ with tempfile.NamedTemporaryFile("w", suffix=".svelte", delete=False) as f:
2301
+ f.write(files['src/lib/Counter.svelte'])
2302
+ temp_path = f.name
2303
+
2304
+ try:
2305
+ api.upload_file(
2306
+ path_or_fileobj=temp_path,
2307
+ path_in_repo="src/lib/Counter.svelte",
2308
+ repo_id=repo_id,
2309
+ repo_type="space"
2310
+ )
2311
+ except Exception as e:
2312
+ error_msg = str(e)
2313
+ if "403 Forbidden" in error_msg and "write token" in error_msg:
2314
+ return gr.update(value=f"Error: Permission denied. Please ensure you have write access to {repo_id} and your token has the correct permissions.", visible=True)
2315
+ else:
2316
+ return gr.update(value=f"Error uploading src/lib/Counter.svelte: {e}", visible=True)
2317
+ finally:
2318
+ import os
2319
+ os.unlink(temp_path)
2320
+
2321
+ # Success - all files uploaded
2322
+ space_url = f"https://huggingface.co/spaces/{repo_id}"
2323
+ action_text = "Updated" if is_update else "Deployed"
2324
+ return gr.update(value=f"✅ {action_text}! [Open your Svelte Space here]({space_url})", visible=True)
2325
+
2326
+ except Exception as e:
2327
+ return gr.update(value=f"Error duplicating Svelte space: {e}. If this is a RepoUrl object error, ensure you are not accessing a .url attribute and use str(duplicated_repo) for the URL.", visible=True)
2328
  # Other SDKs (existing logic)
2329
  if sdk == "static":
2330
  import time