mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
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
This commit is contained in:
@@ -85,6 +85,22 @@ export const StepThree = ({ templateInfo }: StepProps) => {
|
|||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-sm font-semibold">Configuration Files</h3>
|
||||||
|
<ul className="list-disc pl-5">
|
||||||
|
{templateInfo?.details?.configFiles.map((file, index) => (
|
||||||
|
<li key={index}>
|
||||||
|
<strong className="text-sm font-semibold">
|
||||||
|
{file.filePath}
|
||||||
|
</strong>
|
||||||
|
:
|
||||||
|
<span className="text-sm ml-2 text-muted-foreground">
|
||||||
|
{file.content}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,11 +24,7 @@ export interface StepProps {
|
|||||||
setTemplateInfo: React.Dispatch<React.SetStateAction<TemplateInfo>>;
|
setTemplateInfo: React.Dispatch<React.SetStateAction<TemplateInfo>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StepTwo = ({
|
export const StepTwo = ({ templateInfo, setTemplateInfo }: StepProps) => {
|
||||||
stepper,
|
|
||||||
templateInfo,
|
|
||||||
setTemplateInfo,
|
|
||||||
}: StepProps) => {
|
|
||||||
const suggestions = templateInfo.suggestions || [];
|
const suggestions = templateInfo.suggestions || [];
|
||||||
const selectedVariant = templateInfo.details;
|
const selectedVariant = templateInfo.details;
|
||||||
const [showValues, setShowValues] = useState<Record<string, boolean>>({});
|
const [showValues, setShowValues] = useState<Record<string, boolean>>({});
|
||||||
@@ -52,7 +48,9 @@ export const StepTwo = ({
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
toast.error("Error generating suggestions");
|
toast.error("Error generating suggestions", {
|
||||||
|
description: error.message,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}, [templateInfo.userInput]);
|
}, [templateInfo.userInput]);
|
||||||
|
|
||||||
@@ -434,6 +432,78 @@ export const StepTwo = ({
|
|||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
|
<AccordionItem value="mounts">
|
||||||
|
<AccordionTrigger>Configuration Files</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
<ScrollArea className="w-full rounded-md border">
|
||||||
|
<div className="p-4 space-y-4">
|
||||||
|
{selectedVariant?.configFiles?.length > 0 ? (
|
||||||
|
<>
|
||||||
|
<div className="text-sm text-muted-foreground mb-4">
|
||||||
|
This template requires the following
|
||||||
|
configuration files to be mounted:
|
||||||
|
</div>
|
||||||
|
{selectedVariant.configFiles.map(
|
||||||
|
(config, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="space-y-2 border rounded-lg p-4"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<Label className="text-primary">
|
||||||
|
{config.filePath}
|
||||||
|
</Label>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Will be mounted as: ../files
|
||||||
|
{config.filePath}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CodeEditor
|
||||||
|
value={config.content}
|
||||||
|
className="font-mono"
|
||||||
|
onChange={(value) => {
|
||||||
|
if (!selectedVariant?.configFiles)
|
||||||
|
return;
|
||||||
|
const updatedConfigFiles = [
|
||||||
|
...selectedVariant.configFiles,
|
||||||
|
];
|
||||||
|
updatedConfigFiles[index] = {
|
||||||
|
filePath: config.filePath,
|
||||||
|
content: value,
|
||||||
|
};
|
||||||
|
setTemplateInfo({
|
||||||
|
...templateInfo,
|
||||||
|
...(templateInfo.details && {
|
||||||
|
details: {
|
||||||
|
...templateInfo.details,
|
||||||
|
configFiles: updatedConfigFiles,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="text-center text-muted-foreground py-8">
|
||||||
|
<p>
|
||||||
|
This template doesn't require any configuration
|
||||||
|
files.
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-2">
|
||||||
|
All necessary configurations are handled through
|
||||||
|
environment variables.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -47,7 +47,14 @@ interface Details {
|
|||||||
envVariables: EnvVariable[];
|
envVariables: EnvVariable[];
|
||||||
shortDescription: string;
|
shortDescription: string;
|
||||||
domains: Domain[];
|
domains: Domain[];
|
||||||
|
configFiles: Mount[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Mount {
|
||||||
|
filePath: string;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TemplateInfo {
|
export interface TemplateInfo {
|
||||||
userInput: string;
|
userInput: string;
|
||||||
details?: Details | null;
|
details?: Details | null;
|
||||||
@@ -126,6 +133,7 @@ export const TemplateGenerator = ({ projectId }: Props) => {
|
|||||||
...(templateInfo.server?.serverId && {
|
...(templateInfo.server?.serverId && {
|
||||||
serverId: templateInfo.server?.serverId || "",
|
serverId: templateInfo.server?.serverId || "",
|
||||||
}),
|
}),
|
||||||
|
configFiles: templateInfo?.details?.configFiles || [],
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
toast.success("Compose Created");
|
toast.success("Compose Created");
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
apiUpdateAi,
|
apiUpdateAi,
|
||||||
deploySuggestionSchema,
|
deploySuggestionSchema,
|
||||||
} from "@dokploy/server/db/schema/ai";
|
} from "@dokploy/server/db/schema/ai";
|
||||||
import { createDomain } from "@dokploy/server/index";
|
import { createDomain, createMount } from "@dokploy/server/index";
|
||||||
import {
|
import {
|
||||||
deleteAiSettings,
|
deleteAiSettings,
|
||||||
getAiSettingById,
|
getAiSettingById,
|
||||||
@@ -126,8 +126,6 @@ export const aiRouter = createTRPCRouter({
|
|||||||
|
|
||||||
const projectName = slugify(`${project.name} ${input.id}`);
|
const projectName = slugify(`${project.name} ${input.id}`);
|
||||||
|
|
||||||
console.log(input);
|
|
||||||
|
|
||||||
const compose = await createComposeByTemplate({
|
const compose = await createComposeByTemplate({
|
||||||
...input,
|
...input,
|
||||||
composeFile: input.dockerCompose,
|
composeFile: input.dockerCompose,
|
||||||
@@ -136,6 +134,7 @@ export const aiRouter = createTRPCRouter({
|
|||||||
name: input.name,
|
name: input.name,
|
||||||
sourceType: "raw",
|
sourceType: "raw",
|
||||||
appName: `${projectName}-${generatePassword(6)}`,
|
appName: `${projectName}-${generatePassword(6)}`,
|
||||||
|
isolatedDeployment: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (input.domains && input.domains?.length > 0) {
|
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") {
|
if (ctx.user.rol === "member") {
|
||||||
await addNewService(
|
await addNewService(
|
||||||
|
|||||||
@@ -71,4 +71,12 @@ export const deploySuggestionSchema = z.object({
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
|
configFiles: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
filePath: z.string().min(1),
|
||||||
|
content: z.string().min(1),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -153,25 +153,21 @@ export const suggestVariants = async ({
|
|||||||
3. Don't set container_name field in services
|
3. Don't set container_name field in services
|
||||||
4. Don't set version field in the docker compose
|
4. Don't set version field in the docker compose
|
||||||
5. Don't set ports like 'ports: 3000:3000', use 'ports: "3000"' instead
|
5. Don't set ports like 'ports: 3000:3000', use 'ports: "3000"' instead
|
||||||
6. Use dokploy-network in all services
|
6. If a service depends on a database or other service, INCLUDE that service in the docker-compose
|
||||||
7. Add dokploy-network at the end and mark it as external: true
|
7. Make sure all required services are defined in the docker-compose
|
||||||
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
|
|
||||||
|
|
||||||
Volume Mounting Rules:
|
Volume Mounting and Configuration Rules:
|
||||||
1. All file mounts in volumes section MUST use "../files/" prefix
|
1. DO NOT create configuration files unless the service CANNOT work without them
|
||||||
2. NEVER use absolute paths or direct host paths
|
2. Most services can work with just environment variables - USE THEM FIRST
|
||||||
3. Format should be: "../files/folder:/container/path"
|
3. Ask yourself: "Can this be configured with an environment variable instead?"
|
||||||
4. If a service needs configuration files, they should be defined in configFiles array and referenced in volumes
|
4. If and ONLY IF a config file is absolutely required:
|
||||||
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"
|
- Keep it minimal with only critical settings
|
||||||
|
- Use "../files/" prefix for all mounts
|
||||||
|
- Format: "../files/folder:/container/path"
|
||||||
Configuration Files Rules:
|
5. DO NOT add configuration files for:
|
||||||
1. If a service needs configuration files, include them in the configFiles array
|
- Default configurations that work out of the box
|
||||||
2. Each config file should have:
|
- Settings that can be handled by environment variables
|
||||||
- content: The actual content of the configuration file
|
- Proxy or routing configurations (these are handled elsewhere)
|
||||||
- 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
|
|
||||||
|
|
||||||
Environment Variables Rules:
|
Environment Variables Rules:
|
||||||
1. For the envVariables array, provide ACTUAL example values, not placeholders
|
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
|
- 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
|
- port: the internal port the service runs on
|
||||||
- serviceName: the name of the service in the docker-compose
|
- 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:
|
Project details:
|
||||||
${suggestion?.description}
|
${suggestion?.description}
|
||||||
|
|||||||
Reference in New Issue
Block a user