{"id":14534,"date":"2025-09-30T15:59:42","date_gmt":"2025-09-30T12:59:42","guid":{"rendered":"https:\/\/dhtmlx.com\/blog\/?p=14534"},"modified":"2025-09-30T16:59:46","modified_gmt":"2025-09-30T13:59:46","slug":"how-to-build-an-ai-powered-form-builder-with-dhtmlx","status":"publish","type":"post","link":"https:\/\/dhtmlx.com\/blog\/how-to-build-an-ai-powered-form-builder-with-dhtmlx\/","title":{"rendered":"How to Build an AI-Powered Form Builder with DHTMLX"},"content":{"rendered":"<p>Modern web applications commonly come with the capabilities to collect, validate, and process user data on-the-fly. This functional arsenal is implemented via dynamic forms that serve as comminitation channels between users and apps. Despite the widespread use of forms, it is often a tricky task to create this UI element and tailor it to a specific workflow. That\u2019s where <a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxForm\/\" rel=\"noopener\" target=\"_blank\">DHTMLX JavaScript Form<\/a> usually comes to the rescue. This widget from our Suite library is equipped with a range of controls for configuring forms of any scale and complexity. But there is always a room for improvement. What if you could simply describe the form in plain text and see it generated instantly, ready for use and further editing?<\/p>\n<p>In this tutorial, you will learn how to build an AI-powered application that transforms natural language descriptions into fully functional web forms by combining the DHTMLX Form widget with the OpenAI API.<\/p>\n<h2>Understanding the App\u2019s Architecture and UI<\/h2>\n<p>Before we dive into coding, let\u2019s take a quick look at how the app is structured. This will help you understand how the frontend, backend, and AI service interact to generate forms dynamically. We\u2019ll also walk through the user interface layout so you know what the final result should look like and how each part contributes to the workflow.<\/p>\n<p>The app\u2019s architecture includes 3 main parts:<\/p>\n<ol>\n<li><strong>Frontend<\/strong> &#8211; relies on DHTMLX widgets to build the interface, <a href=\"https:\/\/socket.io\/\" rel=\"noopener\" target=\"_blank\">Socket.IO<\/a> to communicate with the backend, and the <a href=\"https:\/\/github.com\/microsoft\/monaco-editor\" rel=\"noopener\" target=\"_blank\">Monaco Editor<\/a> to provide a code editor for viewing and modifying the AI-generated JSON configuration.<\/li>\n<li><strong>Backend<\/strong> &#8211; based on the Node.js server with Express and Socket.IO that brokers communication between the frontend and the AI service.<\/li>\n<li><strong>AI Service<\/strong> &#8211; employs an OpenAI-compatible API that processes user prompts and returns structured JSON describing the form layout.<\/li>\n<\/ol>\n<p>To follow along, you\u2019ll need Node.js installed and an API key from OpenAI (or another API-compatible provider).<\/p>\n<p>Our objective is to build an application with the following UI sections:<\/p>\n<ul>\n<li><strong>Control Panel<\/strong> (left side): contains the Prompt Interface (a textarea for describing the desired form, along with suggestions and a &#8220;Generate Form&#8221; button).<\/li>\n<li><strong>Output Panel<\/strong> (right side): displays the Live Preview at the top, showing the generated form, and the Code View underneath, where the JSON configuration is shown. From here, you can update the code, re-render the form, or copy the configuration.<\/li>\n<\/ul>\n<p>Here\u2019s a quick preview of what the final app looks like:<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2025\/09\/2025-09-30_11-08-05.gif\" alt=\"generating forms with AI and DHTMLX\" width=\"1764\" height=\"812\" class=\"aligncenter size-full wp-image-14536\" \/><a href=\"https:\/\/docs.dhtmlx.com\/docs\/demo\/form-builder-ai\/\" rel=\"noopener\" target=\"_blank\">Open live demo ><\/a><\/p>\n<p><em><strong>Please note:<\/strong> This tutorial focuses on the core logic of connecting the DHTMLX Form widget with an AI service. For simplicity, the HTML structure and CSS styling have been kept minimal. The complete, fully styled source code for the final application is available on <a href=\"https:\/\/github.com\/DHTMLX\/form-builder-ai-demo\" rel=\"noopener\" target=\"_blank\">GitHub<\/a>.<\/em><\/p>\n<p>Let&#8217;s dive into how it&#8217;s built.<\/p>\n<h2>Step 1: Setting Up the Frontend with DHTMLX<\/h2>\n<p>Let\u2019s start by putting together the web page. You need an HTML file (<a href=\"https:\/\/github.com\/DHTMLX\/form-builder-ai-demo\/blob\/main\/frontend\/index.html\" rel=\"noopener\" target=\"_blank\">index.html<\/a>) to define the structure and a JavaScript file (<a href=\"https:\/\/github.com\/DHTMLX\/form-builder-ai-demo\/blob\/main\/frontend\/app.js\" rel=\"noopener\" target=\"_blank\">app.js<\/a>) for the logic.<\/p>\n<p>The HTML file needs containers for four main UI sections: the control panel, prompt suggestions, the form preview, and the JSON editor.<\/p>\n<div class=\"codecolorer-container html4strict default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"html4strict codecolorer\"><span class=\"sc0\">&lt;!DOCTYPE html&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"kw2\">html<\/span>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"kw2\">head<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">title<\/span>&gt;<\/span>DHTMLX Form + AI Generation<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">title<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">link<\/span> <span class=\"kw3\">rel<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;stylesheet&quot;<\/span> <span class=\"kw3\">href<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;https:\/\/cdn.dhtmlx.com\/suite\/edge\/suite.css&quot;<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">script<\/span> <span class=\"kw3\">src<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;https:\/\/cdn.dhtmlx.com\/suite\/edge\/suite.js&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">script<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">script<\/span> <span class=\"kw3\">src<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;\/socket.io\/socket.io.js&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">script<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc-1\">&lt;!-- Monaco Editor for the JSON view --&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">script<\/span> <span class=\"kw3\">src<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;https:\/\/cdn.jsdelivr.net\/npm\/monaco-editor@0.34.1\/min\/vs\/loader.js&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">script<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">link<\/span> <span class=\"kw3\">rel<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;stylesheet&quot;<\/span> <span class=\"kw3\">href<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;style.css&quot;<\/span>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">head<\/span>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"kw2\">body<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">h1<\/span>&gt;<\/span>AI Form Generator<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">h1<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">div<\/span> <span class=\"kw3\">id<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;prompt-container&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">div<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">div<\/span> <span class=\"kw3\">id<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;suggestions-pills&quot;<\/span> <span class=\"kw3\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;suggestions-container&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">div<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">div<\/span> <span class=\"kw3\">id<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;form-preview-container&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">div<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">div<\/span> <span class=\"kw3\">id<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;json-editor-container&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">div<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">script<\/span> <span class=\"kw3\">src<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;app.js&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">script<\/span>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">body<\/span>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">html<\/span>&gt;<\/span><\/div><\/div>\n<p>Next, in app.js, you initialize the control panel, the prompt suggestions, and the Monaco Editor. This gets the entire UI ready before you start adding the AI logic.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;height:600px;\"><div class=\"javascript codecolorer\">document.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;DOMContentLoaded&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ --- Global variables ---<\/span><br \/>\n&nbsp; &nbsp; let generatedForm <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; let jsonEditor <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ --- DHTMLX Widgets Initialization ---<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> controlForm <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> dhx.<span class=\"me1\">Form<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;prompt-container&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; rows<span class=\"sy0\">:<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> type<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;textarea&quot;<\/span><span class=\"sy0\">,<\/span> name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;prompt&quot;<\/span><span class=\"sy0\">,<\/span> placeholder<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Describe your form...&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> type<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;button&quot;<\/span><span class=\"sy0\">,<\/span> name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;generate&quot;<\/span><span class=\"sy0\">,<\/span> text<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;\u2728 Generate Form&quot;<\/span> <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#93;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ --- Prompt Suggestions Logic ---<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> promptSuggestions <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">&quot;row: input, selectbox, selectbox&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">&quot;name, email, message textarea, submit button&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">&quot;row 1: input, selectbox<span class=\"es0\">\\n<\/span>row 2: datepicker, colorpicker&quot;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> suggestionsContainer <span class=\"sy0\">=<\/span> document.<span class=\"me1\">getElementById<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;suggestions-pills&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; promptSuggestions.<span class=\"me1\">forEach<\/span><span class=\"br0\">&#40;<\/span>promptText <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> pill <span class=\"sy0\">=<\/span> document.<span class=\"me1\">createElement<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'button'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; pill.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'prompt-pill'<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; pill.<span class=\"me1\">textContent<\/span> <span class=\"sy0\">=<\/span> promptText<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; pill.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'click'<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; controlForm.<span class=\"me1\">getItem<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;prompt&quot;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">setValue<\/span><span class=\"br0\">&#40;<\/span>promptText<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; suggestionsContainer.<span class=\"me1\">appendChild<\/span><span class=\"br0\">&#40;<\/span>pill<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ --- Monaco Editor Initialization ---<\/span><br \/>\n&nbsp; &nbsp; require.<span class=\"me1\">config<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span> paths<span class=\"sy0\">:<\/span> <span class=\"br0\">&#123;<\/span> <span class=\"st0\">'vs'<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">'https:\/\/cdn.jsdelivr.net\/npm\/monaco-editor@0.34.1\/min\/vs'<\/span> <span class=\"br0\">&#125;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; require<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#91;<\/span><span class=\"st0\">'vs\/editor\/editor.main'<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; jsonEditor <span class=\"sy0\">=<\/span> monaco.<span class=\"me1\">editor<\/span>.<span class=\"me1\">create<\/span><span class=\"br0\">&#40;<\/span>document.<span class=\"me1\">getElementById<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;json-editor-container&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value<span class=\"sy0\">:<\/span> JSON.<span class=\"me1\">stringify<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span> message<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Your generated form config will appear here...&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">4<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> language<span class=\"sy0\">:<\/span> <span class=\"st0\">'json'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; theme<span class=\"sy0\">:<\/span> <span class=\"st0\">'vs-dark'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; automaticLayout<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; readOnly<span class=\"sy0\">:<\/span> <span class=\"kw2\">false<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ More logic will follow in the next steps<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>At this point, the complete UI is rendered, but it doesn&#8217;t do anything yet. The form preview and JSON editor are empty placeholders. In the next step, you\u2019ll bring it to life by connecting it to our AI backend.<\/p>\n<h2>Step 2: Interfacing with the AI<\/h2>\n<p>Now that the UI is ready, it is time to make it work. When a user clicks the &#8220;Generate Form&#8221; button, you need to send their text description to the backend. The backend will forward it to the AI, and upon receiving the response, the form preview and the JSON editor will be populated with data.<\/p>\n<p>The Socket.IO library is perfect for this, as it keeps a persistent connection open for real-time communication.<\/p>\n<p>Here\u2019s the logic to add to app.js inside the <strong>DOMContentLoaded<\/strong> event listener:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"co1\">\/\/ Connect to the backend<\/span><br \/>\n<span class=\"kw1\">const<\/span> socket <span class=\"sy0\">=<\/span> io<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> generateButton <span class=\"sy0\">=<\/span> controlForm.<span class=\"me1\">getItem<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;generate&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"co1\">\/\/ Handle the Generate button click<\/span><br \/>\ngenerateButton.<span class=\"me1\">events<\/span>.<span class=\"me1\">on<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'click'<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> userRequest <span class=\"sy0\">=<\/span> controlForm.<span class=\"me1\">getValue<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">prompt<\/span>.<span class=\"me1\">trim<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>userRequest<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span> <span class=\"coMULTI\">\/* ... error handling ... *\/<\/span> <span class=\"kw1\">return<\/span><span class=\"sy0\">;<\/span> <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ ... show loader and disable button ...<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ Clean up any previously generated form<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>generatedForm<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; generatedForm.<span class=\"me1\">destructor<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; generatedForm <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ Send the prompt to the backend<\/span><br \/>\n&nbsp; &nbsp; socket.<span class=\"me1\">emit<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'generate_form'<\/span><span class=\"sy0\">,<\/span> userRequest<span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span>response<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ ... hide loader and enable button ...<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>response.<span class=\"me1\">success<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">try<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> formConfig <span class=\"sy0\">=<\/span> JSON.<span class=\"me1\">parse<\/span><span class=\"br0\">&#40;<\/span>response.<span class=\"me1\">json<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> prettyJson <span class=\"sy0\">=<\/span> JSON.<span class=\"me1\">stringify<\/span><span class=\"br0\">&#40;<\/span>formConfig<span class=\"sy0\">,<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">4<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Update the JSON editor<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>jsonEditor<span class=\"br0\">&#41;<\/span> jsonEditor.<span class=\"me1\">setValue<\/span><span class=\"br0\">&#40;<\/span>prettyJson<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Render the generated form in the preview panel<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; generatedForm <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> dhx.<span class=\"me1\">Form<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;form-preview-container&quot;<\/span><span class=\"sy0\">,<\/span> formConfig<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span> <span class=\"kw1\">catch<\/span> <span class=\"br0\">&#40;<\/span>e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span> <span class=\"coMULTI\">\/* ... error handling ... *\/<\/span> <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span> <span class=\"kw1\">else<\/span> <span class=\"br0\">&#123;<\/span> <span class=\"coMULTI\">\/* ... error handling ... *\/<\/span> <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p><strong>What&#8217;s happening in this piece of code:<\/strong><\/p>\n<ul>\n<li><strong>socket.emit()<\/strong> sends the user\u2019s prompt to the backend.<\/li>\n<li>The callback function waits for the server to respond.<\/li>\n<li>Once the response arrives, we parse the JSON and use it to update both the Monaco Editor (with <strong>jsonEditor.setValue()<\/strong>) and the form preview (with new <strong>dhx.Form()<\/strong>).<\/li>\n<\/ul>\n<h2>Step 3: Adding Manual Interactivity<\/h2>\n<p>To give users more control, you can add &#8220;Copy&#8221; and &#8220;Update&#8221; buttons. This will allow them to copy the generated JSON or manually edit it and see their changes reflected in the form preview instantly.<\/p>\n<p>First, add the buttons to your index.html file, right after the JSON editor container:<\/p>\n<div class=\"codecolorer-container html4strict default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"html4strict codecolorer\"><span class=\"sc-1\">&lt;!-- index.html --&gt;<\/span><br \/>\n...<br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">div<\/span> <span class=\"kw3\">id<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;json-editor-container&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">div<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">div<\/span> <span class=\"kw3\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;editor-controls&quot;<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">button<\/span> <span class=\"kw3\">id<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;update-btn&quot;<\/span>&gt;<\/span>Update<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">button<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"kw2\">button<\/span> <span class=\"kw3\">id<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;copy-btn&quot;<\/span>&gt;<\/span>Copy<span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">button<\/span>&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sc2\">&lt;<span class=\"sy0\">\/<\/span><span class=\"kw2\">div<\/span>&gt;<\/span><br \/>\n...<\/div><\/div>\n<p>The next step is to add the following JavaScript to your app.js file to make these buttons work:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"co1\">\/\/ --- UI elements ---<\/span><br \/>\n<span class=\"kw1\">const<\/span> copyButton <span class=\"sy0\">=<\/span> document.<span class=\"me1\">getElementById<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;copy-btn&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> updateButton <span class=\"sy0\">=<\/span> document.<span class=\"me1\">getElementById<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;update-btn&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"co1\">\/\/ --- Update from Editor Logic ---<\/span><br \/>\nupdateButton.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'click'<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>jsonEditor<span class=\"br0\">&#41;<\/span> <span class=\"kw1\">return<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> editedCode <span class=\"sy0\">=<\/span> jsonEditor.<span class=\"me1\">getValue<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">try<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> formConfig <span class=\"sy0\">=<\/span> JSON.<span class=\"me1\">parse<\/span><span class=\"br0\">&#40;<\/span>editedCode<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>generatedForm<span class=\"br0\">&#41;<\/span> generatedForm.<span class=\"me1\">destructor<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; generatedForm <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> dhx.<span class=\"me1\">Form<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;form-preview-container&quot;<\/span><span class=\"sy0\">,<\/span> formConfig<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span> <span class=\"kw1\">catch<\/span> <span class=\"br0\">&#40;<\/span>e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span> <span class=\"coMULTI\">\/* ... error handling ... *\/<\/span> <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"co1\">\/\/ --- Copy-to-Clipboard Logic ---<\/span><br \/>\ncopyButton.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'click'<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>jsonEditor<span class=\"br0\">&#41;<\/span> <span class=\"kw1\">return<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> codeToCopy <span class=\"sy0\">=<\/span> jsonEditor.<span class=\"me1\">getValue<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; navigator.<span class=\"me1\">clipboard<\/span>.<span class=\"me1\">writeText<\/span><span class=\"br0\">&#40;<\/span>codeToCopy<span class=\"br0\">&#41;<\/span>.<span class=\"me1\">then<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; copyButton.<span class=\"me1\">textContent<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;Copied!&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; setTimeout<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span> copyButton.<span class=\"me1\">textContent<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;Copy&quot;<\/span><span class=\"sy0\">;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">2000<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"kw1\">catch<\/span><span class=\"br0\">&#40;<\/span>err <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span> <span class=\"coMULTI\">\/* ... error handling ... *\/<\/span> <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Now, users can manually fine-tune the AI\u2019s output and update the form preview, or copy the configuration to use elsewhere.<\/p>\n<h2>Step 4: Instructing the AI (Backend)<\/h2>\n<p>The backend\u2019s main responsibility is to receive a user&#8217;s text prompt from the frontend, combine it with a set of master instructions, and send it to the AI for processing.<\/p>\n<h3>Crafting the System Prompt<\/h3>\n<p>The most critical piece of this entire application is the <strong>system prompt<\/strong>, a detailed set of instructions that tells the AI how to behave. It&#8217;s stored in backend\/formBuilderPrompt.js. Without a strong system prompt, the AI would return inconsistent or invalid JSON. <\/p>\n<p>Our prompt engineering strategy involves several key areas:<\/p>\n<ol>\n<li><strong>Core Rules:<\/strong> Enforce the fundamental output format (e.g., JSON only, required properties).<\/li>\n<li><strong>Layout Logic:<\/strong> Translate simple user keywords like &#8220;row&#8221; into the correct JSON structure for horizontal or vertical layouts.<\/li>\n<li><strong>UI Best Practices:<\/strong> Handle special cases, like how to arrange a &#8220;Submit&#8221; and &#8220;Cancel&#8221; button pair.<\/li>\n<li><strong>Examples:<\/strong> Provide clear, concrete examples of user requests and the desired JSON output, which is one of the most effective ways to guide the model.<\/li>\n<\/ol>\n<p>Here is a snippet of the most important rules from <a href=\"https:\/\/github.com\/DHTMLX\/form-builder-ai-demo\/blob\/main\/backend\/formBuilderPrompt.js\" rel=\"noopener\" target=\"_blank\">formBuilderPrompt.js<\/a>:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"co1\">\/\/ --- CORE RULES ---<\/span><br \/>\n<span class=\"nu0\">1<\/span>. &nbsp;<span class=\"sy0\">**<\/span>JSON ONLY<span class=\"sy0\">:**<\/span> You MUST <span class=\"kw1\">return<\/span> ONLY a valid JSON object. <span class=\"me1\">No<\/span> extra text.<br \/>\n<span class=\"nu0\">2<\/span>. &nbsp;<span class=\"sy0\">**<\/span>TYPE <span class=\"sy0\">&amp;<\/span> UNIQUE NAME<span class=\"sy0\">:**<\/span> Every control object MUST have a \\`type\\` and a unique \\`name\\`.<br \/>\n<span class=\"nu0\">3<\/span>. &nbsp;<span class=\"sy0\">**<\/span>DEFAULT LABELS<span class=\"sy0\">:**<\/span> Provide sensible <span class=\"kw1\">default<\/span> English labels.<br \/>\n<span class=\"nu0\">4<\/span>. &nbsp;<span class=\"sy0\">**<\/span>LABEL POSITION<span class=\"sy0\">:**<\/span> All controls with labels MUST have \\`labelPosition<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;top&quot;<\/span>\\`.<br \/>\n<span class=\"co1\">\/\/....other rules<\/span><\/div><\/div>\n<h3>Connecting to the AI Service<\/h3>\n<p>Now, let&#8217;s look at how this system prompt is used in the <a href=\"https:\/\/github.com\/DHTMLX\/form-builder-ai-demo\/blob\/main\/backend\/server.js\" rel=\"noopener\" target=\"_blank\">backend\/server.js<\/a> file.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"co1\">\/\/ backend\/server.js<\/span><br \/>\nio.<span class=\"me1\">on<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'connection'<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span>socket<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; socket.<span class=\"me1\">on<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'generate_form'<\/span><span class=\"sy0\">,<\/span> async <span class=\"br0\">&#40;<\/span>userRequest<span class=\"sy0\">,<\/span> callback<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ 1. Retrieve the AI instructions (system prompt)<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> systemPrompt <span class=\"sy0\">=<\/span> generateFormBuilderPrompt<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ 2. Prepare the full request for the AI<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> messages <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> role<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;system&quot;<\/span><span class=\"sy0\">,<\/span> content<span class=\"sy0\">:<\/span> systemPrompt <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> role<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;user&quot;<\/span><span class=\"sy0\">,<\/span> content<span class=\"sy0\">:<\/span> userRequest <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">try<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ 3. Call the AI with a low temperature for consistent results<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> res <span class=\"sy0\">=<\/span> await openai.<span class=\"me1\">chat<\/span>.<span class=\"me1\">completions<\/span>.<span class=\"me1\">create<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; model<span class=\"sy0\">:<\/span> <span class=\"st0\">'gpt-4.1-nano'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; messages<span class=\"sy0\">:<\/span> messages<span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; temperature<span class=\"sy0\">:<\/span> <span class=\"nu0\">0.2<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response_format<span class=\"sy0\">:<\/span> <span class=\"br0\">&#123;<\/span> <span class=\"st0\">&quot;type&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;json_object&quot;<\/span> <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ 4. Send the AI's response back to the client<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callback<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span> success<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span> json<span class=\"sy0\">:<\/span> res.<span class=\"me1\">choices<\/span><span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span>.<span class=\"me1\">message<\/span>.<span class=\"me1\">content<\/span> <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span> <span class=\"kw1\">catch<\/span> <span class=\"br0\">&#40;<\/span>e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.<span class=\"me1\">error<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;AI request failed:&quot;<\/span><span class=\"sy0\">,<\/span> e<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callback<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span> success<span class=\"sy0\">:<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">,<\/span> error<span class=\"sy0\">:<\/span> e.<span class=\"me1\">message<\/span> <span class=\"sy0\">||<\/span> <span class=\"st0\">&quot;Failed to generate form from AI.&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p><strong>How it works:<\/strong><\/p>\n<ul>\n<li>You import the <strong>generateFormBuilderPrompt<\/strong> function and call it to get the master instructions.<\/li>\n<li>You create a <strong>messages<\/strong> array, placing our instructions in the \u201csystem\u201d role and the user&#8217;s request in the \u201cuser\u201d role.<\/li>\n<li>You set <strong>temperature: 0.2<\/strong> to make the AI&#8217;s output more predictable and less creative, which is crucial for generating valid configuration files.<\/li>\n<li>You use <strong>response_format: { &#8220;type&#8221;: &#8220;json_object&#8221; }<\/strong> to explicitly request JSON output, a feature supported by newer OpenAI models.<\/li>\n<\/ul>\n<p>By following this approach, your integration with the AI becomes reliable and predictable, providing a seamless experience for users when generating dynamic DHTMLX-based forms.<\/p>\n<h2>Wrapping Up<\/h2>\n<p>By combining DHTMLX Form with the OpenAI API, you can turn plain text into ready-to-use web forms in just a few clicks. This tutorial showed how to set up the UI, connect it to an AI backend, and even refine the generated JSON with live editing. This pattern of structured prompting is a powerful technique for integrating AI into other applications that require reliable, machine-readable output. Learn more about DHTMLX Form and other Suite widgets in the <a href=\"https:\/\/docs.dhtmlx.com\/suite\/form\/\" rel=\"noopener\" target=\"_blank\">documentation<\/a> and download a free <a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxSuite\/download.shtml\" rel=\"noopener\" target=\"_blank\">30-day trial version<\/a> to try any of them in your use-case scenarios.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Modern web applications commonly come with the capabilities to collect, validate, and process user data on-the-fly. This functional arsenal is implemented via dynamic forms that serve as comminitation channels &#8230;<\/p>\n","protected":false},"author":101014,"featured_media":14535,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[71],"tags":[77,33,31,10],"class_list":["post-14534","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-ai","tag-all-posts","tag-form","tag-dhtmlxsuite"],"_links":{"self":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/14534","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/users\/101014"}],"replies":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/comments?post=14534"}],"version-history":[{"count":10,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/14534\/revisions"}],"predecessor-version":[{"id":14546,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/14534\/revisions\/14546"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media\/14535"}],"wp:attachment":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media?parent=14534"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/categories?post=14534"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/tags?post=14534"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}