xLog/src/pages/api/summary.ts

138 lines
3.5 KiB
TypeScript

import { OpenAI } from "langchain"
import { AnalyzeDocumentChain, loadSummarizationChain } from "langchain/chains"
import { PromptTemplate } from "langchain/prompts"
import { NextApiRequest, NextApiResponse } from "next"
import { Metadata } from "@prisma/client"
import { toGateway } from "~/lib/ipfs-parser"
import prisma from "~/lib/prisma.server"
import { cacheGet } from "~/lib/redis.server"
import removeMarkdown from "remove-markdown"
const model = new OpenAI({
openAIApiKey: process.env.OPENAI_API_KEY,
modelName: "gpt-3.5-turbo",
temperature: 0.3,
maxTokens: 400,
})
const chains = new Map<string, AnalyzeDocumentChain>()
const getOriginalSummary = async (cid: string, lang: string) => {
try {
let { content } = await (await fetch(toGateway(`ipfs://${cid}`))).json()
if (content?.length > 5000) {
content = content.slice(0, 5000)
}
if (content?.length < 200) {
return ""
} else if (content) {
console.time(`fetching summary ${cid}, ${lang}`)
let chain = chains.get(lang)
if (!chain) {
const prompt = new PromptTemplate({
template: `Summarize this in "${lang}" language:
"{text}"
CONCISE SUMMARY:`,
inputVariables: ["text"],
})
const combineDocsChain = loadSummarizationChain(model, {
prompt,
combineMapPrompt: prompt,
combinePrompt: prompt,
})
chain = new AnalyzeDocumentChain({
combineDocumentsChain: combineDocsChain,
})
chains.set(lang, chain)
}
const res = await chain.call({
input_document: removeMarkdown(content, {
useImgAltText: true,
gfm: true,
}),
})
console.timeEnd(`fetching summary ${cid}, ${lang}`)
return res?.text
}
} catch (error) {
console.error(error)
console.timeEnd(`fetching summary ${cid}, ${lang}`)
}
}
export async function getSummary(cid: string, lang: string = "en") {
const summary = await cacheGet({
key: ["summary", cid, lang],
getValueFun: async () => {
if (["en", "zh", "zh-TW", "ja"].includes(lang)) {
const key = `ai_summary_${lang.replace("-", "").toLowerCase()}`
const meta = await prisma.metadata.findFirst({
where: {
uri: `ipfs://${cid}`,
},
})
if (meta) {
if (meta?.[key as keyof Metadata]) {
return meta?.[key as keyof Metadata]
} else {
const summary = await getOriginalSummary(cid, lang)
if (summary) {
await prisma.metadata.update({
where: {
uri: `ipfs://${cid}`,
},
data: {
[key as keyof Metadata]: summary,
},
})
return summary
}
}
} else {
const summary = await getOriginalSummary(cid, lang)
if (summary) {
await prisma.metadata.create({
data: {
uri: `ipfs://${cid}`,
[key as keyof Metadata]: summary,
},
})
return summary
}
}
}
},
noUpdate: true,
})
return summary
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
let { cid, lang } = req.query
if (!cid) {
res.status(400).send("Bad Request")
return
}
res.status(200).json({
data: await getSummary(cid as string, lang as string),
})
}