From 5a6e386440e7c9e1591057d33f2c7f02a8aa3051 Mon Sep 17 00:00:00 2001 From: Sheng Fan Date: Sat, 6 Apr 2024 17:23:14 +0800 Subject: [PATCH] Add plugin: Bilibili Video Info Fetching --- app/api/langchain-tools/bilibili_vid_info.ts | 148 +++++++++++++++++++ app/api/langchain-tools/nodejs_tools.ts | 3 + app/api/langchain/tool/agent/agentapi.ts | 3 + app/plugins/cn.ts | 10 ++ 4 files changed, 164 insertions(+) create mode 100644 app/api/langchain-tools/bilibili_vid_info.ts diff --git a/app/api/langchain-tools/bilibili_vid_info.ts b/app/api/langchain-tools/bilibili_vid_info.ts new file mode 100644 index 000000000..3acaf791b --- /dev/null +++ b/app/api/langchain-tools/bilibili_vid_info.ts @@ -0,0 +1,148 @@ +import { Tool } from "@langchain/core/tools"; +import { getRandomUserAgent } from "./ua_tools"; + +export interface Headers { + [key: string]: string; +} + +export interface RequestTool { + headers: Headers; + maxOutputLength?: number; + timeout: number; +} + +async function fetchVideoInfo(prompt: string) { + const headers = new Headers(); + headers.append("User-Agent", getRandomUserAgent()); + let video_param = ""; + if (prompt.toLowerCase().startsWith("av")) { + video_param = `aid=${prompt.slice(2)}`; + } else if (prompt.toLowerCase().startsWith("bv")) { + video_param = `bvid=${prompt}`; + } else { + return "FAIL: Invalid video ID or URL."; + } + const resp = await fetch( + `https://api.bilibili.com/x/web-interface/view?${video_param}`, + { + headers: headers, + }, + ); + + let rawData: { [key: string]: any } = await resp.json(); + let data: { [key: string]: string } = {}; + + // Keep those: bvid, aid, videos, copyright, tname, title, pubdate, desc, state(values see below), owner, argue_info + // state: + // 1 橙色通过 + // 0 开放浏览 + // -1 待审 + // -2 被打回 + // -3 网警锁定 + // -4 被锁定 视频撞车了 + // -5 管理员锁定 + // -6 修复待审 + // -7 暂缓审核 + // -8 补档待审 + // -9 等待转码 + // -10 延迟审核 + // -11 视频源待修 + // -12 转储失败 + // -13 允许评论待审 + // -14 临时回收站 + // -15 分发中 + // -16 转码失败 + // -20 创建未提交 + // -30 创建已提交 + // -40 定时发布 + // -100 用户删除 + // convert state to string + const stateConvertDict: { [key: string]: string } = { + "1": "橙色通过", + "0": "开放浏览", + "-1": "待审", + "-2": "被打回", + "-3": "网警锁定", + "-4": "被锁定", + "-5": "管理员锁定", + "-6": "修复待审", + "-7": "暂缓审核", + "-8": "补档待审", + "-9": "等待转码", + "-10": "延迟审核", + "-11": "视频源待修", + "-12": "转储失败", + "-13": "允许评论待审", + "-14": "临时回收站", + "-15": "分发中", + "-16": "转码失败", + "-20": "创建未提交", + "-30": "创建已提交", + "-40": "定时发布", + "-100": "用户删除", + }; + data["state"] = stateConvertDict[rawData.data.state.toString()]; + + data["bvid"] = rawData.data.bvid; + data["aid"] = rawData.data.aid; + data["videos"] = rawData.data.videos; + data["copyright"] = rawData.data.copyright; + data["tname"] = rawData.data.tname; + data["title"] = rawData.data.title; + data["pubdate"] = rawData.data.pubdate; + data["desc"] = rawData.data.desc; + // data["state"] = rawData.data.state.toString(); + data["owner"] = rawData.data.owner.name; + data["argue_info"] = rawData.data.argue_info; + + return "SUCCESS: Video data should be in this JSON: " + JSON.stringify(data); +} + +export class BilibiliVideoInfoTool extends Tool implements RequestTool { + name = "bilibili_video_info"; + + maxOutputLength = Infinity; + + timeout = 10000; + + constructor( + public headers: Headers = {}, + { maxOutputLength }: { maxOutputLength?: number } = {}, + { timeout }: { timeout?: number } = {}, + ) { + super(...arguments); + + this.maxOutputLength = maxOutputLength ?? this.maxOutputLength; + this.timeout = timeout ?? this.timeout; + } + + /** @ignore */ + async _call(input: string) { + try { + let result = await fetchVideoInfo(input); + // console.log(result) + return result; + } catch (error) { + console.error(error); + return (error as Error).toString(); + } + } + + async fetchWithTimeout( + resource: RequestInfo | URL, + options = {}, + timeout: number = 30000, + ) { + const controller = new AbortController(); + const id = setTimeout(() => controller.abort(), timeout); + const response = await fetch(resource, { + ...options, + signal: controller.signal, + }); + clearTimeout(id); + return response; + } + + description = `A tool that fetches video information from Bilibili. It returns a JSON string containing the video title, uploader, and other information. +Input string must be a Bilibili video ID (e.g. av170001, BV17x411w7KC).`; +} diff --git a/app/api/langchain-tools/nodejs_tools.ts b/app/api/langchain-tools/nodejs_tools.ts index 411ce6330..502c248b7 100644 --- a/app/api/langchain-tools/nodejs_tools.ts +++ b/app/api/langchain-tools/nodejs_tools.ts @@ -7,6 +7,7 @@ import { StableDiffusionNodeWrapper } from "@/app/api/langchain-tools/stable_dif import { Calculator } from "langchain/tools/calculator"; import { WebBrowser } from "langchain/tools/webbrowser"; import { WolframAlphaTool } from "@/app/api/langchain-tools/wolframalpha"; +import { BilibiliVideoInfoTool } from "./bilibili_vid_info"; export class NodeJSTool { private apiKey: string | undefined; @@ -48,6 +49,7 @@ export class NodeJSTool { const arxivAPITool = new ArxivAPIWrapper(); const wolframAlphaTool = new WolframAlphaTool(); const pdfBrowserTool = new PDFBrowser(this.model, this.embeddings); + const bilibiliVideoInfoTool = new BilibiliVideoInfoTool(); let tools = [ calculatorTool, webBrowserTool, @@ -56,6 +58,7 @@ export class NodeJSTool { arxivAPITool, wolframAlphaTool, pdfBrowserTool, + bilibiliVideoInfoTool, ]; return tools; } diff --git a/app/api/langchain/tool/agent/agentapi.ts b/app/api/langchain/tool/agent/agentapi.ts index d5b03a7ba..5f51a8cf4 100644 --- a/app/api/langchain/tool/agent/agentapi.ts +++ b/app/api/langchain/tool/agent/agentapi.ts @@ -293,9 +293,11 @@ export class AgentApi { const tools = []; + // configure the right tool for web searching if (useTools.includes("web-search")) tools.push(searchTool); // console.log(customTools); + // include tools included in this project customTools.forEach((customTool) => { if (customTool) { if (useTools.includes(customTool.name)) { @@ -304,6 +306,7 @@ export class AgentApi { } }); + // include tools from Langchain community useTools.forEach((toolName) => { if (toolName) { var tool = langchainTools[ diff --git a/app/plugins/cn.ts b/app/plugins/cn.ts index 60ca72442..a1c664612 100644 --- a/app/plugins/cn.ts +++ b/app/plugins/cn.ts @@ -95,4 +95,14 @@ export const CN_PLUGINS: BuiltinPlugin[] = [ enable: false, onlyNodeRuntime: false, }, + { + name: "Bilibili视频信息获取", + toolName: "bilibili_video_info", + lang: "cn", + description: "通过Bilibili视频ID获取视频信息,如标题、简介等。", + builtin: true, + createdAt: 1712394126000, + enable: true, + onlyNodeRuntime: true, + }, ];