-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.mjs
101 lines (86 loc) · 3.34 KB
/
index.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import fs from "node:fs/promises";
import "dotenv/config";
import OpenAI from "openai";
import jsdom from "jsdom";
import _ from "lodash";
import { Feed } from "./rss.mjs";
const { JSDOM } = jsdom;
global.DOMParser = new (new JSDOM()).window.DOMParser();
const title = "VOBM";
const description = "Voice of Bayman";
const xmlDir = "gh-pages";
const xmlPath = `${xmlDir}/rss.xml`;
const xmlURL = "https://djrideout.github.io/VOBM/rss.xml";
const vocmURL = "https://vocm.com/feed/";
const prompt = (content) => `You are a stereotypical person from Newfoundland, what one may call a "bayman". You need to summarize the contents of this news article, and do so the same way you would in casual conversation, while maybe throwing in a sarcastic comment or personal opinion on the matter: ${content}`;
let curr = null;
try {
curr = Feed.fromElement(DOMParser.parseFromString(await fs.readFile(xmlPath, "utf8"), "application/xml"));
} catch (ex) {
console.log(`Cannot read ${xmlPath}: ${ex.message}`);
process.exit(); // Recreate this manually if it breaks
}
let next = null;
try {
next = Feed.fromElement(DOMParser.parseFromString(await fetch(vocmURL).then((res) => res.text()), "application/xml"));
} catch (ex) {
console.log(`Cannot fetch ${vocmURL}: ${ex.message}`);
process.exit(); // Nothing to compare to, so exit
}
let currArticles = curr.articles.map((article) => article.guid);
let nextArticles = next.articles.map((article) => article.guid);
let newArticles = _.intersection(nextArticles, _.xor(currArticles, nextArticles));
if (!newArticles.length) {
console.log("No new articles");
process.exit();
}
console.log("New articles:");
for (let article of newArticles) {
console.log(`- ${article}`);
}
const openai = new OpenAI({
organization: process.env.OPENAI_ORG_ID,
project: process.env.OPENAI_PROJECT_ID
});
let buildDate = (new Date()).toUTCString();
curr.title = title;
curr.atomLink = xmlURL;
curr.description = description;
let published = curr.articles;
for (let guid of newArticles) {
let article = next.getArticleByGUID(guid).clone();
if (!article.category.includes("Local News")) {
console.log(`Article ${guid} not Local News, skipping...`);
continue;
}
if (published.length && new Date(article.pubDate) < new Date(published[0].pubDate)) {
console.log(`Article ${guid} older than newest VOBM article, skipping...`);
continue;
}
console.log(`Generating content for article ${guid}...`);
let result = "";
try {
let stream = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: prompt(article.content) }],
stream: true
});
for await (const chunk of stream) {
let content = chunk.choices[0]?.delta?.content ?? "";
content = content.replaceAll("VOCM", "VOBM");
result += content;
}
} catch (ex) {
console.log(`Could not generate content: ${ex.message}`);
continue;
}
console.log(`Content generated for article ${guid}.`);
article.content = result;
article.description = result;
curr.lastBuildDate = buildDate;
curr.addArticle(article);
}
console.log(`Writing XML to file ${xmlPath}...`);
await fs.mkdir(xmlDir, { recursive: true });
await fs.writeFile(xmlPath, curr.toString());
console.log("Done.");