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:
Mauricio Siu
2025-03-02 01:54:39 -06:00
parent e7db3a196c
commit a8fc27e830
6 changed files with 137 additions and 28 deletions

View File

@@ -85,6 +85,22 @@ export const StepThree = ({ templateInfo }: StepProps) => {
)}
</ul>
</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>

View File

@@ -24,11 +24,7 @@ export interface StepProps {
setTemplateInfo: React.Dispatch<React.SetStateAction<TemplateInfo>>;
}
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<Record<string, boolean>>({});
@@ -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 = ({
</ScrollArea>
</AccordionContent>
</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>
</ScrollArea>
</>

View File

@@ -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");

View File

@@ -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(