import React, { useRef, useEffect, useState, ChangeEvent, FormEvent } from "react"; import { Message, useChat } from "ai/react"; import { useAppDispatch, useAppSelector } from "../../store/hook"; import { compiler_state, initEsbuild, } from "../../store/features/compilerSlice"; import { editor_state, set_monaco_input_value, update_editor_code } from "../../store/features/editorSlice"; import { theme_state } from "../../store/features/themeSlice"; import { ModalEnum, open_modal } from "../../store/features/modalSlice"; import ConsoleLog from "./ConsoleLog"; import Iframe from "./Iframe"; import InputCodeTab from "./InputCodeTab"; import Footer from "./Footer"; import Pane from "./Pane"; import { SendIcon } from "../../constants/icon"; import ReactMarkdown from "react-markdown"; import { ChatRequestOptions } from "ai"; const DEFAULT_PROMPT = `You are assisting in a WASM-powered live editor, Codetree, where React code is instantly reflected in the browser. Generate React code with the following constraints: 1. Always import both React and ReactDOM. 2. All logic should be encapsulated within a single app component file. 3. Always use inline styles for styling. 4. Code snippets should conclude with rendering to the DOM's root element: ReactDOM.render(, document.getElementById('root')); 5. Ensure the code is optimized for a live browser environment and adheres strictly to React best practices. Write the code with the above guidelines in mind.`; const Playground = () => { const dispatch = useAppDispatch(); const formRef = useRef(null); const inputRef = useRef(null); const { theme } = useAppSelector(theme_state); const { esbuildStatus, isCompiling, output } = useAppSelector(compiler_state); const { logs, editorValue, isLogTabOpen } = useAppSelector(editor_state); const [markdownCode, setMarkdownCode] = useState(''); const [prevMarkdownCode, setPrevMarkdownCode] = useState(markdownCode); const [isSystemInputVisible, setSystemInputVisible] = useState(false); const [isModelInputVisible, setModelInputVisible] = useState(false); const [aiProvider, setAIProvider] = useState("openai"); const [urlOption, setUrlOption] = useState(null); const [isChatVisible, setIsChatVisible] = useState(true); const [systemMessage, setSystemMessage] = useState( DEFAULT_PROMPT ); const isValidCodeBlock = (markdownCode: string) => { return markdownCode && markdownCode.length > 10 && markdownCode.includes('\n'); } const modifiedHandleSubmit = async (e: FormEvent, chatRequestOptions?: ChatRequestOptions) => { e.preventDefault(); await handleSubmit(e, { ...chatRequestOptions, aiProvider, } as any); }; useEffect(() => { const timer = setInterval(() => { if (isValidCodeBlock(markdownCode) && markdownCode !== prevMarkdownCode) { dispatch(update_editor_code({ type: 'javascript', content: markdownCode })); setPrevMarkdownCode(markdownCode); } }, 2000); return () => { clearInterval(timer); }; }, [markdownCode, prevMarkdownCode, dispatch]); const { append, messages, input, setInput, handleSubmit, ...rest } = useChat({ body: { systemMessage: systemMessage, aiProvider: aiProvider, url: urlOption }, onError: (error) => { console.error(error); }, }); useEffect(() => { if (!esbuildStatus.isReady) { dispatch(initEsbuild()); } }, [dispatch, esbuildStatus]); useEffect(() => { dispatch(open_modal(ModalEnum.TEMPLATE)); }, [dispatch]); useEffect(() => { if(isValidCodeBlock(markdownCode)) { const newEditorValue = { name: "React", description: "By codetree", public: true, iconSrc: "/icons/reactjs.svg", tabs: { javascript: { title: "JS/JSX", entryPoints: "index.js", monacoLanguage: "javascript", data: markdownCode }, html: { title: "index.html", entryPoints: "index.html", monacoLanguage: "html", data: "" }, css: { title: "main.css", entryPoints: "main.css", monacoLanguage: "css", data: "" } } }; dispatch(set_monaco_input_value(newEditorValue as any)); } }, [markdownCode, dispatch]); return (
System Prompt Model Chat {isSystemInputVisible && (