add support for React
This commit is contained in:
parent
4685ca5f0e
commit
dfe8ae4164
@ -70,9 +70,11 @@ async def stream_code(websocket: WebSocket):
|
|||||||
print("Received params")
|
print("Received params")
|
||||||
|
|
||||||
# Read the output settings from the request. Fall back to default if not provided.
|
# Read the output settings from the request. Fall back to default if not provided.
|
||||||
output_settings = {"css": "tailwind"}
|
output_settings = {"css": "tailwind", "js": "vanilla"}
|
||||||
if params["outputSettings"] and params["outputSettings"]["css"]:
|
if params["outputSettings"] and params["outputSettings"]["css"]:
|
||||||
output_settings["css"] = params["outputSettings"]["css"]
|
output_settings["css"] = params["outputSettings"]["css"]
|
||||||
|
if params["outputSettings"] and params["outputSettings"]["js"]:
|
||||||
|
output_settings["js"] = params["outputSettings"]["js"]
|
||||||
print("Using output settings:", output_settings)
|
print("Using output settings:", output_settings)
|
||||||
|
|
||||||
# Get the OpenAI API key from the request. Fall back to environment variable if not provided.
|
# Get the OpenAI API key from the request. Fall back to environment variable if not provided.
|
||||||
|
|||||||
@ -48,6 +48,35 @@ Return only the full code in <html></html> tags.
|
|||||||
Do not include markdown "```" or "```html" at the start or end.
|
Do not include markdown "```" or "```html" at the start or end.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
REACT_TAILWIND_SYSTEM_PROMPT = """
|
||||||
|
You are an expert React/Tailwind developer
|
||||||
|
You take screenshots of a reference web page from the user, and then build single page apps
|
||||||
|
using React and Tailwind CSS.
|
||||||
|
You might also be given a screenshot(The second image) of a web page that you have already built, and asked to
|
||||||
|
update it to look more like the reference image(The first image).
|
||||||
|
|
||||||
|
- Make sure the app looks exactly like the screenshot.
|
||||||
|
- Pay close attention to background color, text color, font size, font family,
|
||||||
|
padding, margin, border, etc. Match the colors and sizes exactly.
|
||||||
|
- Use the exact text from the screenshot.
|
||||||
|
- Do not add comments in the code such as "<!-- Add other navigation links as needed -->" and "<!-- ... other news items ... -->" in place of writing the full code. WRITE THE FULL CODE.
|
||||||
|
- Repeat elements as needed to match the screenshot. For example, if there are 15 items, the code should have 15 items. DO NOT LEAVE comments like "<!-- Repeat for each news item -->" or bad things will happen.
|
||||||
|
- For images, use placeholder images from https://placehold.co and include a detailed description of the image in the alt text so that an image generation AI can generate the image later.
|
||||||
|
|
||||||
|
In terms of libraries,
|
||||||
|
|
||||||
|
- Use these script to include React so that it can run on a standalone page:
|
||||||
|
<script src="https://unpkg.com/react/umd/react.development.js"></script>
|
||||||
|
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
|
||||||
|
<script src="https://unpkg.com/@babel/standalone/babel.js"></script>
|
||||||
|
- Use this script to include Tailwind: <script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
- You can use Google Fonts
|
||||||
|
- Font Awesome for icons: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"></link>
|
||||||
|
|
||||||
|
Return only the full code in <html></html> tags.
|
||||||
|
Do not include markdown "```" or "```html" at the start or end.
|
||||||
|
"""
|
||||||
|
|
||||||
USER_PROMPT = """
|
USER_PROMPT = """
|
||||||
Generate code for a web page that looks exactly like this.
|
Generate code for a web page that looks exactly like this.
|
||||||
"""
|
"""
|
||||||
@ -58,6 +87,8 @@ def assemble_prompt(image_data_url, output_settings: dict, result_image_data_url
|
|||||||
system_content = TAILWIND_SYSTEM_PROMPT
|
system_content = TAILWIND_SYSTEM_PROMPT
|
||||||
if output_settings["css"] == "bootstrap":
|
if output_settings["css"] == "bootstrap":
|
||||||
system_content = BOOTSTRAP_SYSTEM_PROMPT
|
system_content = BOOTSTRAP_SYSTEM_PROMPT
|
||||||
|
if output_settings["js"] == "react":
|
||||||
|
system_content = REACT_TAILWIND_SYSTEM_PROMPT
|
||||||
|
|
||||||
user_content = [
|
user_content = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -50,14 +50,48 @@ Return only the full code in <html></html> tags.
|
|||||||
Do not include markdown "```" or "```html" at the start or end.
|
Do not include markdown "```" or "```html" at the start or end.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
REACT_TAILWIND_SYSTEM_PROMPT = """
|
||||||
|
You are an expert React/Tailwind developer
|
||||||
|
You take screenshots of a reference web page from the user, and then build single page apps
|
||||||
|
using React and Tailwind CSS.
|
||||||
|
You might also be given a screenshot(The second image) of a web page that you have already built, and asked to
|
||||||
|
update it to look more like the reference image(The first image).
|
||||||
|
|
||||||
|
- Make sure the app looks exactly like the screenshot.
|
||||||
|
- Pay close attention to background color, text color, font size, font family,
|
||||||
|
padding, margin, border, etc. Match the colors and sizes exactly.
|
||||||
|
- Use the exact text from the screenshot.
|
||||||
|
- Do not add comments in the code such as "<!-- Add other navigation links as needed -->" and "<!-- ... other news items ... -->" in place of writing the full code. WRITE THE FULL CODE.
|
||||||
|
- Repeat elements as needed to match the screenshot. For example, if there are 15 items, the code should have 15 items. DO NOT LEAVE comments like "<!-- Repeat for each news item -->" or bad things will happen.
|
||||||
|
- For images, use placeholder images from https://placehold.co and include a detailed description of the image in the alt text so that an image generation AI can generate the image later.
|
||||||
|
|
||||||
|
In terms of libraries,
|
||||||
|
|
||||||
|
- Use these script to include React so that it can run on a standalone page:
|
||||||
|
<script src="https://unpkg.com/react/umd/react.development.js"></script>
|
||||||
|
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
|
||||||
|
<script src="https://unpkg.com/@babel/standalone/babel.js"></script>
|
||||||
|
- Use this script to include Tailwind: <script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
- You can use Google Fonts
|
||||||
|
- Font Awesome for icons: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"></link>
|
||||||
|
|
||||||
|
Return only the full code in <html></html> tags.
|
||||||
|
Do not include markdown "```" or "```html" at the start or end.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def test_prompts():
|
def test_prompts():
|
||||||
tailwind_prompt = assemble_prompt(
|
tailwind_prompt = assemble_prompt(
|
||||||
"image_data_url", {"css": "tailwind"}, "result_image_data_url"
|
"image_data_url", {"css": "tailwind", "js": "vanilla"}, "result_image_data_url"
|
||||||
)
|
)
|
||||||
assert tailwind_prompt[0]["content"] == TAILWIND_SYSTEM_PROMPT
|
assert tailwind_prompt[0]["content"] == TAILWIND_SYSTEM_PROMPT
|
||||||
|
|
||||||
bootstrap_prompt = assemble_prompt(
|
bootstrap_prompt = assemble_prompt(
|
||||||
"image_data_url", {"css": "bootstrap"}, "result_image_data_url"
|
"image_data_url", {"css": "bootstrap", "js": "vanilla"}, "result_image_data_url"
|
||||||
)
|
)
|
||||||
assert bootstrap_prompt[0]["content"] == BOOTSTRAP_SYSTEM_PROMPT
|
assert bootstrap_prompt[0]["content"] == BOOTSTRAP_SYSTEM_PROMPT
|
||||||
|
|
||||||
|
react_tailwind_prompt = assemble_prompt(
|
||||||
|
"image_data_url", {"css": "tailwind", "js": "react"}, "result_image_data_url"
|
||||||
|
)
|
||||||
|
assert react_tailwind_prompt[0]["content"] == REACT_TAILWIND_SYSTEM_PROMPT
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import {
|
|||||||
AppState,
|
AppState,
|
||||||
CSSOption,
|
CSSOption,
|
||||||
OutputSettings,
|
OutputSettings,
|
||||||
|
JSFrameworkOption,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import { IS_RUNNING_ON_CLOUD } from "./config";
|
import { IS_RUNNING_ON_CLOUD } from "./config";
|
||||||
import { PicoBadge } from "./components/PicoBadge";
|
import { PicoBadge } from "./components/PicoBadge";
|
||||||
@ -55,6 +56,7 @@ function App() {
|
|||||||
);
|
);
|
||||||
const [outputSettings, setOutputSettings] = useState<OutputSettings>({
|
const [outputSettings, setOutputSettings] = useState<OutputSettings>({
|
||||||
css: CSSOption.TAILWIND,
|
css: CSSOption.TAILWIND,
|
||||||
|
js: JSFrameworkOption.VANILLA,
|
||||||
});
|
});
|
||||||
const [shouldIncludeResultImage, setShouldIncludeResultImage] =
|
const [shouldIncludeResultImage, setShouldIncludeResultImage] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
|
|||||||
@ -5,13 +5,15 @@ import {
|
|||||||
SelectItem,
|
SelectItem,
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
} from "./ui/select";
|
} from "./ui/select";
|
||||||
import { CSSOption, OutputSettings } from "../types";
|
import { CSSOption, JSFrameworkOption, OutputSettings } from "../types";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
AccordionItem,
|
AccordionItem,
|
||||||
AccordionTrigger,
|
AccordionTrigger,
|
||||||
} from "./ui/accordion";
|
} from "./ui/accordion";
|
||||||
|
import { capitalize } from "../lib/utils";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
function displayCSSOption(option: CSSOption) {
|
function displayCSSOption(option: CSSOption) {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
@ -37,25 +39,53 @@ function convertStringToCSSOption(option: string) {
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
outputSettings: OutputSettings;
|
outputSettings: OutputSettings;
|
||||||
setOutputSettings: (outputSettings: OutputSettings) => void;
|
setOutputSettings: React.Dispatch<React.SetStateAction<OutputSettings>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function OutputSettingsSection({ outputSettings, setOutputSettings }: Props) {
|
function OutputSettingsSection({ outputSettings, setOutputSettings }: Props) {
|
||||||
|
const onCSSValueChange = (value: string) => {
|
||||||
|
setOutputSettings((prev) => {
|
||||||
|
if (prev.js === JSFrameworkOption.REACT) {
|
||||||
|
if (value !== CSSOption.TAILWIND) {
|
||||||
|
toast.error(
|
||||||
|
"React only supports Tailwind CSS. Change JS framework to Vanilla to use Bootstrap."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
css: CSSOption.TAILWIND,
|
||||||
|
js: JSFrameworkOption.REACT,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
css: convertStringToCSSOption(value),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onJsFrameworkChange = (value: string) => {
|
||||||
|
if (value === JSFrameworkOption.REACT) {
|
||||||
|
setOutputSettings(() => ({
|
||||||
|
css: CSSOption.TAILWIND,
|
||||||
|
js: value as JSFrameworkOption,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
setOutputSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
js: value as JSFrameworkOption,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion type="single" collapsible className="w-full">
|
<Accordion type="single" collapsible className="w-full">
|
||||||
<AccordionItem value="item-1">
|
<AccordionItem value="item-1">
|
||||||
<AccordionTrigger>Output Settings</AccordionTrigger>
|
<AccordionTrigger>Output Settings</AccordionTrigger>
|
||||||
<AccordionContent>
|
<AccordionContent className="gap-y-2 flex flex-col pt-2">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center pr-2">
|
||||||
<span className="text-sm">CSS</span>
|
<span className="text-sm">CSS</span>
|
||||||
<Select
|
<Select value={outputSettings.css} onValueChange={onCSSValueChange}>
|
||||||
value={outputSettings.css}
|
|
||||||
onValueChange={(value) =>
|
|
||||||
setOutputSettings({
|
|
||||||
css: convertStringToCSSOption(value),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-[180px]">
|
<SelectTrigger className="w-[180px]">
|
||||||
{displayCSSOption(outputSettings.css)}
|
{displayCSSOption(outputSettings.css)}
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
@ -67,6 +97,25 @@ function OutputSettingsSection({ outputSettings, setOutputSettings }: Props) {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex justify-between items-center pr-2">
|
||||||
|
<span className="text-sm">JS Framework</span>
|
||||||
|
<Select
|
||||||
|
value={outputSettings.js}
|
||||||
|
onValueChange={onJsFrameworkChange}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
{capitalize(outputSettings.js)}
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectItem value={JSFrameworkOption.VANILLA}>
|
||||||
|
Vanilla
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={JSFrameworkOption.REACT}>React</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
|||||||
@ -8,8 +8,15 @@ export enum CSSOption {
|
|||||||
BOOTSTRAP = "bootstrap",
|
BOOTSTRAP = "bootstrap",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum JSFrameworkOption {
|
||||||
|
VANILLA = "vanilla",
|
||||||
|
REACT = "react",
|
||||||
|
VUE = "vue",
|
||||||
|
}
|
||||||
|
|
||||||
export interface OutputSettings {
|
export interface OutputSettings {
|
||||||
css: CSSOption;
|
css: CSSOption;
|
||||||
|
js: JSFrameworkOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Settings {
|
export interface Settings {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user