KiteWind / app.py
gstaff's picture
Add initial app files.
bc91045
raw
history blame
No virus
7.63 kB
import os
from pathlib import Path
import gradio as gr
import re
import whisper
import requests
HF_TOKEN = os.getenv("HF_TOKEN")
API_URL = "https://api-inference.huggingface.co/models/HuggingFaceH4/zephyr-7b-beta"
headers = {"Authorization": f"Bearer {HF_TOKEN}"}
code_pattern = r'```python\n(.*?)```'
starting_app_code = """import gradio as gr
def greet(name):
return "Hello " + name + "!"
with gr.Blocks(theme="monochrome") as demo:
name = gr.Textbox(label="Name", value="World")
output = gr.Textbox(label="Output Box")
greet_btn = gr.Button("Greet")
greet_btn.click(fn=greet, inputs=name, outputs=output)
name.submit(fn=greet, inputs=name, outputs=output)
if __name__ == "__main__":
demo.css = "footer {visibility: hidden}"
demo.launch()
"""
html_template = Path('gradio-lite-playground.html').read_text()
pattern = r"# APP CODE START(.*?)# APP CODE END"
load_js = f"""() => {{
const htmlString = '<iframe class="my-frame" width="100%" height="512px" src="about:blank"></iframe>';
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const iframe = doc.querySelector('.my-frame');
const div = document.getElementById('demoDiv');
div.appendChild(iframe);
const frame = document.querySelector('.my-frame');
frame.contentWindow.document.open('text/html', 'replace');
frame.contentWindow.document.write(`{html_template}`);
frame.contentWindow.document.close();
}}"""
# TODO: Works but is inefficient because the iframe has to be reloaded each time
update_iframe_js = f"""(code) => {{
console.log(`UPDATING CODE`);
console.log(code)
const pattern = /# APP CODE START(.*?)# APP CODE END/gs;
const template = `{html_template}`;
const completedTemplate = template.replace(pattern, code);
console.log(completedTemplate);
const oldFrame = document.querySelector('.my-frame');
oldFrame.remove();
const htmlString = '<iframe class="my-frame" width="100%" height="512px" src="about:blank"></iframe>';
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const iframe = doc.querySelector('.my-frame');
const div = document.getElementById('demoDiv');
div.appendChild(iframe);
const frame = document.querySelector('.my-frame');
frame.contentWindow.document.open('text/html', 'replace');
frame.contentWindow.document.write(completedTemplate);
frame.contentWindow.document.close();
console.log(`UPDATE DONE`);
}}"""
copy_snippet_js = f"""async (code) => {{
console.log(`DOWNLOADING CODE`);
const pattern = /# APP CODE START(.*?)# APP CODE END/gs;
const template = `<div id="KiteWindApp">\n<script type="module" crossorigin src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css" />
<gradio-lite>\n# APP CODE START\n\n# APP CODE END\n</gradio-lite>\n</div>\n`;
// Step 1: Generate the HTML content
const completedTemplate = template.replace(pattern, code);
const snippet = completedTemplate;
console.log(snippet);
await navigator.clipboard.writeText(snippet);
console.log(`COPY DONE`);
}}"""
download_code_js = f"""(code) => {{
console.log(`DOWNLOADING CODE`);
const pattern = /# APP CODE START(.*?)# APP CODE END/gs;
const template = `{html_template}`;
// Step 1: Generate the HTML content
const completedTemplate = template.replace(pattern, code);
// 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);
console.log(`DOWNLOAD DONE`);
}}"""
def query(payload):
response = requests.post(API_URL, headers=headers, json=payload)
return response.json()
def generate_text(code, prompt):
print(f"Calling API with prompt:\n{prompt}")
prompt = f"```python\n{code}```\nGiven the code above return only updated code for the following request:\n{prompt}\n<|assistant|>"
params = {"max_new_tokens": 512}
output = query({
"inputs": prompt,
"parameters": params,
})
print(f'API RESPONSE\n{output[0]["generated_text"]}')
assistant_reply = output[0]["generated_text"].split('<|assistant|>')[1]
match = re.search(code_pattern, assistant_reply, re.DOTALL)
new_code = match.group(1)
print(new_code)
# TODO: error handling here
return assistant_reply, new_code
model = whisper.load_model('medium')
def transcribe(audio):
result = model.transcribe(audio, language='en', verbose=False)
return result["text"]
with gr.Blocks() as demo:
gr.Markdown("<h1 align=\"center\">KiteWind πŸͺπŸƒ</h1>")
gr.Markdown("<h4 align=\"center\">Chat-assisted web app creator by <a href=\"https://huggingface.co/gstaff\">@gstaff</a></h4>")
with gr.Row():
with gr.Column():
gr.Markdown("## 1. Run your app in the browser!")
html = gr.HTML(value='<div id="demoDiv"></div>')
gr.Markdown("## 2. Customize using voice requests!")
with gr.Row():
with gr.Column():
with gr.Group():
in_audio = gr.Audio(label="Record a voice request", source='microphone', type='filepath')
in_prompt = gr.Textbox(label="Or type a text request and press Enter",
placeholder="Need an idea? Try one of these:\n- Add a button to reverse the name\n- Change the greeting to Hola\n- Put the reversed name output into a separate textbox\n- Change the theme from monochrome to soft")
out_text = gr.TextArea(label="Chat Assistant Response")
clear = gr.ClearButton([in_prompt, in_audio, out_text])
with gr.Column():
code_area = gr.Code(label="App Code - You can also edit directly and then click Update App", language='python', value=starting_app_code)
update_btn = gr.Button("Update App", variant="primary")
update_btn.click(None, inputs=code_area, outputs=None, _js=update_iframe_js)
in_prompt.submit(generate_text, [code_area, in_prompt], [out_text, code_area]).then(None, inputs=code_area, outputs=None, _js=update_iframe_js)
in_audio.stop_recording(transcribe, [in_audio], [in_prompt]).then(generate_text, [code_area, in_prompt], [out_text, code_area]).then(None, inputs=code_area, outputs=None, _js=update_iframe_js)
with gr.Row():
with gr.Column():
gr.Markdown("## 3. Export your app to share!")
copy_snippet_btn = gr.Button("Copy app snippet to paste in another page")
copy_snippet_btn.click(None, code_area, None, _js=copy_snippet_js)
download_btn = gr.Button("Download app as a standalone file")
download_btn.click(None, code_area, None, _js=download_code_js)
with gr.Row():
with gr.Column():
gr.Markdown("## Current limitations")
with gr.Accordion("Click to view", open=False):
gr.Markdown("- Only gradio-lite apps using the python standard libraries and gradio are supported\n- The chat hasn't been tuned on gradio library data; it may make mistakes\n- The app needs to fully reload each time it is changed")
demo.load(None, None, None, _js=load_js)
demo.css = "footer {visibility: hidden}"
if __name__ == "__main__":
demo.queue().launch()