akhaliq HF Staff commited on
Commit
e2ce9d8
·
1 Parent(s): 586f5a7

add preview for transformers js

Browse files
Files changed (1) hide show
  1. app.py +98 -6
app.py CHANGED
@@ -805,6 +805,96 @@ def format_transformers_js_output(files):
805
  output.append(files['style.css'])
806
  return '\n'.join(output)
807
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
808
  def parse_svelte_output(text):
809
  """Parse Svelte output to extract individual files"""
810
  files = {
@@ -2218,7 +2308,7 @@ This will help me create a better design for you."""
2218
  yield {
2219
  code_output: formatted_output,
2220
  history: _history,
2221
- sandbox: send_to_sandbox(files['index.html']),
2222
  history_output: history_to_chatbot_messages(_history),
2223
  }
2224
  else:
@@ -2462,16 +2552,17 @@ This will help me create a better design for you."""
2462
  yield {
2463
  code_output: gr.update(value=formatted_output, language="html"),
2464
  history_output: history_to_chatbot_messages(_history),
2465
- sandbox: send_to_sandbox(files['index.html']) if files['index.html'] else "<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>",
2466
  }
2467
  elif has_existing_content:
2468
  # Model is returning search/replace changes for transformers.js - apply them
2469
  last_content = _history[-1][1] if _history and len(_history[-1]) > 1 else ""
2470
  modified_content = apply_transformers_js_search_replace_changes(last_content, content)
 
2471
  yield {
2472
  code_output: gr.update(value=modified_content, language="html"),
2473
  history_output: history_to_chatbot_messages(_history),
2474
- sandbox: send_to_sandbox(parse_transformers_js_output(modified_content)['index.html']) if parse_transformers_js_output(modified_content)['index.html'] else "<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>",
2475
  }
2476
  else:
2477
  # Still streaming, show partial content
@@ -2549,7 +2640,7 @@ This will help me create a better design for you."""
2549
  yield {
2550
  code_output: formatted_output,
2551
  history: _history,
2552
- sandbox: send_to_sandbox(files['index.html']),
2553
  history_output: history_to_chatbot_messages(_history),
2554
  }
2555
  elif has_existing_content:
@@ -2557,10 +2648,11 @@ This will help me create a better design for you."""
2557
  last_content = _history[-1][1] if _history and len(_history[-1]) > 1 else ""
2558
  modified_content = apply_transformers_js_search_replace_changes(last_content, content)
2559
  _history.append([query, modified_content])
 
2560
  yield {
2561
  code_output: modified_content,
2562
  history: _history,
2563
- sandbox: send_to_sandbox(parse_transformers_js_output(modified_content)['index.html']),
2564
  history_output: history_to_chatbot_messages(_history),
2565
  }
2566
  else:
@@ -3650,7 +3742,7 @@ with gr.Blocks(
3650
  if language == "transformers.js":
3651
  files = parse_transformers_js_output(code)
3652
  if files['index.html']:
3653
- return send_to_sandbox(files['index.html'])
3654
  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>"
3655
  if language == "svelte":
3656
  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>"
 
805
  output.append(files['style.css'])
806
  return '\n'.join(output)
807
 
808
+ def build_transformers_inline_html(files: dict) -> str:
809
+ """Merge transformers.js three-file output into a single self-contained HTML document.
810
+
811
+ - Inlines style.css into a <style> tag
812
+ - Inlines index.js into a <script type="module"> tag
813
+ - Rewrites ESM imports for transformers.js to a stable CDN URL so it works in data: iframes
814
+ """
815
+ import re as _re
816
+
817
+ html = files.get('index.html') or ''
818
+ js = files.get('index.js') or ''
819
+ css = files.get('style.css') or ''
820
+
821
+ # Normalize JS imports to CDN (handle both @huggingface/transformers and legacy @xenova/transformers)
822
+ cdn_url = "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.7.1"
823
+ js = _re.sub(r"from\s+['\"]@huggingface/transformers['\"]", f"from '{cdn_url}'", js)
824
+ js = _re.sub(r"from\s+['\"]@xenova/transformers['\"]", f"from '{cdn_url}'", js)
825
+
826
+ # Prepend a small prelude to reduce persistent caching during preview
827
+ # Note: importing env alongside user's own imports is fine in ESM
828
+ if js.strip():
829
+ prelude = (
830
+ f"import {{ env }} from '{cdn_url}';\n"
831
+ "try { env.useBrowserCache = false; } catch (e) {}\n"
832
+ )
833
+ js = prelude + js
834
+
835
+ # If index.html missing or doesn't look like a full document, create a minimal shell
836
+ doc = html.strip()
837
+ if not doc or ('<html' not in doc.lower()):
838
+ doc = (
839
+ "<!DOCTYPE html>\n"
840
+ "<html>\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Transformers.js App</title>\n</head>\n"
841
+ "<body>\n<div id=\"app\"></div>\n</body>\n</html>"
842
+ )
843
+
844
+ # Remove local references to style.css and index.js to avoid duplicates when inlining
845
+ doc = _re.sub(r"<link[^>]+href=\"[^\"]*style\.css\"[^>]*>\s*", "", doc, flags=_re.IGNORECASE)
846
+ doc = _re.sub(r"<script[^>]+src=\"[^\"]*index\.js\"[^>]*>\s*</script>\s*", "", doc, flags=_re.IGNORECASE)
847
+
848
+ # Inline CSS: insert before </head> or create a <head>
849
+ style_tag = f"<style>\n{css}\n</style>" if css else ""
850
+ if style_tag:
851
+ if '</head>' in doc.lower():
852
+ # Preserve original casing by finding closing head case-insensitively
853
+ match = _re.search(r"</head>", doc, flags=_re.IGNORECASE)
854
+ if match:
855
+ idx = match.start()
856
+ doc = doc[:idx] + style_tag + doc[idx:]
857
+ else:
858
+ # No head; insert at top of body
859
+ match = _re.search(r"<body[^>]*>", doc, flags=_re.IGNORECASE)
860
+ if match:
861
+ idx = match.end()
862
+ doc = doc[:idx] + "\n" + style_tag + doc[idx:]
863
+ else:
864
+ # Append at beginning
865
+ doc = style_tag + doc
866
+
867
+ # Inline JS: insert before </body>
868
+ script_tag = f"<script type=\"module\">\n{js}\n</script>" if js else ""
869
+ # Cleanup script to clear Cache Storage and IndexedDB on unload to free model weights
870
+ cleanup_tag = (
871
+ "<script>\n"
872
+ "(function(){\n"
873
+ " function cleanup(){\n"
874
+ " try { if (window.caches && caches.keys) { caches.keys().then(keys => keys.forEach(k => caches.delete(k))); } } catch(e){}\n"
875
+ " try { if (window.indexedDB && indexedDB.databases) { indexedDB.databases().then(dbs => dbs.forEach(db => db && db.name && indexedDB.deleteDatabase(db.name))); } } catch(e){}\n"
876
+ " }\n"
877
+ " window.addEventListener('pagehide', cleanup, { once: true });\n"
878
+ " window.addEventListener('beforeunload', cleanup, { once: true });\n"
879
+ "})();\n"
880
+ "</script>"
881
+ )
882
+ if script_tag:
883
+ match = _re.search(r"</body>", doc, flags=_re.IGNORECASE)
884
+ if match:
885
+ idx = match.start()
886
+ doc = doc[:idx] + script_tag + cleanup_tag + doc[idx:]
887
+ else:
888
+ # Append at end
889
+ doc = doc + script_tag + cleanup_tag
890
+
891
+ return doc
892
+
893
+ def send_transformers_to_sandbox(files: dict) -> str:
894
+ """Build a self-contained HTML document from transformers.js files and return an iframe preview."""
895
+ merged_html = build_transformers_inline_html(files)
896
+ return send_to_sandbox(merged_html)
897
+
898
  def parse_svelte_output(text):
899
  """Parse Svelte output to extract individual files"""
900
  files = {
 
2308
  yield {
2309
  code_output: formatted_output,
2310
  history: _history,
2311
+ sandbox: send_transformers_to_sandbox(files),
2312
  history_output: history_to_chatbot_messages(_history),
2313
  }
2314
  else:
 
2552
  yield {
2553
  code_output: gr.update(value=formatted_output, language="html"),
2554
  history_output: history_to_chatbot_messages(_history),
2555
+ sandbox: send_transformers_to_sandbox(files) if files['index.html'] else "<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>",
2556
  }
2557
  elif has_existing_content:
2558
  # Model is returning search/replace changes for transformers.js - apply them
2559
  last_content = _history[-1][1] if _history and len(_history[-1]) > 1 else ""
2560
  modified_content = apply_transformers_js_search_replace_changes(last_content, content)
2561
+ _mf = parse_transformers_js_output(modified_content)
2562
  yield {
2563
  code_output: gr.update(value=modified_content, language="html"),
2564
  history_output: history_to_chatbot_messages(_history),
2565
+ sandbox: send_transformers_to_sandbox(_mf) if _mf['index.html'] else "<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>",
2566
  }
2567
  else:
2568
  # Still streaming, show partial content
 
2640
  yield {
2641
  code_output: formatted_output,
2642
  history: _history,
2643
+ sandbox: send_transformers_to_sandbox(files),
2644
  history_output: history_to_chatbot_messages(_history),
2645
  }
2646
  elif has_existing_content:
 
2648
  last_content = _history[-1][1] if _history and len(_history[-1]) > 1 else ""
2649
  modified_content = apply_transformers_js_search_replace_changes(last_content, content)
2650
  _history.append([query, modified_content])
2651
+ _mf = parse_transformers_js_output(modified_content)
2652
  yield {
2653
  code_output: modified_content,
2654
  history: _history,
2655
+ sandbox: send_transformers_to_sandbox(_mf),
2656
  history_output: history_to_chatbot_messages(_history),
2657
  }
2658
  else:
 
3742
  if language == "transformers.js":
3743
  files = parse_transformers_js_output(code)
3744
  if files['index.html']:
3745
+ return send_transformers_to_sandbox(files)
3746
  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>"
3747
  if language == "svelte":
3748
  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>"