diff --git a/src/app/api/generate/route.ts b/src/app/api/generate/route.ts index 3c7f56f..8eaaeee 100644 --- a/src/app/api/generate/route.ts +++ b/src/app/api/generate/route.ts @@ -1,18 +1,30 @@ import { NextResponse } from "next/server"; import { getGeminiModel } from "@/lib/gemini"; import { getRepoData, getRepoContents } from "@/lib/octokit"; +import { SUPPORTED_LANGUAGES } from "@/constants/languages"; export const dynamic = "force-dynamic"; /** * AI README Generation Endpoint - * Optimized for data accuracy and clean prompt interpolation. + * Optimized for data accuracy, clean prompt interpolation, and multi-language support. + * + * @param {Request} req - The incoming request object containing the repo URL and optional language. + * @returns {Promise} A JSON response containing the generated Markdown or an error message. */ export async function POST(req: Request) { let rawUrl: string; + let language: string; try { const body = await req.json(); rawUrl = body.url; + const rawLanguage = + typeof body.language === "string" ? body.language.trim() : ""; + const normalized = + rawLanguage.charAt(0).toUpperCase() + rawLanguage.slice(1).toLowerCase(); + language = (SUPPORTED_LANGUAGES as readonly string[]).includes(normalized) + ? normalized + : "English"; } catch { return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }); } @@ -96,7 +108,7 @@ export async function POST(req: Request) { // Fix: Prompt updated with neutral fallbacks and dynamic license const prompt = ` **Role**: You are a Principal Solutions Architect and World-Class Technical Writer. -**Task**: Generate a professional, high-conversion README.md for the GitHub repository: "${repo}". +**Task**: Generate a professional, high-conversion README.md for the GitHub repository: "${repo}" in the following language: **${language}**. --- ### 1. PROJECT CONTEXT (VERIFIED DATA) diff --git a/src/app/generate/GeneratePageClient.tsx b/src/app/generate/GeneratePageClient.tsx index 8980251..77215d1 100644 --- a/src/app/generate/GeneratePageClient.tsx +++ b/src/app/generate/GeneratePageClient.tsx @@ -26,14 +26,17 @@ export default function GeneratePageClient({ repoSlug }: GeneratePageProps) { } }, [repoSlug]); - const handleGenerate = async (githubUrl: string) => { + const handleGenerate = async ( + githubUrl: string, + language: string = "English", + ) => { setIsLoading(true); setMarkdown(""); try { const response = await fetch("/api/generate", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ url: githubUrl }), + body: JSON.stringify({ url: githubUrl, language }), }); if (!response.ok) { diff --git a/src/components/Generator/SearchInput.tsx b/src/components/Generator/SearchInput.tsx index 1f6d1fe..eee2617 100644 --- a/src/components/Generator/SearchInput.tsx +++ b/src/components/Generator/SearchInput.tsx @@ -2,14 +2,22 @@ import React, { useState } from "react"; import { Loader2, Github, AlertCircle } from "lucide-react"; import { Button } from "../ui/Button"; +import { SUPPORTED_LANGUAGES } from "@/constants/languages"; interface SearchInputProps { - onGenerate: (url: string) => void; + onGenerate: (url: string, language: string) => void; isLoading: boolean; initialValue?: string; // optional initial value ariaLabel?: string; // optional aria-label for accessibility } +/** + * SearchInput Component + * Renders a responsive form for GitHub URL input and language selection. + * + * @param {SearchInputProps} props - The component props. + * @returns {JSX.Element} The rendered search input form. + */ export const SearchInput = ({ onGenerate, isLoading, @@ -18,6 +26,7 @@ export const SearchInput = ({ }: SearchInputProps) => { // Initialize state directly from initialValue once const [url, setUrl] = useState(initialValue || ""); + const [language, setLanguage] = useState("English"); const [error, setError] = useState(null); const handleSubmit = (e: React.FormEvent) => { @@ -28,36 +37,59 @@ export const SearchInput = ({ /^https?:\/\/(www\.)?github\.com\/[\w.-]+\/[\w.-]+\/?$/; if (githubUrlPattern.test(url.trim())) { - onGenerate(url.trim()); + onGenerate(url.trim(), language); } else { setError("Please enter a valid GitHub repository URL."); } }; return ( -
-
-
- +
+ +
+
+ +
+ { + setUrl(e.target.value); + if (error) setError(null); + }} + placeholder="https://github.com/username/repo" + aria-label={ariaLabel} + className={`w-full bg-zinc-900/50 border ${ + error ? "border-red-500/50" : "border-white/10" + } rounded-2xl py-6 pl-14 pr-4 text-white placeholder:text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500/50 transition-all backdrop-blur-xl`} + />
- { - setUrl(e.target.value); - if (error) setError(null); - }} - placeholder="https://github.com/username/repo" - aria-label={ariaLabel} - className={`w-full bg-zinc-900/50 border ${ - error ? "border-red-500/50" : "border-white/10" - } rounded-2xl py-6 pl-14 pr-40 text-white placeholder:text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500/50 transition-all backdrop-blur-xl`} - /> -
+ +
+ +