diff --git a/docs/multi-step-integration-guide.md b/docs/multi-step-integration-guide.md new file mode 100644 index 0000000..84e271f --- /dev/null +++ b/docs/multi-step-integration-guide.md @@ -0,0 +1,491 @@ +# Multi-Step README Generation Pipeline - Integration Guide + +This guide provides complete instructions for integrating the multi-step README generation pipeline into an existing Next.js application, specifically for the ReadmeGenAI project. + +## ๐Ÿ“‹ Overview + +The new pipeline solves the token limit issues by: +- **Section-by-section generation**: Each section is generated individually within token limits +- **Retry logic**: Failed sections are automatically retried with simplified prompts +- **Smart dependency management**: Sections are generated in optimal order based on dependencies +- **Continuation support**: Truncated content can be automatically completed +- **Fallback mechanisms**: Critical sections always have fallback content + +## ๐Ÿš€ Quick Integration + +### 1. Install Dependencies + +```bash +npm install @google/generative-ai @octokit/rest +``` + +### 2. Replace Existing API Route + +Replace the content of `src/app/api/generate/route.ts`: + +```typescript +import { handleReadmeGeneration } from '@/lib/multi-step-readme-generator'; + +export async function POST(request: Request) { + return handleReadmeGeneration(request); +} +``` + +### 3. Environment Variables + +Ensure these environment variables are set: + +```env +GEMINI_API_KEY=your_gemini_api_key +GITHUB_TOKEN=your_github_token # Optional but recommended for higher rate limits +``` + +### 4. Update Frontend (Optional) + +Enhance the frontend to show generation progress: + +```typescript +// In your component +const [generationStats, setGenerationStats] = useState(null); + +const handleGenerate = async (githubUrl: string) => { + setIsLoading(true); + + try { + const response = await fetch('/api/generate', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ githubUrl }), + }); + + const result = await response.json(); + + if (result.success) { + setReadme(result.readme); + setGenerationStats(result.stats); + } else { + setError(result.error); + } + } catch (error) { + setError('Generation failed'); + } finally { + setIsLoading(false); + } +}; +``` + +## ๐Ÿ”ง Advanced Configuration + +### Custom Configuration + +You can customize the generation behavior: + +```typescript +import { MultiStepReadmeGenerator } from '@/lib/multi-step-readme-generator'; + +const generator = new MultiStepReadmeGenerator( + process.env.GEMINI_API_KEY!, + process.env.GITHUB_TOKEN, + { + maxRetries: 5, // Increase retries for better reliability + maxTokensPerSection: 1000, // Allow longer sections + temperature: 0.5, // More conservative generation + concurrentSections: 2, // Reduce concurrency to avoid rate limits + enableContinuation: true, // Enable automatic continuation + } +); +``` + +### Custom Section Planning + +Define custom sections for specific project types: + +```typescript +import { SectionPlanner, ReadmeSection } from '@/lib/multi-step-readme-generator'; + +// Custom sections for a specific project type +const customSections: ReadmeSection[] = [ + { + id: 'header', + title: 'Project Header', + priority: 'critical', + order: 1, + estimatedTokens: 200, + dependencies: [], + }, + { + id: 'quick-start', + title: 'Quick Start', + priority: 'high', + order: 2, + estimatedTokens: 400, + dependencies: ['header'], + }, + // ... more sections +]; + +const result = await assembler.generateCompleteReadme( + metadata, + structure, + customSections +); +``` + +## ๐Ÿ“Š Monitoring and Analytics + +### Generation Stats + +The new pipeline provides detailed statistics: + +```typescript +interface GenerationStats { + sectionsGenerated: number; // How many sections were successfully generated + sectionsTotal: number; // Total sections planned + tokensUsed: number; // Total tokens consumed + timeElapsed: number; // Generation time in milliseconds +} +``` + +### Error Handling + +Comprehensive error information: + +```typescript +interface GenerationResult { + success: boolean; + readme?: string; + stats: GenerationStats; + errors: string[]; // Detailed error messages +} +``` + +### Logging Integration + +Add logging to track generation performance: + +```typescript +// In your API route +const result = await generator.generateReadme(githubUrl); + +// Log metrics +console.log(`README generated for ${githubUrl}:`, { + success: result.success, + sectionsGenerated: result.stats.sectionsGenerated, + timeElapsed: result.stats.timeElapsed, + tokensUsed: result.stats.tokensUsed, +}); + +// Log errors for debugging +if (result.errors.length > 0) { + console.error('Generation errors:', result.errors); +} +``` + +## ๐Ÿ”„ Migration from Existing Implementation + +### Step 1: Backup Current Implementation + +```bash +# Backup current generate route +cp src/app/api/generate/route.ts src/app/api/generate/route.ts.backup +``` + +### Step 2: Gradual Migration + +Implement a feature flag for gradual rollout: + +```typescript +// src/app/api/generate/route.ts +import { handleReadmeGeneration as newHandler } from '@/lib/multi-step-readme-generator'; +import { handleReadmeGeneration as oldHandler } from '@/lib/old-readme-generator'; + +export async function POST(request: Request) { + const useNewPipeline = process.env.USE_NEW_README_PIPELINE === 'true'; + + if (useNewPipeline) { + return newHandler(request); + } else { + return oldHandler(request); + } +} +``` + +### Step 3: A/B Testing + +Compare old vs new implementation: + +```typescript +export async function POST(request: Request) { + const body = await request.json(); + const { githubUrl, useNewPipeline } = body; + + if (useNewPipeline) { + return handleReadmeGeneration(request); + } else { + // Use old implementation + return oldReadmeGeneration(request); + } +} +``` + +## ๐Ÿ› ๏ธ Troubleshooting + +### Common Issues and Solutions + +#### 1. Token Limit Exceeded + +**Problem**: Even individual sections exceed token limits +**Solution**: Reduce `maxTokensPerSection` or simplify prompts + +```typescript +const generator = new MultiStepReadmeGenerator(apiKey, githubToken, { + maxTokensPerSection: 600, // Reduce from default 800 +}); +``` + +#### 2. Rate Limiting + +**Problem**: API rate limits exceeded +**Solution**: Reduce concurrency and add delays + +```typescript +const generator = new MultiStepReadmeGenerator(apiKey, githubToken, { + concurrentSections: 1, // Generate one section at a time +}); +``` + +#### 3. GitHub API Rate Limits + +**Problem**: Repository analysis fails due to rate limits +**Solution**: Provide GitHub token and implement caching + +```typescript +// Implement simple caching +const cache = new Map(); + +class CachedRepositoryAnalyzer extends RepositoryAnalyzer { + async analyzeRepository(owner: string, repo: string) { + const key = `${owner}/${repo}`; + + if (cache.has(key)) { + return cache.get(key); + } + + const result = await super.analyzeRepository(owner, repo); + cache.set(key, result); + + return result; + } +} +``` + +#### 4. Incomplete Sections + +**Problem**: Some sections are consistently incomplete +**Solution**: Increase retries or customize prompts + +```typescript +// Custom prompt for problematic section +const customPrompts = { + installation: `Generate concise installation instructions for "${metadata.name}". + + Context: ${structure.techStack.primary} project + + Requirements: + - Prerequisites (if any) + - Single command installation + - Verification step + + Keep it under 300 words. Return only markdown.`, +}; +``` + +### Debug Mode + +Enable detailed logging: + +```typescript +// Set environment variable +process.env.DEBUG_README_GENERATION = 'true'; + +// In the generator +if (process.env.DEBUG_README_GENERATION === 'true') { + console.log('Section generation details:', { + sectionId, + prompt: prompt.substring(0, 200) + '...', + result: result.success ? 'success' : 'failed', + tokensUsed: result.tokensUsed, + }); +} +``` + +## ๐Ÿ“ˆ Performance Optimizations + +### 1. Caching Strategy + +Implement Redis caching for repository analysis: + +```typescript +import Redis from 'ioredis'; + +const redis = new Redis(process.env.REDIS_URL); + +class CachedAnalyzer extends RepositoryAnalyzer { + async analyzeRepository(owner: string, repo: string) { + const key = `repo:${owner}:${repo}`; + const cached = await redis.get(key); + + if (cached) { + return JSON.parse(cached); + } + + const result = await super.analyzeRepository(owner, repo); + await redis.setex(key, 3600, JSON.stringify(result)); // 1 hour cache + + return result; + } +} +``` + +### 2. Background Processing + +For large repositories, use background jobs: + +```typescript +import Bull from 'bull'; + +const readmeQueue = new Bull('readme generation'); + +// API route for immediate response +export async function POST(request: Request) { + const { githubUrl } = await request.json(); + + const job = await readmeQueue.add('generate', { githubUrl }); + + return Response.json({ + jobId: job.id, + status: 'queued', + }); +} + +// Background worker +readmeQueue.process('generate', async (job) => { + const { githubUrl } = job.data; + const generator = new MultiStepReadmeGenerator(...); + + return generator.generateReadme(githubUrl); +}); +``` + +### 3. Streaming Responses + +Stream sections as they're generated: + +```typescript +export async function POST(request: Request) { + const { githubUrl } = await request.json(); + + const stream = new ReadableStream({ + async start(controller) { + const generator = new MultiStepReadmeGenerator(...); + + // Override assembler to stream results + const originalAssembler = generator.assembler; + generator.assembler.generateSectionsInBatches = async (...args) => { + // Stream each section as it's completed + // Implementation details... + }; + + const result = await generator.generateReadme(githubUrl); + controller.close(); + }, + }); + + return new Response(stream, { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + }, + }); +} +``` + +## ๐Ÿงช Testing + +### Unit Tests + +```typescript +// __tests__/readme-generator.test.ts +import { MultiStepReadmeGenerator, RepositoryAnalyzer } from '@/lib/multi-step-readme-generator'; + +describe('MultiStepReadmeGenerator', () => { + it('should generate complete README for public repository', async () => { + const generator = new MultiStepReadmeGenerator( + process.env.GEMINI_API_KEY, + process.env.GITHUB_TOKEN + ); + + const result = await generator.generateReadme( + 'https://github.com/octocat/Hello-World' + ); + + expect(result.success).toBe(true); + expect(result.readme).toContain('# Hello-World'); + expect(result.stats.sectionsGenerated).toBeGreaterThan(0); + }); +}); +``` + +### Integration Tests + +```typescript +describe('API Integration', () => { + it('should handle README generation request', async () => { + const response = await fetch('/api/generate', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + githubUrl: 'https://github.com/octocat/Hello-World' + }), + }); + + const result = await response.json(); + + expect(response.status).toBe(200); + expect(result.success).toBe(true); + expect(result.readme).toBeDefined(); + }); +}); +``` + +## ๐Ÿ“š API Reference + +### Main Classes + +- **`MultiStepReadmeGenerator`**: Main orchestrator class +- **`RepositoryAnalyzer`**: Analyzes GitHub repositories +- **`SectionPlanner`**: Plans optimal README sections +- **`SectionGenerator`**: Generates individual sections +- **`ReadmeAssembler`**: Assembles and validates final README + +### Configuration Options + +```typescript +interface GenerationConfig { + maxRetries: number; // Default: 3 + maxTokensPerSection: number; // Default: 800 + temperature: number; // Default: 0.7 + concurrentSections: number; // Default: 3 + enableContinuation: boolean; // Default: true +} +``` + +### Section Types + +- **Critical**: `header`, `description`, `installation` +- **High**: `features`, `usage`, `api` +- **Medium**: `configuration`, `development`, `contributing`, `deployment` +- **Low**: `testing`, `examples` + +This comprehensive integration guide provides everything needed to successfully implement the multi-step README generation pipeline in the ReadmeGenAI project, solving the token limit issues while providing a more robust and reliable generation process. \ No newline at end of file diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..8603b53 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,9 @@ +# * +User-agent: * +Allow: / + +# Host +Host: https://readmegen-ai.vercel.app + +# Sitemaps +Sitemap: https://readmegen-ai.vercel.app/sitemap.xml diff --git a/public/sitemap-0.xml b/public/sitemap-0.xml new file mode 100644 index 0000000..2f06acb --- /dev/null +++ b/public/sitemap-0.xml @@ -0,0 +1,8 @@ + + +https://readmegen-ai.vercel.app2026-04-04T06:46:25.330Zweekly1 +https://readmegen-ai.vercel.app/docs2026-04-04T06:46:25.330Zmonthly0.8 +https://readmegen-ai.vercel.app/examples2026-04-04T06:46:25.330Zmonthly0.8 +https://readmegen-ai.vercel.app/features2026-04-04T06:46:25.330Zmonthly0.8 +https://readmegen-ai.vercel.app/generate2026-04-04T06:46:25.330Zweekly0.9 + \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..b3a9e11 --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,4 @@ + + +https://readmegen-ai.vercel.app/sitemap-0.xml + \ No newline at end of file diff --git a/src/app/api/generate/route.ts b/src/app/api/generate/route.ts index acb17e5..41d7c29 100644 --- a/src/app/api/generate/route.ts +++ b/src/app/api/generate/route.ts @@ -1,40 +1,36 @@ -import { NextResponse } from "next/server"; -import { getGeminiModel } from "@/lib/gemini"; -import { getRepoData, getRepoContents } from "@/lib/octokit"; -import { SUPPORTED_LANGUAGES } from "@/constants/languages"; +import { NextRequest, NextResponse } from "next/server"; +import { MultiStepReadmeGenerator } from "@/lib/multi-step-readme-generator"; export const dynamic = "force-dynamic"; /** - * AI README Generation Endpoint - * Optimized for data accuracy, clean prompt interpolation, and multi-language support. + * Enhanced Multi-Step README Generation Endpoint * - * @param {Request} req - The incoming Next.js/standard Web API Request object containing the repo URL and optional language. - * @returns {Promise} A JSON response containing the generated Markdown or an error message. + * This endpoint uses a sophisticated multi-step approach to generate READMEs: + * 1. Repository Analysis - Smart analysis with token-conscious filtering + * 2. Section Planning - Dynamic sections based on project type + * 3. Section Generation - Individual section generation within token limits + * 4. Assembly & Validation - Retry logic and fallback mechanisms + * + * Fixes token limit issues from issue #101 by generating sections individually. */ -export async function POST(req: Request) { - let rawUrl: string; - let language: string; +export async function POST(request: NextRequest) { try { - const body = await req.json(); - rawUrl = body.url; - language = body.language || "English"; - } catch { - return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }); - } + const body = await request.json(); + const { url: githubUrl } = body; - try { - const trimmedUrl = rawUrl?.trim(); - if (!trimmedUrl) { + // Validate required fields + if (!githubUrl) { return NextResponse.json( { error: "GitHub URL is required" }, { status: 400 }, ); } + // Validate GitHub URL format let parsedUrl: URL; try { - parsedUrl = new URL(trimmedUrl); + parsedUrl = new URL(githubUrl.trim()); } catch { return NextResponse.json( { error: "Please provide a valid URL" }, @@ -63,107 +59,78 @@ export async function POST(req: Request) { ); } - const [repoInfo, repoContents] = await Promise.all([ - getRepoData(owner, repo), - getRepoContents(owner, repo), - ]); - - const files = Array.isArray(repoContents) - ? repoContents.map((f: { name: string }) => f.name) - : []; - const fileListString = - files.length > 0 ? files.join(", ") : "Standard repository structure"; - - // Tech Stack detection logic - const hasNode = files.includes("package.json"); - const hasPython = - files.includes("requirements.txt") || files.includes("setup.py"); - const hasDocker = - files.includes("Dockerfile") || files.includes("docker-compose.yml"); - - // Fix: Cleanly joined Tech Stack labels - const stackLabels = - [ - hasNode && "Node.js Environment", - hasPython && "Python Environment", - hasDocker && "Containerized", - ] - .filter(Boolean) - .join(", ") || "Generic Software Environment"; - - // Fix: Dynamic License detection - const licenseName = - repoInfo?.license?.name || - repoInfo?.license?.spdx_id || - "the repository's license file"; - - const model = getGeminiModel(); - - // 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}" in the following language: **${language}**. - ---- -### 1. PROJECT CONTEXT (VERIFIED DATA) -- **Project Name**: ${repo} -- **Description**: ${repoInfo?.description || "No description provided."} -- **Primary Language**: ${repoInfo?.language || "Language unknown"} -- **Detected Root Files**: ${fileListString} -- **Tech Stack Context**: ${stackLabels} - ---- -### 2. STRICT README STRUCTURE REQUIREMENTS - -1. **Visual Header**: - - Center-aligned H1 with project name. - - A compelling 1-sentence tagline describing the **Value Proposition**. - - A centered row of Shields.io badges (Build, License, PRs Welcome, Stars). - -2. **The Strategic "Why" (Overview)**: - - **The Problem**: Use a blockquote to describe the real-world pain point this project solves. - - **The Solution**: Explain how this project provides a superior outcome for the user. - -3. **Key Features**: - - Minimum 5 features. Use emojis and focus on **User Benefits**. - -4. **Technical Architecture**: - - Provide a table of the tech stack: | Technology | Purpose | Key Benefit |. - - Create a tree-style directory structure code block using ๐Ÿ“ for folders and ๐Ÿ“„ for files based on the file manifest provided. - -5. **Operational Setup**: - - **Prerequisites**: List required runtimes. - - **Installation**: Provide step-by-step terminal commands. - ${hasNode ? "- Use npm/yarn/pnpm since package.json was detected." : ""} - ${hasPython ? "- Use pip/venv since Python markers were detected." : ""} - - **Environment**: If any .env or config files are in the manifest, include a configuration section. - -6. **Community & Governance**: - - Professional "Contributing" section (Fork -> Branch -> PR). - - Detailed "License" section: Reference ${licenseName} and provide a summary of permissions. - ---- -### 3. TONE & STYLE -- **Tone**: Authoritative, polished, and developer-centric. -- **Visuals**: Extensive use of Markdown formatting. -- **Constraint**: Return ONLY the raw Markdown. No conversational filler. - `; - - const result = await model.generateContent(prompt); - const response = await result.response; - const markdown = response.text().trim(); - const cleanMarkdown = markdown - .replace(/^```(markdown|md)?\n/, "") - .replace(/\n```$/, ""); + // Initialize the multi-step generator with enhanced configuration + const generator = new MultiStepReadmeGenerator( + process.env.GEMINI_API_KEY!, + process.env.GITHUB_TOKEN, // Optional GitHub token for higher rate limits + { + maxRetries: 3, + maxTokensPerSection: 800, // Smaller token limit per section + temperature: 0.7, + concurrentSections: 3, // Generate multiple sections in parallel + enableContinuation: true, // Enable automatic continuation for truncated content + }, + ); - return NextResponse.json({ markdown: cleanMarkdown }); - } catch (error: unknown) { - const message = - error instanceof Error ? error.message : "Internal Server Error"; - console.error("README Generation Failed:", message); + // Generate README with detailed tracking + const startTime = Date.now(); + console.log("Starting multi-step README generation for", githubUrl); + + const result = await generator.generateReadme(githubUrl); + const endTime = Date.now(); + + // Log generation statistics for monitoring + console.log("README generation completed for", githubUrl, { + success: result.success, + sectionsGenerated: result.stats.sectionsGenerated, + sectionsTotal: result.stats.sectionsTotal, + tokensUsed: result.stats.tokensUsed, + timeElapsed: endTime - startTime, + errors: result.errors.length, + }); + + if (!result.success) { + console.error("README generation failed:", result.errors); + return NextResponse.json( + { + error: "Failed to generate README using multi-step pipeline", + details: result.errors, + stats: result.stats, + }, + { status: 500 }, + ); + } + // Return successful result with enhanced metadata + return NextResponse.json({ + success: true, + markdown: result.readme, // Keep 'markdown' key for compatibility with existing frontend + stats: { + sectionsGenerated: result.stats.sectionsGenerated, + sectionsTotal: result.stats.sectionsTotal, + tokensUsed: result.stats.tokensUsed, + timeElapsed: result.stats.timeElapsed, + generationMethod: "multi-step", // Indicate the method used + }, + metadata: { + name: result.metadata?.name, + description: result.metadata?.description, + language: result.metadata?.language, + stars: result.metadata?.stars, + license: result.metadata?.license, + projectType: result.structure?.projectType, + techStack: result.structure?.techStack.primary, + frameworks: result.structure?.techStack.frameworks, + }, + warnings: result.errors.length > 0 ? result.errors : undefined, + }); + } catch (error) { + console.error("Multi-step README generation API error:", error); return NextResponse.json( - { error: "Failed to generate README. Check your URL and try again." }, + { + error: "Internal server error in multi-step README generation", + message: error instanceof Error ? error.message : "Unknown error", + }, { status: 500 }, ); } diff --git a/src/app/api/generate/route.ts.backup b/src/app/api/generate/route.ts.backup new file mode 100644 index 0000000..acb17e5 --- /dev/null +++ b/src/app/api/generate/route.ts.backup @@ -0,0 +1,170 @@ +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, clean prompt interpolation, and multi-language support. + * + * @param {Request} req - The incoming Next.js/standard Web API 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; + language = body.language || "English"; + } catch { + return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }); + } + + try { + const trimmedUrl = rawUrl?.trim(); + if (!trimmedUrl) { + return NextResponse.json( + { error: "GitHub URL is required" }, + { status: 400 }, + ); + } + + let parsedUrl: URL; + try { + parsedUrl = new URL(trimmedUrl); + } catch { + return NextResponse.json( + { error: "Please provide a valid URL" }, + { status: 400 }, + ); + } + + if ( + parsedUrl.hostname !== "github.com" && + parsedUrl.hostname !== "www.github.com" + ) { + return NextResponse.json( + { error: "Only GitHub URLs are supported" }, + { status: 400 }, + ); + } + + const pathSegments = parsedUrl.pathname.split("/").filter(Boolean); + const owner = pathSegments[0]; + const repo = pathSegments[1]; + + if (!owner || !repo) { + return NextResponse.json( + { error: "URL must include owner and repository name" }, + { status: 400 }, + ); + } + + const [repoInfo, repoContents] = await Promise.all([ + getRepoData(owner, repo), + getRepoContents(owner, repo), + ]); + + const files = Array.isArray(repoContents) + ? repoContents.map((f: { name: string }) => f.name) + : []; + const fileListString = + files.length > 0 ? files.join(", ") : "Standard repository structure"; + + // Tech Stack detection logic + const hasNode = files.includes("package.json"); + const hasPython = + files.includes("requirements.txt") || files.includes("setup.py"); + const hasDocker = + files.includes("Dockerfile") || files.includes("docker-compose.yml"); + + // Fix: Cleanly joined Tech Stack labels + const stackLabels = + [ + hasNode && "Node.js Environment", + hasPython && "Python Environment", + hasDocker && "Containerized", + ] + .filter(Boolean) + .join(", ") || "Generic Software Environment"; + + // Fix: Dynamic License detection + const licenseName = + repoInfo?.license?.name || + repoInfo?.license?.spdx_id || + "the repository's license file"; + + const model = getGeminiModel(); + + // 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}" in the following language: **${language}**. + +--- +### 1. PROJECT CONTEXT (VERIFIED DATA) +- **Project Name**: ${repo} +- **Description**: ${repoInfo?.description || "No description provided."} +- **Primary Language**: ${repoInfo?.language || "Language unknown"} +- **Detected Root Files**: ${fileListString} +- **Tech Stack Context**: ${stackLabels} + +--- +### 2. STRICT README STRUCTURE REQUIREMENTS + +1. **Visual Header**: + - Center-aligned H1 with project name. + - A compelling 1-sentence tagline describing the **Value Proposition**. + - A centered row of Shields.io badges (Build, License, PRs Welcome, Stars). + +2. **The Strategic "Why" (Overview)**: + - **The Problem**: Use a blockquote to describe the real-world pain point this project solves. + - **The Solution**: Explain how this project provides a superior outcome for the user. + +3. **Key Features**: + - Minimum 5 features. Use emojis and focus on **User Benefits**. + +4. **Technical Architecture**: + - Provide a table of the tech stack: | Technology | Purpose | Key Benefit |. + - Create a tree-style directory structure code block using ๐Ÿ“ for folders and ๐Ÿ“„ for files based on the file manifest provided. + +5. **Operational Setup**: + - **Prerequisites**: List required runtimes. + - **Installation**: Provide step-by-step terminal commands. + ${hasNode ? "- Use npm/yarn/pnpm since package.json was detected." : ""} + ${hasPython ? "- Use pip/venv since Python markers were detected." : ""} + - **Environment**: If any .env or config files are in the manifest, include a configuration section. + +6. **Community & Governance**: + - Professional "Contributing" section (Fork -> Branch -> PR). + - Detailed "License" section: Reference ${licenseName} and provide a summary of permissions. + +--- +### 3. TONE & STYLE +- **Tone**: Authoritative, polished, and developer-centric. +- **Visuals**: Extensive use of Markdown formatting. +- **Constraint**: Return ONLY the raw Markdown. No conversational filler. + `; + + const result = await model.generateContent(prompt); + const response = await result.response; + const markdown = response.text().trim(); + const cleanMarkdown = markdown + .replace(/^```(markdown|md)?\n/, "") + .replace(/\n```$/, ""); + + return NextResponse.json({ markdown: cleanMarkdown }); + } catch (error: unknown) { + const message = + error instanceof Error ? error.message : "Internal Server Error"; + console.error("README Generation Failed:", message); + + return NextResponse.json( + { error: "Failed to generate README. Check your URL and try again." }, + { status: 500 }, + ); + } +} diff --git a/src/components/Generator/SearchInput.tsx b/src/components/Generator/SearchInput.tsx index dc3829b..d590c90 100644 --- a/src/components/Generator/SearchInput.tsx +++ b/src/components/Generator/SearchInput.tsx @@ -29,20 +29,6 @@ export const SearchInput = ({ const [language, setLanguage] = useState("English"); const [error, setError] = useState(null); - const languages = [ - "English", - "Spanish", - "French", - "German", - "Chinese", - "Japanese", - "Korean", - "Portuguese", - "Russian", - "Arabic", - "Turkish", - ]; - const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setError(null); @@ -88,7 +74,7 @@ export const SearchInput = ({ onChange={(e) => setLanguage(e.target.value)} className="bg-zinc-900/50 border border-white/10 rounded-2xl px-6 py-6 text-white focus:outline-none focus:ring-2 focus:ring-blue-500/50 transition-all backdrop-blur-xl appearance-none cursor-pointer min-w-[140px]" > - {languages.map((lang) => ( + {SUPPORTED_LANGUAGES.map((lang) => (