{"id":14678,"date":"2025-11-27T11:11:57","date_gmt":"2025-11-27T08:11:57","guid":{"rendered":"https:\/\/dhtmlx.com\/blog\/?p=14678"},"modified":"2026-06-30T17:00:20","modified_gmt":"2026-06-30T14:00:20","slug":"building-intelligent-gantt-chart-maker-dhtmlx-ai","status":"publish","type":"post","link":"https:\/\/dhtmlx.com\/blog\/building-intelligent-gantt-chart-maker-dhtmlx-ai\/","title":{"rendered":"Building an Intelligent Gantt Chart Maker with DHTMLX and AI"},"content":{"rendered":"<p>Delivering intuitive ways to work with project data becomes essential for modern applications. But it doesn\u2019t seem like a trivial task, right? However, with the rise of AI technologies, you have the opportunity to achieve this goal using the DHTMLX Gantt component paired with a smart AI assistant.<\/p>\n<p>In this tutorial, you\u2019ll learn how to create a textual AI layer on top of an existing Gantt chart without rewriting the entire frontend. It will allow you to promptly configure and manage the Gantt chart with natural language instructions (prompts), while AI translates these instructions into true actions under the hood. <\/p>\n<h2>Key Elements of AI Gantt Maker and How They Work Together<\/h2>\n<p>First, let us briefly outline the integral parts of the <a href=\"https:\/\/dhtmlx.com\/docs\/demo\/ai-gantt-maker\/\" rel=\"noopener\" target=\"_blank\">AI Gantt Maker<\/a> and how they work together. <\/p>\n<p>The system\u2019s architecture includes 3 main elements:<\/p>\n<ul>\n<li><strong><a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxGantt\/\" rel=\"noopener\" target=\"_blank\">DHTMLX Gantt<\/a><\/strong> &#8211; the main project visualisation component<\/li>\n<li><strong>AI assistant<\/strong> &#8211; a simple chat UI for communicating with AI, i.e., issuing commands in plain English<\/li>\n<li><strong>Functions layer<\/strong> &#8211; a predefined set of operations (also known as function calling or <a href=\"https:\/\/platform.openai.com\/docs\/guides\/function-calling?lang=javascript\" rel=\"noopener\" target=\"_blank\">tool calling<\/a> schema) that are allowed to be utilised by AI models, thereby ensuring predictable and structured responses to user prompts.<\/li>\n<\/ul>\n<p>Together, these elements enable users to create complete project structures, manage tasks and dependencies, adjust timeline settings, change visual styles, and export the Gantt chart via natural language commands. <\/p>\n<p>For instance, here is how the AI Gantt Maker will respond to the command like &#8220;Create a project called Constructing a Fitness Club, including only the following three stages: Site Preparation, Construction Work, and Equipment Installation&#8221;:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2025\/11\/image1-2.gif\" alt=\"Gantt Maker built with DHTMLX and AI\" width=\"1920\" height=\"856\" class=\"aligncenter size-full wp-image-14679\" \/><a href=\"https:\/\/dhtmlx.com\/docs\/demo\/ai-gantt-maker\/\" rel=\"noopener\" target=\"_blank\">Open live demo ><\/a><\/p>\n<p>To give you the full picture of how it all works as a single mechanism, here is the workflow overview:<\/p>\n<ul>\n<li>The user enters a natural language instruction (prompt) into the chat UI.<\/li>\n<li>The chat (AI assistant) sends the user\u2019s message along with the current Gantt state to the backend.<\/li>\n<li>The backend passes it with system prompt and tools to the selected AI service (LLM).<\/li>\n<li>LLM responds with a structured function call related to the required operation.<\/li>\n<li>The frontend analyses the response and updates the Gantt chart accordingly.<\/li>\n<\/ul>\n<p>There are a few more things that we want to mention before proceeding to the implementation stage:<\/p>\n<ul>\n<li><strong>Technology stack.<\/strong> Our demo includes a React+Vite frontend, an Express+Socket.IO backend, and an LLM accessed via the OpenAI API (any other compatible AI service can be used as well). Everything is containerised with Docker.<\/li>\n<li><strong>AI model compatibility.<\/strong>  The project works best with gpt-5-nano and gpt-4.1-mini, while gpt-4.1-nano has noticeable limitations in following the schema. If you decide to choose any other AI service, make sure it supports structured outputs (function calling).<\/li>\n<li><strong>Demo on GitHub.<\/strong> The complete, fully styled source code of the AI Gantt Maker project is available in the <a href=\"https:\/\/github.com\/DHTMLX\/gantt-maker-ai-demo\/\" rel=\"noopener\" target=\"_blank\">GitHub repository<\/a>.<\/li>\n<\/ul>\n<p>Without further ado, let\u2019s explore what you need to do to build your own AI Gantt Maker.<\/p>\n<h2>Frontend Implementation<\/h2>\n<p>The frontend implementation lays the foundation for how users interact with the AI-assisted Gantt builder. At this stage, you need to initialize the DHTMLX Gantt component, add the AI assistant (chat UI) for prompt input, and establish a connection to the backend.<\/p>\n<h3>1. Initializing Gantt<\/h3>\n<p>The Gantt component is initialized once (<a href=\"https:\/\/github.com\/DHTMLX\/gantt-maker-ai-demo\/blob\/main\/frontend\/src\/main.ts\" rel=\"noopener\" target=\"_blank\">main.ts<\/a>) and configured with columns, plugins (auto-scheduling, undo, export, markers, tooltip), date parsing, and zoom\/fit helpers:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> gantt <span class=\"sy0\">=<\/span> Gantt.<span class=\"me1\">getGanttInstance<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\ngantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">columns<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#123;<\/span> name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;wbs&quot;<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;WBS&quot;<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span> <span class=\"nu0\">60<\/span><span class=\"sy0\">,<\/span> resize<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span> template<span class=\"sy0\">:<\/span> gantt.<span class=\"me1\">getWBSCode<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; <span class=\"br0\">&#123;<\/span> name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;text&quot;<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Task name&quot;<\/span><span class=\"sy0\">,<\/span> tree<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span> <span class=\"nu0\">250<\/span><span class=\"sy0\">,<\/span> resize<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; <span class=\"br0\">&#123;<\/span> name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;start_date&quot;<\/span><span class=\"sy0\">,<\/span> align<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;center&quot;<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span> <span class=\"nu0\">100<\/span><span class=\"sy0\">,<\/span> resize<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; <span class=\"br0\">&#123;<\/span> name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;duration&quot;<\/span><span class=\"sy0\">,<\/span> align<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;center&quot;<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span> <span class=\"nu0\">80<\/span><span class=\"sy0\">,<\/span> resize<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; <span class=\"br0\">&#123;<\/span> name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;add&quot;<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span> <span class=\"nu0\">40<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><br \/>\ngantt.<span class=\"me1\">plugins<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; auto_scheduling<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; undo<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; export_api<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; marker<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; tooltip<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\ngantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">auto_scheduling<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\ngantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">open_tree_initially<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\ngantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">auto_types<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\ngantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">scale_height<\/span> <span class=\"sy0\">=<\/span> <span class=\"nu0\">60<\/span><span class=\"sy0\">;<\/span><br \/>\ninitZoom<span class=\"br0\">&#40;<\/span>gantt<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nfitTaskText<span class=\"br0\">&#40;<\/span>gantt<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<h3>2. Setting Up the Chat UI<\/h3>\n<p>The chat UI (right pane) is created with a lightweight chat widget that provides an entry point for interacting with the AI assistant. To add the chat UI to your project, you need the <strong>initChat()<\/strong> method, which injects the chat structure and event listeners for sending messages:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"co1\">\/\/ chat-widget.ts - The core chat initialization function<\/span><br \/>\n<span class=\"kw5\">export<\/span> <span class=\"kw1\">const<\/span> initChat <span class=\"sy0\">=<\/span> <span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span> socket<span class=\"sy0\">,<\/span> runCommand<span class=\"sy0\">,<\/span> getProject <span class=\"br0\">&#125;<\/span><span class=\"sy0\">:<\/span> InitChatOptions<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"co1\">\/\/ Injects the chat HTML structure into the page<\/span><br \/>\n<span class=\"kw1\">const<\/span> chatWidgetContainer <span class=\"sy0\">=<\/span> document.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;#chat_panel&quot;<\/span><span class=\"br0\">&#41;<\/span> as HTMLElement<span class=\"sy0\">;<\/span><br \/>\n&nbsp; chatWidgetContainer.<span class=\"me1\">innerHTML<\/span> <span class=\"sy0\">=<\/span> `...`<span class=\"sy0\">;<\/span> <span class=\"co1\">\/\/ HTML for header, messages, input, etc.<\/span><br \/>\n&nbsp; <span class=\"co1\">\/\/ Sets up event listeners for sending messages<\/span><br \/>\n&nbsp; chatSubmit.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'click'<\/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=\"kw1\">const<\/span> message <span class=\"sy0\">=<\/span> chatInput.<span class=\"me1\">value<\/span>.<span class=\"me1\">trim<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; \u2026<br \/>\n&nbsp; &nbsp; sendUserMessage<span class=\"br0\">&#40;<\/span>message<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"co1\">\/\/ ... other logic for suggestions and displaying messages<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The chat UI is responsible for the following: <\/p>\n<ul>\n<li>accepting natural-language input and sending it (with the current project state) via the WebSocket (Socket.IO) using the <strong>sendUserMessage()<\/strong> function<\/li>\n<li>displaying AI messages and safely rendering Markdown content with the <strong>displayReply()<\/strong> function<\/li>\n<li>offering context-aware suggestions for further user actions injected with the <strong>onCallback()<\/strong> function<\/li>\n<li>providing the command guide with prompt examples<\/li>\n<\/ul>\n<p>The full code for the chat widget can be found <a href=\"https:\/\/github.com\/DHTMLX\/gantt-maker-ai-demo\/blob\/main\/frontend\/src\/chat-widget.ts\" rel=\"noopener\" target=\"_blank\">here<\/a>.<\/p>\n<h3>3. Establishing Real-Time Communication with the Backend<\/h3>\n<p>Next, you need to set communication between the frontend and backend parts of your AI Gantt Maker, ensuring the delivery of commands to LLM and the corresponding Gantt updates in real time. <\/p>\n<p>This connection is established using the Socket.IO library. It uses WebSockets as a communication channel between the frontend and backend.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> SOCKET_URL <span class=\"sy0\">=<\/span> <span class=\"kw5\">import<\/span>.<span class=\"me1\">meta<\/span>.<span class=\"me1\">env<\/span>.<span class=\"me1\">VITE_SOCKET_URL<\/span> <span class=\"sy0\">||<\/span> `$<span class=\"br0\">&#123;<\/span>window.<span class=\"me1\">location<\/span>.<span class=\"me1\">origin<\/span><span class=\"br0\">&#125;<\/span>`<span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> socket <span class=\"sy0\">=<\/span> io<span class=\"br0\">&#40;<\/span>SOCKET_URL<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>This way, you will establish seamless, real-time collaboration between the Gantt chart, AI assistant, and AI service.<\/p>\n<h2>Backend Implementation: Connecting Gantt with AI<\/h2>\n<p>The backend serves as a traffic controller between the chat UI, the AI model, and the Gantt chart. To be more specific, it receives user prompts, prepares and sends requests to LLM, and returns structured commands that can be executed on the frontend. <\/p>\n<p>Let us delve into the details and clarify the key aspects of backend responsibilities in the AI Gantt Maker.<\/p>\n<h3>1. Loading Allowed Operations (Tools) for AI<\/h3>\n<p>The backend provides the AI model with a set of tools that define the actions the AI model can perform with the required arguments. Each tool corresponds to a specific operation in the project: generating a project structure (<strong>generate_project<\/strong>), creating tasks (<strong>add_task<\/strong>), editing tasks (<strong>update_task<\/strong>), etc. <\/p>\n<p>The OpenAI models support &#8220;<a href=\"https:\/\/platform.openai.com\/docs\/guides\/function-calling\" rel=\"noopener\" target=\"_blank\">function calling<\/a>&#8221; mode, where each tool is described using a JSON schema. The model examines these schemas and, when appropriate, responds not with free-form text but with a structured function call such as:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; <span class=\"st0\">&quot;tool&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;add_task&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; <span class=\"st0\">&quot;arguments&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">&quot;text&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Prepare design mockups&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">&quot;start_date&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;2026-03-10&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">&quot;duration&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"nu0\">4<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">&quot;parent&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"nu0\">12<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>For instance, if the user inputs a request like &#8220;Add a task \u2018Write documentation\u2019 starting next Monday, duration 3 days, under phase 102.&#8221;, the <strong>add_task<\/strong> tool comes into play:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; type<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;function&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">function<\/span><span class=\"sy0\">:<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;add_task&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; description<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Create a single new task, optionally under a parent task.&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; parameters<span class=\"sy0\">:<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; type<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;object&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; additionalProperties<span class=\"sy0\">:<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; properties<span class=\"sy0\">:<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id<span class=\"sy0\">:<\/span> taskProperties.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text<span class=\"sy0\">:<\/span> taskProperties.<span class=\"me1\">text<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; start_date<span class=\"sy0\">:<\/span> taskProperties.<span class=\"me1\">start_date<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duration<span class=\"sy0\">:<\/span> taskProperties.<span class=\"me1\">duration<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parent<span class=\"sy0\">:<\/span> taskProperties.<span class=\"me1\">parent<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; progress<span class=\"sy0\">:<\/span> taskProperties.<span class=\"me1\">progress<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; required<span class=\"sy0\">:<\/span> <span class=\"br0\">&#91;<\/span><span class=\"st0\">&quot;text&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">&quot;start_date&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">&quot;duration&quot;<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><\/div><\/div>\n<p>Each schema ensures that the AI produces structured responses compatible with the Gantt API, preventing invalid or unexpected commands.<\/p>\n<h3>2. Handling User Prompts<\/h3>\n<p>After receiving a prompt from the frontend via Socket.IO, the backend complements it with the system prompt (context+project data) and available tools (collected into a single array <strong>schemaList<\/strong>) and embeds all the information in a comprehensive API request. Then, the backend sends the request to the AI model (OpenAI API).<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw5\">import<\/span> <span class=\"br0\">&#123;<\/span> schemaList <span class=\"br0\">&#125;<\/span> from <span class=\"st0\">&quot;.\/schemaList&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\nsocket.<span class=\"me1\">on<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;user_msg&quot;<\/span><span class=\"sy0\">,<\/span> async <span class=\"br0\">&#40;<\/span>payload<span class=\"sy0\">:<\/span> UserMsgPayload <span class=\"sy0\">|<\/span> string<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n\u2026<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> <span class=\"br0\">&#123;<\/span> message <span class=\"br0\">&#125;<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">typeof<\/span> payload <span class=\"sy0\">===<\/span> <span class=\"st0\">&quot;string&quot;<\/span> <span class=\"sy0\">?<\/span> JSON.<span class=\"me1\">parse<\/span><span class=\"br0\">&#40;<\/span>payload<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">:<\/span> payload<span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; getMessagesHistoryByClient<span class=\"br0\">&#40;<\/span>socket.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span> generateSystemPrompt<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; saveMessage<span class=\"br0\">&#40;<\/span>socket.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span> <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> message <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span>let turn <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span> turn <span class=\"sy0\">&lt;<\/span> MAX_TURNS<span class=\"sy0\">;<\/span> turn<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> history <span class=\"sy0\">=<\/span> trimHistory<span class=\"br0\">&#40;<\/span>getHistory<span class=\"br0\">&#40;<\/span>socket.<span class=\"me1\">id<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> response <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; model<span class=\"sy0\">:<\/span> MODEL<span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; messages<span class=\"sy0\">:<\/span> history<span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tools<span class=\"sy0\">:<\/span> schemaList<span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tool_choice<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;auto&quot;<\/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; \u2026<br \/>\n<br \/>\n<br \/>\n\u2026<\/div><\/div>\n<p>The <strong>generateSystemPrompt()<\/strong> function creates a detailed context for the AI, including tasks, dependencies, and project rules. <strong>getMessagesHistoryByClient()<\/strong> creates a user history (if it doesn\u2019t exist) that accepts two arguments: socket ID and system prompt. Otherwise the existing history is used. <strong>saveMessage()<\/strong> adds a user message to the user history. <strong>trimHistory()<\/strong> keeps the last N message blocks, while preserving tool-call\/tool-result pairs. <\/p>\n<p>With the conversation history support, you enable the AI assistant to maintain context across multiple interactions, enhancing accuracy in responses and reducing ambiguity. <\/p>\n<p>For the complete list of available functions, including task dependencies, styling, chart configuration, and export operations, refer to the full <a href=\"https:\/\/github.com\/DHTMLX\/gantt-maker-ai-demo\/blob\/main\/backend\/schemaList.ts\" rel=\"noopener\" target=\"_blank\">schemaList.ts<\/a> file in the project repository.<\/p>\n<h3>3. Generation and Processing of the AI Model\u2019s Response<\/h3>\n<p>After receiving the request from the backend, the AI model (LLM) analyzes which function from schemaList is best suited for a given task.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> response <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; model<span class=\"sy0\">:<\/span> MODEL<span class=\"sy0\">,<\/span><br \/>\n&nbsp; messages<span class=\"sy0\">:<\/span> history<span class=\"sy0\">,<\/span><br \/>\n&nbsp; tools<span class=\"sy0\">:<\/span> schemaList<span class=\"sy0\">,<\/span><br \/>\n&nbsp; tool_choice<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;auto&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> msg <span class=\"sy0\">=<\/span> response.<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=\"sy0\">;<\/span><\/div><\/div>\n<p>There are two possible scenarios: <\/p>\n<ul>\n<li>when the LLM response doesn\u2019t have tool calls, we just respond directly to the frontend:<\/li>\n<\/ul>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>msg.<span class=\"me1\">tool_calls<\/span><span class=\"sy0\">?<\/span>.<span class=\"me1\">length<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; socket.<span class=\"me1\">emit<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;assistant_msg&quot;<\/span><span class=\"sy0\">,<\/span> msg.<span class=\"me1\">content<\/span> <span class=\"sy0\">??<\/span> <span class=\"st0\">&quot;&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; saveMessage<span class=\"br0\">&#40;<\/span>socket.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#123;<\/span> role<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;assistant&quot;<\/span><span class=\"sy0\">,<\/span> content<span class=\"sy0\">:<\/span> msg.<span class=\"me1\">content<\/span> <span class=\"sy0\">??<\/span> <span class=\"st0\">&quot;&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<ul>\n<li>If there are tool calls from LLM, we need to proccess them and save to the user\u2019s history:<\/li>\n<\/ul>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">saveMessage<span class=\"br0\">&#40;<\/span>socket.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#123;<\/span> role<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;assistant&quot;<\/span><span class=\"sy0\">,<\/span> tool_calls<span class=\"sy0\">:<\/span> msg.<span class=\"me1\">tool_calls<\/span> <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">const<\/span> call of msg.<span class=\"me1\">tool_calls<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/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> result <span class=\"sy0\">=<\/span> await executeToolCall<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span> socket<span class=\"sy0\">,<\/span> call <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; saveMessage<span class=\"br0\">&#40;<\/span>socket.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#123;<\/span> role<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;tool&quot;<\/span><span class=\"sy0\">,<\/span> tool_call_id<span class=\"sy0\">:<\/span> call.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span> content<span class=\"sy0\">:<\/span> JSON.<span class=\"me1\">stringify<\/span><span class=\"br0\">&#40;<\/span>result<span class=\"br0\">&#41;<\/span> <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=\"kw1\">catch<\/span> <span class=\"br0\">&#40;<\/span>err<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; saveMessage<span class=\"br0\">&#40;<\/span>socket.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; role<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;tool&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tool_call_id<span class=\"sy0\">:<\/span> call.<span class=\"me1\">id<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content<span class=\"sy0\">:<\/span> JSON.<span class=\"me1\">stringify<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span> ok<span class=\"sy0\">:<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">,<\/span> error<span class=\"sy0\">:<\/span> <span class=\"kw4\">String<\/span><span class=\"br0\">&#40;<\/span>err<span class=\"br0\">&#41;<\/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><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<h3>4. Frontend Execution and Gantt Updates<\/h3>\n<p>Once the backend returns the <strong>tool_call<\/strong> event in response to user prompts, the frontend needs to interpret and execute it to update the Gantt chart. On the frontend, the returned tool calls are handled by the command runner (<strong>runCommand<\/strong> function).<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"co1\">\/\/ Receiving and executing tool calls<\/span><br \/>\nsocket.<span class=\"me1\">on<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'tool_call'<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span>txt<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; let handled <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"kw1\">try<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> <span class=\"br0\">&#123;<\/span> cmd<span class=\"sy0\">,<\/span> params <span class=\"br0\">&#125;<\/span> <span class=\"sy0\">=<\/span> JSON.<span class=\"me1\">parse<\/span><span class=\"br0\">&#40;<\/span>txt<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>cmd <span class=\"sy0\">&amp;&amp;<\/span> cmd <span class=\"sy0\">!==<\/span> <span class=\"st0\">'none'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; runCommand<span class=\"br0\">&#40;<\/span>cmd<span class=\"sy0\">,<\/span> params<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; hideLoader<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; onCallback<span class=\"br0\">&#40;<\/span>cmd<span class=\"sy0\">,<\/span> params<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; handled <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&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; hideLoader<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; displayReply<span class=\"br0\">&#40;<\/span>`Something wrong had happened<span class=\"sy0\">:<\/span> $<span class=\"br0\">&#123;<\/span>e.<span class=\"me1\">message<\/span><span class=\"br0\">&#125;<\/span>`<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; handled <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>handled<span class=\"br0\">&#41;<\/span> displayReply<span class=\"br0\">&#40;<\/span>`Couldn<span class=\"st0\">'t handle this: ${txt}`);<br \/>\n});<\/span><\/div><\/div>\n<p>The <strong>runCommand<\/strong> function acts as a dispatcher, mapping AI commands to specific DHTMLX Gantt API calls (command-runner.ts):<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw5\">export<\/span> <span class=\"kw1\">default<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>gantt<span class=\"sy0\">:<\/span> Static<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; <span class=\"kw1\">return<\/span> <span class=\"kw1\">function<\/span> runCommand <span class=\"br0\">&#40;<\/span>cmd<span class=\"sy0\">:<\/span> string<span class=\"sy0\">,<\/span> args<span class=\"sy0\">:<\/span> any<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> strToDate <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">date<\/span>.<span class=\"me1\">str_to_date<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;%Y-%m-%d&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> dateToStr <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">date<\/span>.<span class=\"me1\">date_to_str<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;%Y-%m-%d&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">switch<\/span> <span class=\"br0\">&#40;<\/span>cmd<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">case<\/span> <span class=\"st0\">&quot;add_task&quot;<\/span><span class=\"sy0\">:<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">addTask<\/span><span class=\"br0\">&#40;<\/span>args<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">break<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">case<\/span> <span class=\"st0\">&quot;delete_task&quot;<\/span><span class=\"sy0\">:<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">deleteTask<\/span><span class=\"br0\">&#40;<\/span>args.<span class=\"me1\">id<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">break<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">case<\/span> <span class=\"st0\">&quot;add_link&quot;<\/span><span class=\"sy0\">:<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">addLink<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id<span class=\"sy0\">:<\/span> gantt.<span class=\"me1\">uid<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source<span class=\"sy0\">:<\/span> args.<span class=\"me1\">source<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; target<span class=\"sy0\">:<\/span> args.<span class=\"me1\">target<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type<span class=\"sy0\">:<\/span> args.<span class=\"me1\">type<\/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; <span class=\"kw1\">break<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <br \/>\n<span class=\"co1\">\/\/ ... handling other commands<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>As a result, corresponding Gantt API methods are executed, and the Gantt chart is immediately updated in accordance with the user\u2019s request. <\/p>\n<p>It puts together all the pieces of the interaction cycle implemented in the DHTMLX AI Gantt Maker. To find out more technical details, check out the <a href=\"https:\/\/github.com\/DHTMLX\/gantt-maker-ai-demo\/\" rel=\"noopener\" target=\"_blank\">GitHub repository<\/a> of our demo project.<\/p>\n<h2>Note on Demo Limitations<\/h2>\n<p>The DHTMLX AI Gantt Maker demo suits well for demonstration purposes, but it should be mentioned that we\u2019ve intentionally simplified several aspects of such integrations, which are likely to be an issue in real-world scenarios. For instance, our system struggles to resolve ambiguous commands and has a limited context size for large projects. Therefore, it is necessary to address these limitations when working on production-grade solutions.<\/p>\n<h2>Final Thoughts<\/h2>\n<p>In this tutorial, we explored how AI can be used to bring your project management experience with DHTMLX Gantt to a new level. Our demo shows how routine tasks that once kept you busy for hours can now be solved in minutes using simple instructions in plain English. While the current implementation is good enough to show the potential of using JavaScript UI components like DHTMLX Gantt with AI, there are plenty of opportunities to enhance the current solution for more complex tasks. For instance, you can expand the set of supported commands, enrich functional capabilities with new operations (undo, auto-scheduling, etc.), integrate a more sophisticated chat widget, and more. With such improvements, your AI Gantt Maker can become a centerpiece of any modern project management app. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Delivering intuitive ways to work with project data becomes essential for modern applications. But it doesn\u2019t seem like a trivial task, right? However, with the rise of AI technologies, &#8230;<\/p>\n","protected":false},"author":101014,"featured_media":14680,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[71],"tags":[77,33,20],"class_list":["post-14678","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-ai","tag-all-posts","tag-gantt"],"_links":{"self":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/14678","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=14678"}],"version-history":[{"count":11,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/14678\/revisions"}],"predecessor-version":[{"id":15749,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/14678\/revisions\/15749"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media\/14680"}],"wp:attachment":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media?parent=14678"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/categories?post=14678"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/tags?post=14678"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}