File size: 13,355 Bytes
1ba22b4 4b286f3 1ba22b4 4b286f3 82502f1 4b286f3 1ba22b4 82502f1 1ba22b4 4b286f3 1ba22b4 4b286f3 149da6f 73c77f1 a8e9c78 73c77f1 82502f1 4b286f3 82502f1 4b286f3 73c77f1 7563e81 73c77f1 a8e9c78 82502f1 4b286f3 82502f1 4b286f3 149da6f 4b286f3 1ba22b4 4b286f3 149da6f 82502f1 4b286f3 82502f1 4b286f3 149da6f 82502f1 4b286f3 149da6f 4b286f3 1ba22b4 a8e9c78 82502f1 3aacece 713a4fb 3aacece 82502f1 713a4fb a8e9c78 713a4fb a8e9c78 713a4fb a8e9c78 713a4fb a8e9c78 713a4fb 82502f1 73c77f1 a8e9c78 73c77f1 a8e9c78 73c77f1 a8e9c78 82502f1 1ba22b4 713a4fb 4b286f3 82502f1 4b286f3 73c77f1 a8e9c78 73c77f1 1ba22b4 a8e9c78 7563e81 82502f1 4b286f3 7563e81 4b286f3 a8e9c78 4b286f3 1ba22b4 4b286f3 7563e81 82502f1 4b286f3 1ba22b4 a8e9c78 7563e81 4b286f3 a8e9c78 82502f1 4b286f3 82502f1 4b286f3 82502f1 4b286f3 82502f1 4b286f3 82502f1 4b286f3 1ba22b4 149da6f 7563e81 149da6f 4b286f3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
from enum import Enum
from pathlib import Path
class DemoType(Enum):
GRADIO = 1
STREAMLIT = 2
gradio_lite_html_template = Path('templates/gradio-lite/gradio-lite-template.html').read_text()
stlite_html_template = Path('templates/stlite/stlite-template.html').read_text()
gradio_lite_snippet_template = Path('templates/gradio-lite/gradio-lite-snippet-template.html').read_text()
stlite_snippet_template = Path('templates/stlite/stlite-snippet-template.html').read_text()
def starting_app_code(demo_type: DemoType) -> str:
if demo_type == DemoType.GRADIO:
return Path('templates/gradio-lite/gradio_lite_starting_code.py').read_text().replace('`', r'\`')
elif demo_type == DemoType.STREAMLIT:
return Path('templates/stlite/stlite_starting_code.py').read_text().replace('`', r'\`')
raise NotImplementedError(f'{demo_type} is not a supported demo type')
def load_js(demo_type: DemoType) -> str:
if demo_type == DemoType.GRADIO:
return f"""() => {{
if (window.gradioLiteLoaded) {{
return
}}
// Get the query string from the URL
const queryString = window.location.search;
// Use a function to parse the query string into an object
function parseQueryString(queryString) {{
const params = {{}};
const queryStringWithoutQuestionMark = queryString.substring(1); // Remove the leading question mark
const keyValuePairs = queryStringWithoutQuestionMark.split('&');
keyValuePairs.forEach(keyValue => {{
const [key, value] = keyValue.split('=');
if (value) {{
params[key] = decodeURIComponent(value.replace(/\+/g, ' '));
}}
}});
return params;
}}
// Parse the query string into an object
const queryParams = parseQueryString(queryString);
// Access individual parameters
const codeValue = queryParams.code;
const requirementsValue = queryParams.requirements;
const htmlString = '<iframe id="gradio-iframe" width="100%" height="512px" src="about:blank"></iframe>';
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const iframe = doc.getElementById('gradio-iframe');
const div = document.getElementById('gradioDemoDiv');
div.appendChild(iframe);
let template = `{gradio_lite_html_template.replace('STARTING_CODE', starting_app_code(demo_type))}`;
if (codeValue) {{
template = `{gradio_lite_html_template}`.replace('STARTING_CODE', codeValue.replaceAll(String.fromCharCode(92), String.fromCharCode(92) + String.fromCharCode(92)).replaceAll('`', String.fromCharCode(92) + '`'));
}}
template = template.replace('STARTING_REQUIREMENTS', requirementsValue || '');
const frame = document.getElementById('gradio-iframe');
frame.contentWindow.document.open('text/html', 'replace');
frame.contentWindow.document.write(template);
frame.contentWindow.document.close();
window.gradioLiteLoaded = true;
}}"""
elif demo_type == DemoType.STREAMLIT:
return f"""() => {{
if (window.stliteLoaded) {{
return
}}
const htmlString = '<iframe id="stlite-iframe" width="100%" height="512px" src="about:blank"></iframe>';
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const iframe = doc.getElementById('stlite-iframe');
const div = document.getElementById('stliteDemoDiv');
div.appendChild(iframe);
const template = `{stlite_html_template.replace('STARTING_CODE', starting_app_code(demo_type))}`;
const frame = document.getElementById('stlite-iframe');
frame.contentWindow.document.open();
frame.contentWindow.document.write(template);
frame.contentWindow.document.close();
window.stliteLoaded = true;
}}"""
raise NotImplementedError(f'{demo_type} is not a supported demo type')
def update_iframe_js(demo_type: DemoType) -> str:
if demo_type == DemoType.GRADIO:
return f"""async (code, requirements) => {{
const formattedRequirements = requirements.split('\\n').filter(x => x && !x.startsWith('#')).map(x => x.trim());
let errorResult = null;
const attemptedRequirements = new Set();
const installedRequirements = [];
async function update() {{
// Remove existing stylesheet so it will be reloaded;
// see https://github.com/gradio-app/gradio/blob/200237d73c169f39514465efc163db756969d3ac/js/app/src/lite/css.ts#L41
const demoFrameWindow = document.getElementById('gradio-iframe').contentWindow;
const oldStyle = demoFrameWindow.document.querySelector("head style");
oldStyle.remove();
const appController = demoFrameWindow.window.appController;
const newCode = code + ` # Update tag ${{Math.random()}}`;
try {{
await appController.install(formattedRequirements);
await appController.run_code(newCode);
}}
catch (e) {{
// Replace old style if code error prevented new style from loading.
const newStyle = demoFrameWindow.document.querySelector("head style");
if (!newStyle) {{
demoFrameWindow.document.head.appendChild(oldStyle);
}}
// If the error is caused by a missing module try once to install it and update again.
if (e.toString().includes('ModuleNotFoundError')) {{
try {{
const guessedModuleName = e.toString().split("'")[1].replaceAll('_', '-');
if (attemptedRequirements.has(guessedModuleName)) {{
throw Error(`Could not install pyodide module ${{guessedModuleName}}`);
}}
console.log(`Attempting to install missing pyodide module "${{guessedModuleName}}"`);
attemptedRequirements.add(guessedModuleName);
await appController.install([guessedModuleName]);
installedRequirements.push(guessedModuleName);
return await update();
}}
catch (err) {{
console.log(err);
}}
}}
// Hide app so the error traceback is visible.
// First div in main is the error traceback, second is the app.
const appBody = demoFrameWindow.document.querySelectorAll("div.main > div")[1];
appBody.style.visibility = "hidden";
errorResult = e.toString();
const allRequirements = formattedRequirements.concat(installedRequirements);
console.log(allRequirements, errorResult);
return [allRequirements, errorResult];
}}
}};
await update();
const allRequirements = formattedRequirements.concat(installedRequirements);
// Update URL query params to include the current demo code state
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.set('requirements', allRequirements.join('\\n'));
currentUrl.searchParams.set('code', code);
// Replace the current URL with the updated one
history.replaceState({{}}, '', currentUrl.href);
return [allRequirements, errorResult];
}}"""
elif demo_type == DemoType.STREAMLIT:
return f"""async (code, requirements) => {{
async function update() {{
const appController = document.getElementById('stlite-iframe').contentWindow.window.appController;
const newCode = code + ` # Update tag ${{Math.random()}}`;
const entrypointFile = "streamlit_app.py";
appController.writeFile(entrypointFile, newCode);
}};
await update();
}}"""
raise NotImplementedError(f'{demo_type} is not a supported demo type')
def copy_share_link_js(demo_type: DemoType) -> str:
if demo_type == DemoType.GRADIO:
return f"""async () => {{
const shareLink = document.URL;
await navigator.clipboard.writeText(shareLink);
}}"""
raise NotImplementedError(f'{demo_type} is not a supported demo type')
def copy_snippet_js(demo_type: DemoType) -> str:
if demo_type == DemoType.GRADIO:
return f"""async (code, requirements) => {{
const escapedCode = code.replaceAll(String.fromCharCode(92), String.fromCharCode(92) + String.fromCharCode(92) + String.fromCharCode(92) + String.fromCharCode(92)).replaceAll('`', String.fromCharCode(92) + '`');
const template = `{gradio_lite_snippet_template}`;
// Step 1: Generate the HTML content
const completedTemplate = template.replace('STARTING_CODE', escapedCode).replace('STARTING_REQUIREMENTS', requirements);
const snippet = completedTemplate;
await navigator.clipboard.writeText(snippet);
return [code, requirements];
}}"""
elif demo_type == DemoType.STREAMLIT:
return f"""async (code) => {{
const escapedCode = code.replaceAll(String.fromCharCode(92), String.fromCharCode(92) + String.fromCharCode(92) + String.fromCharCode(92)).replaceAll('`', String.fromCharCode(92) + '`');
const template = `{stlite_snippet_template}`;
// Step 1: Generate the HTML content
const completedTemplate = template.replace('STARTING_CODE', code);
const snippet = completedTemplate;
await navigator.clipboard.writeText(snippet);
}}"""
raise NotImplementedError(f'{demo_type} is not a supported demo type')
def download_code_js(demo_type: DemoType) -> str:
if demo_type == demo_type.GRADIO:
return f"""(code, requirements) => {{
const escapedCode = code.replaceAll(String.fromCharCode(92), String.fromCharCode(92) + String.fromCharCode(92)).replaceAll('`', String.fromCharCode(92) + '`');
// Step 1: Generate the HTML content
const completedTemplate = `{gradio_lite_html_template}`.replace('STARTING_CODE', escapedCode).replace('STARTING_REQUIREMENTS', requirements);
// Step 2: Create a Blob from the HTML content
const blob = new Blob([completedTemplate], {{ type: "text/html" }});
// Step 3: Create a URL for the Blob
const url = URL.createObjectURL(blob);
// Step 4: Create a download link
const downloadLink = document.createElement("a");
downloadLink.href = url;
downloadLink.download = "gradio-lite-app.html"; // Specify the filename for the download
// Step 5: Trigger a click event on the download link
downloadLink.click();
// Clean up by revoking the URL
URL.revokeObjectURL(url);
}}"""
elif demo_type == demo_type.STREAMLIT:
return f"""(code) => {{
const escapedCode = code.replaceAll(String.fromCharCode(92), String.fromCharCode(92) + String.fromCharCode(92)).replaceAll('`', String.fromCharCode(92) + '`');
// Step 1: Generate the HTML content
const completedTemplate = `{stlite_html_template}`.replace('STARTING_CODE', escapedCode);
// Step 2: Create a Blob from the HTML content
const blob = new Blob([completedTemplate], {{ type: "text/html" }});
// Step 3: Create a URL for the Blob
const url = URL.createObjectURL(blob);
// Step 4: Create a download link
const downloadLink = document.createElement("a");
downloadLink.href = url;
downloadLink.download = "stlite-app.html"; // Specify the filename for the download
// Step 5: Trigger a click event on the download link
downloadLink.click();
// Clean up by revoking the URL
URL.revokeObjectURL(url);
}}"""
raise NotImplementedError(f'{demo_type} is not a supported demo type')
|