I was trying to use the youtube API to fetch me the related youtube videos based on the topics using youtube api. When it tries to load videos and analyze the transcript it throws me this error
An exception occurred: SyntaxError: Unexpected end of JSON input at JSON.parse (<anonymous>) at strict_output (webpack-internal:///(rsc)/./src/lib/gpt.ts:59:31) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async POST (webpack-internal:///(rsc)/./src/app/api/chapter/getInfo/route.ts:40:29) at async eval (webpack-internal:///(rsc)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:254:37)
route ts file:
// /api/chapter/getIntoimport { prisma } from "@/lib/db";import { strict_output } from "@/lib/gpt";import { getQuestionsFromTranscript, getTranscript, searchYoutube,} from "@/lib/youtube";import { NextResponse } from "next/server";import { z } from "zod";const bodyParser = z.object({ chapterId: z.string(),});export async function POST(req: Request, res: Response) { try { const body = await req.json(); const { chapterId } = bodyParser.parse(body); const chapter = await prisma.chapter.findUnique({ where: { id: chapterId, }, }); if (!chapter) { return NextResponse.json( { success: false, error: "Chapter not found", }, { status: 404 } ); } const videoId = await searchYoutube(chapter.youtubeSearchQuery); let transcript = await getTranscript(videoId); let maxLength = 500; transcript = transcript.split(" ").slice(0, maxLength).join(" "); const { summary }: { summary: string } = await strict_output("You are an AI capable of summarising a youtube transcript","summarise strictly within 250 words or less and do not talk of the sponsors or anything unrelated to the main topic, also do not introduce what the summary is about.\n" + transcript, { summary: "summary of the transcript" } ); const questions = await getQuestionsFromTranscript( transcript, chapter.name ); await prisma.question.createMany({ data: questions.map((question) => { let options = [ question.answer, question.option1, question.option2, question.option3, ]; options = options.sort(() => Math.random() - 0.5); return { question: question.question, answer: question.answer, options: JSON.stringify(options), chapterId: chapterId, }; }), }); await prisma.chapter.update({ where: { id: chapterId }, data: { videoId: videoId, summary: summary, }, }); return NextResponse.json({ success: true }); } catch (error) { if (error instanceof z.ZodError) { return NextResponse.json( { success: false, error: "Invalid body", }, { status: 400 } ); } else { return NextResponse.json( { success: false, error: "unknown", }, { status: 500 } ); } }}
GPT TS file:
import { Configuration, OpenAIApi } from "openai";const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY,});const openai = new OpenAIApi(configuration);interface OutputFormat { [key: string]: string | string[] | OutputFormat;}export async function strict_output( system_prompt: string, user_prompt: string | string[], output_format: OutputFormat, default_category: string = "", output_value_only: boolean = false, model: string = "gpt-3.5-turbo", temperature: number = 1, num_tries: number = 3, verbose: boolean = false) { // if the user input is in a list, we also process the output as a list of json const list_input: boolean = Array.isArray(user_prompt); // if the output format contains dynamic elements of < or >, then add to the prompt to handle dynamic elements const dynamic_elements: boolean = /<.*?>/.test(JSON.stringify(output_format)); // if the output format contains list elements of [ or ], then we add to the prompt to handle lists const list_output: boolean = /\[.*?\]/.test(JSON.stringify(output_format)); // start off with no error message let error_msg: string = ""; for (let i = 0; i < num_tries; i++) { let output_format_prompt: string = `\nYou are to output ${ list_output && "an array of objects in" } the following in json format: ${JSON.stringify( output_format )}. \nDo not put quotation marks or escape character \\ in the output fields.`; if (list_output) { output_format_prompt += `\nIf output field is a list, classify output into the best element of the list.`; } // if output_format contains dynamic elements, process it accordingly if (dynamic_elements) { output_format_prompt += `\nAny text enclosed by < and > indicates you must generate content to replace it. Example input: Go to <location>, Example output: Go to the garden\nAny output key containing < and > indicates you must generate the key name to replace it. Example input: {'<location>': 'description of location'}, Example output: {school: a place for education}`; } // if input is in a list format, ask it to generate json in a list if (list_input) { output_format_prompt += `\nGenerate an array of json, one json for each input element.`; } // Use OpenAI to get a response const response = await openai.createChatCompletion({ temperature: temperature, model: model, messages: [ { role: "system", content: system_prompt + output_format_prompt + error_msg, }, { role: "user", content: user_prompt.toString() }, ], }); let res: string = response.data.choices[0].message?.content?.replace(/'/g, '"') ?? ""; // ensure that we don't replace away apostrophes in text res = res.replace(/(\w)"(\w)/g, "$1'$2"); if (verbose) { console.log("System prompt:", system_prompt + output_format_prompt + error_msg ); console.log("\nUser prompt:", user_prompt); console.log("\nGPT response:", res); } // try-catch block to ensure output format is adhered to try { let output: any = JSON.parse(res); if (list_input) { if (!Array.isArray(output)) { throw new Error("Output format not in an array of json"); } } else { output = [output]; } // check for each element in the output_list, the format is correctly adhered to for (let index = 0; index < output.length; index++) { for (const key in output_format) { // unable to ensure accuracy of dynamic output header, so skip it if (/<.*?>/.test(key)) { continue; } // if output field missing, raise an error if (!(key in output[index])) { throw new Error(`${key} not in json output`); } // check that one of the choices given for the list of words is an unknown if (Array.isArray(output_format[key])) { const choices = output_format[key] as string[]; // ensure output is not a list if (Array.isArray(output[index][key])) { output[index][key] = output[index][key][0]; } // output the default category (if any) if GPT is unable to identify the category if (!choices.includes(output[index][key]) && default_category) { output[index][key] = default_category; } // if the output is a description format, get only the label if (output[index][key].includes(":")) { output[index][key] = output[index][key].split(":")[0]; } } } // if we just want the values for the outputs if (output_value_only) { output[index] = Object.values(output[index]); // just output without the list if there is only one element if (output[index].length === 1) { output[index] = output[index][0]; } } } return list_input ? output : output[0]; } catch (e) { error_msg = `\n\nResult: ${res}\n\nError message: ${e}`; console.log("An exception occurred:", e); console.log("Current invalid json format ", res); } } return [];}
I have provide the related codes where the problem occurs. Especially in the route.ts code when trying to parse the summary , Im facing the error. Kindly have a look and help me . If anything is needed let me know :)