feat: file path above each code snippet
This commit is contained in:
parent
1630a5a9cd
commit
0ae89341d2
@ -1,16 +1,22 @@
|
||||
import { currentUser } from "@clerk/nextjs"
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { TIERS } from "@/lib/tiers"
|
||||
import {
|
||||
ignoredFiles,
|
||||
ignoredFolders,
|
||||
} from "@/components/editor/AIChat/lib/ignored-paths"
|
||||
import { templateConfigs } from "@/lib/templates"
|
||||
import { TIERS } from "@/lib/tiers"
|
||||
import { TFile, TFolder } from "@/lib/types"
|
||||
import { ignoredFiles, ignoredFolders } from "@/components/editor/AIChat/lib/ignored-paths"
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { currentUser } from "@clerk/nextjs"
|
||||
|
||||
const anthropic = new Anthropic({
|
||||
apiKey: process.env.ANTHROPIC_API_KEY!,
|
||||
})
|
||||
|
||||
// Format file structure for context
|
||||
function formatFileStructure(items: (TFile | TFolder)[] | undefined, prefix = ""): string {
|
||||
function formatFileStructure(
|
||||
items: (TFile | TFolder)[] | undefined,
|
||||
prefix = ""
|
||||
): string {
|
||||
if (!items || !Array.isArray(items)) {
|
||||
return "No files available"
|
||||
}
|
||||
@ -23,15 +29,23 @@ function formatFileStructure(items: (TFile | TFolder)[] | undefined, prefix = ""
|
||||
|
||||
return sortedItems
|
||||
.map((item) => {
|
||||
if (item.type === "file" && !ignoredFiles.some(
|
||||
(pattern) => item.name.endsWith(pattern.replace("*", "")) || item.name === pattern
|
||||
)) {
|
||||
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}│ `)
|
||||
const folderContent = formatFileStructure(
|
||||
item.children,
|
||||
`${prefix}│ `
|
||||
)
|
||||
return `${prefix}├── ${item.name}/\n${folderContent}`
|
||||
}
|
||||
return null
|
||||
@ -94,6 +108,7 @@ export async function POST(request: Request) {
|
||||
line,
|
||||
templateType,
|
||||
files,
|
||||
projectName,
|
||||
} = await request.json()
|
||||
|
||||
// Get template configuration
|
||||
@ -138,13 +153,23 @@ Instructions: ${messages[0].content}
|
||||
|
||||
Respond only with the modified code that can directly replace the existing code.`
|
||||
} else {
|
||||
systemMessage = `You are an intelligent programming assistant for a ${templateType} project. Please respond to the following request concisely. If your response includes code, please format it using triple backticks (\`\`\`) with the appropriate language identifier. For example:
|
||||
systemMessage = `You are an intelligent programming assistant for a ${templateType} project. Please respond to the following request concisely. When providing code:
|
||||
|
||||
\`\`\`python
|
||||
print("Hello, World!")
|
||||
1. Format it using triple backticks (\`\`\`) with the appropriate language identifier.
|
||||
2. Always specify the complete file path in the format:
|
||||
${projectName}/filepath/to/file.ext
|
||||
|
||||
3. If creating a new file, specify the path as:
|
||||
${projectName}/filepath/to/file.ext (new file)
|
||||
|
||||
4. Format your code blocks as:
|
||||
|
||||
${projectName}/filepath/to/file.ext
|
||||
\`\`\`language
|
||||
code here
|
||||
\`\`\`
|
||||
|
||||
Provide a clear and concise explanation along with any code snippets. Keep your response brief and to the point.
|
||||
If multiple files are involved, repeat the format for each file. Provide a clear and concise explanation along with any code snippets. Keep your response brief and to the point.
|
||||
|
||||
This is the project template:
|
||||
${templateContext}
|
||||
|
@ -21,6 +21,7 @@ export default function AIChat({
|
||||
handleApplyCode,
|
||||
mergeDecorationsCollection,
|
||||
setMergeDecorationsCollection,
|
||||
projectName,
|
||||
}: AIChatProps) {
|
||||
// Initialize socket and messages
|
||||
const { socket } = useSocket()
|
||||
@ -152,7 +153,8 @@ export default function AIChat({
|
||||
activeFileContent,
|
||||
false,
|
||||
templateType,
|
||||
files
|
||||
files,
|
||||
projectName
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,8 @@ export const handleSend = async (
|
||||
activeFileContent: string,
|
||||
isEditMode: boolean = false,
|
||||
templateType: string,
|
||||
files: (TFile | TFolder)[]
|
||||
files: (TFile | TFolder)[],
|
||||
projectName: string
|
||||
) => {
|
||||
// Return if input is empty and context is null
|
||||
if (input.trim() === "" && !context) return
|
||||
@ -145,6 +146,7 @@ export const handleSend = async (
|
||||
isEditMode: isEditMode,
|
||||
templateType: templateType,
|
||||
files: files,
|
||||
projectName: projectName,
|
||||
}),
|
||||
signal: abortControllerRef.current.signal,
|
||||
})
|
||||
@ -241,3 +243,9 @@ export const looksLikeCode = (text: string): boolean => {
|
||||
|
||||
return codeIndicators.some((pattern) => pattern.test(text))
|
||||
}
|
||||
|
||||
// Add this new function after looksLikeCode function
|
||||
export const isFilePath = (text: string): boolean => {
|
||||
// Match patterns like project/path/to/file.ext or project/path/to/file.ext (new file)
|
||||
return /^[a-zA-Z0-9_-]+\/[\w/-]+\.[a-zA-Z0-9]+(\s+\(new file\))?$/.test(text)
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { Check, CornerUpLeft, X } from "lucide-react"
|
||||
import { Check, CornerUpLeft, X, FileText } from "lucide-react"
|
||||
import monaco from "monaco-editor"
|
||||
import { Components } from "react-markdown"
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
|
||||
import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism"
|
||||
import { Button } from "../../../ui/button"
|
||||
import ApplyButton from "../ApplyButton"
|
||||
import { stringifyContent } from "./chatUtils"
|
||||
import { stringifyContent, isFilePath } from "./chatUtils"
|
||||
|
||||
// Create markdown components for chat message component
|
||||
export const createMarkdownComponents = (
|
||||
@ -126,8 +126,20 @@ export const createMarkdownComponents = (
|
||||
)
|
||||
},
|
||||
// Render markdown elements
|
||||
p: ({ node, children, ...props }) =>
|
||||
renderMarkdownElement({ node, children, ...props }),
|
||||
p: ({ node, children, ...props }) => {
|
||||
const content = stringifyContent(children)
|
||||
|
||||
if (isFilePath(content)) {
|
||||
return (
|
||||
<div className="relative group flex items-center gap-2 px-2 py-1 bg-secondary/50 rounded-md my-2 text-xs w-fit">
|
||||
<FileText className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-mono">{content}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return renderMarkdownElement({ node, children, ...props })
|
||||
},
|
||||
h1: ({ node, children, ...props }) =>
|
||||
renderMarkdownElement({ node, children, ...props }),
|
||||
h2: ({ node, children, ...props }) =>
|
||||
|
@ -56,6 +56,7 @@ export interface AIChatProps {
|
||||
files: (TFile | TFolder)[]
|
||||
templateType: string
|
||||
templateConfig?: TemplateConfig
|
||||
projectName: string
|
||||
handleApplyCode: (mergedCode: string) => void
|
||||
mergeDecorationsCollection?: monaco.editor.IEditorDecorationsCollection
|
||||
setMergeDecorationsCollection?: (collection: undefined) => void
|
||||
|
@ -1284,6 +1284,7 @@ export default function CodeEditor({
|
||||
lastCopiedRangeRef={lastCopiedRangeRef}
|
||||
files={files}
|
||||
templateType={sandboxData.type}
|
||||
projectName={sandboxData.name}
|
||||
handleApplyCode={handleApplyCode}
|
||||
mergeDecorationsCollection={mergeDecorationsCollection}
|
||||
setMergeDecorationsCollection={setMergeDecorationsCollection}
|
||||
|
Loading…
x
Reference in New Issue
Block a user