discord-botREADME.md4 matches
15- **AI Integration**: Leverages Anthropic's Claude API for analysis
16- **Discord Integration**:
17- Bot token for fetching messages
18- Slash commands for user interactions
19- Webhook endpoint for Discord interactions
502. Copy the contents of the backend directory
513. Set up the required environment variables
524. Create a cron schedule for periodically fetching messages and processing links
5354## Usage
58- `GET /health`: Check if the service is running
59- `POST /api/interactions`: Discord interactions endpoint
60- `POST /api/fetch-dms`: Manually trigger DM fetching
61- `POST /api/process-links`: Manually trigger link processing
62- `POST /api/query`: Process a query about your messages
63- `POST /api/commands/search`: Endpoint for search commands
64- `POST /api/register-commands`: Register Discord slash commands
65- `GET /api/cron/fetch-dms`: Cron endpoint for fetching DMs
66- `GET /api/cron/process-links`: Cron endpoint for processing links
67
discord-botlink-analyzer.ts1 match
142export async function extractLinkMetadata(url: string): Promise<MetadataResult> {
143try {
144// In a production system, you'd want to actually fetch the page content
145// For simplicity, we'll make an educated guess based on the URL
146
discord-botindex.ts18 matches
3import { cors } from "https://esm.sh/@hono/cors@0.0.8";
4import { initializeDatabase } from "./database.ts";
5import { fetchAndStoreDMs } from "./discord-client.ts";
6import { handleDiscordInteractionRequest } from "./discord-interactions.ts";
7import { batchProcessLinks } from "./link-analyzer.ts";
85});
8687// Manual trigger for fetching DMs
88app.post("/api/fetch-dms", async c => {
89try {
90log("Manually triggering DM fetch...", "info");
91const messages = await fetchAndStoreDMs();
92return c.json({
93success: true,
94message: "DM fetch completed successfully",
95count: messages.length,
96timestamp: new Date().toISOString()
97});
98} catch (error) {
99log(`Error fetching DMs: ${error instanceof Error ? error.message : String(error)}`, "error");
100return c.json({
101success: false,
247248/**
249* Handles the scheduled DM fetch cron job
250*/
251export async function cronFetchDMs() {
252try {
253log("Running scheduled DM fetch...", "info");
254await initializeServices(); // Ensure services are initialized
255const messages = await fetchAndStoreDMs();
256
257log(`Scheduled DM fetch completed successfully. Fetched ${messages.length} messages.`, "info");
258return {
259success: true,
260message: "Scheduled DM fetch completed successfully",
261count: messages.length,
262timestamp: new Date().toISOString()
263};
264} catch (error) {
265log(`Error in DM fetch cron job: ${error instanceof Error ? error.message : String(error)}`, "error");
266return {
267success: false,
297298// Expose cron endpoints via HTTP as well
299app.get("/api/cron/fetch-dms", async c => {
300const result = await cronFetchDMs();
301return c.json(result, result.success ? 200 : 500);
302});
313});
314315// Export the fetch handler for Val.town HTTP vals
316export default app.fetch;
53
54try {
55const response = await fetch(endpoint, {
56method: 'PUT',
57headers: {
discord-botdiscord-client.ts27 matches
67/**
8* Handle fetching DMs between users using Discord's API
9*/
10export class DiscordClient {
16
17/**
18* Fetch DMs between the user and their partner
19* @returns {Promise<Array>} - Array of message objects
20*/
21async fetchDMsBetweenUsers() {
22try {
23const myUserId = Deno.env.get("DISCORD_USER_ID");
31const dmChannel = await this.getDMChannel(spouseUserId);
32
33// Fetch messages from the DM channel
34const messages = await this.fetchMessagesFromChannel(dmChannel.id, myUserId, spouseUserId);
35
36console.log(`Fetched ${messages.length} messages`);
37
38// Save messages to database
41return messages;
42} catch (error) {
43console.error("Error fetching DMs:", error);
44throw error;
45}
53async getDMChannel(userId: string) {
54try {
55const response = await fetch(`${API_BASE}/users/@me/channels`, {
56method: "POST",
57headers: {
77
78/**
79* Fetch messages from a channel
80* @param channelId - The channel ID to fetch messages from
81* @param myUserId - The user's ID
82* @param spouseUserId - The spouse's ID
83* @returns - Array of message objects
84*/
85async fetchMessagesFromChannel(channelId: string, myUserId: string, spouseUserId: string) {
86const messages = [];
87let lastId;
88let keepFetching = true;
89
90// Fetch messages in batches of 100 (Discord API limit)
91while (keepFetching) {
92let url = `${API_BASE}/channels/${channelId}/messages?limit=100`;
93if (lastId) {
95}
96
97const response = await fetch(url, {
98headers: {
99"Authorization": `Bot ${this.token}`
103if (!response.ok) {
104const error = await response.text();
105throw new Error(`Failed to fetch messages: ${error}`);
106}
107
108const fetchedMessages = await response.json();
109
110if (fetchedMessages.length === 0) {
111keepFetching = false;
112break;
113}
114
115// Process and store fetched messages
116for (const msg of fetchedMessages) {
117// Only store messages from the two users we care about
118if (msg.author.id === myUserId || msg.author.id === spouseUserId) {
129
130// Get the ID of the last message for pagination
131lastId = fetchedMessages[fetchedMessages.length - 1].id;
132
133// If we got fewer messages than requested, we've reached the end
134if (fetchedMessages.length < 100) {
135keepFetching = false;
136}
137}
142143/**
144* Function to run the message fetching process
145*/
146export async function fetchAndStoreDMs() {
147const token = Deno.env.get("DISCORD_TOKEN");
148if (!token) {
151
152const client = new DiscordClient(token);
153return await client.fetchDMsBetweenUsers();
154}
23name: 'discordDMBotCron',
24isPublic: false,
25description: 'Cron job to fetch Discord DMs periodically'
26},
27{
discord-botApp.tsx4 matches
21const [error, setError] = useState<string | null>(null);
22
23// Fetch server health status on component mount
24useEffect(() => {
25async function checkHealth() {
26try {
27setStatus('loading');
28const response = await fetch('/health');
29if (!response.ok) {
30throw new Error(`Health check failed: ${response.status}`);
116</tr>
117<tr>
118<td className="px-6 py-4 whitespace-nowrap font-mono text-sm">/api/fetch-dms</td>
119<td className="px-6 py-4 whitespace-nowrap text-sm">POST</td>
120<td className="px-6 py-4 text-sm">Manually trigger DM fetching</td>
121</tr>
122<tr>
discord-botDISCORD_BOT_SETUP.md3 matches
112- Find your deployed functions
113- Add the same environment variables from your `.env` file
1145. Set up a scheduled task for periodic DM fetching:
115- Create a new scheduled task in Val.town
116- Use the `discordDMBotCron` function
129- `/analyze Summarize our furniture discussions`
1301313. You can also manually trigger a DM fetch:
132```
133node val-town-cron.js
141- Verify that the bot has proper permissions
142143### Cannot fetch DMs
144- Ensure both you and your spouse have DMed each other at least once
145- Verify that all tokens and IDs in the `.env` file are correct
vt-discordindex.ts2 matches
21});
2223// HTTP vals expect an exported "fetch handler"
24// This is how you "run the server" in Val Town with Hono
25export default app.fetch;
MLSpointsPerMillionmain.tsx30 matches
375}
376377async function fetchClubProfileFromApi(
378transfermarktId: string | null | undefined,
379): Promise<ClubProfile | null> {
382}
383try {
384const response = await fetch(`/api/clubProfile/${transfermarktId}`);
385if (!response.ok) {
386console.error(
387`Failed to fetch profile from API for ${transfermarktId}: ${response.status}`,
388);
389return null;
401} catch (error) {
402console.error(
403`Error fetching profile from API for ${transfermarktId}:`,
404error,
405);
635setIsLoading(true);
636setErrorMessage(null);
637fetch("/api/standings")
638.then((response) => response.json())
639.then((data: Standings) => {
648} else {
649console.error(
650"Fetched standings data is not in the expected format:",
651data,
652);
653setStandings([]);
654setLastUpdated("Error fetching base standings");
655setErrorMessage(
656"Failed to load standings data. Invalid format received.",
660if (data.error) {
661console.warn(
662"Server reported an error fetching standings:",
663data.error,
664);
667})
668.catch((error) => {
669console.error("Error fetching base standings:", error);
670setLastUpdated("Error fetching base standings");
671setErrorMessage(
672`Failed to load standings data: ${(error as Error).message}`,
681setIsLoading(true);
682683const fetchAllProfiles = async () => {
684const allEntries = standings.flatMap((conf) => conf.entries);
685const uniqueTmIds = [
695setClubValues((prev) => ({ ...prev, ...initialValues }));
696697const profilePromises = uniqueTmIds.map((tmId) => fetchClubProfileFromApi(tmId));
698const results = await Promise.allSettled(profilePromises);
699707if (result.status === "rejected") {
708console.error(
709`Failed to fetch profile for ID ${tmId}:`,
710result.reason,
711);
719};
720721fetchAllProfiles();
722}, [standings]);
723876}
877878async function fetchAndCacheClubProfile_SERVER(
879transfermarktId: string,
880): Promise<ClubProfile | null> {
904const options = { method: "GET", headers: { accept: "application/json" } };
905try {
906const response = await fetch(url, options);
907let result: ClubProfile | null = null;
908let errorMsg: string | null = null;
915}
916} else {
917errorMsg = `Club profile fetch failed for ${transfermarktId}: ${response.status} ${await response.text().catch(
918() => ""
919)}`;
936} catch (error) {
937console.error(
938`Error during fetch/process profile for ${transfermarktId}:`,
939error,
940);
944}
945946async function fetchMLSStandings(): Promise<Standings> {
947const KEY = "MLSpointsPerMillion_mls_standings_v2";
948let storedData: Standings | null = null;
962|| now - storedData.timestamp > STANDINGS_CACHE_DURATION
963) {
964console.log("Fetching fresh MLS standings data...");
965const url = "https://major-league-soccer-standings.p.rapidapi.com/";
966const apiKey = Deno.env.get("RAPIDAPI_KEY")
980};
981try {
982const response = await fetch(url, options);
983if (!response.ok) {
984throw new Error(
996storedData = { timestamp: now, standings: result };
997await blob.setJSON(KEY, storedData);
998console.log("Successfully fetched and cached new standings data.");
999return storedData;
1000} catch (error) {
1001console.error("Error fetching or processing MLS standings:", error);
1002if (storedData) {
1003console.warn("Returning stale standings data due to fetch error.");
1004return {
1005...storedData,
1006error: `Failed to fetch fresh standings: ${(error as Error).message}. Displaying cached data.`,
1007};
1008} else {
1010timestamp: now,
1011standings: [],
1012error: `Failed to fetch MLS standings: ${(error as Error).message}`,
1013};
1014}
1030// API endpoint for standings data
1031if (url.pathname === "/api/standings") {
1032const standingsData = await fetchMLSStandings();
1033return new Response(JSON.stringify(standingsData), {
1034headers: headers_json,
1047});
1048try {
1049const profileData = await fetchAndCacheClubProfile_SERVER(transfermarktId);
1050if (profileData)
1051return new Response(JSON.stringify(profileData), {
1054}); else
1055return new Response(
1056JSON.stringify({ error: "Profile not found or fetch failed" }),
1057{ headers: headers_json, status: 404 },
1058);
1059} catch (error) {
1060console.error(`Server error fetching profile ${transfermarktId}:`, error);
1061return new Response(
1062JSON.stringify({