yt-transcript-strapi-plugin 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{App-Dk5vxL_c.js → App-DKY3upWd.js} +2 -2
- package/dist/_chunks/{App-Dk5vxL_c.js.map → App-DKY3upWd.js.map} +1 -1
- package/dist/_chunks/{App-BZXINnvY.mjs → App-DXPFDMBH.mjs} +2 -2
- package/dist/_chunks/{App-BZXINnvY.mjs.map → App-DXPFDMBH.mjs.map} +1 -1
- package/dist/_chunks/{index-xAToV0M5.mjs → index-Cf76FLRe.mjs} +3 -3
- package/dist/_chunks/index-Cf76FLRe.mjs.map +1 -0
- package/dist/_chunks/{index-CenWR5nf.js → index-CpWYZFmv.js} +3 -3
- package/dist/_chunks/index-CpWYZFmv.js.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/pluginId.d.ts +1 -1
- package/dist/server/index.js +35 -243
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +34 -242
- package/dist/server/index.mjs.map +1 -1
- package/package.json +11 -4
- package/dist/_chunks/index-CenWR5nf.js.map +0 -1
- package/dist/_chunks/index-xAToV0M5.mjs.map +0 -1
|
@@ -5,7 +5,7 @@ const admin = require("@strapi/strapi/admin");
|
|
|
5
5
|
const reactRouterDom = require("react-router-dom");
|
|
6
6
|
const designSystem = require("@strapi/design-system");
|
|
7
7
|
const reactIntl = require("react-intl");
|
|
8
|
-
const index = require("./index-
|
|
8
|
+
const index = require("./index-CpWYZFmv.js");
|
|
9
9
|
const HomePage = () => {
|
|
10
10
|
const { formatMessage } = reactIntl.useIntl();
|
|
11
11
|
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { children: /* @__PURE__ */ jsxRuntime.jsxs("h1", { children: [
|
|
@@ -20,4 +20,4 @@ const App = () => {
|
|
|
20
20
|
] });
|
|
21
21
|
};
|
|
22
22
|
exports.App = App;
|
|
23
|
-
//# sourceMappingURL=App-
|
|
23
|
+
//# sourceMappingURL=App-DKY3upWd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App-
|
|
1
|
+
{"version":3,"file":"App-DKY3upWd.js","sources":["../../admin/src/pages/HomePage.tsx","../../admin/src/pages/App.tsx"],"sourcesContent":["import { Main } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { getTranslation } from '../utils/getTranslation';\n\nconst HomePage = () => {\n const { formatMessage } = useIntl();\n\n return (\n <Main>\n <h1>Welcome to {formatMessage({ id: getTranslation('plugin.name') })}</h1>\n </Main>\n );\n};\n\nexport { HomePage };\n","import { Page } from '@strapi/strapi/admin';\nimport { Routes, Route } from 'react-router-dom';\n\nimport { HomePage } from './HomePage';\n\nconst App = () => {\n return (\n <Routes>\n <Route index element={<HomePage />} />\n <Route path=\"*\" element={<Page.Error />} />\n </Routes>\n );\n};\n\nexport { App };\n"],"names":["useIntl","jsx","Main","jsxs","getTranslation","Routes","Route","Page"],"mappings":";;;;;;;;AAKA,MAAM,WAAW,MAAM;AACf,QAAA,EAAE,cAAc,IAAIA,kBAAQ;AAGhC,SAAAC,2BAAAA,IAACC,aAAAA,MACC,EAAA,UAAAC,2BAAAA,KAAC,MAAG,EAAA,UAAA;AAAA,IAAA;AAAA,IAAY,cAAc,EAAE,IAAIC,MAAe,eAAA,aAAa,EAAG,CAAA;AAAA,EAAA,EAAA,CAAE,EACvE,CAAA;AAEJ;ACRA,MAAM,MAAM,MAAM;AAChB,yCACGC,uBACC,EAAA,UAAA;AAAA,IAAAJ,+BAACK,eAAAA,SAAM,OAAK,MAAC,SAASL,+BAAC,WAAS,CAAA,GAAI;AAAA,IACpCA,+BAACK,eAAAA,SAAM,MAAK,KAAI,SAAUL,2BAAAA,IAAAM,MAAA,KAAK,OAAL,CAAA,CAAW,EAAI,CAAA;AAAA,EAAA,GAC3C;AAEJ;;"}
|
|
@@ -3,7 +3,7 @@ import { Page } from "@strapi/strapi/admin";
|
|
|
3
3
|
import { Routes, Route } from "react-router-dom";
|
|
4
4
|
import { Main } from "@strapi/design-system";
|
|
5
5
|
import { useIntl } from "react-intl";
|
|
6
|
-
import { g as getTranslation } from "./index-
|
|
6
|
+
import { g as getTranslation } from "./index-Cf76FLRe.mjs";
|
|
7
7
|
const HomePage = () => {
|
|
8
8
|
const { formatMessage } = useIntl();
|
|
9
9
|
return /* @__PURE__ */ jsx(Main, { children: /* @__PURE__ */ jsxs("h1", { children: [
|
|
@@ -20,4 +20,4 @@ const App = () => {
|
|
|
20
20
|
export {
|
|
21
21
|
App
|
|
22
22
|
};
|
|
23
|
-
//# sourceMappingURL=App-
|
|
23
|
+
//# sourceMappingURL=App-DXPFDMBH.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App-
|
|
1
|
+
{"version":3,"file":"App-DXPFDMBH.mjs","sources":["../../admin/src/pages/HomePage.tsx","../../admin/src/pages/App.tsx"],"sourcesContent":["import { Main } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { getTranslation } from '../utils/getTranslation';\n\nconst HomePage = () => {\n const { formatMessage } = useIntl();\n\n return (\n <Main>\n <h1>Welcome to {formatMessage({ id: getTranslation('plugin.name') })}</h1>\n </Main>\n );\n};\n\nexport { HomePage };\n","import { Page } from '@strapi/strapi/admin';\nimport { Routes, Route } from 'react-router-dom';\n\nimport { HomePage } from './HomePage';\n\nconst App = () => {\n return (\n <Routes>\n <Route index element={<HomePage />} />\n <Route path=\"*\" element={<Page.Error />} />\n </Routes>\n );\n};\n\nexport { App };\n"],"names":[],"mappings":";;;;;;AAKA,MAAM,WAAW,MAAM;AACf,QAAA,EAAE,cAAc,IAAI,QAAQ;AAGhC,SAAA,oBAAC,MACC,EAAA,UAAA,qBAAC,MAAG,EAAA,UAAA;AAAA,IAAA;AAAA,IAAY,cAAc,EAAE,IAAI,eAAe,aAAa,EAAG,CAAA;AAAA,EAAA,EAAA,CAAE,EACvE,CAAA;AAEJ;ACRA,MAAM,MAAM,MAAM;AAChB,8BACG,QACC,EAAA,UAAA;AAAA,IAAA,oBAAC,SAAM,OAAK,MAAC,SAAS,oBAAC,WAAS,CAAA,GAAI;AAAA,IACpC,oBAAC,SAAM,MAAK,KAAI,SAAU,oBAAA,KAAK,OAAL,CAAA,CAAW,EAAI,CAAA;AAAA,EAAA,GAC3C;AAEJ;"}
|
|
@@ -17,7 +17,7 @@ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
|
|
17
17
|
);
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
-
const PLUGIN_ID = "yt-transcript";
|
|
20
|
+
const PLUGIN_ID = "yt-transcript-strapi-plugin";
|
|
21
21
|
const getTranslation = (id) => `${PLUGIN_ID}.${id}`;
|
|
22
22
|
const Initializer = ({ setPlugin }) => {
|
|
23
23
|
const ref = useRef(setPlugin);
|
|
@@ -37,7 +37,7 @@ const index = {
|
|
|
37
37
|
defaultMessage: PLUGIN_ID
|
|
38
38
|
},
|
|
39
39
|
Component: async () => {
|
|
40
|
-
const { App } = await import("./App-
|
|
40
|
+
const { App } = await import("./App-DXPFDMBH.mjs");
|
|
41
41
|
return App;
|
|
42
42
|
}
|
|
43
43
|
});
|
|
@@ -72,4 +72,4 @@ export {
|
|
|
72
72
|
getTranslation as g,
|
|
73
73
|
index as i
|
|
74
74
|
};
|
|
75
|
-
//# sourceMappingURL=index-
|
|
75
|
+
//# sourceMappingURL=index-Cf76FLRe.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-Cf76FLRe.mjs","sources":["../../admin/src/pluginId.ts","../../admin/src/utils/getTranslation.ts","../../admin/src/components/Initializer.tsx","../../admin/src/components/PluginIcon.tsx","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'yt-transcript-strapi-plugin';\n","import { PLUGIN_ID } from '../pluginId';\n\nconst getTranslation = (id: string) => `${PLUGIN_ID}.${id}`;\n\nexport { getTranslation };\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import { PuzzlePiece } from '@strapi/icons';\n\nconst PluginIcon = () => <PuzzlePiece />;\n\nexport { PluginIcon };\n","import { getTranslation } from './utils/getTranslation';\nimport { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport { PluginIcon } from './components/PluginIcon';\n\nexport default {\n register(app: any) {\n app.addMenuLink({\n to: `plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: PLUGIN_ID,\n },\n Component: async () => {\n const { App } = await import('./pages/App');\n\n return App;\n },\n });\n\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n },\n\n async registerTrads(app: any) {\n const { locales } = app;\n\n const importedTranslations = await Promise.all(\n (locales as string[]).map((locale) => {\n return import(`./translations/${locale}.json`)\n .then(({ default: data }) => {\n return {\n data: getTranslation(data),\n locale,\n };\n })\n .catch(() => {\n return {\n data: {},\n locale,\n };\n });\n })\n );\n\n return importedTranslations;\n },\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACEzB,MAAM,iBAAiB,CAAC,OAAe,GAAG,SAAS,IAAI,EAAE;ACMzD,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACjD,QAAA,MAAM,OAAO,SAAS;AAE5B,YAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,EAAE;AAEE,SAAA;AACT;ACdA,MAAM,aAAa,MAAM,oBAAC,aAAY,EAAA;ACGtC,MAAe,QAAA;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,YAAY;AAAA,MACd,IAAI,WAAW,SAAS;AAAA,MACxB,MAAM;AAAA,MACN,WAAW;AAAA,QACT,IAAI,GAAG,SAAS;AAAA,QAChB,gBAAgB;AAAA,MAClB;AAAA,MACA,WAAW,YAAY;AACrB,cAAM,EAAE,IAAA,IAAQ,MAAM,OAAO,oBAAa;AAEnC,eAAA;AAAA,MAAA;AAAA,IACT,CACD;AAED,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,KAAU;AACtB,UAAA,EAAE,YAAY;AAEd,UAAA,uBAAuB,MAAM,QAAQ;AAAA,MACxC,QAAqB,IAAI,CAAC,WAAW;AAC7B,eAAA,qCAA+B,uBAAA,OAAA,EAAA,0BAAA,MAAA,OAAA,mBAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA,EACnC,KAAK,CAAC,EAAE,SAAS,WAAW;AACpB,iBAAA;AAAA,YACL,MAAM,eAAe,IAAI;AAAA,YACzB;AAAA,UACF;AAAA,QAAA,CACD,EACA,MAAM,MAAM;AACJ,iBAAA;AAAA,YACL,MAAM,CAAC;AAAA,YACP;AAAA,UACF;AAAA,QAAA,CACD;AAAA,MACJ,CAAA;AAAA,IACH;AAEO,WAAA;AAAA,EAAA;AAEX;"}
|
|
@@ -18,7 +18,7 @@ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
|
|
18
18
|
);
|
|
19
19
|
});
|
|
20
20
|
};
|
|
21
|
-
const PLUGIN_ID = "yt-transcript";
|
|
21
|
+
const PLUGIN_ID = "yt-transcript-strapi-plugin";
|
|
22
22
|
const getTranslation = (id) => `${PLUGIN_ID}.${id}`;
|
|
23
23
|
const Initializer = ({ setPlugin }) => {
|
|
24
24
|
const ref = react.useRef(setPlugin);
|
|
@@ -38,7 +38,7 @@ const index = {
|
|
|
38
38
|
defaultMessage: PLUGIN_ID
|
|
39
39
|
},
|
|
40
40
|
Component: async () => {
|
|
41
|
-
const { App } = await Promise.resolve().then(() => require("./App-
|
|
41
|
+
const { App } = await Promise.resolve().then(() => require("./App-DKY3upWd.js"));
|
|
42
42
|
return App;
|
|
43
43
|
}
|
|
44
44
|
});
|
|
@@ -71,4 +71,4 @@ const index = {
|
|
|
71
71
|
};
|
|
72
72
|
exports.getTranslation = getTranslation;
|
|
73
73
|
exports.index = index;
|
|
74
|
-
//# sourceMappingURL=index-
|
|
74
|
+
//# sourceMappingURL=index-CpWYZFmv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CpWYZFmv.js","sources":["../../admin/src/pluginId.ts","../../admin/src/utils/getTranslation.ts","../../admin/src/components/Initializer.tsx","../../admin/src/components/PluginIcon.tsx","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'yt-transcript-strapi-plugin';\n","import { PLUGIN_ID } from '../pluginId';\n\nconst getTranslation = (id: string) => `${PLUGIN_ID}.${id}`;\n\nexport { getTranslation };\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import { PuzzlePiece } from '@strapi/icons';\n\nconst PluginIcon = () => <PuzzlePiece />;\n\nexport { PluginIcon };\n","import { getTranslation } from './utils/getTranslation';\nimport { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport { PluginIcon } from './components/PluginIcon';\n\nexport default {\n register(app: any) {\n app.addMenuLink({\n to: `plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: PLUGIN_ID,\n },\n Component: async () => {\n const { App } = await import('./pages/App');\n\n return App;\n },\n });\n\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n },\n\n async registerTrads(app: any) {\n const { locales } = app;\n\n const importedTranslations = await Promise.all(\n (locales as string[]).map((locale) => {\n return import(`./translations/${locale}.json`)\n .then(({ default: data }) => {\n return {\n data: getTranslation(data),\n locale,\n };\n })\n .catch(() => {\n return {\n data: {},\n locale,\n };\n });\n })\n );\n\n return importedTranslations;\n },\n};\n"],"names":["useRef","useEffect","jsx","PuzzlePiece"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACEzB,MAAM,iBAAiB,CAAC,OAAe,GAAG,SAAS,IAAI,EAAE;ACMzD,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACjD,QAAA,MAAMA,aAAO,SAAS;AAE5BC,QAAAA,UAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,EAAE;AAEE,SAAA;AACT;ACdA,MAAM,aAAa,MAAMC,2BAAAA,IAACC,MAAY,aAAA,EAAA;ACGtC,MAAe,QAAA;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,YAAY;AAAA,MACd,IAAI,WAAW,SAAS;AAAA,MACxB,MAAM;AAAA,MACN,WAAW;AAAA,QACT,IAAI,GAAG,SAAS;AAAA,QAChB,gBAAgB;AAAA,MAClB;AAAA,MACA,WAAW,YAAY;AACrB,cAAM,EAAE,IAAA,IAAQ,MAAM,QAAA,QAAA,EAAA,KAAA,MAAA,QAAO,mBAAa,CAAA;AAEnC,eAAA;AAAA,MAAA;AAAA,IACT,CACD;AAED,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,KAAU;AACtB,UAAA,EAAE,YAAY;AAEd,UAAA,uBAAuB,MAAM,QAAQ;AAAA,MACxC,QAAqB,IAAI,CAAC,WAAW;AAC7B,eAAA,qCAA+B,uBAAA,OAAA,EAAA,0BAAA,MAAA,QAAA,QAAA,EAAA,KAAA,MAAA,QAAA,kBAAA,CAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA,EACnC,KAAK,CAAC,EAAE,SAAS,WAAW;AACpB,iBAAA;AAAA,YACL,MAAM,eAAe,IAAI;AAAA,YACzB;AAAA,UACF;AAAA,QAAA,CACD,EACA,MAAM,MAAM;AACJ,iBAAA;AAAA,YACL,MAAM,CAAC;AAAA,YACP;AAAA,UACF;AAAA,QAAA,CACD;AAAA,MACJ,CAAA;AAAA,IACH;AAEO,WAAA;AAAA,EAAA;AAEX;;;"}
|
package/dist/admin/index.js
CHANGED
package/dist/admin/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PLUGIN_ID = "yt-transcript";
|
|
1
|
+
export declare const PLUGIN_ID = "yt-transcript-strapi-plugin";
|
package/dist/server/index.js
CHANGED
|
@@ -21,8 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
22
|
mod
|
|
23
23
|
));
|
|
24
|
-
const
|
|
25
|
-
const tiktoken = require("@langchain/core/utils/tiktoken");
|
|
24
|
+
const textsplitters = require("@langchain/textsplitters");
|
|
26
25
|
const prompts = require("@langchain/core/prompts");
|
|
27
26
|
const openai = require("@langchain/openai");
|
|
28
27
|
const bootstrap = ({ strapi: strapi2 }) => {
|
|
@@ -110,27 +109,27 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
110
109
|
const videoId = extractYouTubeID(ctx.params.videoId);
|
|
111
110
|
if (!videoId) return ctx.body = { error: "Invalid YouTube URL or ID", data: null };
|
|
112
111
|
console.log("Looking for transcript in database");
|
|
113
|
-
const found = await strapi2.plugin("yt-transcript").service("service").findTranscript(videoId);
|
|
112
|
+
const found = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").findTranscript(videoId);
|
|
114
113
|
if (found) {
|
|
115
114
|
console.log("Transcript found.");
|
|
116
115
|
return ctx.body = { data: found };
|
|
117
116
|
}
|
|
118
117
|
console.log("Transcript not found. Fetching new transcript.");
|
|
119
|
-
const transcriptData = await strapi2.plugin("yt-transcript").service("service").getTranscript(videoId);
|
|
118
|
+
const transcriptData = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").getTranscript(videoId);
|
|
120
119
|
console.log("New transcript fetched.");
|
|
121
|
-
const readableTranscript = await strapi2.plugin("yt-transcript").service("service").generateHumanReadableTranscript(transcriptData.fullTranscript);
|
|
120
|
+
const readableTranscript = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").generateHumanReadableTranscript(transcriptData.fullTranscript);
|
|
122
121
|
console.log("Human readable transcript generated.");
|
|
123
122
|
const payload = {
|
|
124
|
-
title: transcriptData
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
transcriptWithTimeCodes: transcriptData.transcriptWithTimeCodes,
|
|
123
|
+
title: transcriptData?.title || "No title found",
|
|
124
|
+
videoId: transcriptData?.videoId,
|
|
125
|
+
thumbnailUrl: transcriptData?.thumbnailUrl || "No thumbnail URL found",
|
|
126
|
+
fullTranscript: transcriptData?.fullTranscript,
|
|
127
|
+
transcriptWithTimeCodes: transcriptData?.transcriptWithTimeCodes,
|
|
130
128
|
readableTranscript
|
|
131
129
|
};
|
|
130
|
+
console.log("Payload:", payload);
|
|
132
131
|
console.log("Saving new transcript to database.");
|
|
133
|
-
const transcript2 = await strapi2.plugin("yt-transcript").service("service").saveTranscript(payload);
|
|
132
|
+
const transcript2 = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").saveTranscript(payload);
|
|
134
133
|
ctx.body = { data: transcript2 };
|
|
135
134
|
}
|
|
136
135
|
});
|
|
@@ -169,213 +168,6 @@ const routes = {
|
|
|
169
168
|
routes: [...admin]
|
|
170
169
|
}
|
|
171
170
|
};
|
|
172
|
-
class TextSplitter extends documents.BaseDocumentTransformer {
|
|
173
|
-
constructor(fields) {
|
|
174
|
-
super(fields);
|
|
175
|
-
Object.defineProperty(this, "lc_namespace", {
|
|
176
|
-
enumerable: true,
|
|
177
|
-
configurable: true,
|
|
178
|
-
writable: true,
|
|
179
|
-
value: ["langchain", "document_transformers", "text_splitters"]
|
|
180
|
-
});
|
|
181
|
-
Object.defineProperty(this, "chunkSize", {
|
|
182
|
-
enumerable: true,
|
|
183
|
-
configurable: true,
|
|
184
|
-
writable: true,
|
|
185
|
-
value: 1e3
|
|
186
|
-
});
|
|
187
|
-
Object.defineProperty(this, "chunkOverlap", {
|
|
188
|
-
enumerable: true,
|
|
189
|
-
configurable: true,
|
|
190
|
-
writable: true,
|
|
191
|
-
value: 200
|
|
192
|
-
});
|
|
193
|
-
Object.defineProperty(this, "keepSeparator", {
|
|
194
|
-
enumerable: true,
|
|
195
|
-
configurable: true,
|
|
196
|
-
writable: true,
|
|
197
|
-
value: false
|
|
198
|
-
});
|
|
199
|
-
Object.defineProperty(this, "lengthFunction", {
|
|
200
|
-
enumerable: true,
|
|
201
|
-
configurable: true,
|
|
202
|
-
writable: true,
|
|
203
|
-
value: void 0
|
|
204
|
-
});
|
|
205
|
-
this.chunkSize = fields?.chunkSize ?? this.chunkSize;
|
|
206
|
-
this.chunkOverlap = fields?.chunkOverlap ?? this.chunkOverlap;
|
|
207
|
-
this.keepSeparator = fields?.keepSeparator ?? this.keepSeparator;
|
|
208
|
-
this.lengthFunction = fields?.lengthFunction ?? ((text) => text.length);
|
|
209
|
-
if (this.chunkOverlap >= this.chunkSize) {
|
|
210
|
-
throw new Error("Cannot have chunkOverlap >= chunkSize");
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
async transformDocuments(documents2, chunkHeaderOptions = {}) {
|
|
214
|
-
return this.splitDocuments(documents2, chunkHeaderOptions);
|
|
215
|
-
}
|
|
216
|
-
splitOnSeparator(text, separator) {
|
|
217
|
-
let splits;
|
|
218
|
-
if (separator) {
|
|
219
|
-
if (this.keepSeparator) {
|
|
220
|
-
const regexEscapedSeparator = separator.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
221
|
-
splits = text.split(new RegExp(`(?=${regexEscapedSeparator})`));
|
|
222
|
-
} else {
|
|
223
|
-
splits = text.split(separator);
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
splits = text.split("");
|
|
227
|
-
}
|
|
228
|
-
return splits.filter((s) => s !== "");
|
|
229
|
-
}
|
|
230
|
-
async createDocuments(texts, metadatas = [], chunkHeaderOptions = {}) {
|
|
231
|
-
const _metadatas = metadatas.length > 0 ? metadatas : [...Array(texts.length)].map(() => ({}));
|
|
232
|
-
const { chunkHeader = "", chunkOverlapHeader = "(cont'd) ", appendChunkOverlapHeader = false } = chunkHeaderOptions;
|
|
233
|
-
const documents$1 = new Array();
|
|
234
|
-
for (let i = 0; i < texts.length; i += 1) {
|
|
235
|
-
const text = texts[i];
|
|
236
|
-
let lineCounterIndex = 1;
|
|
237
|
-
let prevChunk = null;
|
|
238
|
-
let indexPrevChunk = -1;
|
|
239
|
-
for (const chunk of await this.splitText(text)) {
|
|
240
|
-
let pageContent = chunkHeader;
|
|
241
|
-
const indexChunk = text.indexOf(chunk, indexPrevChunk + 1);
|
|
242
|
-
if (prevChunk === null) {
|
|
243
|
-
const newLinesBeforeFirstChunk = this.numberOfNewLines(text, 0, indexChunk);
|
|
244
|
-
lineCounterIndex += newLinesBeforeFirstChunk;
|
|
245
|
-
} else {
|
|
246
|
-
const indexEndPrevChunk = indexPrevChunk + await this.lengthFunction(prevChunk);
|
|
247
|
-
if (indexEndPrevChunk < indexChunk) {
|
|
248
|
-
const numberOfIntermediateNewLines = this.numberOfNewLines(text, indexEndPrevChunk, indexChunk);
|
|
249
|
-
lineCounterIndex += numberOfIntermediateNewLines;
|
|
250
|
-
} else if (indexEndPrevChunk > indexChunk) {
|
|
251
|
-
const numberOfIntermediateNewLines = this.numberOfNewLines(text, indexChunk, indexEndPrevChunk);
|
|
252
|
-
lineCounterIndex -= numberOfIntermediateNewLines;
|
|
253
|
-
}
|
|
254
|
-
if (appendChunkOverlapHeader) {
|
|
255
|
-
pageContent += chunkOverlapHeader;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
const newLinesCount = this.numberOfNewLines(chunk);
|
|
259
|
-
const loc = _metadatas[i].loc && typeof _metadatas[i].loc === "object" ? { ..._metadatas[i].loc } : {};
|
|
260
|
-
loc.lines = {
|
|
261
|
-
from: lineCounterIndex,
|
|
262
|
-
to: lineCounterIndex + newLinesCount
|
|
263
|
-
};
|
|
264
|
-
const metadataWithLinesNumber = {
|
|
265
|
-
..._metadatas[i],
|
|
266
|
-
loc
|
|
267
|
-
};
|
|
268
|
-
pageContent += chunk;
|
|
269
|
-
documents$1.push(new documents.Document({
|
|
270
|
-
pageContent,
|
|
271
|
-
metadata: metadataWithLinesNumber
|
|
272
|
-
}));
|
|
273
|
-
lineCounterIndex += newLinesCount;
|
|
274
|
-
prevChunk = chunk;
|
|
275
|
-
indexPrevChunk = indexChunk;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
return documents$1;
|
|
279
|
-
}
|
|
280
|
-
numberOfNewLines(text, start, end) {
|
|
281
|
-
const textSection = text.slice(start, end);
|
|
282
|
-
return (textSection.match(/\n/g) || []).length;
|
|
283
|
-
}
|
|
284
|
-
async splitDocuments(documents2, chunkHeaderOptions = {}) {
|
|
285
|
-
const selectedDocuments = documents2.filter((doc) => doc.pageContent !== void 0);
|
|
286
|
-
const texts = selectedDocuments.map((doc) => doc.pageContent);
|
|
287
|
-
const metadatas = selectedDocuments.map((doc) => doc.metadata);
|
|
288
|
-
return this.createDocuments(texts, metadatas, chunkHeaderOptions);
|
|
289
|
-
}
|
|
290
|
-
joinDocs(docs, separator) {
|
|
291
|
-
const text = docs.join(separator).trim();
|
|
292
|
-
return text === "" ? null : text;
|
|
293
|
-
}
|
|
294
|
-
async mergeSplits(splits, separator) {
|
|
295
|
-
const docs = [];
|
|
296
|
-
const currentDoc = [];
|
|
297
|
-
let total = 0;
|
|
298
|
-
for (const d of splits) {
|
|
299
|
-
const _len = await this.lengthFunction(d);
|
|
300
|
-
if (total + _len + currentDoc.length * separator.length > this.chunkSize) {
|
|
301
|
-
if (total > this.chunkSize) {
|
|
302
|
-
console.warn(`Created a chunk of size ${total}, +
|
|
303
|
-
which is longer than the specified ${this.chunkSize}`);
|
|
304
|
-
}
|
|
305
|
-
if (currentDoc.length > 0) {
|
|
306
|
-
const doc2 = this.joinDocs(currentDoc, separator);
|
|
307
|
-
if (doc2 !== null) {
|
|
308
|
-
docs.push(doc2);
|
|
309
|
-
}
|
|
310
|
-
while (total > this.chunkOverlap || total + _len + currentDoc.length * separator.length > this.chunkSize && total > 0) {
|
|
311
|
-
total -= await this.lengthFunction(currentDoc[0]);
|
|
312
|
-
currentDoc.shift();
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
currentDoc.push(d);
|
|
317
|
-
total += _len;
|
|
318
|
-
}
|
|
319
|
-
const doc = this.joinDocs(currentDoc, separator);
|
|
320
|
-
if (doc !== null) {
|
|
321
|
-
docs.push(doc);
|
|
322
|
-
}
|
|
323
|
-
return docs;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
class TokenTextSplitter extends TextSplitter {
|
|
327
|
-
static lc_name() {
|
|
328
|
-
return "TokenTextSplitter";
|
|
329
|
-
}
|
|
330
|
-
constructor(fields) {
|
|
331
|
-
super(fields);
|
|
332
|
-
Object.defineProperty(this, "encodingName", {
|
|
333
|
-
enumerable: true,
|
|
334
|
-
configurable: true,
|
|
335
|
-
writable: true,
|
|
336
|
-
value: void 0
|
|
337
|
-
});
|
|
338
|
-
Object.defineProperty(this, "allowedSpecial", {
|
|
339
|
-
enumerable: true,
|
|
340
|
-
configurable: true,
|
|
341
|
-
writable: true,
|
|
342
|
-
value: void 0
|
|
343
|
-
});
|
|
344
|
-
Object.defineProperty(this, "disallowedSpecial", {
|
|
345
|
-
enumerable: true,
|
|
346
|
-
configurable: true,
|
|
347
|
-
writable: true,
|
|
348
|
-
value: void 0
|
|
349
|
-
});
|
|
350
|
-
Object.defineProperty(this, "tokenizer", {
|
|
351
|
-
enumerable: true,
|
|
352
|
-
configurable: true,
|
|
353
|
-
writable: true,
|
|
354
|
-
value: void 0
|
|
355
|
-
});
|
|
356
|
-
this.encodingName = fields?.encodingName ?? "gpt2";
|
|
357
|
-
this.allowedSpecial = fields?.allowedSpecial ?? [];
|
|
358
|
-
this.disallowedSpecial = fields?.disallowedSpecial ?? "all";
|
|
359
|
-
}
|
|
360
|
-
async splitText(text) {
|
|
361
|
-
if (!this.tokenizer) {
|
|
362
|
-
this.tokenizer = await tiktoken.getEncoding(this.encodingName);
|
|
363
|
-
}
|
|
364
|
-
const splits = [];
|
|
365
|
-
const input_ids = this.tokenizer.encode(text, this.allowedSpecial, this.disallowedSpecial);
|
|
366
|
-
let start_idx = 0;
|
|
367
|
-
while (start_idx < input_ids.length) {
|
|
368
|
-
if (start_idx > 0) {
|
|
369
|
-
start_idx -= this.chunkOverlap;
|
|
370
|
-
}
|
|
371
|
-
const end_idx = Math.min(start_idx + this.chunkSize, input_ids.length);
|
|
372
|
-
const chunk_ids = input_ids.slice(start_idx, end_idx);
|
|
373
|
-
splits.push(this.tokenizer.decode(chunk_ids));
|
|
374
|
-
start_idx = end_idx;
|
|
375
|
-
}
|
|
376
|
-
return splits;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
171
|
async function initializeModel({
|
|
380
172
|
openAIApiKey,
|
|
381
173
|
model,
|
|
@@ -404,32 +196,30 @@ const fetchTranscript = async (identifier) => {
|
|
|
404
196
|
const info2 = await youtube.getInfo(identifier);
|
|
405
197
|
const transcriptData = await info2.getTranscript();
|
|
406
198
|
console.log("Transcript data fetched");
|
|
407
|
-
const transcriptWithTimeCodes = transcriptData?.transcript?.content?.body?.initial_segments.map(
|
|
408
|
-
(segment)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
);
|
|
199
|
+
const transcriptWithTimeCodes = transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => {
|
|
200
|
+
const segmentDuration = Number(segment.end_ms) - Number(segment.start_ms);
|
|
201
|
+
return {
|
|
202
|
+
text: segment.snippet.text,
|
|
203
|
+
start: Number(segment.start_ms),
|
|
204
|
+
end: Number(segment.end_ms),
|
|
205
|
+
duration: segmentDuration
|
|
206
|
+
};
|
|
207
|
+
});
|
|
418
208
|
console.log("Transcript with time codes generated");
|
|
419
209
|
console.log("Cleaning thumbnail URL");
|
|
420
|
-
const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments.map(
|
|
421
|
-
|
|
422
|
-
).join(" ");
|
|
210
|
+
const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => segment.snippet.text).join(" ");
|
|
211
|
+
console.log(fullTranscript, "full transcript");
|
|
423
212
|
console.log("Full transcript generated");
|
|
424
|
-
|
|
425
|
-
const
|
|
426
|
-
const
|
|
427
|
-
|
|
213
|
+
console.log("Getting basic info");
|
|
214
|
+
const title = info2.basic_info?.title;
|
|
215
|
+
const videoId = info2.basic_info?.id;
|
|
216
|
+
console.log("Getting thumbnail URL");
|
|
217
|
+
const thumbnailUrl = info2?.basic_info?.thumbnail[0]?.url;
|
|
428
218
|
console.log("Returning transcript data");
|
|
429
219
|
return {
|
|
430
|
-
title,
|
|
431
220
|
videoId,
|
|
432
|
-
|
|
221
|
+
...title ? { title } : { title: "No title found" },
|
|
222
|
+
...thumbnailUrl ? { thumbnailUrl: cleanImageUrl(thumbnailUrl) } : { thumbnailUrl: "" },
|
|
433
223
|
fullTranscript,
|
|
434
224
|
transcriptWithTimeCodes
|
|
435
225
|
};
|
|
@@ -452,7 +242,7 @@ async function processTextChunks(chunks, model) {
|
|
|
452
242
|
return processedChunks.join(" ");
|
|
453
243
|
}
|
|
454
244
|
async function generateModifiedTranscript(rawTranscript) {
|
|
455
|
-
const pluginSettings = await strapi.config.get("plugin::yt-transcript");
|
|
245
|
+
const pluginSettings = await strapi.config.get("plugin::yt-transcript-strapi-plugin");
|
|
456
246
|
if (!pluginSettings.openAIApiKey || !pluginSettings.model || !pluginSettings.temp || !pluginSettings.maxTokens) {
|
|
457
247
|
throw new Error("Missing required configuration for YTTranscript");
|
|
458
248
|
}
|
|
@@ -462,7 +252,7 @@ async function generateModifiedTranscript(rawTranscript) {
|
|
|
462
252
|
temp: pluginSettings.temp,
|
|
463
253
|
maxTokens: pluginSettings.maxTokens
|
|
464
254
|
});
|
|
465
|
-
const splitter = new TokenTextSplitter({
|
|
255
|
+
const splitter = new textsplitters.TokenTextSplitter({
|
|
466
256
|
chunkSize: 1e3,
|
|
467
257
|
chunkOverlap: 200
|
|
468
258
|
});
|
|
@@ -481,13 +271,15 @@ const service = ({ strapi: strapi2 }) => ({
|
|
|
481
271
|
return transcriptData;
|
|
482
272
|
},
|
|
483
273
|
async saveTranscript(payload) {
|
|
484
|
-
return await strapi2.documents("plugin::yt-transcript.transcript").create({
|
|
274
|
+
return await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript").create({
|
|
485
275
|
data: payload
|
|
486
276
|
});
|
|
487
277
|
},
|
|
488
278
|
async findTranscript(videoId) {
|
|
489
279
|
console.log("Finding transcript for videoId:", videoId);
|
|
490
|
-
const
|
|
280
|
+
const test = await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript");
|
|
281
|
+
console.log("Test:", test);
|
|
282
|
+
const transcriptData = await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript").findFirst({
|
|
491
283
|
filters: { videoId }
|
|
492
284
|
});
|
|
493
285
|
console.log("Transcript found:", transcriptData?.title, "found");
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/transcript/index.ts","../../server/src/content-types/index.ts","../../server/src/utils/extract-youtube-id.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/middlewares/index.ts","../../server/src/policies/index.ts","../../server/src/routes/content-api.ts","../../server/src/routes/admin.ts","../../server/src/routes/index.ts","../../node_modules/@langchain/textsplitters/dist/text_splitter.js","../../server/src/utils/openai.ts","../../server/src/utils/fetch-transcript.ts","../../server/src/services/service.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["import type { Core } from '@strapi/strapi';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","import type { Core } from '@strapi/strapi';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n // register phase\n};\n\nexport default register;\n","export default {\n default: {},\n validator() {},\n};\n","import schema from './schema.json';\n\nexport default {\n schema,\n};","import transcript from './transcript';\n\nexport default {\n transcript,\n};\n\n\n","export function extractYouTubeID(urlOrID: string): string | null {\n // Regular expression for YouTube ID format\n const regExpID = /^[a-zA-Z0-9_-]{11}$/;\n\n // Check if the input is a YouTube ID\n if (regExpID.test(urlOrID)) {\n return urlOrID;\n }\n\n // Regular expression for standard YouTube links\n const regExpStandard = /youtube\\.com\\/watch\\?v=([a-zA-Z0-9_-]+)/;\n\n // Regular expression for YouTube Shorts links\n const regExpShorts = /youtube\\.com\\/shorts\\/([a-zA-Z0-9_-]+)/;\n\n // Check for standard YouTube link\n const matchStandard = urlOrID.match(regExpStandard);\n if (matchStandard) {\n return matchStandard[1];\n }\n\n // Check for YouTube Shorts link\n const matchShorts = urlOrID.match(regExpShorts);\n if (matchShorts) {\n return matchShorts[1];\n }\n\n // Return null if no match is found\n return null;\n}","import type { Core } from '@strapi/strapi';\nimport { extractYouTubeID } from '../utils/extract-youtube-id';\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(ctx) {\n const videoId = extractYouTubeID(ctx.params.videoId);\n\n if (!videoId) return (ctx.body = { error: 'Invalid YouTube URL or ID', data: null });\n\n console.log(\"Looking for transcript in database\");\n\n const found = await strapi\n .plugin('yt-transcript')\n .service('service')\n .findTranscript(videoId);\n\n if (found) {\n console.log(\"Transcript found.\");\n return (ctx.body = { data: found });\n }\n\n console.log(\"Transcript not found. Fetching new transcript.\");\n\n const transcriptData = await strapi\n .plugin('yt-transcript')\n .service('service')\n .getTranscript(videoId);\n\n console.log(\"New transcript fetched.\");\n\n const readableTranscript = await strapi\n .plugin('yt-transcript')\n .service('service')\n .generateHumanReadableTranscript(transcriptData.fullTranscript);\n\n console.log(\"Human readable transcript generated.\");\n\n const payload = {\n title: transcriptData.title,\n transcript: transcriptData.transcript,\n videoId: transcriptData.videoId,\n thumbnailUrl: transcriptData.thumbnailUrl,\n fullTranscript: transcriptData.fullTranscript,\n transcriptWithTimeCodes: transcriptData.transcriptWithTimeCodes,\n readableTranscript: readableTranscript,\n };\n\n console.log(\"Saving new transcript to database.\");\n\n const transcript = await strapi\n .plugin('yt-transcript')\n .service('service')\n .saveTranscript(payload);\n\n ctx.body = { data: transcript };\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default {};\n","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","\"use strict\";\n\nimport contentApi from \"./content-api\";\nimport admin from \"./admin\";\n\nexport default {\n \"content-api\": {\n type: \"content-api\",\n routes: [...contentApi],\n },\n admin: {\n type: \"admin\",\n routes: [...admin],\n },\n};","import { Document, BaseDocumentTransformer } from \"@langchain/core/documents\";\nimport { getEncoding } from \"@langchain/core/utils/tiktoken\";\nexport class TextSplitter extends BaseDocumentTransformer {\n constructor(fields) {\n super(fields);\n Object.defineProperty(this, \"lc_namespace\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: [\"langchain\", \"document_transformers\", \"text_splitters\"]\n });\n Object.defineProperty(this, \"chunkSize\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: 1000\n });\n Object.defineProperty(this, \"chunkOverlap\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: 200\n });\n Object.defineProperty(this, \"keepSeparator\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: false\n });\n Object.defineProperty(this, \"lengthFunction\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n this.chunkSize = fields?.chunkSize ?? this.chunkSize;\n this.chunkOverlap = fields?.chunkOverlap ?? this.chunkOverlap;\n this.keepSeparator = fields?.keepSeparator ?? this.keepSeparator;\n this.lengthFunction =\n fields?.lengthFunction ?? ((text) => text.length);\n if (this.chunkOverlap >= this.chunkSize) {\n throw new Error(\"Cannot have chunkOverlap >= chunkSize\");\n }\n }\n async transformDocuments(documents, chunkHeaderOptions = {}) {\n return this.splitDocuments(documents, chunkHeaderOptions);\n }\n splitOnSeparator(text, separator) {\n let splits;\n if (separator) {\n if (this.keepSeparator) {\n const regexEscapedSeparator = separator.replace(/[/\\-\\\\^$*+?.()|[\\]{}]/g, \"\\\\$&\");\n splits = text.split(new RegExp(`(?=${regexEscapedSeparator})`));\n }\n else {\n splits = text.split(separator);\n }\n }\n else {\n splits = text.split(\"\");\n }\n return splits.filter((s) => s !== \"\");\n }\n async createDocuments(texts, \n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n metadatas = [], chunkHeaderOptions = {}) {\n // if no metadata is provided, we create an empty one for each text\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const _metadatas = metadatas.length > 0\n ? metadatas\n : [...Array(texts.length)].map(() => ({}));\n const { chunkHeader = \"\", chunkOverlapHeader = \"(cont'd) \", appendChunkOverlapHeader = false, } = chunkHeaderOptions;\n const documents = new Array();\n for (let i = 0; i < texts.length; i += 1) {\n const text = texts[i];\n let lineCounterIndex = 1;\n let prevChunk = null;\n let indexPrevChunk = -1;\n for (const chunk of await this.splitText(text)) {\n let pageContent = chunkHeader;\n // we need to count the \\n that are in the text before getting removed by the splitting\n const indexChunk = text.indexOf(chunk, indexPrevChunk + 1);\n if (prevChunk === null) {\n const newLinesBeforeFirstChunk = this.numberOfNewLines(text, 0, indexChunk);\n lineCounterIndex += newLinesBeforeFirstChunk;\n }\n else {\n const indexEndPrevChunk = indexPrevChunk + (await this.lengthFunction(prevChunk));\n if (indexEndPrevChunk < indexChunk) {\n const numberOfIntermediateNewLines = this.numberOfNewLines(text, indexEndPrevChunk, indexChunk);\n lineCounterIndex += numberOfIntermediateNewLines;\n }\n else if (indexEndPrevChunk > indexChunk) {\n const numberOfIntermediateNewLines = this.numberOfNewLines(text, indexChunk, indexEndPrevChunk);\n lineCounterIndex -= numberOfIntermediateNewLines;\n }\n if (appendChunkOverlapHeader) {\n pageContent += chunkOverlapHeader;\n }\n }\n const newLinesCount = this.numberOfNewLines(chunk);\n const loc = _metadatas[i].loc && typeof _metadatas[i].loc === \"object\"\n ? { ..._metadatas[i].loc }\n : {};\n loc.lines = {\n from: lineCounterIndex,\n to: lineCounterIndex + newLinesCount,\n };\n const metadataWithLinesNumber = {\n ..._metadatas[i],\n loc,\n };\n pageContent += chunk;\n documents.push(new Document({\n pageContent,\n metadata: metadataWithLinesNumber,\n }));\n lineCounterIndex += newLinesCount;\n prevChunk = chunk;\n indexPrevChunk = indexChunk;\n }\n }\n return documents;\n }\n numberOfNewLines(text, start, end) {\n const textSection = text.slice(start, end);\n return (textSection.match(/\\n/g) || []).length;\n }\n async splitDocuments(documents, chunkHeaderOptions = {}) {\n const selectedDocuments = documents.filter((doc) => doc.pageContent !== undefined);\n const texts = selectedDocuments.map((doc) => doc.pageContent);\n const metadatas = selectedDocuments.map((doc) => doc.metadata);\n return this.createDocuments(texts, metadatas, chunkHeaderOptions);\n }\n joinDocs(docs, separator) {\n const text = docs.join(separator).trim();\n return text === \"\" ? null : text;\n }\n async mergeSplits(splits, separator) {\n const docs = [];\n const currentDoc = [];\n let total = 0;\n for (const d of splits) {\n const _len = await this.lengthFunction(d);\n if (total + _len + currentDoc.length * separator.length >\n this.chunkSize) {\n if (total > this.chunkSize) {\n console.warn(`Created a chunk of size ${total}, +\nwhich is longer than the specified ${this.chunkSize}`);\n }\n if (currentDoc.length > 0) {\n const doc = this.joinDocs(currentDoc, separator);\n if (doc !== null) {\n docs.push(doc);\n }\n // Keep on popping if:\n // - we have a larger chunk than in the chunk overlap\n // - or if we still have any chunks and the length is long\n while (total > this.chunkOverlap ||\n (total + _len + currentDoc.length * separator.length >\n this.chunkSize &&\n total > 0)) {\n total -= await this.lengthFunction(currentDoc[0]);\n currentDoc.shift();\n }\n }\n }\n currentDoc.push(d);\n total += _len;\n }\n const doc = this.joinDocs(currentDoc, separator);\n if (doc !== null) {\n docs.push(doc);\n }\n return docs;\n }\n}\nexport class CharacterTextSplitter extends TextSplitter {\n static lc_name() {\n return \"CharacterTextSplitter\";\n }\n constructor(fields) {\n super(fields);\n Object.defineProperty(this, \"separator\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: \"\\n\\n\"\n });\n this.separator = fields?.separator ?? this.separator;\n }\n async splitText(text) {\n // First we naively split the large input into a bunch of smaller ones.\n const splits = this.splitOnSeparator(text, this.separator);\n return this.mergeSplits(splits, this.keepSeparator ? \"\" : this.separator);\n }\n}\nexport const SupportedTextSplitterLanguages = [\n \"cpp\",\n \"go\",\n \"java\",\n \"js\",\n \"php\",\n \"proto\",\n \"python\",\n \"rst\",\n \"ruby\",\n \"rust\",\n \"scala\",\n \"swift\",\n \"markdown\",\n \"latex\",\n \"html\",\n \"sol\",\n];\nexport class RecursiveCharacterTextSplitter extends TextSplitter {\n static lc_name() {\n return \"RecursiveCharacterTextSplitter\";\n }\n constructor(fields) {\n super(fields);\n Object.defineProperty(this, \"separators\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: [\"\\n\\n\", \"\\n\", \" \", \"\"]\n });\n this.separators = fields?.separators ?? this.separators;\n this.keepSeparator = fields?.keepSeparator ?? true;\n }\n async _splitText(text, separators) {\n const finalChunks = [];\n // Get appropriate separator to use\n let separator = separators[separators.length - 1];\n let newSeparators;\n for (let i = 0; i < separators.length; i += 1) {\n const s = separators[i];\n if (s === \"\") {\n separator = s;\n break;\n }\n if (text.includes(s)) {\n separator = s;\n newSeparators = separators.slice(i + 1);\n break;\n }\n }\n // Now that we have the separator, split the text\n const splits = this.splitOnSeparator(text, separator);\n // Now go merging things, recursively splitting longer texts.\n let goodSplits = [];\n const _separator = this.keepSeparator ? \"\" : separator;\n for (const s of splits) {\n if ((await this.lengthFunction(s)) < this.chunkSize) {\n goodSplits.push(s);\n }\n else {\n if (goodSplits.length) {\n const mergedText = await this.mergeSplits(goodSplits, _separator);\n finalChunks.push(...mergedText);\n goodSplits = [];\n }\n if (!newSeparators) {\n finalChunks.push(s);\n }\n else {\n const otherInfo = await this._splitText(s, newSeparators);\n finalChunks.push(...otherInfo);\n }\n }\n }\n if (goodSplits.length) {\n const mergedText = await this.mergeSplits(goodSplits, _separator);\n finalChunks.push(...mergedText);\n }\n return finalChunks;\n }\n async splitText(text) {\n return this._splitText(text, this.separators);\n }\n static fromLanguage(language, options) {\n return new RecursiveCharacterTextSplitter({\n ...options,\n separators: RecursiveCharacterTextSplitter.getSeparatorsForLanguage(language),\n });\n }\n static getSeparatorsForLanguage(language) {\n if (language === \"cpp\") {\n return [\n // Split along class definitions\n \"\\nclass \",\n // Split along function definitions\n \"\\nvoid \",\n \"\\nint \",\n \"\\nfloat \",\n \"\\ndouble \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"go\") {\n return [\n // Split along function definitions\n \"\\nfunc \",\n \"\\nvar \",\n \"\\nconst \",\n \"\\ntype \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"java\") {\n return [\n // Split along class definitions\n \"\\nclass \",\n // Split along method definitions\n \"\\npublic \",\n \"\\nprotected \",\n \"\\nprivate \",\n \"\\nstatic \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"js\") {\n return [\n // Split along function definitions\n \"\\nfunction \",\n \"\\nconst \",\n \"\\nlet \",\n \"\\nvar \",\n \"\\nclass \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\nswitch \",\n \"\\ncase \",\n \"\\ndefault \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"php\") {\n return [\n // Split along function definitions\n \"\\nfunction \",\n // Split along class definitions\n \"\\nclass \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nforeach \",\n \"\\nwhile \",\n \"\\ndo \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"proto\") {\n return [\n // Split along message definitions\n \"\\nmessage \",\n // Split along service definitions\n \"\\nservice \",\n // Split along enum definitions\n \"\\nenum \",\n // Split along option definitions\n \"\\noption \",\n // Split along import statements\n \"\\nimport \",\n // Split along syntax declarations\n \"\\nsyntax \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"python\") {\n return [\n // First, try to split along class definitions\n \"\\nclass \",\n \"\\ndef \",\n \"\\n\\tdef \",\n // Now split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"rst\") {\n return [\n // Split along section titles\n \"\\n===\\n\",\n \"\\n---\\n\",\n \"\\n***\\n\",\n // Split along directive markers\n \"\\n.. \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"ruby\") {\n return [\n // Split along method definitions\n \"\\ndef \",\n \"\\nclass \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nunless \",\n \"\\nwhile \",\n \"\\nfor \",\n \"\\ndo \",\n \"\\nbegin \",\n \"\\nrescue \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"rust\") {\n return [\n // Split along function definitions\n \"\\nfn \",\n \"\\nconst \",\n \"\\nlet \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nwhile \",\n \"\\nfor \",\n \"\\nloop \",\n \"\\nmatch \",\n \"\\nconst \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"scala\") {\n return [\n // Split along class definitions\n \"\\nclass \",\n \"\\nobject \",\n // Split along method definitions\n \"\\ndef \",\n \"\\nval \",\n \"\\nvar \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\nmatch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"swift\") {\n return [\n // Split along function definitions\n \"\\nfunc \",\n // Split along class definitions\n \"\\nclass \",\n \"\\nstruct \",\n \"\\nenum \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\ndo \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"markdown\") {\n return [\n // First, try to split along Markdown headings (starting with level 2)\n \"\\n## \",\n \"\\n### \",\n \"\\n#### \",\n \"\\n##### \",\n \"\\n###### \",\n // Note the alternative syntax for headings (below) is not handled here\n // Heading level 2\n // ---------------\n // End of code block\n \"```\\n\\n\",\n // Horizontal lines\n \"\\n\\n***\\n\\n\",\n \"\\n\\n---\\n\\n\",\n \"\\n\\n___\\n\\n\",\n // Note that this splitter doesn't handle horizontal lines defined\n // by *three or more* of ***, ---, or ___, but this is not handled\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"latex\") {\n return [\n // First, try to split along Latex sections\n \"\\n\\\\chapter{\",\n \"\\n\\\\section{\",\n \"\\n\\\\subsection{\",\n \"\\n\\\\subsubsection{\",\n // Now split by environments\n \"\\n\\\\begin{enumerate}\",\n \"\\n\\\\begin{itemize}\",\n \"\\n\\\\begin{description}\",\n \"\\n\\\\begin{list}\",\n \"\\n\\\\begin{quote}\",\n \"\\n\\\\begin{quotation}\",\n \"\\n\\\\begin{verse}\",\n \"\\n\\\\begin{verbatim}\",\n // Now split by math environments\n \"\\n\\\\begin{align}\",\n \"$$\",\n \"$\",\n // Now split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"html\") {\n return [\n // First, try to split along HTML tags\n \"<body>\",\n \"<div>\",\n \"<p>\",\n \"<br>\",\n \"<li>\",\n \"<h1>\",\n \"<h2>\",\n \"<h3>\",\n \"<h4>\",\n \"<h5>\",\n \"<h6>\",\n \"<span>\",\n \"<table>\",\n \"<tr>\",\n \"<td>\",\n \"<th>\",\n \"<ul>\",\n \"<ol>\",\n \"<header>\",\n \"<footer>\",\n \"<nav>\",\n // Head\n \"<head>\",\n \"<style>\",\n \"<script>\",\n \"<meta>\",\n \"<title>\",\n // Normal type of lines\n \" \",\n \"\",\n ];\n }\n else if (language === \"sol\") {\n return [\n // Split along compiler informations definitions\n \"\\npragma \",\n \"\\nusing \",\n // Split along contract definitions\n \"\\ncontract \",\n \"\\ninterface \",\n \"\\nlibrary \",\n // Split along method definitions\n \"\\nconstructor \",\n \"\\ntype \",\n \"\\nfunction \",\n \"\\nevent \",\n \"\\nmodifier \",\n \"\\nerror \",\n \"\\nstruct \",\n \"\\nenum \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\ndo while \",\n \"\\nassembly \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else {\n throw new Error(`Language ${language} is not supported.`);\n }\n }\n}\n/**\n * Implementation of splitter which looks at tokens.\n */\nexport class TokenTextSplitter extends TextSplitter {\n static lc_name() {\n return \"TokenTextSplitter\";\n }\n constructor(fields) {\n super(fields);\n Object.defineProperty(this, \"encodingName\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"allowedSpecial\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"disallowedSpecial\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"tokenizer\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n this.encodingName = fields?.encodingName ?? \"gpt2\";\n this.allowedSpecial = fields?.allowedSpecial ?? [];\n this.disallowedSpecial = fields?.disallowedSpecial ?? \"all\";\n }\n async splitText(text) {\n if (!this.tokenizer) {\n this.tokenizer = await getEncoding(this.encodingName);\n }\n const splits = [];\n const input_ids = this.tokenizer.encode(text, this.allowedSpecial, this.disallowedSpecial);\n let start_idx = 0;\n while (start_idx < input_ids.length) {\n if (start_idx > 0) {\n start_idx -= this.chunkOverlap;\n }\n const end_idx = Math.min(start_idx + this.chunkSize, input_ids.length);\n const chunk_ids = input_ids.slice(start_idx, end_idx);\n splits.push(this.tokenizer.decode(chunk_ids));\n start_idx = end_idx;\n }\n return splits;\n }\n}\nexport class MarkdownTextSplitter extends RecursiveCharacterTextSplitter {\n constructor(fields) {\n super({\n ...fields,\n separators: RecursiveCharacterTextSplitter.getSeparatorsForLanguage(\"markdown\"),\n });\n }\n}\nexport class LatexTextSplitter extends RecursiveCharacterTextSplitter {\n constructor(fields) {\n super({\n ...fields,\n separators: RecursiveCharacterTextSplitter.getSeparatorsForLanguage(\"latex\"),\n });\n }\n}\n","import { ChatOpenAI } from \"@langchain/openai\";\n\ninterface InitializeModelProps {\n openAIApiKey: string;\n model: string;\n temp: number;\n maxTokens?: number;\n}\n\nexport async function initializeModel({\n openAIApiKey,\n model,\n temp,\n}: InitializeModelProps) {\n return new ChatOpenAI({\n temperature: temp,\n openAIApiKey: openAIApiKey,\n modelName: model,\n maxTokens: 1000,\n });\n}","export interface TranscriptSegment {\n text: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface TranscriptData {\n title: string;\n videoId: string;\n thumbnailUrl: string;\n fullTranscript: string;\n transcriptWithTimeCodes: TranscriptSegment[];\n}\n\nconst fetchTranscript = async (\n identifier: string\n): Promise<TranscriptData> => {\n console.log(\"Fetching Transcript - Calling fetchTranscript Utils\");\n const { Innertube } = await import('youtubei.js');\n\n console.log(\"Creating YouTube instance\");\n\n const youtube = await Innertube.create({\n lang: 'en',\n location: 'US',\n retrieve_player: false,\n });\n\n try {\n const info = await youtube.getInfo(identifier);\n const transcriptData = await info.getTranscript();\n\n console.log(\"Transcript data fetched\");\n\n const transcriptWithTimeCodes: TranscriptSegment[] = transcriptData?.transcript?.content?.body?.initial_segments.map(\n (segment) => {\n const segmentDuration = Number(segment.end_ms) - Number(segment.start_ms);\n return {\n text: segment.snippet.text,\n start: Number(segment.start_ms),\n end: Number(segment.end_ms),\n duration: segmentDuration,\n };\n }\n );\n\n console.log(\"Transcript with time codes generated\");\n\n function cleanImageUrl(url) {\n return url.split('?')[0];\n }\n\n console.log(\"Cleaning thumbnail URL\");\n\n const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments.map(\n (segment) => segment.snippet.text\n ).join(' ');\n\n console.log(\"Full transcript generated\");\n\n const title = info.basic_info.title;\n const videoId = info.basic_info.id;\n const thumbnailUrl = info.basic_info.thumbnail[0].url;\n const thumbnailUrlCleaned = cleanImageUrl(thumbnailUrl);\n\n console.log(\"Returning transcript data\");\n\n return {\n title,\n videoId,\n thumbnailUrl: thumbnailUrlCleaned || \"\",\n fullTranscript,\n transcriptWithTimeCodes,\n };\n } catch (error) {\n console.error('Error fetching transcript:', error);\n throw error;\n }\n};\n\nexport default fetchTranscript;","import type { Core } from '@strapi/strapi';\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport { TokenTextSplitter } from \"@langchain/textsplitters\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\n\nimport { initializeModel } from \"../utils/openai\";\nimport fetchTranscript from '../utils/fetch-transcript';\n\ninterface YTTranscriptConfig {\n openAIApiKey: string;\n model?: string;\n temp?: number;\n maxTokens?: number;\n}\n\nasync function processTextChunks(chunks: string[], model: ChatOpenAI) {\n const punctuationPrompt = PromptTemplate.fromTemplate(\n \"Add proper punctuation and capitalization to the following text chunk:\\n\\n{chunk}\"\n );\n const punctuationChain = punctuationPrompt.pipe(model);\n\n const processedChunks = await Promise.all(\n chunks.map(async (chunk) => {\n const result = await punctuationChain.invoke({ chunk });\n return result.content as string;\n })\n );\n\n return processedChunks.join(\" \");\n}\n\nexport async function generateModifiedTranscript (rawTranscript: string) {\n const pluginSettings = await strapi.config.get('plugin::yt-transcript') as YTTranscriptConfig; \n \n if (!pluginSettings.openAIApiKey || !pluginSettings.model || !pluginSettings.temp || !pluginSettings.maxTokens) {\n throw new Error('Missing required configuration for YTTranscript');\n }\n\n const chatModel = await initializeModel({\n openAIApiKey: pluginSettings.openAIApiKey,\n model: pluginSettings.model,\n temp: pluginSettings.temp,\n maxTokens: pluginSettings.maxTokens,\n });\n\n const splitter = new TokenTextSplitter({\n chunkSize: 1000,\n chunkOverlap: 200,\n });\n\n const transcriptChunks = await splitter.createDocuments([rawTranscript]);\n const chunkTexts = transcriptChunks.map(chunk => chunk.pageContent);\n const modifiedTranscript = await processTextChunks(chunkTexts, chatModel);\n return modifiedTranscript;\n}\n\nconst service = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(identifier: string) {\n console.log(\"Fetching Transcript - Calling fetchTranscript Service\");\n const youtubeIdRegex = /^[a-zA-Z0-9_-]{11}$/;\n const isValid = youtubeIdRegex.test(identifier);\n if (!isValid) return { error: 'Invalid video ID', data: null };\n const transcriptData = await fetchTranscript(identifier);\n return transcriptData;\n },\n\n async saveTranscript(payload) {\n // console.log('Saving transcript:', payload);\n return await strapi.documents('plugin::yt-transcript.transcript').create({\n data: payload,\n });\n },\n\n async findTranscript(videoId) {\n console.log('Finding transcript for videoId:', videoId);\n const transcriptData = await strapi.documents('plugin::yt-transcript.transcript').findFirst({\n filters: { videoId },\n });\n\n console.log('Transcript found:', transcriptData?.title, 'found');\n\n if (!transcriptData) return null;\n return transcriptData;\n },\n\n async generateHumanReadableTranscript(transcript) {\n console.log('Generating human readable transcript:');\n const modifiedTranscript = await generateModifiedTranscript(transcript);\n return modifiedTranscript;\n },\n});\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy,\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","transcript","BaseDocumentTransformer","documents","Document","doc","getEncoding","ChatOpenAI","info","PromptTemplate"],"mappings":"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","x_google_ignoreList":[14]}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/transcript/index.ts","../../server/src/content-types/index.ts","../../server/src/utils/extract-youtube-id.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/middlewares/index.ts","../../server/src/policies/index.ts","../../server/src/routes/content-api.ts","../../server/src/routes/admin.ts","../../server/src/routes/index.ts","../../server/src/utils/openai.ts","../../server/src/utils/fetch-transcript.ts","../../server/src/services/service.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["import type { Core } from '@strapi/strapi';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","import type { Core } from '@strapi/strapi';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n // register phase\n};\n\nexport default register;\n","export default {\n default: {},\n validator() {},\n};\n","import schema from './schema.json';\n\nexport default {\n schema,\n};","import transcript from './transcript';\n\nexport default {\n transcript,\n};\n\n\n","export function extractYouTubeID(urlOrID: string): string | null {\n // Regular expression for YouTube ID format\n const regExpID = /^[a-zA-Z0-9_-]{11}$/;\n\n // Check if the input is a YouTube ID\n if (regExpID.test(urlOrID)) {\n return urlOrID;\n }\n\n // Regular expression for standard YouTube links\n const regExpStandard = /youtube\\.com\\/watch\\?v=([a-zA-Z0-9_-]+)/;\n\n // Regular expression for YouTube Shorts links\n const regExpShorts = /youtube\\.com\\/shorts\\/([a-zA-Z0-9_-]+)/;\n\n // Check for standard YouTube link\n const matchStandard = urlOrID.match(regExpStandard);\n if (matchStandard) {\n return matchStandard[1];\n }\n\n // Check for YouTube Shorts link\n const matchShorts = urlOrID.match(regExpShorts);\n if (matchShorts) {\n return matchShorts[1];\n }\n\n // Return null if no match is found\n return null;\n}","import type { Core } from '@strapi/strapi';\nimport { extractYouTubeID } from '../utils/extract-youtube-id';\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(ctx) {\n const videoId = extractYouTubeID(ctx.params.videoId);\n\n if (!videoId) return (ctx.body = { error: 'Invalid YouTube URL or ID', data: null });\n\n console.log(\"Looking for transcript in database\");\n\n const found = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .findTranscript(videoId);\n\n if (found) {\n console.log(\"Transcript found.\");\n return (ctx.body = { data: found });\n }\n\n console.log(\"Transcript not found. Fetching new transcript.\");\n\n const transcriptData = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .getTranscript(videoId);\n\n console.log(\"New transcript fetched.\");\n\n const readableTranscript = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .generateHumanReadableTranscript(transcriptData.fullTranscript);\n\n console.log(\"Human readable transcript generated.\");\n\n const payload = {\n title: transcriptData?.title || \"No title found\",\n videoId: transcriptData?.videoId,\n thumbnailUrl: transcriptData?.thumbnailUrl || \"No thumbnail URL found\",\n fullTranscript: transcriptData?.fullTranscript,\n transcriptWithTimeCodes: transcriptData?.transcriptWithTimeCodes,\n readableTranscript: readableTranscript,\n };\n\n console.log(\"Payload:\", payload);\n\n console.log(\"Saving new transcript to database.\");\n\n const transcript = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .saveTranscript(payload);\n\n ctx.body = { data: transcript };\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default {};\n","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","\"use strict\";\n\nimport contentApi from \"./content-api\";\nimport admin from \"./admin\";\n\nexport default {\n \"content-api\": {\n type: \"content-api\",\n routes: [...contentApi],\n },\n admin: {\n type: \"admin\",\n routes: [...admin],\n },\n};","import { ChatOpenAI } from \"@langchain/openai\";\n\ninterface InitializeModelProps {\n openAIApiKey: string;\n model: string;\n temp: number;\n maxTokens?: number;\n}\n\nexport async function initializeModel({\n openAIApiKey,\n model,\n temp,\n}: InitializeModelProps) {\n return new ChatOpenAI({\n temperature: temp,\n openAIApiKey: openAIApiKey,\n modelName: model,\n maxTokens: 1000,\n });\n}","export interface TranscriptSegment {\n text: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface TranscriptData {\n title: string;\n videoId: string;\n thumbnailUrl: string;\n fullTranscript: string;\n transcriptWithTimeCodes: TranscriptSegment[];\n}\n\nconst fetchTranscript = async (identifier: string): Promise<TranscriptData> => {\n console.log('Fetching Transcript - Calling fetchTranscript Utils');\n const { Innertube } = await import('youtubei.js');\n\n console.log('Creating YouTube instance');\n\n const youtube = await Innertube.create({\n lang: 'en',\n location: 'US',\n retrieve_player: false,\n });\n\n try {\n const info = await youtube.getInfo(identifier);\n const transcriptData = await info.getTranscript();\n\n console.log('Transcript data fetched');\n\n const transcriptWithTimeCodes: TranscriptSegment[] =\n transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => {\n const segmentDuration = Number(segment.end_ms) - Number(segment.start_ms);\n return {\n text: segment.snippet.text,\n start: Number(segment.start_ms),\n end: Number(segment.end_ms),\n duration: segmentDuration,\n };\n });\n\n console.log('Transcript with time codes generated');\n\n function cleanImageUrl(url) {\n return url.split('?')[0];\n }\n\n console.log('Cleaning thumbnail URL');\n\n const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments\n .map((segment) => segment.snippet.text)\n .join(' ');\n\n console.log(fullTranscript, 'full transcript');\n\n console.log('Full transcript generated');\n\n console.log('Getting basic info');\n\n const title = info.basic_info?.title;\n const videoId = info.basic_info?.id;\n\n console.log('Getting thumbnail URL');\n const thumbnailUrl = info?.basic_info?.thumbnail[0]?.url;\n\n console.log('Returning transcript data');\n\n return {\n videoId,\n ...(title ? { title } : { title: 'No title found' }),\n ...(thumbnailUrl ? { thumbnailUrl: cleanImageUrl(thumbnailUrl) } : { thumbnailUrl: '' }),\n fullTranscript,\n transcriptWithTimeCodes,\n };\n } catch (error) {\n console.error('Error fetching transcript:', error);\n throw error;\n }\n};\n\nexport default fetchTranscript;\n","import type { Core } from '@strapi/strapi';\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport { TokenTextSplitter } from \"@langchain/textsplitters\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\n\nimport { initializeModel } from \"../utils/openai\";\nimport fetchTranscript from '../utils/fetch-transcript';\n\ninterface YTTranscriptConfig {\n openAIApiKey: string;\n model?: string;\n temp?: number;\n maxTokens?: number;\n}\n\nasync function processTextChunks(chunks: string[], model: ChatOpenAI) {\n const punctuationPrompt = PromptTemplate.fromTemplate(\n \"Add proper punctuation and capitalization to the following text chunk:\\n\\n{chunk}\"\n );\n const punctuationChain = punctuationPrompt.pipe(model);\n\n const processedChunks = await Promise.all(\n chunks.map(async (chunk) => {\n const result = await punctuationChain.invoke({ chunk });\n return result.content as string;\n })\n );\n\n return processedChunks.join(\" \");\n}\n\nexport async function generateModifiedTranscript (rawTranscript: string) {\n const pluginSettings = await strapi.config.get('plugin::yt-transcript-strapi-plugin') as YTTranscriptConfig; \n \n if (!pluginSettings.openAIApiKey || !pluginSettings.model || !pluginSettings.temp || !pluginSettings.maxTokens) {\n throw new Error('Missing required configuration for YTTranscript');\n }\n\n const chatModel = await initializeModel({\n openAIApiKey: pluginSettings.openAIApiKey,\n model: pluginSettings.model,\n temp: pluginSettings.temp,\n maxTokens: pluginSettings.maxTokens,\n });\n\n const splitter = new TokenTextSplitter({\n chunkSize: 1000,\n chunkOverlap: 200,\n });\n\n const transcriptChunks = await splitter.createDocuments([rawTranscript]);\n const chunkTexts = transcriptChunks.map(chunk => chunk.pageContent);\n const modifiedTranscript = await processTextChunks(chunkTexts, chatModel);\n return modifiedTranscript;\n}\n\nconst service = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(identifier: string) {\n console.log(\"Fetching Transcript - Calling fetchTranscript Service\");\n const youtubeIdRegex = /^[a-zA-Z0-9_-]{11}$/;\n const isValid = youtubeIdRegex.test(identifier);\n if (!isValid) return { error: 'Invalid video ID', data: null };\n const transcriptData = await fetchTranscript(identifier);\n return transcriptData;\n },\n\n async saveTranscript(payload) {\n // console.log('Saving transcript:', payload);\n return await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript').create({\n data: payload,\n });\n },\n\n async findTranscript(videoId) {\n console.log('Finding transcript for videoId:', videoId);\n\n const test = await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript')\n\n console.log('Test:', test);\n\n const transcriptData = await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript').findFirst({\n filters: { videoId },\n });\n\n\n console.log('Transcript found:', transcriptData?.title, 'found');\n\n if (!transcriptData) return null;\n return transcriptData;\n },\n\n async generateHumanReadableTranscript(transcript) {\n console.log('Generating human readable transcript:');\n const modifiedTranscript = await generateModifiedTranscript(transcript);\n return modifiedTranscript;\n },\n});\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy,\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","transcript","ChatOpenAI","info","PromptTemplate","TokenTextSplitter"],"mappings":"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"}
|
package/dist/server/index.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getEncoding } from "@langchain/core/utils/tiktoken";
|
|
1
|
+
import { TokenTextSplitter } from "@langchain/textsplitters";
|
|
3
2
|
import { PromptTemplate } from "@langchain/core/prompts";
|
|
4
3
|
import { ChatOpenAI } from "@langchain/openai";
|
|
5
4
|
const bootstrap = ({ strapi: strapi2 }) => {
|
|
@@ -87,27 +86,27 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
87
86
|
const videoId = extractYouTubeID(ctx.params.videoId);
|
|
88
87
|
if (!videoId) return ctx.body = { error: "Invalid YouTube URL or ID", data: null };
|
|
89
88
|
console.log("Looking for transcript in database");
|
|
90
|
-
const found = await strapi2.plugin("yt-transcript").service("service").findTranscript(videoId);
|
|
89
|
+
const found = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").findTranscript(videoId);
|
|
91
90
|
if (found) {
|
|
92
91
|
console.log("Transcript found.");
|
|
93
92
|
return ctx.body = { data: found };
|
|
94
93
|
}
|
|
95
94
|
console.log("Transcript not found. Fetching new transcript.");
|
|
96
|
-
const transcriptData = await strapi2.plugin("yt-transcript").service("service").getTranscript(videoId);
|
|
95
|
+
const transcriptData = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").getTranscript(videoId);
|
|
97
96
|
console.log("New transcript fetched.");
|
|
98
|
-
const readableTranscript = await strapi2.plugin("yt-transcript").service("service").generateHumanReadableTranscript(transcriptData.fullTranscript);
|
|
97
|
+
const readableTranscript = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").generateHumanReadableTranscript(transcriptData.fullTranscript);
|
|
99
98
|
console.log("Human readable transcript generated.");
|
|
100
99
|
const payload = {
|
|
101
|
-
title: transcriptData
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
transcriptWithTimeCodes: transcriptData.transcriptWithTimeCodes,
|
|
100
|
+
title: transcriptData?.title || "No title found",
|
|
101
|
+
videoId: transcriptData?.videoId,
|
|
102
|
+
thumbnailUrl: transcriptData?.thumbnailUrl || "No thumbnail URL found",
|
|
103
|
+
fullTranscript: transcriptData?.fullTranscript,
|
|
104
|
+
transcriptWithTimeCodes: transcriptData?.transcriptWithTimeCodes,
|
|
107
105
|
readableTranscript
|
|
108
106
|
};
|
|
107
|
+
console.log("Payload:", payload);
|
|
109
108
|
console.log("Saving new transcript to database.");
|
|
110
|
-
const transcript2 = await strapi2.plugin("yt-transcript").service("service").saveTranscript(payload);
|
|
109
|
+
const transcript2 = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").saveTranscript(payload);
|
|
111
110
|
ctx.body = { data: transcript2 };
|
|
112
111
|
}
|
|
113
112
|
});
|
|
@@ -146,213 +145,6 @@ const routes = {
|
|
|
146
145
|
routes: [...admin]
|
|
147
146
|
}
|
|
148
147
|
};
|
|
149
|
-
class TextSplitter extends BaseDocumentTransformer {
|
|
150
|
-
constructor(fields) {
|
|
151
|
-
super(fields);
|
|
152
|
-
Object.defineProperty(this, "lc_namespace", {
|
|
153
|
-
enumerable: true,
|
|
154
|
-
configurable: true,
|
|
155
|
-
writable: true,
|
|
156
|
-
value: ["langchain", "document_transformers", "text_splitters"]
|
|
157
|
-
});
|
|
158
|
-
Object.defineProperty(this, "chunkSize", {
|
|
159
|
-
enumerable: true,
|
|
160
|
-
configurable: true,
|
|
161
|
-
writable: true,
|
|
162
|
-
value: 1e3
|
|
163
|
-
});
|
|
164
|
-
Object.defineProperty(this, "chunkOverlap", {
|
|
165
|
-
enumerable: true,
|
|
166
|
-
configurable: true,
|
|
167
|
-
writable: true,
|
|
168
|
-
value: 200
|
|
169
|
-
});
|
|
170
|
-
Object.defineProperty(this, "keepSeparator", {
|
|
171
|
-
enumerable: true,
|
|
172
|
-
configurable: true,
|
|
173
|
-
writable: true,
|
|
174
|
-
value: false
|
|
175
|
-
});
|
|
176
|
-
Object.defineProperty(this, "lengthFunction", {
|
|
177
|
-
enumerable: true,
|
|
178
|
-
configurable: true,
|
|
179
|
-
writable: true,
|
|
180
|
-
value: void 0
|
|
181
|
-
});
|
|
182
|
-
this.chunkSize = fields?.chunkSize ?? this.chunkSize;
|
|
183
|
-
this.chunkOverlap = fields?.chunkOverlap ?? this.chunkOverlap;
|
|
184
|
-
this.keepSeparator = fields?.keepSeparator ?? this.keepSeparator;
|
|
185
|
-
this.lengthFunction = fields?.lengthFunction ?? ((text) => text.length);
|
|
186
|
-
if (this.chunkOverlap >= this.chunkSize) {
|
|
187
|
-
throw new Error("Cannot have chunkOverlap >= chunkSize");
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
async transformDocuments(documents, chunkHeaderOptions = {}) {
|
|
191
|
-
return this.splitDocuments(documents, chunkHeaderOptions);
|
|
192
|
-
}
|
|
193
|
-
splitOnSeparator(text, separator) {
|
|
194
|
-
let splits;
|
|
195
|
-
if (separator) {
|
|
196
|
-
if (this.keepSeparator) {
|
|
197
|
-
const regexEscapedSeparator = separator.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
198
|
-
splits = text.split(new RegExp(`(?=${regexEscapedSeparator})`));
|
|
199
|
-
} else {
|
|
200
|
-
splits = text.split(separator);
|
|
201
|
-
}
|
|
202
|
-
} else {
|
|
203
|
-
splits = text.split("");
|
|
204
|
-
}
|
|
205
|
-
return splits.filter((s) => s !== "");
|
|
206
|
-
}
|
|
207
|
-
async createDocuments(texts, metadatas = [], chunkHeaderOptions = {}) {
|
|
208
|
-
const _metadatas = metadatas.length > 0 ? metadatas : [...Array(texts.length)].map(() => ({}));
|
|
209
|
-
const { chunkHeader = "", chunkOverlapHeader = "(cont'd) ", appendChunkOverlapHeader = false } = chunkHeaderOptions;
|
|
210
|
-
const documents = new Array();
|
|
211
|
-
for (let i = 0; i < texts.length; i += 1) {
|
|
212
|
-
const text = texts[i];
|
|
213
|
-
let lineCounterIndex = 1;
|
|
214
|
-
let prevChunk = null;
|
|
215
|
-
let indexPrevChunk = -1;
|
|
216
|
-
for (const chunk of await this.splitText(text)) {
|
|
217
|
-
let pageContent = chunkHeader;
|
|
218
|
-
const indexChunk = text.indexOf(chunk, indexPrevChunk + 1);
|
|
219
|
-
if (prevChunk === null) {
|
|
220
|
-
const newLinesBeforeFirstChunk = this.numberOfNewLines(text, 0, indexChunk);
|
|
221
|
-
lineCounterIndex += newLinesBeforeFirstChunk;
|
|
222
|
-
} else {
|
|
223
|
-
const indexEndPrevChunk = indexPrevChunk + await this.lengthFunction(prevChunk);
|
|
224
|
-
if (indexEndPrevChunk < indexChunk) {
|
|
225
|
-
const numberOfIntermediateNewLines = this.numberOfNewLines(text, indexEndPrevChunk, indexChunk);
|
|
226
|
-
lineCounterIndex += numberOfIntermediateNewLines;
|
|
227
|
-
} else if (indexEndPrevChunk > indexChunk) {
|
|
228
|
-
const numberOfIntermediateNewLines = this.numberOfNewLines(text, indexChunk, indexEndPrevChunk);
|
|
229
|
-
lineCounterIndex -= numberOfIntermediateNewLines;
|
|
230
|
-
}
|
|
231
|
-
if (appendChunkOverlapHeader) {
|
|
232
|
-
pageContent += chunkOverlapHeader;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
const newLinesCount = this.numberOfNewLines(chunk);
|
|
236
|
-
const loc = _metadatas[i].loc && typeof _metadatas[i].loc === "object" ? { ..._metadatas[i].loc } : {};
|
|
237
|
-
loc.lines = {
|
|
238
|
-
from: lineCounterIndex,
|
|
239
|
-
to: lineCounterIndex + newLinesCount
|
|
240
|
-
};
|
|
241
|
-
const metadataWithLinesNumber = {
|
|
242
|
-
..._metadatas[i],
|
|
243
|
-
loc
|
|
244
|
-
};
|
|
245
|
-
pageContent += chunk;
|
|
246
|
-
documents.push(new Document({
|
|
247
|
-
pageContent,
|
|
248
|
-
metadata: metadataWithLinesNumber
|
|
249
|
-
}));
|
|
250
|
-
lineCounterIndex += newLinesCount;
|
|
251
|
-
prevChunk = chunk;
|
|
252
|
-
indexPrevChunk = indexChunk;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return documents;
|
|
256
|
-
}
|
|
257
|
-
numberOfNewLines(text, start, end) {
|
|
258
|
-
const textSection = text.slice(start, end);
|
|
259
|
-
return (textSection.match(/\n/g) || []).length;
|
|
260
|
-
}
|
|
261
|
-
async splitDocuments(documents, chunkHeaderOptions = {}) {
|
|
262
|
-
const selectedDocuments = documents.filter((doc) => doc.pageContent !== void 0);
|
|
263
|
-
const texts = selectedDocuments.map((doc) => doc.pageContent);
|
|
264
|
-
const metadatas = selectedDocuments.map((doc) => doc.metadata);
|
|
265
|
-
return this.createDocuments(texts, metadatas, chunkHeaderOptions);
|
|
266
|
-
}
|
|
267
|
-
joinDocs(docs, separator) {
|
|
268
|
-
const text = docs.join(separator).trim();
|
|
269
|
-
return text === "" ? null : text;
|
|
270
|
-
}
|
|
271
|
-
async mergeSplits(splits, separator) {
|
|
272
|
-
const docs = [];
|
|
273
|
-
const currentDoc = [];
|
|
274
|
-
let total = 0;
|
|
275
|
-
for (const d of splits) {
|
|
276
|
-
const _len = await this.lengthFunction(d);
|
|
277
|
-
if (total + _len + currentDoc.length * separator.length > this.chunkSize) {
|
|
278
|
-
if (total > this.chunkSize) {
|
|
279
|
-
console.warn(`Created a chunk of size ${total}, +
|
|
280
|
-
which is longer than the specified ${this.chunkSize}`);
|
|
281
|
-
}
|
|
282
|
-
if (currentDoc.length > 0) {
|
|
283
|
-
const doc2 = this.joinDocs(currentDoc, separator);
|
|
284
|
-
if (doc2 !== null) {
|
|
285
|
-
docs.push(doc2);
|
|
286
|
-
}
|
|
287
|
-
while (total > this.chunkOverlap || total + _len + currentDoc.length * separator.length > this.chunkSize && total > 0) {
|
|
288
|
-
total -= await this.lengthFunction(currentDoc[0]);
|
|
289
|
-
currentDoc.shift();
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
currentDoc.push(d);
|
|
294
|
-
total += _len;
|
|
295
|
-
}
|
|
296
|
-
const doc = this.joinDocs(currentDoc, separator);
|
|
297
|
-
if (doc !== null) {
|
|
298
|
-
docs.push(doc);
|
|
299
|
-
}
|
|
300
|
-
return docs;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
class TokenTextSplitter extends TextSplitter {
|
|
304
|
-
static lc_name() {
|
|
305
|
-
return "TokenTextSplitter";
|
|
306
|
-
}
|
|
307
|
-
constructor(fields) {
|
|
308
|
-
super(fields);
|
|
309
|
-
Object.defineProperty(this, "encodingName", {
|
|
310
|
-
enumerable: true,
|
|
311
|
-
configurable: true,
|
|
312
|
-
writable: true,
|
|
313
|
-
value: void 0
|
|
314
|
-
});
|
|
315
|
-
Object.defineProperty(this, "allowedSpecial", {
|
|
316
|
-
enumerable: true,
|
|
317
|
-
configurable: true,
|
|
318
|
-
writable: true,
|
|
319
|
-
value: void 0
|
|
320
|
-
});
|
|
321
|
-
Object.defineProperty(this, "disallowedSpecial", {
|
|
322
|
-
enumerable: true,
|
|
323
|
-
configurable: true,
|
|
324
|
-
writable: true,
|
|
325
|
-
value: void 0
|
|
326
|
-
});
|
|
327
|
-
Object.defineProperty(this, "tokenizer", {
|
|
328
|
-
enumerable: true,
|
|
329
|
-
configurable: true,
|
|
330
|
-
writable: true,
|
|
331
|
-
value: void 0
|
|
332
|
-
});
|
|
333
|
-
this.encodingName = fields?.encodingName ?? "gpt2";
|
|
334
|
-
this.allowedSpecial = fields?.allowedSpecial ?? [];
|
|
335
|
-
this.disallowedSpecial = fields?.disallowedSpecial ?? "all";
|
|
336
|
-
}
|
|
337
|
-
async splitText(text) {
|
|
338
|
-
if (!this.tokenizer) {
|
|
339
|
-
this.tokenizer = await getEncoding(this.encodingName);
|
|
340
|
-
}
|
|
341
|
-
const splits = [];
|
|
342
|
-
const input_ids = this.tokenizer.encode(text, this.allowedSpecial, this.disallowedSpecial);
|
|
343
|
-
let start_idx = 0;
|
|
344
|
-
while (start_idx < input_ids.length) {
|
|
345
|
-
if (start_idx > 0) {
|
|
346
|
-
start_idx -= this.chunkOverlap;
|
|
347
|
-
}
|
|
348
|
-
const end_idx = Math.min(start_idx + this.chunkSize, input_ids.length);
|
|
349
|
-
const chunk_ids = input_ids.slice(start_idx, end_idx);
|
|
350
|
-
splits.push(this.tokenizer.decode(chunk_ids));
|
|
351
|
-
start_idx = end_idx;
|
|
352
|
-
}
|
|
353
|
-
return splits;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
148
|
async function initializeModel({
|
|
357
149
|
openAIApiKey,
|
|
358
150
|
model,
|
|
@@ -381,32 +173,30 @@ const fetchTranscript = async (identifier) => {
|
|
|
381
173
|
const info2 = await youtube.getInfo(identifier);
|
|
382
174
|
const transcriptData = await info2.getTranscript();
|
|
383
175
|
console.log("Transcript data fetched");
|
|
384
|
-
const transcriptWithTimeCodes = transcriptData?.transcript?.content?.body?.initial_segments.map(
|
|
385
|
-
(segment)
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
);
|
|
176
|
+
const transcriptWithTimeCodes = transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => {
|
|
177
|
+
const segmentDuration = Number(segment.end_ms) - Number(segment.start_ms);
|
|
178
|
+
return {
|
|
179
|
+
text: segment.snippet.text,
|
|
180
|
+
start: Number(segment.start_ms),
|
|
181
|
+
end: Number(segment.end_ms),
|
|
182
|
+
duration: segmentDuration
|
|
183
|
+
};
|
|
184
|
+
});
|
|
395
185
|
console.log("Transcript with time codes generated");
|
|
396
186
|
console.log("Cleaning thumbnail URL");
|
|
397
|
-
const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments.map(
|
|
398
|
-
|
|
399
|
-
).join(" ");
|
|
187
|
+
const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => segment.snippet.text).join(" ");
|
|
188
|
+
console.log(fullTranscript, "full transcript");
|
|
400
189
|
console.log("Full transcript generated");
|
|
401
|
-
|
|
402
|
-
const
|
|
403
|
-
const
|
|
404
|
-
|
|
190
|
+
console.log("Getting basic info");
|
|
191
|
+
const title = info2.basic_info?.title;
|
|
192
|
+
const videoId = info2.basic_info?.id;
|
|
193
|
+
console.log("Getting thumbnail URL");
|
|
194
|
+
const thumbnailUrl = info2?.basic_info?.thumbnail[0]?.url;
|
|
405
195
|
console.log("Returning transcript data");
|
|
406
196
|
return {
|
|
407
|
-
title,
|
|
408
197
|
videoId,
|
|
409
|
-
|
|
198
|
+
...title ? { title } : { title: "No title found" },
|
|
199
|
+
...thumbnailUrl ? { thumbnailUrl: cleanImageUrl(thumbnailUrl) } : { thumbnailUrl: "" },
|
|
410
200
|
fullTranscript,
|
|
411
201
|
transcriptWithTimeCodes
|
|
412
202
|
};
|
|
@@ -429,7 +219,7 @@ async function processTextChunks(chunks, model) {
|
|
|
429
219
|
return processedChunks.join(" ");
|
|
430
220
|
}
|
|
431
221
|
async function generateModifiedTranscript(rawTranscript) {
|
|
432
|
-
const pluginSettings = await strapi.config.get("plugin::yt-transcript");
|
|
222
|
+
const pluginSettings = await strapi.config.get("plugin::yt-transcript-strapi-plugin");
|
|
433
223
|
if (!pluginSettings.openAIApiKey || !pluginSettings.model || !pluginSettings.temp || !pluginSettings.maxTokens) {
|
|
434
224
|
throw new Error("Missing required configuration for YTTranscript");
|
|
435
225
|
}
|
|
@@ -458,13 +248,15 @@ const service = ({ strapi: strapi2 }) => ({
|
|
|
458
248
|
return transcriptData;
|
|
459
249
|
},
|
|
460
250
|
async saveTranscript(payload) {
|
|
461
|
-
return await strapi2.documents("plugin::yt-transcript.transcript").create({
|
|
251
|
+
return await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript").create({
|
|
462
252
|
data: payload
|
|
463
253
|
});
|
|
464
254
|
},
|
|
465
255
|
async findTranscript(videoId) {
|
|
466
256
|
console.log("Finding transcript for videoId:", videoId);
|
|
467
|
-
const
|
|
257
|
+
const test = await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript");
|
|
258
|
+
console.log("Test:", test);
|
|
259
|
+
const transcriptData = await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript").findFirst({
|
|
468
260
|
filters: { videoId }
|
|
469
261
|
});
|
|
470
262
|
console.log("Transcript found:", transcriptData?.title, "found");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/transcript/index.ts","../../server/src/content-types/index.ts","../../server/src/utils/extract-youtube-id.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/middlewares/index.ts","../../server/src/policies/index.ts","../../server/src/routes/content-api.ts","../../server/src/routes/admin.ts","../../server/src/routes/index.ts","../../node_modules/@langchain/textsplitters/dist/text_splitter.js","../../server/src/utils/openai.ts","../../server/src/utils/fetch-transcript.ts","../../server/src/services/service.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["import type { Core } from '@strapi/strapi';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","import type { Core } from '@strapi/strapi';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n // register phase\n};\n\nexport default register;\n","export default {\n default: {},\n validator() {},\n};\n","import schema from './schema.json';\n\nexport default {\n schema,\n};","import transcript from './transcript';\n\nexport default {\n transcript,\n};\n\n\n","export function extractYouTubeID(urlOrID: string): string | null {\n // Regular expression for YouTube ID format\n const regExpID = /^[a-zA-Z0-9_-]{11}$/;\n\n // Check if the input is a YouTube ID\n if (regExpID.test(urlOrID)) {\n return urlOrID;\n }\n\n // Regular expression for standard YouTube links\n const regExpStandard = /youtube\\.com\\/watch\\?v=([a-zA-Z0-9_-]+)/;\n\n // Regular expression for YouTube Shorts links\n const regExpShorts = /youtube\\.com\\/shorts\\/([a-zA-Z0-9_-]+)/;\n\n // Check for standard YouTube link\n const matchStandard = urlOrID.match(regExpStandard);\n if (matchStandard) {\n return matchStandard[1];\n }\n\n // Check for YouTube Shorts link\n const matchShorts = urlOrID.match(regExpShorts);\n if (matchShorts) {\n return matchShorts[1];\n }\n\n // Return null if no match is found\n return null;\n}","import type { Core } from '@strapi/strapi';\nimport { extractYouTubeID } from '../utils/extract-youtube-id';\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(ctx) {\n const videoId = extractYouTubeID(ctx.params.videoId);\n\n if (!videoId) return (ctx.body = { error: 'Invalid YouTube URL or ID', data: null });\n\n console.log(\"Looking for transcript in database\");\n\n const found = await strapi\n .plugin('yt-transcript')\n .service('service')\n .findTranscript(videoId);\n\n if (found) {\n console.log(\"Transcript found.\");\n return (ctx.body = { data: found });\n }\n\n console.log(\"Transcript not found. Fetching new transcript.\");\n\n const transcriptData = await strapi\n .plugin('yt-transcript')\n .service('service')\n .getTranscript(videoId);\n\n console.log(\"New transcript fetched.\");\n\n const readableTranscript = await strapi\n .plugin('yt-transcript')\n .service('service')\n .generateHumanReadableTranscript(transcriptData.fullTranscript);\n\n console.log(\"Human readable transcript generated.\");\n\n const payload = {\n title: transcriptData.title,\n transcript: transcriptData.transcript,\n videoId: transcriptData.videoId,\n thumbnailUrl: transcriptData.thumbnailUrl,\n fullTranscript: transcriptData.fullTranscript,\n transcriptWithTimeCodes: transcriptData.transcriptWithTimeCodes,\n readableTranscript: readableTranscript,\n };\n\n console.log(\"Saving new transcript to database.\");\n\n const transcript = await strapi\n .plugin('yt-transcript')\n .service('service')\n .saveTranscript(payload);\n\n ctx.body = { data: transcript };\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default {};\n","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","\"use strict\";\n\nimport contentApi from \"./content-api\";\nimport admin from \"./admin\";\n\nexport default {\n \"content-api\": {\n type: \"content-api\",\n routes: [...contentApi],\n },\n admin: {\n type: \"admin\",\n routes: [...admin],\n },\n};","import { Document, BaseDocumentTransformer } from \"@langchain/core/documents\";\nimport { getEncoding } from \"@langchain/core/utils/tiktoken\";\nexport class TextSplitter extends BaseDocumentTransformer {\n constructor(fields) {\n super(fields);\n Object.defineProperty(this, \"lc_namespace\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: [\"langchain\", \"document_transformers\", \"text_splitters\"]\n });\n Object.defineProperty(this, \"chunkSize\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: 1000\n });\n Object.defineProperty(this, \"chunkOverlap\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: 200\n });\n Object.defineProperty(this, \"keepSeparator\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: false\n });\n Object.defineProperty(this, \"lengthFunction\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n this.chunkSize = fields?.chunkSize ?? this.chunkSize;\n this.chunkOverlap = fields?.chunkOverlap ?? this.chunkOverlap;\n this.keepSeparator = fields?.keepSeparator ?? this.keepSeparator;\n this.lengthFunction =\n fields?.lengthFunction ?? ((text) => text.length);\n if (this.chunkOverlap >= this.chunkSize) {\n throw new Error(\"Cannot have chunkOverlap >= chunkSize\");\n }\n }\n async transformDocuments(documents, chunkHeaderOptions = {}) {\n return this.splitDocuments(documents, chunkHeaderOptions);\n }\n splitOnSeparator(text, separator) {\n let splits;\n if (separator) {\n if (this.keepSeparator) {\n const regexEscapedSeparator = separator.replace(/[/\\-\\\\^$*+?.()|[\\]{}]/g, \"\\\\$&\");\n splits = text.split(new RegExp(`(?=${regexEscapedSeparator})`));\n }\n else {\n splits = text.split(separator);\n }\n }\n else {\n splits = text.split(\"\");\n }\n return splits.filter((s) => s !== \"\");\n }\n async createDocuments(texts, \n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n metadatas = [], chunkHeaderOptions = {}) {\n // if no metadata is provided, we create an empty one for each text\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const _metadatas = metadatas.length > 0\n ? metadatas\n : [...Array(texts.length)].map(() => ({}));\n const { chunkHeader = \"\", chunkOverlapHeader = \"(cont'd) \", appendChunkOverlapHeader = false, } = chunkHeaderOptions;\n const documents = new Array();\n for (let i = 0; i < texts.length; i += 1) {\n const text = texts[i];\n let lineCounterIndex = 1;\n let prevChunk = null;\n let indexPrevChunk = -1;\n for (const chunk of await this.splitText(text)) {\n let pageContent = chunkHeader;\n // we need to count the \\n that are in the text before getting removed by the splitting\n const indexChunk = text.indexOf(chunk, indexPrevChunk + 1);\n if (prevChunk === null) {\n const newLinesBeforeFirstChunk = this.numberOfNewLines(text, 0, indexChunk);\n lineCounterIndex += newLinesBeforeFirstChunk;\n }\n else {\n const indexEndPrevChunk = indexPrevChunk + (await this.lengthFunction(prevChunk));\n if (indexEndPrevChunk < indexChunk) {\n const numberOfIntermediateNewLines = this.numberOfNewLines(text, indexEndPrevChunk, indexChunk);\n lineCounterIndex += numberOfIntermediateNewLines;\n }\n else if (indexEndPrevChunk > indexChunk) {\n const numberOfIntermediateNewLines = this.numberOfNewLines(text, indexChunk, indexEndPrevChunk);\n lineCounterIndex -= numberOfIntermediateNewLines;\n }\n if (appendChunkOverlapHeader) {\n pageContent += chunkOverlapHeader;\n }\n }\n const newLinesCount = this.numberOfNewLines(chunk);\n const loc = _metadatas[i].loc && typeof _metadatas[i].loc === \"object\"\n ? { ..._metadatas[i].loc }\n : {};\n loc.lines = {\n from: lineCounterIndex,\n to: lineCounterIndex + newLinesCount,\n };\n const metadataWithLinesNumber = {\n ..._metadatas[i],\n loc,\n };\n pageContent += chunk;\n documents.push(new Document({\n pageContent,\n metadata: metadataWithLinesNumber,\n }));\n lineCounterIndex += newLinesCount;\n prevChunk = chunk;\n indexPrevChunk = indexChunk;\n }\n }\n return documents;\n }\n numberOfNewLines(text, start, end) {\n const textSection = text.slice(start, end);\n return (textSection.match(/\\n/g) || []).length;\n }\n async splitDocuments(documents, chunkHeaderOptions = {}) {\n const selectedDocuments = documents.filter((doc) => doc.pageContent !== undefined);\n const texts = selectedDocuments.map((doc) => doc.pageContent);\n const metadatas = selectedDocuments.map((doc) => doc.metadata);\n return this.createDocuments(texts, metadatas, chunkHeaderOptions);\n }\n joinDocs(docs, separator) {\n const text = docs.join(separator).trim();\n return text === \"\" ? null : text;\n }\n async mergeSplits(splits, separator) {\n const docs = [];\n const currentDoc = [];\n let total = 0;\n for (const d of splits) {\n const _len = await this.lengthFunction(d);\n if (total + _len + currentDoc.length * separator.length >\n this.chunkSize) {\n if (total > this.chunkSize) {\n console.warn(`Created a chunk of size ${total}, +\nwhich is longer than the specified ${this.chunkSize}`);\n }\n if (currentDoc.length > 0) {\n const doc = this.joinDocs(currentDoc, separator);\n if (doc !== null) {\n docs.push(doc);\n }\n // Keep on popping if:\n // - we have a larger chunk than in the chunk overlap\n // - or if we still have any chunks and the length is long\n while (total > this.chunkOverlap ||\n (total + _len + currentDoc.length * separator.length >\n this.chunkSize &&\n total > 0)) {\n total -= await this.lengthFunction(currentDoc[0]);\n currentDoc.shift();\n }\n }\n }\n currentDoc.push(d);\n total += _len;\n }\n const doc = this.joinDocs(currentDoc, separator);\n if (doc !== null) {\n docs.push(doc);\n }\n return docs;\n }\n}\nexport class CharacterTextSplitter extends TextSplitter {\n static lc_name() {\n return \"CharacterTextSplitter\";\n }\n constructor(fields) {\n super(fields);\n Object.defineProperty(this, \"separator\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: \"\\n\\n\"\n });\n this.separator = fields?.separator ?? this.separator;\n }\n async splitText(text) {\n // First we naively split the large input into a bunch of smaller ones.\n const splits = this.splitOnSeparator(text, this.separator);\n return this.mergeSplits(splits, this.keepSeparator ? \"\" : this.separator);\n }\n}\nexport const SupportedTextSplitterLanguages = [\n \"cpp\",\n \"go\",\n \"java\",\n \"js\",\n \"php\",\n \"proto\",\n \"python\",\n \"rst\",\n \"ruby\",\n \"rust\",\n \"scala\",\n \"swift\",\n \"markdown\",\n \"latex\",\n \"html\",\n \"sol\",\n];\nexport class RecursiveCharacterTextSplitter extends TextSplitter {\n static lc_name() {\n return \"RecursiveCharacterTextSplitter\";\n }\n constructor(fields) {\n super(fields);\n Object.defineProperty(this, \"separators\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: [\"\\n\\n\", \"\\n\", \" \", \"\"]\n });\n this.separators = fields?.separators ?? this.separators;\n this.keepSeparator = fields?.keepSeparator ?? true;\n }\n async _splitText(text, separators) {\n const finalChunks = [];\n // Get appropriate separator to use\n let separator = separators[separators.length - 1];\n let newSeparators;\n for (let i = 0; i < separators.length; i += 1) {\n const s = separators[i];\n if (s === \"\") {\n separator = s;\n break;\n }\n if (text.includes(s)) {\n separator = s;\n newSeparators = separators.slice(i + 1);\n break;\n }\n }\n // Now that we have the separator, split the text\n const splits = this.splitOnSeparator(text, separator);\n // Now go merging things, recursively splitting longer texts.\n let goodSplits = [];\n const _separator = this.keepSeparator ? \"\" : separator;\n for (const s of splits) {\n if ((await this.lengthFunction(s)) < this.chunkSize) {\n goodSplits.push(s);\n }\n else {\n if (goodSplits.length) {\n const mergedText = await this.mergeSplits(goodSplits, _separator);\n finalChunks.push(...mergedText);\n goodSplits = [];\n }\n if (!newSeparators) {\n finalChunks.push(s);\n }\n else {\n const otherInfo = await this._splitText(s, newSeparators);\n finalChunks.push(...otherInfo);\n }\n }\n }\n if (goodSplits.length) {\n const mergedText = await this.mergeSplits(goodSplits, _separator);\n finalChunks.push(...mergedText);\n }\n return finalChunks;\n }\n async splitText(text) {\n return this._splitText(text, this.separators);\n }\n static fromLanguage(language, options) {\n return new RecursiveCharacterTextSplitter({\n ...options,\n separators: RecursiveCharacterTextSplitter.getSeparatorsForLanguage(language),\n });\n }\n static getSeparatorsForLanguage(language) {\n if (language === \"cpp\") {\n return [\n // Split along class definitions\n \"\\nclass \",\n // Split along function definitions\n \"\\nvoid \",\n \"\\nint \",\n \"\\nfloat \",\n \"\\ndouble \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"go\") {\n return [\n // Split along function definitions\n \"\\nfunc \",\n \"\\nvar \",\n \"\\nconst \",\n \"\\ntype \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"java\") {\n return [\n // Split along class definitions\n \"\\nclass \",\n // Split along method definitions\n \"\\npublic \",\n \"\\nprotected \",\n \"\\nprivate \",\n \"\\nstatic \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"js\") {\n return [\n // Split along function definitions\n \"\\nfunction \",\n \"\\nconst \",\n \"\\nlet \",\n \"\\nvar \",\n \"\\nclass \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\nswitch \",\n \"\\ncase \",\n \"\\ndefault \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"php\") {\n return [\n // Split along function definitions\n \"\\nfunction \",\n // Split along class definitions\n \"\\nclass \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nforeach \",\n \"\\nwhile \",\n \"\\ndo \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"proto\") {\n return [\n // Split along message definitions\n \"\\nmessage \",\n // Split along service definitions\n \"\\nservice \",\n // Split along enum definitions\n \"\\nenum \",\n // Split along option definitions\n \"\\noption \",\n // Split along import statements\n \"\\nimport \",\n // Split along syntax declarations\n \"\\nsyntax \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"python\") {\n return [\n // First, try to split along class definitions\n \"\\nclass \",\n \"\\ndef \",\n \"\\n\\tdef \",\n // Now split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"rst\") {\n return [\n // Split along section titles\n \"\\n===\\n\",\n \"\\n---\\n\",\n \"\\n***\\n\",\n // Split along directive markers\n \"\\n.. \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"ruby\") {\n return [\n // Split along method definitions\n \"\\ndef \",\n \"\\nclass \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nunless \",\n \"\\nwhile \",\n \"\\nfor \",\n \"\\ndo \",\n \"\\nbegin \",\n \"\\nrescue \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"rust\") {\n return [\n // Split along function definitions\n \"\\nfn \",\n \"\\nconst \",\n \"\\nlet \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nwhile \",\n \"\\nfor \",\n \"\\nloop \",\n \"\\nmatch \",\n \"\\nconst \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"scala\") {\n return [\n // Split along class definitions\n \"\\nclass \",\n \"\\nobject \",\n // Split along method definitions\n \"\\ndef \",\n \"\\nval \",\n \"\\nvar \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\nmatch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"swift\") {\n return [\n // Split along function definitions\n \"\\nfunc \",\n // Split along class definitions\n \"\\nclass \",\n \"\\nstruct \",\n \"\\nenum \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\ndo \",\n \"\\nswitch \",\n \"\\ncase \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"markdown\") {\n return [\n // First, try to split along Markdown headings (starting with level 2)\n \"\\n## \",\n \"\\n### \",\n \"\\n#### \",\n \"\\n##### \",\n \"\\n###### \",\n // Note the alternative syntax for headings (below) is not handled here\n // Heading level 2\n // ---------------\n // End of code block\n \"```\\n\\n\",\n // Horizontal lines\n \"\\n\\n***\\n\\n\",\n \"\\n\\n---\\n\\n\",\n \"\\n\\n___\\n\\n\",\n // Note that this splitter doesn't handle horizontal lines defined\n // by *three or more* of ***, ---, or ___, but this is not handled\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"latex\") {\n return [\n // First, try to split along Latex sections\n \"\\n\\\\chapter{\",\n \"\\n\\\\section{\",\n \"\\n\\\\subsection{\",\n \"\\n\\\\subsubsection{\",\n // Now split by environments\n \"\\n\\\\begin{enumerate}\",\n \"\\n\\\\begin{itemize}\",\n \"\\n\\\\begin{description}\",\n \"\\n\\\\begin{list}\",\n \"\\n\\\\begin{quote}\",\n \"\\n\\\\begin{quotation}\",\n \"\\n\\\\begin{verse}\",\n \"\\n\\\\begin{verbatim}\",\n // Now split by math environments\n \"\\n\\\\begin{align}\",\n \"$$\",\n \"$\",\n // Now split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else if (language === \"html\") {\n return [\n // First, try to split along HTML tags\n \"<body>\",\n \"<div>\",\n \"<p>\",\n \"<br>\",\n \"<li>\",\n \"<h1>\",\n \"<h2>\",\n \"<h3>\",\n \"<h4>\",\n \"<h5>\",\n \"<h6>\",\n \"<span>\",\n \"<table>\",\n \"<tr>\",\n \"<td>\",\n \"<th>\",\n \"<ul>\",\n \"<ol>\",\n \"<header>\",\n \"<footer>\",\n \"<nav>\",\n // Head\n \"<head>\",\n \"<style>\",\n \"<script>\",\n \"<meta>\",\n \"<title>\",\n // Normal type of lines\n \" \",\n \"\",\n ];\n }\n else if (language === \"sol\") {\n return [\n // Split along compiler informations definitions\n \"\\npragma \",\n \"\\nusing \",\n // Split along contract definitions\n \"\\ncontract \",\n \"\\ninterface \",\n \"\\nlibrary \",\n // Split along method definitions\n \"\\nconstructor \",\n \"\\ntype \",\n \"\\nfunction \",\n \"\\nevent \",\n \"\\nmodifier \",\n \"\\nerror \",\n \"\\nstruct \",\n \"\\nenum \",\n // Split along control flow statements\n \"\\nif \",\n \"\\nfor \",\n \"\\nwhile \",\n \"\\ndo while \",\n \"\\nassembly \",\n // Split by the normal type of lines\n \"\\n\\n\",\n \"\\n\",\n \" \",\n \"\",\n ];\n }\n else {\n throw new Error(`Language ${language} is not supported.`);\n }\n }\n}\n/**\n * Implementation of splitter which looks at tokens.\n */\nexport class TokenTextSplitter extends TextSplitter {\n static lc_name() {\n return \"TokenTextSplitter\";\n }\n constructor(fields) {\n super(fields);\n Object.defineProperty(this, \"encodingName\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"allowedSpecial\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"disallowedSpecial\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"tokenizer\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n this.encodingName = fields?.encodingName ?? \"gpt2\";\n this.allowedSpecial = fields?.allowedSpecial ?? [];\n this.disallowedSpecial = fields?.disallowedSpecial ?? \"all\";\n }\n async splitText(text) {\n if (!this.tokenizer) {\n this.tokenizer = await getEncoding(this.encodingName);\n }\n const splits = [];\n const input_ids = this.tokenizer.encode(text, this.allowedSpecial, this.disallowedSpecial);\n let start_idx = 0;\n while (start_idx < input_ids.length) {\n if (start_idx > 0) {\n start_idx -= this.chunkOverlap;\n }\n const end_idx = Math.min(start_idx + this.chunkSize, input_ids.length);\n const chunk_ids = input_ids.slice(start_idx, end_idx);\n splits.push(this.tokenizer.decode(chunk_ids));\n start_idx = end_idx;\n }\n return splits;\n }\n}\nexport class MarkdownTextSplitter extends RecursiveCharacterTextSplitter {\n constructor(fields) {\n super({\n ...fields,\n separators: RecursiveCharacterTextSplitter.getSeparatorsForLanguage(\"markdown\"),\n });\n }\n}\nexport class LatexTextSplitter extends RecursiveCharacterTextSplitter {\n constructor(fields) {\n super({\n ...fields,\n separators: RecursiveCharacterTextSplitter.getSeparatorsForLanguage(\"latex\"),\n });\n }\n}\n","import { ChatOpenAI } from \"@langchain/openai\";\n\ninterface InitializeModelProps {\n openAIApiKey: string;\n model: string;\n temp: number;\n maxTokens?: number;\n}\n\nexport async function initializeModel({\n openAIApiKey,\n model,\n temp,\n}: InitializeModelProps) {\n return new ChatOpenAI({\n temperature: temp,\n openAIApiKey: openAIApiKey,\n modelName: model,\n maxTokens: 1000,\n });\n}","export interface TranscriptSegment {\n text: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface TranscriptData {\n title: string;\n videoId: string;\n thumbnailUrl: string;\n fullTranscript: string;\n transcriptWithTimeCodes: TranscriptSegment[];\n}\n\nconst fetchTranscript = async (\n identifier: string\n): Promise<TranscriptData> => {\n console.log(\"Fetching Transcript - Calling fetchTranscript Utils\");\n const { Innertube } = await import('youtubei.js');\n\n console.log(\"Creating YouTube instance\");\n\n const youtube = await Innertube.create({\n lang: 'en',\n location: 'US',\n retrieve_player: false,\n });\n\n try {\n const info = await youtube.getInfo(identifier);\n const transcriptData = await info.getTranscript();\n\n console.log(\"Transcript data fetched\");\n\n const transcriptWithTimeCodes: TranscriptSegment[] = transcriptData?.transcript?.content?.body?.initial_segments.map(\n (segment) => {\n const segmentDuration = Number(segment.end_ms) - Number(segment.start_ms);\n return {\n text: segment.snippet.text,\n start: Number(segment.start_ms),\n end: Number(segment.end_ms),\n duration: segmentDuration,\n };\n }\n );\n\n console.log(\"Transcript with time codes generated\");\n\n function cleanImageUrl(url) {\n return url.split('?')[0];\n }\n\n console.log(\"Cleaning thumbnail URL\");\n\n const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments.map(\n (segment) => segment.snippet.text\n ).join(' ');\n\n console.log(\"Full transcript generated\");\n\n const title = info.basic_info.title;\n const videoId = info.basic_info.id;\n const thumbnailUrl = info.basic_info.thumbnail[0].url;\n const thumbnailUrlCleaned = cleanImageUrl(thumbnailUrl);\n\n console.log(\"Returning transcript data\");\n\n return {\n title,\n videoId,\n thumbnailUrl: thumbnailUrlCleaned || \"\",\n fullTranscript,\n transcriptWithTimeCodes,\n };\n } catch (error) {\n console.error('Error fetching transcript:', error);\n throw error;\n }\n};\n\nexport default fetchTranscript;","import type { Core } from '@strapi/strapi';\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport { TokenTextSplitter } from \"@langchain/textsplitters\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\n\nimport { initializeModel } from \"../utils/openai\";\nimport fetchTranscript from '../utils/fetch-transcript';\n\ninterface YTTranscriptConfig {\n openAIApiKey: string;\n model?: string;\n temp?: number;\n maxTokens?: number;\n}\n\nasync function processTextChunks(chunks: string[], model: ChatOpenAI) {\n const punctuationPrompt = PromptTemplate.fromTemplate(\n \"Add proper punctuation and capitalization to the following text chunk:\\n\\n{chunk}\"\n );\n const punctuationChain = punctuationPrompt.pipe(model);\n\n const processedChunks = await Promise.all(\n chunks.map(async (chunk) => {\n const result = await punctuationChain.invoke({ chunk });\n return result.content as string;\n })\n );\n\n return processedChunks.join(\" \");\n}\n\nexport async function generateModifiedTranscript (rawTranscript: string) {\n const pluginSettings = await strapi.config.get('plugin::yt-transcript') as YTTranscriptConfig; \n \n if (!pluginSettings.openAIApiKey || !pluginSettings.model || !pluginSettings.temp || !pluginSettings.maxTokens) {\n throw new Error('Missing required configuration for YTTranscript');\n }\n\n const chatModel = await initializeModel({\n openAIApiKey: pluginSettings.openAIApiKey,\n model: pluginSettings.model,\n temp: pluginSettings.temp,\n maxTokens: pluginSettings.maxTokens,\n });\n\n const splitter = new TokenTextSplitter({\n chunkSize: 1000,\n chunkOverlap: 200,\n });\n\n const transcriptChunks = await splitter.createDocuments([rawTranscript]);\n const chunkTexts = transcriptChunks.map(chunk => chunk.pageContent);\n const modifiedTranscript = await processTextChunks(chunkTexts, chatModel);\n return modifiedTranscript;\n}\n\nconst service = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(identifier: string) {\n console.log(\"Fetching Transcript - Calling fetchTranscript Service\");\n const youtubeIdRegex = /^[a-zA-Z0-9_-]{11}$/;\n const isValid = youtubeIdRegex.test(identifier);\n if (!isValid) return { error: 'Invalid video ID', data: null };\n const transcriptData = await fetchTranscript(identifier);\n return transcriptData;\n },\n\n async saveTranscript(payload) {\n // console.log('Saving transcript:', payload);\n return await strapi.documents('plugin::yt-transcript.transcript').create({\n data: payload,\n });\n },\n\n async findTranscript(videoId) {\n console.log('Finding transcript for videoId:', videoId);\n const transcriptData = await strapi.documents('plugin::yt-transcript.transcript').findFirst({\n filters: { videoId },\n });\n\n console.log('Transcript found:', transcriptData?.title, 'found');\n\n if (!transcriptData) return null;\n return transcriptData;\n },\n\n async generateHumanReadableTranscript(transcript) {\n console.log('Generating human readable transcript:');\n const modifiedTranscript = await generateModifiedTranscript(transcript);\n return modifiedTranscript;\n },\n});\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy,\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","transcript","doc","info"],"mappings":";;;;AAEA,MAAM,YAAY,CAAC,EAAE,QAAAA,cAAsC;AAE3D;ACFA,MAAM,UAAU,CAAC,EAAE,QAAAA,cAAsC;AAEzD;ACFA,MAAM,WAAW,CAAC,EAAE,QAAAA,cAAsC;AAE1D;ACJA,MAAe,SAAA;AAAA,EACb,SAAS,CAAC;AAAA,EACV,YAAY;AAAA,EAAA;AACd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACDA,MAAe,aAAA;AAAA,EACb;AACF;ACFA,MAAe,eAAA;AAAA,EACb;AACF;ACJO,SAAS,iBAAiB,SAAgC;AAE/D,QAAM,WAAW;AAGb,MAAA,SAAS,KAAK,OAAO,GAAG;AACnB,WAAA;AAAA,EAAA;AAIT,QAAM,iBAAiB;AAGvB,QAAM,eAAe;AAGf,QAAA,gBAAgB,QAAQ,MAAM,cAAc;AAClD,MAAI,eAAe;AACjB,WAAO,cAAc,CAAC;AAAA,EAAA;AAIlB,QAAA,cAAc,QAAQ,MAAM,YAAY;AAC9C,MAAI,aAAa;AACf,WAAO,YAAY,CAAC;AAAA,EAAA;AAIf,SAAA;AACT;AC3BA,MAAM,aAAa,CAAC,EAAE,QAAAA,eAAuC;AAAA,EAC3D,MAAM,cAAc,KAAK;AACvB,UAAM,UAAU,iBAAiB,IAAI,OAAO,OAAO;AAE/C,QAAA,CAAC,QAAiB,QAAA,IAAI,OAAO,EAAE,OAAO,6BAA6B,MAAM,KAAK;AAElF,YAAQ,IAAI,oCAAoC;AAE1C,UAAA,QAAQ,MAAMA,QACjB,OAAO,eAAe,EACtB,QAAQ,SAAS,EACjB,eAAe,OAAO;AAEzB,QAAI,OAAO;AACT,cAAQ,IAAI,mBAAmB;AAC/B,aAAQ,IAAI,OAAO,EAAE,MAAM,MAAM;AAAA,IAAA;AAGnC,YAAQ,IAAI,gDAAgD;AAEtD,UAAA,iBAAiB,MAAMA,QAC1B,OAAO,eAAe,EACtB,QAAQ,SAAS,EACjB,cAAc,OAAO;AAExB,YAAQ,IAAI,yBAAyB;AAE/B,UAAA,qBAAqB,MAAMA,QAC9B,OAAO,eAAe,EACtB,QAAQ,SAAS,EACjB,gCAAgC,eAAe,cAAc;AAEhE,YAAQ,IAAI,sCAAsC;AAElD,UAAM,UAAU;AAAA,MACd,OAAO,eAAe;AAAA,MACtB,YAAY,eAAe;AAAA,MAC3B,SAAS,eAAe;AAAA,MACxB,cAAc,eAAe;AAAA,MAC7B,gBAAgB,eAAe;AAAA,MAC/B,yBAAyB,eAAe;AAAA,MACxC;AAAA,IACF;AAEA,YAAQ,IAAI,oCAAoC;AAE1C,UAAAC,cAAa,MAAMD,QACtB,OAAO,eAAe,EACtB,QAAQ,SAAS,EACjB,eAAe,OAAO;AAErB,QAAA,OAAO,EAAE,MAAMC,YAAW;AAAA,EAAA;AAElC;ACrDA,MAAe,cAAA;AAAA,EACb;AACF;ACJA,MAAA,cAAe,CAAC;ACAhB,MAAA,WAAe,CAAC;ACAhB,MAAe,aAAA;AAAA,EACb;AAAA,IACE,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,MACN,UAAU,CAAA;AAAA,IAAC;AAAA,EACb;AAEJ;ACTA,MAAe,QAAA;AAAA,EACb;AAAA,IACE,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,MACN,UAAU,CAAA;AAAA,IAAC;AAAA,EACb;AAEJ;ACJA,MAAe,SAAA;AAAA,EACb,eAAe;AAAA,IACb,MAAM;AAAA,IACN,QAAQ,CAAC,GAAG,UAAU;AAAA,EACxB;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,CAAC,GAAG,KAAK;AAAA,EAAA;AAErB;ACZO,MAAM,qBAAqB,wBAAwB;AAAA,EACtD,YAAY,QAAQ;AAChB,UAAM,MAAM;AACZ,WAAO,eAAe,MAAM,gBAAgB;AAAA,MACxC,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,OAAO,CAAC,aAAa,yBAAyB,gBAAgB;AAAA,IAC1E,CAAS;AACD,WAAO,eAAe,MAAM,aAAa;AAAA,MACrC,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IACnB,CAAS;AACD,WAAO,eAAe,MAAM,gBAAgB;AAAA,MACxC,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IACnB,CAAS;AACD,WAAO,eAAe,MAAM,iBAAiB;AAAA,MACzC,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IACnB,CAAS;AACD,WAAO,eAAe,MAAM,kBAAkB;AAAA,MAC1C,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IACnB,CAAS;AACD,SAAK,YAAY,QAAQ,aAAa,KAAK;AAC3C,SAAK,eAAe,QAAQ,gBAAgB,KAAK;AACjD,SAAK,gBAAgB,QAAQ,iBAAiB,KAAK;AACnD,SAAK,iBACD,QAAQ,mBAAmB,CAAC,SAAS,KAAK;AAC9C,QAAI,KAAK,gBAAgB,KAAK,WAAW;AACrC,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACnE;AAAA,EACA;AAAA,EACI,MAAM,mBAAmB,WAAW,qBAAqB,IAAI;AACzD,WAAO,KAAK,eAAe,WAAW,kBAAkB;AAAA,EAChE;AAAA,EACI,iBAAiB,MAAM,WAAW;AAC9B,QAAI;AACJ,QAAI,WAAW;AACX,UAAI,KAAK,eAAe;AACpB,cAAM,wBAAwB,UAAU,QAAQ,0BAA0B,MAAM;AAChF,iBAAS,KAAK,MAAM,IAAI,OAAO,MAAM,qBAAqB,GAAG,CAAC;AAAA,MAC9E,OACiB;AACD,iBAAS,KAAK,MAAM,SAAS;AAAA,MAC7C;AAAA,IACA,OACa;AACD,eAAS,KAAK,MAAM,EAAE;AAAA,IAClC;AACQ,WAAO,OAAO,OAAO,CAAC,MAAM,MAAM,EAAE;AAAA,EAC5C;AAAA,EACI,MAAM,gBAAgB,OAEtB,YAAY,CAAA,GAAI,qBAAqB,IAAI;AAGrC,UAAM,aAAa,UAAU,SAAS,IAChC,YACA,CAAC,GAAG,MAAM,MAAM,MAAM,CAAC,EAAE,IAAI,OAAO,CAAA,EAAG;AAC7C,UAAM,EAAE,cAAc,IAAI,qBAAqB,aAAa,2BAA2B,MAAK,IAAM;AAClG,UAAM,YAAY,IAAI,MAAO;AAC7B,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;AACtC,YAAM,OAAO,MAAM,CAAC;AACpB,UAAI,mBAAmB;AACvB,UAAI,YAAY;AAChB,UAAI,iBAAiB;AACrB,iBAAW,SAAS,MAAM,KAAK,UAAU,IAAI,GAAG;AAC5C,YAAI,cAAc;AAElB,cAAM,aAAa,KAAK,QAAQ,OAAO,iBAAiB,CAAC;AACzD,YAAI,cAAc,MAAM;AACpB,gBAAM,2BAA2B,KAAK,iBAAiB,MAAM,GAAG,UAAU;AAC1E,8BAAoB;AAAA,QACxC,OACqB;AACD,gBAAM,oBAAoB,iBAAkB,MAAM,KAAK,eAAe,SAAS;AAC/E,cAAI,oBAAoB,YAAY;AAChC,kBAAM,+BAA+B,KAAK,iBAAiB,MAAM,mBAAmB,UAAU;AAC9F,gCAAoB;AAAA,UAC5C,WAC6B,oBAAoB,YAAY;AACrC,kBAAM,+BAA+B,KAAK,iBAAiB,MAAM,YAAY,iBAAiB;AAC9F,gCAAoB;AAAA,UAC5C;AACoB,cAAI,0BAA0B;AAC1B,2BAAe;AAAA,UACvC;AAAA,QACA;AACgB,cAAM,gBAAgB,KAAK,iBAAiB,KAAK;AACjD,cAAM,MAAM,WAAW,CAAC,EAAE,OAAO,OAAO,WAAW,CAAC,EAAE,QAAQ,WACxD,EAAE,GAAG,WAAW,CAAC,EAAE,IAAG,IACtB,CAAE;AACR,YAAI,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,IAAI,mBAAmB;AAAA,QAC1B;AACD,cAAM,0BAA0B;AAAA,UAC5B,GAAG,WAAW,CAAC;AAAA,UACf;AAAA,QACH;AACD,uBAAe;AACf,kBAAU,KAAK,IAAI,SAAS;AAAA,UACxB;AAAA,UACA,UAAU;AAAA,QAC9B,CAAiB,CAAC;AACF,4BAAoB;AACpB,oBAAY;AACZ,yBAAiB;AAAA,MACjC;AAAA,IACA;AACQ,WAAO;AAAA,EACf;AAAA,EACI,iBAAiB,MAAM,OAAO,KAAK;AAC/B,UAAM,cAAc,KAAK,MAAM,OAAO,GAAG;AACzC,YAAQ,YAAY,MAAM,KAAK,KAAK,CAAE,GAAE;AAAA,EAChD;AAAA,EACI,MAAM,eAAe,WAAW,qBAAqB,IAAI;AACrD,UAAM,oBAAoB,UAAU,OAAO,CAAC,QAAQ,IAAI,gBAAgB,MAAS;AACjF,UAAM,QAAQ,kBAAkB,IAAI,CAAC,QAAQ,IAAI,WAAW;AAC5D,UAAM,YAAY,kBAAkB,IAAI,CAAC,QAAQ,IAAI,QAAQ;AAC7D,WAAO,KAAK,gBAAgB,OAAO,WAAW,kBAAkB;AAAA,EACxE;AAAA,EACI,SAAS,MAAM,WAAW;AACtB,UAAM,OAAO,KAAK,KAAK,SAAS,EAAE,KAAM;AACxC,WAAO,SAAS,KAAK,OAAO;AAAA,EACpC;AAAA,EACI,MAAM,YAAY,QAAQ,WAAW;AACjC,UAAM,OAAO,CAAE;AACf,UAAM,aAAa,CAAE;AACrB,QAAI,QAAQ;AACZ,eAAW,KAAK,QAAQ;AACpB,YAAM,OAAO,MAAM,KAAK,eAAe,CAAC;AACxC,UAAI,QAAQ,OAAO,WAAW,SAAS,UAAU,SAC7C,KAAK,WAAW;AAChB,YAAI,QAAQ,KAAK,WAAW;AACxB,kBAAQ,KAAK,2BAA2B,KAAK;AAAA,qCAC5B,KAAK,SAAS,EAAE;AAAA,QACrD;AACgB,YAAI,WAAW,SAAS,GAAG;AACvB,gBAAMC,OAAM,KAAK,SAAS,YAAY,SAAS;AAC/C,cAAIA,SAAQ,MAAM;AACd,iBAAK,KAAKA,IAAG;AAAA,UACrC;AAIoB,iBAAO,QAAQ,KAAK,gBACf,QAAQ,OAAO,WAAW,SAAS,UAAU,SAC1C,KAAK,aACL,QAAQ,GAAI;AAChB,qBAAS,MAAM,KAAK,eAAe,WAAW,CAAC,CAAC;AAChD,uBAAW,MAAO;AAAA,UAC1C;AAAA,QACA;AAAA,MACA;AACY,iBAAW,KAAK,CAAC;AACjB,eAAS;AAAA,IACrB;AACQ,UAAM,MAAM,KAAK,SAAS,YAAY,SAAS;AAC/C,QAAI,QAAQ,MAAM;AACd,WAAK,KAAK,GAAG;AAAA,IACzB;AACQ,WAAO;AAAA,EACf;AACA;AA2dO,MAAM,0BAA0B,aAAa;AAAA,EAChD,OAAO,UAAU;AACb,WAAO;AAAA,EACf;AAAA,EACI,YAAY,QAAQ;AAChB,UAAM,MAAM;AACZ,WAAO,eAAe,MAAM,gBAAgB;AAAA,MACxC,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IACnB,CAAS;AACD,WAAO,eAAe,MAAM,kBAAkB;AAAA,MAC1C,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IACnB,CAAS;AACD,WAAO,eAAe,MAAM,qBAAqB;AAAA,MAC7C,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IACnB,CAAS;AACD,WAAO,eAAe,MAAM,aAAa;AAAA,MACrC,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IACnB,CAAS;AACD,SAAK,eAAe,QAAQ,gBAAgB;AAC5C,SAAK,iBAAiB,QAAQ,kBAAkB,CAAE;AAClD,SAAK,oBAAoB,QAAQ,qBAAqB;AAAA,EAC9D;AAAA,EACI,MAAM,UAAU,MAAM;AAClB,QAAI,CAAC,KAAK,WAAW;AACjB,WAAK,YAAY,MAAM,YAAY,KAAK,YAAY;AAAA,IAChE;AACQ,UAAM,SAAS,CAAE;AACjB,UAAM,YAAY,KAAK,UAAU,OAAO,MAAM,KAAK,gBAAgB,KAAK,iBAAiB;AACzF,QAAI,YAAY;AAChB,WAAO,YAAY,UAAU,QAAQ;AACjC,UAAI,YAAY,GAAG;AACf,qBAAa,KAAK;AAAA,MAClC;AACY,YAAM,UAAU,KAAK,IAAI,YAAY,KAAK,WAAW,UAAU,MAAM;AACrE,YAAM,YAAY,UAAU,MAAM,WAAW,OAAO;AACpD,aAAO,KAAK,KAAK,UAAU,OAAO,SAAS,CAAC;AAC5C,kBAAY;AAAA,IACxB;AACQ,WAAO;AAAA,EACf;AACA;ACtrBA,eAAsB,gBAAgB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,SAAO,IAAI,WAAW;AAAA,IACpB,aAAa;AAAA,IACb;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,EAAA,CACZ;AACH;ACLA,MAAM,kBAAkB,OACtB,eAC4B;AAC5B,UAAQ,IAAI,qDAAqD;AACjE,QAAM,EAAE,UAAA,IAAc,MAAM,OAAO,aAAa;AAEhD,UAAQ,IAAI,2BAA2B;AAEjC,QAAA,UAAU,MAAM,UAAU,OAAO;AAAA,IACrC,MAAM;AAAA,IACN,UAAU;AAAA,IACV,iBAAiB;AAAA,EAAA,CAClB;AAEG,MAAA;AAoBO,QAAA,gBAAT,SAAuB,KAAK;AAC1B,aAAO,IAAI,MAAM,GAAG,EAAE,CAAC;AAAA,IACzB;AArBA,UAAMC,QAAO,MAAM,QAAQ,QAAQ,UAAU;AACvC,UAAA,iBAAiB,MAAMA,MAAK,cAAc;AAEhD,YAAQ,IAAI,yBAAyB;AAErC,UAAM,0BAA+C,gBAAgB,YAAY,SAAS,MAAM,iBAAiB;AAAA,MAC/G,CAAC,YAAY;AACX,cAAM,kBAAkB,OAAO,QAAQ,MAAM,IAAI,OAAO,QAAQ,QAAQ;AACjE,eAAA;AAAA,UACL,MAAM,QAAQ,QAAQ;AAAA,UACtB,OAAO,OAAO,QAAQ,QAAQ;AAAA,UAC9B,KAAK,OAAO,QAAQ,MAAM;AAAA,UAC1B,UAAU;AAAA,QACZ;AAAA,MAAA;AAAA,IAEJ;AAEA,YAAQ,IAAI,sCAAsC;AAMlD,YAAQ,IAAI,wBAAwB;AAEpC,UAAM,iBAAiB,gBAAgB,YAAY,SAAS,MAAM,iBAAiB;AAAA,MACjF,CAAC,YAAY,QAAQ,QAAQ;AAAA,IAAA,EAC7B,KAAK,GAAG;AAEV,YAAQ,IAAI,2BAA2B;AAEjC,UAAA,QAAQA,MAAK,WAAW;AACxB,UAAA,UAAUA,MAAK,WAAW;AAChC,UAAM,eAAeA,MAAK,WAAW,UAAU,CAAC,EAAE;AAC5C,UAAA,sBAAsB,cAAc,YAAY;AAEtD,YAAQ,IAAI,2BAA2B;AAEhC,WAAA;AAAA,MACL;AAAA,MACA;AAAA,MACA,cAAc,uBAAuB;AAAA,MACrC;AAAA,MACA;AAAA,IACF;AAAA,WACO,OAAO;AACN,YAAA,MAAM,8BAA8B,KAAK;AAC3C,UAAA;AAAA,EAAA;AAEV;AChEA,eAAe,kBAAkB,QAAkB,OAAmB;AACpE,QAAM,oBAAoB,eAAe;AAAA,IACvC;AAAA,EACF;AACM,QAAA,mBAAmB,kBAAkB,KAAK,KAAK;AAE/C,QAAA,kBAAkB,MAAM,QAAQ;AAAA,IACpC,OAAO,IAAI,OAAO,UAAU;AAC1B,YAAM,SAAS,MAAM,iBAAiB,OAAO,EAAE,OAAO;AACtD,aAAO,OAAO;AAAA,IACf,CAAA;AAAA,EACH;AAEO,SAAA,gBAAgB,KAAK,GAAG;AACjC;AAEA,eAAsB,2BAA4B,eAAuB;AACvE,QAAM,iBAAiB,MAAM,OAAO,OAAO,IAAI,uBAAuB;AAElE,MAAA,CAAC,eAAe,gBAAgB,CAAC,eAAe,SAAS,CAAC,eAAe,QAAQ,CAAC,eAAe,WAAW;AACxG,UAAA,IAAI,MAAM,iDAAiD;AAAA,EAAA;AAG7D,QAAA,YAAY,MAAM,gBAAgB;AAAA,IACtC,cAAc,eAAe;AAAA,IAC7B,OAAO,eAAe;AAAA,IACtB,MAAM,eAAe;AAAA,IACrB,WAAW,eAAe;AAAA,EAAA,CAC3B;AAEK,QAAA,WAAW,IAAI,kBAAkB;AAAA,IACrC,WAAW;AAAA,IACX,cAAc;AAAA,EAAA,CACf;AAED,QAAM,mBAAmB,MAAM,SAAS,gBAAgB,CAAC,aAAa,CAAC;AACvE,QAAM,aAAa,iBAAiB,IAAI,CAAA,UAAS,MAAM,WAAW;AAClE,QAAM,qBAAqB,MAAM,kBAAkB,YAAY,SAAS;AACjE,SAAA;AACT;AAEA,MAAM,UAAU,CAAC,EAAE,QAAAH,eAAuC;AAAA,EACxD,MAAM,cAAc,YAAoB;AACtC,YAAQ,IAAI,uDAAuD;AACnE,UAAM,iBAAiB;AACjB,UAAA,UAAU,eAAe,KAAK,UAAU;AAC9C,QAAI,CAAC,QAAS,QAAO,EAAE,OAAO,oBAAoB,MAAM,KAAK;AACvD,UAAA,iBAAiB,MAAM,gBAAgB,UAAU;AAChD,WAAA;AAAA,EACT;AAAA,EAEA,MAAM,eAAe,SAAS;AAE5B,WAAO,MAAMA,QAAO,UAAU,kCAAkC,EAAE,OAAO;AAAA,MACvE,MAAM;AAAA,IAAA,CACP;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,SAAS;AACpB,YAAA,IAAI,mCAAmC,OAAO;AACtD,UAAM,iBAAmB,MAAMA,QAAO,UAAU,kCAAkC,EAAE,UAAU;AAAA,MAC5F,SAAS,EAAE,QAAQ;AAAA,IAAA,CACpB;AAED,YAAQ,IAAI,qBAAqB,gBAAgB,OAAO,OAAO;AAE3D,QAAA,CAAC,eAAuB,QAAA;AACrB,WAAA;AAAA,EACT;AAAA,EAEA,MAAM,gCAAgCC,aAAY;AAChD,YAAQ,IAAI,uCAAuC;AAC7C,UAAA,qBAAqB,MAAM,2BAA2BA,WAAU;AAC/D,WAAA;AAAA,EAAA;AAEX;ACxFA,MAAe,WAAA;AAAA,EACb;AACF;ACcA,MAAe,QAAA;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;","x_google_ignoreList":[14]}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/transcript/index.ts","../../server/src/content-types/index.ts","../../server/src/utils/extract-youtube-id.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/middlewares/index.ts","../../server/src/policies/index.ts","../../server/src/routes/content-api.ts","../../server/src/routes/admin.ts","../../server/src/routes/index.ts","../../server/src/utils/openai.ts","../../server/src/utils/fetch-transcript.ts","../../server/src/services/service.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["import type { Core } from '@strapi/strapi';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","import type { Core } from '@strapi/strapi';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n // register phase\n};\n\nexport default register;\n","export default {\n default: {},\n validator() {},\n};\n","import schema from './schema.json';\n\nexport default {\n schema,\n};","import transcript from './transcript';\n\nexport default {\n transcript,\n};\n\n\n","export function extractYouTubeID(urlOrID: string): string | null {\n // Regular expression for YouTube ID format\n const regExpID = /^[a-zA-Z0-9_-]{11}$/;\n\n // Check if the input is a YouTube ID\n if (regExpID.test(urlOrID)) {\n return urlOrID;\n }\n\n // Regular expression for standard YouTube links\n const regExpStandard = /youtube\\.com\\/watch\\?v=([a-zA-Z0-9_-]+)/;\n\n // Regular expression for YouTube Shorts links\n const regExpShorts = /youtube\\.com\\/shorts\\/([a-zA-Z0-9_-]+)/;\n\n // Check for standard YouTube link\n const matchStandard = urlOrID.match(regExpStandard);\n if (matchStandard) {\n return matchStandard[1];\n }\n\n // Check for YouTube Shorts link\n const matchShorts = urlOrID.match(regExpShorts);\n if (matchShorts) {\n return matchShorts[1];\n }\n\n // Return null if no match is found\n return null;\n}","import type { Core } from '@strapi/strapi';\nimport { extractYouTubeID } from '../utils/extract-youtube-id';\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(ctx) {\n const videoId = extractYouTubeID(ctx.params.videoId);\n\n if (!videoId) return (ctx.body = { error: 'Invalid YouTube URL or ID', data: null });\n\n console.log(\"Looking for transcript in database\");\n\n const found = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .findTranscript(videoId);\n\n if (found) {\n console.log(\"Transcript found.\");\n return (ctx.body = { data: found });\n }\n\n console.log(\"Transcript not found. Fetching new transcript.\");\n\n const transcriptData = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .getTranscript(videoId);\n\n console.log(\"New transcript fetched.\");\n\n const readableTranscript = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .generateHumanReadableTranscript(transcriptData.fullTranscript);\n\n console.log(\"Human readable transcript generated.\");\n\n const payload = {\n title: transcriptData?.title || \"No title found\",\n videoId: transcriptData?.videoId,\n thumbnailUrl: transcriptData?.thumbnailUrl || \"No thumbnail URL found\",\n fullTranscript: transcriptData?.fullTranscript,\n transcriptWithTimeCodes: transcriptData?.transcriptWithTimeCodes,\n readableTranscript: readableTranscript,\n };\n\n console.log(\"Payload:\", payload);\n\n console.log(\"Saving new transcript to database.\");\n\n const transcript = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .saveTranscript(payload);\n\n ctx.body = { data: transcript };\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default {};\n","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","\"use strict\";\n\nimport contentApi from \"./content-api\";\nimport admin from \"./admin\";\n\nexport default {\n \"content-api\": {\n type: \"content-api\",\n routes: [...contentApi],\n },\n admin: {\n type: \"admin\",\n routes: [...admin],\n },\n};","import { ChatOpenAI } from \"@langchain/openai\";\n\ninterface InitializeModelProps {\n openAIApiKey: string;\n model: string;\n temp: number;\n maxTokens?: number;\n}\n\nexport async function initializeModel({\n openAIApiKey,\n model,\n temp,\n}: InitializeModelProps) {\n return new ChatOpenAI({\n temperature: temp,\n openAIApiKey: openAIApiKey,\n modelName: model,\n maxTokens: 1000,\n });\n}","export interface TranscriptSegment {\n text: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface TranscriptData {\n title: string;\n videoId: string;\n thumbnailUrl: string;\n fullTranscript: string;\n transcriptWithTimeCodes: TranscriptSegment[];\n}\n\nconst fetchTranscript = async (identifier: string): Promise<TranscriptData> => {\n console.log('Fetching Transcript - Calling fetchTranscript Utils');\n const { Innertube } = await import('youtubei.js');\n\n console.log('Creating YouTube instance');\n\n const youtube = await Innertube.create({\n lang: 'en',\n location: 'US',\n retrieve_player: false,\n });\n\n try {\n const info = await youtube.getInfo(identifier);\n const transcriptData = await info.getTranscript();\n\n console.log('Transcript data fetched');\n\n const transcriptWithTimeCodes: TranscriptSegment[] =\n transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => {\n const segmentDuration = Number(segment.end_ms) - Number(segment.start_ms);\n return {\n text: segment.snippet.text,\n start: Number(segment.start_ms),\n end: Number(segment.end_ms),\n duration: segmentDuration,\n };\n });\n\n console.log('Transcript with time codes generated');\n\n function cleanImageUrl(url) {\n return url.split('?')[0];\n }\n\n console.log('Cleaning thumbnail URL');\n\n const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments\n .map((segment) => segment.snippet.text)\n .join(' ');\n\n console.log(fullTranscript, 'full transcript');\n\n console.log('Full transcript generated');\n\n console.log('Getting basic info');\n\n const title = info.basic_info?.title;\n const videoId = info.basic_info?.id;\n\n console.log('Getting thumbnail URL');\n const thumbnailUrl = info?.basic_info?.thumbnail[0]?.url;\n\n console.log('Returning transcript data');\n\n return {\n videoId,\n ...(title ? { title } : { title: 'No title found' }),\n ...(thumbnailUrl ? { thumbnailUrl: cleanImageUrl(thumbnailUrl) } : { thumbnailUrl: '' }),\n fullTranscript,\n transcriptWithTimeCodes,\n };\n } catch (error) {\n console.error('Error fetching transcript:', error);\n throw error;\n }\n};\n\nexport default fetchTranscript;\n","import type { Core } from '@strapi/strapi';\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport { TokenTextSplitter } from \"@langchain/textsplitters\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\n\nimport { initializeModel } from \"../utils/openai\";\nimport fetchTranscript from '../utils/fetch-transcript';\n\ninterface YTTranscriptConfig {\n openAIApiKey: string;\n model?: string;\n temp?: number;\n maxTokens?: number;\n}\n\nasync function processTextChunks(chunks: string[], model: ChatOpenAI) {\n const punctuationPrompt = PromptTemplate.fromTemplate(\n \"Add proper punctuation and capitalization to the following text chunk:\\n\\n{chunk}\"\n );\n const punctuationChain = punctuationPrompt.pipe(model);\n\n const processedChunks = await Promise.all(\n chunks.map(async (chunk) => {\n const result = await punctuationChain.invoke({ chunk });\n return result.content as string;\n })\n );\n\n return processedChunks.join(\" \");\n}\n\nexport async function generateModifiedTranscript (rawTranscript: string) {\n const pluginSettings = await strapi.config.get('plugin::yt-transcript-strapi-plugin') as YTTranscriptConfig; \n \n if (!pluginSettings.openAIApiKey || !pluginSettings.model || !pluginSettings.temp || !pluginSettings.maxTokens) {\n throw new Error('Missing required configuration for YTTranscript');\n }\n\n const chatModel = await initializeModel({\n openAIApiKey: pluginSettings.openAIApiKey,\n model: pluginSettings.model,\n temp: pluginSettings.temp,\n maxTokens: pluginSettings.maxTokens,\n });\n\n const splitter = new TokenTextSplitter({\n chunkSize: 1000,\n chunkOverlap: 200,\n });\n\n const transcriptChunks = await splitter.createDocuments([rawTranscript]);\n const chunkTexts = transcriptChunks.map(chunk => chunk.pageContent);\n const modifiedTranscript = await processTextChunks(chunkTexts, chatModel);\n return modifiedTranscript;\n}\n\nconst service = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(identifier: string) {\n console.log(\"Fetching Transcript - Calling fetchTranscript Service\");\n const youtubeIdRegex = /^[a-zA-Z0-9_-]{11}$/;\n const isValid = youtubeIdRegex.test(identifier);\n if (!isValid) return { error: 'Invalid video ID', data: null };\n const transcriptData = await fetchTranscript(identifier);\n return transcriptData;\n },\n\n async saveTranscript(payload) {\n // console.log('Saving transcript:', payload);\n return await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript').create({\n data: payload,\n });\n },\n\n async findTranscript(videoId) {\n console.log('Finding transcript for videoId:', videoId);\n\n const test = await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript')\n\n console.log('Test:', test);\n\n const transcriptData = await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript').findFirst({\n filters: { videoId },\n });\n\n\n console.log('Transcript found:', transcriptData?.title, 'found');\n\n if (!transcriptData) return null;\n return transcriptData;\n },\n\n async generateHumanReadableTranscript(transcript) {\n console.log('Generating human readable transcript:');\n const modifiedTranscript = await generateModifiedTranscript(transcript);\n return modifiedTranscript;\n },\n});\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy,\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","transcript","info"],"mappings":";;;AAEA,MAAM,YAAY,CAAC,EAAE,QAAAA,cAAsC;AAE3D;ACFA,MAAM,UAAU,CAAC,EAAE,QAAAA,cAAsC;AAEzD;ACFA,MAAM,WAAW,CAAC,EAAE,QAAAA,cAAsC;AAE1D;ACJA,MAAe,SAAA;AAAA,EACb,SAAS,CAAC;AAAA,EACV,YAAY;AAAA,EAAA;AACd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACDA,MAAe,aAAA;AAAA,EACb;AACF;ACFA,MAAe,eAAA;AAAA,EACb;AACF;ACJO,SAAS,iBAAiB,SAAgC;AAE/D,QAAM,WAAW;AAGb,MAAA,SAAS,KAAK,OAAO,GAAG;AACnB,WAAA;AAAA,EAAA;AAIT,QAAM,iBAAiB;AAGvB,QAAM,eAAe;AAGf,QAAA,gBAAgB,QAAQ,MAAM,cAAc;AAClD,MAAI,eAAe;AACjB,WAAO,cAAc,CAAC;AAAA,EAAA;AAIlB,QAAA,cAAc,QAAQ,MAAM,YAAY;AAC9C,MAAI,aAAa;AACf,WAAO,YAAY,CAAC;AAAA,EAAA;AAIf,SAAA;AACT;AC3BA,MAAM,aAAa,CAAC,EAAE,QAAAA,eAAuC;AAAA,EAC3D,MAAM,cAAc,KAAK;AACvB,UAAM,UAAU,iBAAiB,IAAI,OAAO,OAAO;AAE/C,QAAA,CAAC,QAAiB,QAAA,IAAI,OAAO,EAAE,OAAO,6BAA6B,MAAM,KAAK;AAElF,YAAQ,IAAI,oCAAoC;AAE1C,UAAA,QAAQ,MAAMA,QACjB,OAAO,6BAA6B,EACpC,QAAQ,SAAS,EACjB,eAAe,OAAO;AAEzB,QAAI,OAAO;AACT,cAAQ,IAAI,mBAAmB;AAC/B,aAAQ,IAAI,OAAO,EAAE,MAAM,MAAM;AAAA,IAAA;AAGnC,YAAQ,IAAI,gDAAgD;AAEtD,UAAA,iBAAiB,MAAMA,QAC1B,OAAO,6BAA6B,EACpC,QAAQ,SAAS,EACjB,cAAc,OAAO;AAExB,YAAQ,IAAI,yBAAyB;AAE/B,UAAA,qBAAqB,MAAMA,QAC9B,OAAO,6BAA6B,EACpC,QAAQ,SAAS,EACjB,gCAAgC,eAAe,cAAc;AAEhE,YAAQ,IAAI,sCAAsC;AAElD,UAAM,UAAU;AAAA,MACd,OAAO,gBAAgB,SAAS;AAAA,MAChC,SAAS,gBAAgB;AAAA,MACzB,cAAc,gBAAgB,gBAAgB;AAAA,MAC9C,gBAAgB,gBAAgB;AAAA,MAChC,yBAAyB,gBAAgB;AAAA,MACzC;AAAA,IACF;AAEQ,YAAA,IAAI,YAAY,OAAO;AAE/B,YAAQ,IAAI,oCAAoC;AAE1C,UAAAC,cAAa,MAAMD,QACtB,OAAO,6BAA6B,EACpC,QAAQ,SAAS,EACjB,eAAe,OAAO;AAErB,QAAA,OAAO,EAAE,MAAMC,YAAW;AAAA,EAAA;AAElC;ACtDA,MAAe,cAAA;AAAA,EACb;AACF;ACJA,MAAA,cAAe,CAAC;ACAhB,MAAA,WAAe,CAAC;ACAhB,MAAe,aAAA;AAAA,EACb;AAAA,IACE,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,MACN,UAAU,CAAA;AAAA,IAAC;AAAA,EACb;AAEJ;ACTA,MAAe,QAAA;AAAA,EACb;AAAA,IACE,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,MACN,UAAU,CAAA;AAAA,IAAC;AAAA,EACb;AAEJ;ACJA,MAAe,SAAA;AAAA,EACb,eAAe;AAAA,IACb,MAAM;AAAA,IACN,QAAQ,CAAC,GAAG,UAAU;AAAA,EACxB;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,CAAC,GAAG,KAAK;AAAA,EAAA;AAErB;ACLA,eAAsB,gBAAgB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,SAAO,IAAI,WAAW;AAAA,IACpB,aAAa;AAAA,IACb;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,EAAA,CACZ;AACH;ACLA,MAAM,kBAAkB,OAAO,eAAgD;AAC7E,UAAQ,IAAI,qDAAqD;AACjE,QAAM,EAAE,UAAA,IAAc,MAAM,OAAO,aAAa;AAEhD,UAAQ,IAAI,2BAA2B;AAEjC,QAAA,UAAU,MAAM,UAAU,OAAO;AAAA,IACrC,MAAM;AAAA,IACN,UAAU;AAAA,IACV,iBAAiB;AAAA,EAAA,CAClB;AAEG,MAAA;AAmBO,QAAA,gBAAT,SAAuB,KAAK;AAC1B,aAAO,IAAI,MAAM,GAAG,EAAE,CAAC;AAAA,IACzB;AApBA,UAAMC,QAAO,MAAM,QAAQ,QAAQ,UAAU;AACvC,UAAA,iBAAiB,MAAMA,MAAK,cAAc;AAEhD,YAAQ,IAAI,yBAAyB;AAE/B,UAAA,0BACJ,gBAAgB,YAAY,SAAS,MAAM,iBAAiB,IAAI,CAAC,YAAY;AAC3E,YAAM,kBAAkB,OAAO,QAAQ,MAAM,IAAI,OAAO,QAAQ,QAAQ;AACjE,aAAA;AAAA,QACL,MAAM,QAAQ,QAAQ;AAAA,QACtB,OAAO,OAAO,QAAQ,QAAQ;AAAA,QAC9B,KAAK,OAAO,QAAQ,MAAM;AAAA,QAC1B,UAAU;AAAA,MACZ;AAAA,IAAA,CACD;AAEH,YAAQ,IAAI,sCAAsC;AAMlD,YAAQ,IAAI,wBAAwB;AAEpC,UAAM,iBAAiB,gBAAgB,YAAY,SAAS,MAAM,iBAC/D,IAAI,CAAC,YAAY,QAAQ,QAAQ,IAAI,EACrC,KAAK,GAAG;AAEH,YAAA,IAAI,gBAAgB,iBAAiB;AAE7C,YAAQ,IAAI,2BAA2B;AAEvC,YAAQ,IAAI,oBAAoB;AAE1B,UAAA,QAAQA,MAAK,YAAY;AACzB,UAAA,UAAUA,MAAK,YAAY;AAEjC,YAAQ,IAAI,uBAAuB;AACnC,UAAM,eAAeA,OAAM,YAAY,UAAU,CAAC,GAAG;AAErD,YAAQ,IAAI,2BAA2B;AAEhC,WAAA;AAAA,MACL;AAAA,MACA,GAAI,QAAQ,EAAE,MAAU,IAAA,EAAE,OAAO,iBAAiB;AAAA,MAClD,GAAI,eAAe,EAAE,cAAc,cAAc,YAAY,MAAM,EAAE,cAAc,GAAG;AAAA,MACtF;AAAA,MACA;AAAA,IACF;AAAA,WACO,OAAO;AACN,YAAA,MAAM,8BAA8B,KAAK;AAC3C,UAAA;AAAA,EAAA;AAEV;AClEA,eAAe,kBAAkB,QAAkB,OAAmB;AACpE,QAAM,oBAAoB,eAAe;AAAA,IACvC;AAAA,EACF;AACM,QAAA,mBAAmB,kBAAkB,KAAK,KAAK;AAE/C,QAAA,kBAAkB,MAAM,QAAQ;AAAA,IACpC,OAAO,IAAI,OAAO,UAAU;AAC1B,YAAM,SAAS,MAAM,iBAAiB,OAAO,EAAE,OAAO;AACtD,aAAO,OAAO;AAAA,IACf,CAAA;AAAA,EACH;AAEO,SAAA,gBAAgB,KAAK,GAAG;AACjC;AAEA,eAAsB,2BAA4B,eAAuB;AACvE,QAAM,iBAAiB,MAAM,OAAO,OAAO,IAAI,qCAAqC;AAEhF,MAAA,CAAC,eAAe,gBAAgB,CAAC,eAAe,SAAS,CAAC,eAAe,QAAQ,CAAC,eAAe,WAAW;AACxG,UAAA,IAAI,MAAM,iDAAiD;AAAA,EAAA;AAG7D,QAAA,YAAY,MAAM,gBAAgB;AAAA,IACtC,cAAc,eAAe;AAAA,IAC7B,OAAO,eAAe;AAAA,IACtB,MAAM,eAAe;AAAA,IACrB,WAAW,eAAe;AAAA,EAAA,CAC3B;AAEK,QAAA,WAAW,IAAI,kBAAkB;AAAA,IACrC,WAAW;AAAA,IACX,cAAc;AAAA,EAAA,CACf;AAED,QAAM,mBAAmB,MAAM,SAAS,gBAAgB,CAAC,aAAa,CAAC;AACvE,QAAM,aAAa,iBAAiB,IAAI,CAAA,UAAS,MAAM,WAAW;AAClE,QAAM,qBAAqB,MAAM,kBAAkB,YAAY,SAAS;AACjE,SAAA;AACT;AAEA,MAAM,UAAU,CAAC,EAAE,QAAAF,eAAuC;AAAA,EACxD,MAAM,cAAc,YAAoB;AACtC,YAAQ,IAAI,uDAAuD;AACnE,UAAM,iBAAiB;AACjB,UAAA,UAAU,eAAe,KAAK,UAAU;AAC9C,QAAI,CAAC,QAAS,QAAO,EAAE,OAAO,oBAAoB,MAAM,KAAK;AACvD,UAAA,iBAAiB,MAAM,gBAAgB,UAAU;AAChD,WAAA;AAAA,EACT;AAAA,EAEA,MAAM,eAAe,SAAS;AAE5B,WAAO,MAAMA,QAAO,UAAU,gDAAgD,EAAE,OAAO;AAAA,MACrF,MAAM;AAAA,IAAA,CACP;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,SAAS;AACpB,YAAA,IAAI,mCAAmC,OAAO;AAEtD,UAAM,OAAO,MAAMA,QAAO,UAAU,gDAAgD;AAE5E,YAAA,IAAI,SAAS,IAAI;AAEzB,UAAM,iBAAmB,MAAMA,QAAO,UAAU,gDAAgD,EAAE,UAAU;AAAA,MAC1G,SAAS,EAAE,QAAQ;AAAA,IAAA,CACpB;AAGD,YAAQ,IAAI,qBAAqB,gBAAgB,OAAO,OAAO;AAE3D,QAAA,CAAC,eAAuB,QAAA;AACrB,WAAA;AAAA,EACT;AAAA,EAEA,MAAM,gCAAgCC,aAAY;AAChD,YAAQ,IAAI,uCAAuC;AAC7C,UAAA,qBAAqB,MAAM,2BAA2BA,WAAU;AAC/D,WAAA;AAAA,EAAA;AAEX;AC9FA,MAAe,WAAA;AAAA,EACb;AACF;ACcA,MAAe,QAAA;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.0.
|
|
3
|
-
"keywords": [
|
|
2
|
+
"version": "0.0.10",
|
|
3
|
+
"keywords": [
|
|
4
|
+
"yt-transcript-strapi-plugin",
|
|
5
|
+
"youtube",
|
|
6
|
+
"transcript",
|
|
7
|
+
"strapi",
|
|
8
|
+
"plugin"
|
|
9
|
+
],
|
|
4
10
|
"type": "commonjs",
|
|
5
11
|
"repository": {
|
|
6
12
|
"type": "git",
|
|
@@ -37,7 +43,8 @@
|
|
|
37
43
|
},
|
|
38
44
|
"dependencies": {
|
|
39
45
|
"@langchain/core": "^0.3.18",
|
|
40
|
-
"@langchain/openai": "^0.3.
|
|
46
|
+
"@langchain/openai": "^0.3.14",
|
|
47
|
+
"@langchain/textsplitters": "^0.1.0",
|
|
41
48
|
"@strapi/design-system": "^2.0.0-rc.12",
|
|
42
49
|
"@strapi/icons": "^2.0.0-rc.12",
|
|
43
50
|
"langchain": "^0.3.5",
|
|
@@ -67,7 +74,7 @@
|
|
|
67
74
|
},
|
|
68
75
|
"strapi": {
|
|
69
76
|
"kind": "plugin",
|
|
70
|
-
"name": "yt-transcript",
|
|
77
|
+
"name": "yt-transcript-strapi-plugin",
|
|
71
78
|
"displayName": "YT Transcript",
|
|
72
79
|
"description": "Get YT Video Transcript"
|
|
73
80
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-CenWR5nf.js","sources":["../../admin/src/pluginId.ts","../../admin/src/utils/getTranslation.ts","../../admin/src/components/Initializer.tsx","../../admin/src/components/PluginIcon.tsx","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'yt-transcript';\n","import { PLUGIN_ID } from '../pluginId';\n\nconst getTranslation = (id: string) => `${PLUGIN_ID}.${id}`;\n\nexport { getTranslation };\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import { PuzzlePiece } from '@strapi/icons';\n\nconst PluginIcon = () => <PuzzlePiece />;\n\nexport { PluginIcon };\n","import { getTranslation } from './utils/getTranslation';\nimport { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport { PluginIcon } from './components/PluginIcon';\n\nexport default {\n register(app: any) {\n app.addMenuLink({\n to: `plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: PLUGIN_ID,\n },\n Component: async () => {\n const { App } = await import('./pages/App');\n\n return App;\n },\n });\n\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n },\n\n async registerTrads(app: any) {\n const { locales } = app;\n\n const importedTranslations = await Promise.all(\n (locales as string[]).map((locale) => {\n return import(`./translations/${locale}.json`)\n .then(({ default: data }) => {\n return {\n data: getTranslation(data),\n locale,\n };\n })\n .catch(() => {\n return {\n data: {},\n locale,\n };\n });\n })\n );\n\n return importedTranslations;\n },\n};\n"],"names":["useRef","useEffect","jsx","PuzzlePiece"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACEzB,MAAM,iBAAiB,CAAC,OAAe,GAAG,SAAS,IAAI,EAAE;ACMzD,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACjD,QAAA,MAAMA,aAAO,SAAS;AAE5BC,QAAAA,UAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,EAAE;AAEE,SAAA;AACT;ACdA,MAAM,aAAa,MAAMC,2BAAAA,IAACC,MAAY,aAAA,EAAA;ACGtC,MAAe,QAAA;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,YAAY;AAAA,MACd,IAAI,WAAW,SAAS;AAAA,MACxB,MAAM;AAAA,MACN,WAAW;AAAA,QACT,IAAI,GAAG,SAAS;AAAA,QAChB,gBAAgB;AAAA,MAClB;AAAA,MACA,WAAW,YAAY;AACrB,cAAM,EAAE,IAAA,IAAQ,MAAM,QAAA,QAAA,EAAA,KAAA,MAAA,QAAO,mBAAa,CAAA;AAEnC,eAAA;AAAA,MAAA;AAAA,IACT,CACD;AAED,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,KAAU;AACtB,UAAA,EAAE,YAAY;AAEd,UAAA,uBAAuB,MAAM,QAAQ;AAAA,MACxC,QAAqB,IAAI,CAAC,WAAW;AAC7B,eAAA,qCAA+B,uBAAA,OAAA,EAAA,0BAAA,MAAA,QAAA,QAAA,EAAA,KAAA,MAAA,QAAA,kBAAA,CAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA,EACnC,KAAK,CAAC,EAAE,SAAS,WAAW;AACpB,iBAAA;AAAA,YACL,MAAM,eAAe,IAAI;AAAA,YACzB;AAAA,UACF;AAAA,QAAA,CACD,EACA,MAAM,MAAM;AACJ,iBAAA;AAAA,YACL,MAAM,CAAC;AAAA,YACP;AAAA,UACF;AAAA,QAAA,CACD;AAAA,MACJ,CAAA;AAAA,IACH;AAEO,WAAA;AAAA,EAAA;AAEX;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-xAToV0M5.mjs","sources":["../../admin/src/pluginId.ts","../../admin/src/utils/getTranslation.ts","../../admin/src/components/Initializer.tsx","../../admin/src/components/PluginIcon.tsx","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'yt-transcript';\n","import { PLUGIN_ID } from '../pluginId';\n\nconst getTranslation = (id: string) => `${PLUGIN_ID}.${id}`;\n\nexport { getTranslation };\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import { PuzzlePiece } from '@strapi/icons';\n\nconst PluginIcon = () => <PuzzlePiece />;\n\nexport { PluginIcon };\n","import { getTranslation } from './utils/getTranslation';\nimport { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport { PluginIcon } from './components/PluginIcon';\n\nexport default {\n register(app: any) {\n app.addMenuLink({\n to: `plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: PLUGIN_ID,\n },\n Component: async () => {\n const { App } = await import('./pages/App');\n\n return App;\n },\n });\n\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n },\n\n async registerTrads(app: any) {\n const { locales } = app;\n\n const importedTranslations = await Promise.all(\n (locales as string[]).map((locale) => {\n return import(`./translations/${locale}.json`)\n .then(({ default: data }) => {\n return {\n data: getTranslation(data),\n locale,\n };\n })\n .catch(() => {\n return {\n data: {},\n locale,\n };\n });\n })\n );\n\n return importedTranslations;\n },\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACEzB,MAAM,iBAAiB,CAAC,OAAe,GAAG,SAAS,IAAI,EAAE;ACMzD,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACjD,QAAA,MAAM,OAAO,SAAS;AAE5B,YAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,EAAE;AAEE,SAAA;AACT;ACdA,MAAM,aAAa,MAAM,oBAAC,aAAY,EAAA;ACGtC,MAAe,QAAA;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,YAAY;AAAA,MACd,IAAI,WAAW,SAAS;AAAA,MACxB,MAAM;AAAA,MACN,WAAW;AAAA,QACT,IAAI,GAAG,SAAS;AAAA,QAChB,gBAAgB;AAAA,MAClB;AAAA,MACA,WAAW,YAAY;AACrB,cAAM,EAAE,IAAA,IAAQ,MAAM,OAAO,oBAAa;AAEnC,eAAA;AAAA,MAAA;AAAA,IACT,CACD;AAED,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,KAAU;AACtB,UAAA,EAAE,YAAY;AAEd,UAAA,uBAAuB,MAAM,QAAQ;AAAA,MACxC,QAAqB,IAAI,CAAC,WAAW;AAC7B,eAAA,qCAA+B,uBAAA,OAAA,EAAA,0BAAA,MAAA,OAAA,mBAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA,EACnC,KAAK,CAAC,EAAE,SAAS,WAAW;AACpB,iBAAA;AAAA,YACL,MAAM,eAAe,IAAI;AAAA,YACzB;AAAA,UACF;AAAA,QAAA,CACD,EACA,MAAM,MAAM;AACJ,iBAAA;AAAA,YACL,MAAM,CAAC;AAAA,YACP;AAAA,UACF;AAAA,QAAA,CACD;AAAA,MACJ,CAAA;AAAA,IACH;AAEO,WAAA;AAAA,EAAA;AAEX;"}
|