feat: add dynamic file structure context in AI chat

- Improved file structure formatting with tree-like visualization
- Added filtering for ignored files and folders
- Added scripts section to template context
- Fixed folder hierarchy display with proper indentation
- Maintains sorting with folders first, then files alphabetically
- Now uses actual project files instead of template structure

Example output:
├── app/
│   ├── api/
│   └── page.tsx
├── components/
└── package.json
This commit is contained in:
Akhileshrangani4 2024-11-30 15:53:17 -05:00
parent e384607d24
commit 534b148b86
3 changed files with 45 additions and 6 deletions

View File

@ -2,11 +2,44 @@ import { currentUser } from "@clerk/nextjs"
import { Anthropic } from "@anthropic-ai/sdk"
import { TIERS } from "@/lib/tiers"
import { templateConfigs } from "@/lib/templates"
import { TFile, TFolder } from "@/lib/types"
import { ignoredFiles, ignoredFolders } from "@/components/editor/AIChat/lib/ignored-paths"
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY!,
})
// Format file structure for context
function formatFileStructure(items: (TFile | TFolder)[] | undefined, prefix = ""): string {
if (!items || !Array.isArray(items)) {
return "No files available"
}
// Sort items to show folders first, then files
const sortedItems = [...items].sort((a, b) => {
if (a.type === b.type) return a.name.localeCompare(b.name)
return a.type === "folder" ? -1 : 1
})
return sortedItems
.map((item) => {
if (item.type === "file" && !ignoredFiles.some(
(pattern) => item.name.endsWith(pattern.replace("*", "")) || item.name === pattern
)) {
return `${prefix}├── ${item.name}`
} else if (
item.type === "folder" &&
!ignoredFolders.some((folder) => folder === item.name)
) {
const folderContent = formatFileStructure(item.children, `${prefix}`)
return `${prefix}├── ${item.name}/\n${folderContent}`
}
return null
})
.filter(Boolean)
.join("\n")
}
export async function POST(request: Request) {
try {
const user = await currentUser()
@ -60,6 +93,7 @@ export async function POST(request: Request) {
fileName,
line,
templateType,
files,
} = await request.json()
// Get template configuration
@ -70,16 +104,17 @@ export async function POST(request: Request) {
? `
Project Template: ${templateConfig.name}
File Structure:
${Object.entries(templateConfig.fileStructure)
.map(([path, info]) => `${path} - ${info.description}`)
.join("\n")}
Current File Structure:
${files ? formatFileStructure(files) : "No files available"}
Conventions:
${templateConfig.conventions.join("\n")}
Dependencies:
${JSON.stringify(templateConfig.dependencies, null, 2)}
Scripts:
${JSON.stringify(templateConfig.scripts, null, 2)}
`
: ""

View File

@ -148,7 +148,8 @@ export default function AIChat({
abortControllerRef,
activeFileContent,
false,
templateType
templateType,
files
)
}

View File

@ -1,3 +1,4 @@
import { TFolder, TFile } from "@/lib/types"
import React from "react"
// Stringify content for chat message component
@ -91,7 +92,8 @@ export const handleSend = async (
abortControllerRef: React.MutableRefObject<AbortController | null>,
activeFileContent: string,
isEditMode: boolean = false,
templateType: string
templateType: string,
files: (TFile | TFolder)[]
) => {
// Return if input is empty and context is null
if (input.trim() === "" && !context) return
@ -142,6 +144,7 @@ export const handleSend = async (
activeFileContent: activeFileContent,
isEditMode: isEditMode,
templateType: templateType,
files: files,
}),
signal: abortControllerRef.current.signal,
})