feat: include cost in announcements

This commit is contained in:
2025-12-23 14:37:26 -08:00
parent 7dcb20f4e4
commit 98aefb0b12
3 changed files with 45 additions and 8 deletions
+11 -6
View File
@@ -10,8 +10,8 @@ import {
announcementJsonSchema,
announcementSystemMessage,
} from "../config/announcements.js";
import type { AnnouncementResponse }
from "../interfaces/announcementResponse.js";
import { getAiCost } from "../utils/getAiCost.js";
import type { AnnouncementResponse } from "../interfaces/announcementResponse.js";
/**
* Generates announcements for all platforms using AI.
@@ -20,7 +20,7 @@ import type { AnnouncementResponse }
*/
export const generateAnnouncements = async(
content: string,
): Promise<AnnouncementResponse | null> => {
): Promise<{ cost: string; response: AnnouncementResponse } | null> => {
if (process.env.ANTHROPIC_KEY === undefined) {
return null;
}
@@ -46,12 +46,17 @@ export const generateAnnouncements = async(
},
system: announcementSystemMessage,
});
const text = response.content.find((m) => {
const { usage, content: responseContent } = response;
const text = responseContent.find((m) => {
return m.type === "text";
});
if (text?.text === undefined) {
return null;
}
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Being lazy.
return JSON.parse(text.text) as AnnouncementResponse;
return {
cost: getAiCost(usage),
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Being lazy.
response: JSON.parse(text.text) as AnnouncementResponse,
};
};
+3 -2
View File
@@ -86,7 +86,7 @@ export const announcementRoutes: FastifyPluginAsync = async(server) => {
});
}
const { bluesky, discord, reddit, twitter } = announcement;
const { bluesky, discord, reddit, twitter } = announcement.response;
const { title: discordTitle, content: discordContent } = discord;
const { title: redditTitle, content: redditContent } = reddit;
@@ -111,8 +111,9 @@ export const announcementRoutes: FastifyPluginAsync = async(server) => {
const blueskyPost = await announceOnBluesky(bluesky);
const twitterPost = await announceOnTwitter(twitter);
return await reply.status(201).send({
cost: announcement.cost,
message: `Announcement processed. Discord: ${discordPost}, Reddit: ${redditPost}, Bluesky: ${blueskyPost}, Twitter: ${twitterPost}`,
rawPost: announcement,
rawPost: announcement.response,
});
},
);
+31
View File
@@ -0,0 +1,31 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import type { BetaUsage } from "@anthropic-ai/sdk/resources/beta.js";
/**
* Calculates the cost of an AI response.
* @param usage - The usage payload from Anthropic.
* @returns A description of the cost of the AI response.
*/
export const getAiCost = (usage: BetaUsage): string => {
const { input_tokens: inputTokens, output_tokens: outputTokens } = usage;
const costPerInputToken = 5 / 1_000_000;
const costPerOutputToken = 25 / 1_000_000;
const inputCost = inputTokens * costPerInputToken;
const outputCost = outputTokens * costPerOutputToken;
const totalCost = inputCost + outputCost;
return `Input cost: ${inputCost.toLocaleString("en-GB", {
currency: "USD",
style: "currency",
})} Output cost: ${outputCost.toLocaleString("en-GB", {
currency: "USD",
style: "currency",
})} Total cost: ${totalCost.toLocaleString("en-GB", {
currency: "USD",
style: "currency",
})}`;
};