From a8fc27e830e4378581f5bd69a3f1040bced2b909 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 2 Mar 2025 01:54:39 -0600 Subject: [PATCH] feat(ai): add configuration files support for AI template generation - Enhance template generation with configFiles feature - Update StepTwo and StepThree components to display and edit configuration files - Modify AI router and schemas to support configuration file mounting - Refine AI service prompt to provide stricter guidelines for config file usage --- .../dashboard/project/ai/step-three.tsx | 16 ++++ .../dashboard/project/ai/step-two.tsx | 82 +++++++++++++++++-- .../project/ai/template-generator.tsx | 8 ++ apps/dokploy/server/api/routers/ai.ts | 17 +++- packages/server/src/db/schema/ai.ts | 8 ++ packages/server/src/services/ai.ts | 34 ++++---- 6 files changed, 137 insertions(+), 28 deletions(-) diff --git a/apps/dokploy/components/dashboard/project/ai/step-three.tsx b/apps/dokploy/components/dashboard/project/ai/step-three.tsx index efd899010..8aa014e30 100644 --- a/apps/dokploy/components/dashboard/project/ai/step-three.tsx +++ b/apps/dokploy/components/dashboard/project/ai/step-three.tsx @@ -85,6 +85,22 @@ export const StepThree = ({ templateInfo }: StepProps) => { )} +
+

Configuration Files

+ +
diff --git a/apps/dokploy/components/dashboard/project/ai/step-two.tsx b/apps/dokploy/components/dashboard/project/ai/step-two.tsx index 7660f473e..14a929fce 100644 --- a/apps/dokploy/components/dashboard/project/ai/step-two.tsx +++ b/apps/dokploy/components/dashboard/project/ai/step-two.tsx @@ -24,11 +24,7 @@ export interface StepProps { setTemplateInfo: React.Dispatch>; } -export const StepTwo = ({ - stepper, - templateInfo, - setTemplateInfo, -}: StepProps) => { +export const StepTwo = ({ templateInfo, setTemplateInfo }: StepProps) => { const suggestions = templateInfo.suggestions || []; const selectedVariant = templateInfo.details; const [showValues, setShowValues] = useState>({}); @@ -52,7 +48,9 @@ export const StepTwo = ({ }); }) .catch((error) => { - toast.error("Error generating suggestions"); + toast.error("Error generating suggestions", { + description: error.message, + }); }); }, [templateInfo.userInput]); @@ -434,6 +432,78 @@ export const StepTwo = ({ + + Configuration Files + + +
+ {selectedVariant?.configFiles?.length > 0 ? ( + <> +
+ This template requires the following + configuration files to be mounted: +
+ {selectedVariant.configFiles.map( + (config, index) => ( +
+
+
+ +

+ Will be mounted as: ../files + {config.filePath} +

+
+
+ { + if (!selectedVariant?.configFiles) + return; + const updatedConfigFiles = [ + ...selectedVariant.configFiles, + ]; + updatedConfigFiles[index] = { + filePath: config.filePath, + content: value, + }; + setTemplateInfo({ + ...templateInfo, + ...(templateInfo.details && { + details: { + ...templateInfo.details, + configFiles: updatedConfigFiles, + }, + }), + }); + }} + /> +
+ ), + )} + + ) : ( +
+

+ This template doesn't require any configuration + files. +

+

+ All necessary configurations are handled through + environment variables. +

+
+ )} +
+
+
+
diff --git a/apps/dokploy/components/dashboard/project/ai/template-generator.tsx b/apps/dokploy/components/dashboard/project/ai/template-generator.tsx index c9f07c1b6..7fad2e35d 100644 --- a/apps/dokploy/components/dashboard/project/ai/template-generator.tsx +++ b/apps/dokploy/components/dashboard/project/ai/template-generator.tsx @@ -47,7 +47,14 @@ interface Details { envVariables: EnvVariable[]; shortDescription: string; domains: Domain[]; + configFiles: Mount[]; } + +interface Mount { + filePath: string; + content: string; +} + export interface TemplateInfo { userInput: string; details?: Details | null; @@ -126,6 +133,7 @@ export const TemplateGenerator = ({ projectId }: Props) => { ...(templateInfo.server?.serverId && { serverId: templateInfo.server?.serverId || "", }), + configFiles: templateInfo?.details?.configFiles || [], }) .then(async () => { toast.success("Compose Created"); diff --git a/apps/dokploy/server/api/routers/ai.ts b/apps/dokploy/server/api/routers/ai.ts index e37aba15f..80a4d0cc4 100644 --- a/apps/dokploy/server/api/routers/ai.ts +++ b/apps/dokploy/server/api/routers/ai.ts @@ -11,7 +11,7 @@ import { apiUpdateAi, deploySuggestionSchema, } from "@dokploy/server/db/schema/ai"; -import { createDomain } from "@dokploy/server/index"; +import { createDomain, createMount } from "@dokploy/server/index"; import { deleteAiSettings, getAiSettingById, @@ -126,8 +126,6 @@ export const aiRouter = createTRPCRouter({ const projectName = slugify(`${project.name} ${input.id}`); - console.log(input); - const compose = await createComposeByTemplate({ ...input, composeFile: input.dockerCompose, @@ -136,6 +134,7 @@ export const aiRouter = createTRPCRouter({ name: input.name, sourceType: "raw", appName: `${projectName}-${generatePassword(6)}`, + isolatedDeployment: true, }); if (input.domains && input.domains?.length > 0) { @@ -148,6 +147,18 @@ export const aiRouter = createTRPCRouter({ }); } } + if (input.configFiles && input.configFiles?.length > 0) { + for (const mount of input.configFiles) { + await createMount({ + filePath: mount.filePath, + mountPath: "", + content: mount.content, + serviceId: compose.composeId, + serviceType: "compose", + type: "file", + }); + } + } if (ctx.user.rol === "member") { await addNewService( diff --git a/packages/server/src/db/schema/ai.ts b/packages/server/src/db/schema/ai.ts index 51f443d90..3704c3dd9 100644 --- a/packages/server/src/db/schema/ai.ts +++ b/packages/server/src/db/schema/ai.ts @@ -71,4 +71,12 @@ export const deploySuggestionSchema = z.object({ }), ) .optional(), + configFiles: z + .array( + z.object({ + filePath: z.string().min(1), + content: z.string().min(1), + }), + ) + .optional(), }); diff --git a/packages/server/src/services/ai.ts b/packages/server/src/services/ai.ts index cb2b14ff0..3b7750a98 100644 --- a/packages/server/src/services/ai.ts +++ b/packages/server/src/services/ai.ts @@ -153,25 +153,21 @@ export const suggestVariants = async ({ 3. Don't set container_name field in services 4. Don't set version field in the docker compose 5. Don't set ports like 'ports: 3000:3000', use 'ports: "3000"' instead - 6. Use dokploy-network in all services - 7. Add dokploy-network at the end and mark it as external: true - 8. If a service depends on a database or other service, INCLUDE that service in the docker-compose - 9. Make sure all required services are defined in the docker-compose + 6. If a service depends on a database or other service, INCLUDE that service in the docker-compose + 7. Make sure all required services are defined in the docker-compose - Volume Mounting Rules: - 1. All file mounts in volumes section MUST use "../files/" prefix - 2. NEVER use absolute paths or direct host paths - 3. Format should be: "../files/folder:/container/path" - 4. If a service needs configuration files, they should be defined in configFiles array and referenced in volumes - 5. Example: if you define a config file with filePath: "/nginx/nginx.conf", reference it in volumes as "../files/nginx/nginx.conf:/etc/nginx/nginx.conf" - - - Configuration Files Rules: - 1. If a service needs configuration files, include them in the configFiles array - 2. Each config file should have: - - content: The actual content of the configuration file - - filePath: The relative path where the file should be stored (e.g., "/nginx/nginx.conf") - 3. Make sure to reference these files correctly in the docker-compose volumes section + Volume Mounting and Configuration Rules: + 1. DO NOT create configuration files unless the service CANNOT work without them + 2. Most services can work with just environment variables - USE THEM FIRST + 3. Ask yourself: "Can this be configured with an environment variable instead?" + 4. If and ONLY IF a config file is absolutely required: + - Keep it minimal with only critical settings + - Use "../files/" prefix for all mounts + - Format: "../files/folder:/container/path" + 5. DO NOT add configuration files for: + - Default configurations that work out of the box + - Settings that can be handled by environment variables + - Proxy or routing configurations (these are handled elsewhere) Environment Variables Rules: 1. For the envVariables array, provide ACTUAL example values, not placeholders @@ -186,7 +182,7 @@ export const suggestVariants = async ({ - host: the domain name for the service in format: {service-name}-{random-3-chars-hex}-${ip ? ip.replaceAll(".", "-") : ""}.traefik.me - port: the internal port the service runs on - serviceName: the name of the service in the docker-compose - 2. Make sure the service is properly configured in the docker-compose to work with the specified port + 2. Make sure the service is properly configured to work with the specified port Project details: ${suggestion?.description}