yandexgpt_tg_bot/api.mjs

86 lines
2.6 KiB
JavaScript

import {
reader,
readerTaskEither as rte,
readonlyArray,
taskEither,
} from "fp-ts";
import { flow, pipe } from "fp-ts/lib/function.js";
// parseJsonCont :: string -> string -> TaskEither string string
const parseJsonCont = (attr) => (source) => {
try {
const data = JSON.parse(source)[attr];
if (!data) throw new Error(`Key '${attr}' doesn't exist`);
return taskEither.right(data);
} catch (e) {
return taskEither.left(`Invalid json data: ${e}`);
}
};
const YANDEX_GPT_API_URL = "https://300.ya.ru/api/sharing-url";
// getYandexGptSharedUrl ::
// string ->
// ReaderTaskEither {yandexGptApiToken} string string
const getYandexGptSharedUrl = (articleUrl) =>
pipe(
reader.ask(),
reader.map(({ yandexGptApiToken }) =>
pipe(
taskEither.tryCatch(
() =>
fetch(YANDEX_GPT_API_URL, {
method: "POST",
headers: new Headers({
"Content-Type": "application/json",
"Authorization": `OAuth ${yandexGptApiToken}`,
}),
body: JSON.stringify({ article_url: articleUrl }),
}),
String,
),
/* TODO: fix to many requests error
{
ok: false,
error_code: 429,
description: 'Too Many Requests: retry after 5',
parameters: { retry_after: 5 }
}
*/
taskEither.flatMap((res) =>
taskEither.tryCatch(() => res.json(), String)
),
taskEither.flatMap((data) =>
data.status === "success" && data.sharing_url
? taskEither.right(data.sharing_url)
: taskEither.left(`Invalid response: ${JSON.stringify(data)}`)
),
)
),
);
// getYandexGptTesisesFromSharedUrl :: string -> TaskEither string[] string
const getYandexGptTesisesFromSharedUrl = (sharingUrl) =>
pipe(
taskEither.tryCatch(() => fetch(sharingUrl), String),
taskEither.flatMap((res) => taskEither.tryCatch(() => res.text(), String)),
taskEither.flatMap((html) =>
taskEither.fromNullable("Cannot find data in the shared url")(
/<script.+?type="application\/json".*?>([\s\S]+?)<\/script>/.exec(
html,
)[1],
)
),
taskEither.flatMap(parseJsonCont("body")),
taskEither.flatMap(parseJsonCont("thesis")),
taskEither.map(readonlyArray.map((t) => t.content)),
);
// describeArticle ::
// string ->
// ReaderTaskEither {yandexGptApiToken} string string
export const describeArticle = flow(
getYandexGptSharedUrl,
rte.flatMapTaskEither(getYandexGptTesisesFromSharedUrl),
);