Spaces:
Running
Running
| import { NextRequest, NextResponse } from "next/server"; | |
| import { generateText } from "ai"; | |
| import { getProviderForModel } from "@/lib/ai/provider-manager"; | |
| import { extractFilesFromAI, sanitizeBranchName } from "@/lib/ai-utils"; | |
| import { pushToGitHub } from "@/lib/github"; | |
| import { appConfig } from "@/config/app.config"; | |
| export async function GET() { | |
| return NextResponse.json({ message: "Submit job endpoint (v1) is active. Use POST to submit a paper." }); | |
| } | |
| export async function POST(request: NextRequest) { | |
| try { | |
| const { | |
| arxivUrl, | |
| paperContent, | |
| repo, | |
| paperName, | |
| model = appConfig.ai.defaultModel | |
| } = await request.json(); | |
| if (!repo) { | |
| return NextResponse.json({ error: "Target GitHub repository is required (e.g. 'owner/repo')" }, { status: 400 }); | |
| } | |
| if (!paperName) { | |
| return NextResponse.json({ error: "Paper name is required for branch naming" }, { status: 400 }); | |
| } | |
| const githubToken = process.env.PERSONAL_ACCESS_TOKEN; | |
| if (!githubToken) { | |
| return NextResponse.json({ error: "GitHub PERSONAL_ACCESS_TOKEN not configured in environment" }, { status: 500 }); | |
| } | |
| let finalPaperContent = paperContent || ""; | |
| // 1. Get paper content from Arxiv if URL is provided | |
| if (arxivUrl && !paperContent) { | |
| console.log(`[submit-job] Scraping Arxiv: ${arxivUrl}`); | |
| try { | |
| const scrapeResponse = await fetch(`${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/api/scrape-website`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ url: arxivUrl }) | |
| }); | |
| if (scrapeResponse.ok) { | |
| const scrapeData = await scrapeResponse.json(); | |
| if (scrapeData.success) { | |
| finalPaperContent = scrapeData.data.content; | |
| } else { | |
| console.warn(`[submit-job] Scrape failed: ${scrapeData.error}`); | |
| } | |
| } | |
| } catch (error) { | |
| console.error(`[submit-job] Error calling scrape API:`, error); | |
| } | |
| } | |
| if (!finalPaperContent) { | |
| return NextResponse.json({ error: "No paper content provided or found at URL" }, { status: 400 }); | |
| } | |
| // 2. Generate Code from Paper | |
| console.log(`[submit-job] Generating code for: ${paperName}`); | |
| const { client, actualModel } = getProviderForModel(model); | |
| const systemPrompt = `You are an expert React developer. Your task is to transform the provided research paper content into a functional React application using Vite and Tailwind CSS. | |
| The application should: | |
| 1. Visualize the core concepts or findings of the paper. | |
| 2. Provide interactive components if applicable (e.g., simulators, calculators, data explorers). | |
| 3. Have a professional, clean UI. | |
| 4. Include a detailed "About" section summarizing the paper. | |
| Output format: | |
| Generate multiple files using the <file path="..."> format. | |
| Always start with src/index.css, then src/App.jsx, then components. | |
| Do NOT include tailwind.config.js or vite.config.js. | |
| ${finalPaperContent.substring(0, 10000)} // Truncated paper content for prompt`; | |
| const { text: generatedContent } = await generateText({ | |
| model: client(actualModel), | |
| system: "You transform research papers into interactive React code.", | |
| prompt: systemPrompt, | |
| }); | |
| // 3. Extract Files | |
| const files = extractFilesFromAI(generatedContent); | |
| if (files.length === 0) { | |
| return NextResponse.json({ | |
| error: "AI failed to generate code in the expected format", | |
| rawResponse: generatedContent.substring(0, 500) | |
| }, { status: 500 }); | |
| } | |
| // 4. Push to GitHub | |
| const branchName = sanitizeBranchName(paperName); | |
| const githubResult = await pushToGitHub(repo, branchName, files, githubToken); | |
| return NextResponse.json({ | |
| success: true, | |
| message: `Successfully transformed paper to code and pushed to GitHub`, | |
| githubUrl: githubResult.url, | |
| branch: branchName, | |
| filesCount: files.length | |
| }); | |
| } catch (error: any) { | |
| console.error("[submit-job] Error:", error); | |
| return NextResponse.json({ | |
| success: false, | |
| error: error.message || "An unexpected error occurred" | |
| }, { status: 500 }); | |
| } | |
| } | |