Skip to content

Commit

Permalink
Merge pull request #139 from dcSpark/feature/add-wikimedia-historical…
Browse files Browse the repository at this point in the history
…-events-tool

feat: add wikimedia-historical-events tool
  • Loading branch information
guillevalin authored Feb 4, 2025
2 parents b5d35db + 9e03f1e commit 3edae50
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 0 deletions.
Binary file added tools/wikimedia-historical-events/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tools/wikimedia-historical-events/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 68 additions & 0 deletions tools/wikimedia-historical-events/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { expect } from '@jest/globals';
import { getToolTestClient } from '../../src/test/utils';
import * as path from 'path';

describe('Wikimedia Historical Events Tool', () => {
const toolPath = path.join(__dirname, 'tool.ts');
const client = getToolTestClient();

it('fetches historical events with default parameters', async () => {
const response = await client.executeToolFromFile(toolPath, {}, {});
console.log("Response: ", response);

expect(response).toHaveProperty('events');
expect(response.events).toHaveProperty('selected_date');
expect(response.events).toHaveProperty('events');
expect(response.events).toHaveProperty('births');
expect(response.events).toHaveProperty('deaths');
expect(response.events).toHaveProperty('holidays');

if (response.events.events && response.events.events.length > 0) {
const firstEvent = response.events.events[0];
expect(firstEvent).toHaveProperty('text');
expect(firstEvent).toHaveProperty('year');
expect(firstEvent).toHaveProperty('links');
expect(Array.isArray(firstEvent.links)).toBe(true);
}
}, 30000);

it('respects type parameter for specific event types', async () => {
const response = await client.executeToolFromFile(toolPath, {
type: 'births'
});

expect(response.events).toHaveProperty('births');
expect(response.events).not.toHaveProperty('events');
expect(response.events).not.toHaveProperty('deaths');
expect(response.events).not.toHaveProperty('holidays');

if (response.events.births && response.events.births.length > 0) {
const firstBirth = response.events.births[0];
expect(firstBirth).toHaveProperty('text');
expect(firstBirth).toHaveProperty('year');
expect(firstBirth).toHaveProperty('links');
}
}, 30000);

it('handles custom date parameter', async () => {
const response = await client.executeToolFromFile(toolPath, {
date: '2024-01-01'
});

expect(response.events.selected_date).toBe('2024-01-01');
expect(response.events).toHaveProperty('events');
}, 30000);

it('handles custom language', async () => {
const response = await client.executeToolFromFile(toolPath, {}, {
language: 'fr'
});

if (response.events.events && response.events.events.length > 0) {
const firstEvent = response.events.events[0];
if (firstEvent.links.length > 0) {
expect(firstEvent.links[0].url).toMatch(/^https:\/\/fr\.wikipedia\.org\/wiki\//);
}
}
}, 30000);
});
88 changes: 88 additions & 0 deletions tools/wikimedia-historical-events/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"id": "wikimedia-historical-events",
"version": "1.0.0",
"name": "Wikimedia Historical Events",
"description": "Get historical events, births, deaths, and holidays for a specific date from Wikimedia",
"author": "Shinkai",
"keywords": [
"wikimedia",
"history",
"wikipedia",
"events",
"onthisday",
"births",
"deaths",
"holidays"
],
"configurations": {
"type": "object",
"properties": {
"project": {
"type": "string",
"description": "Wikimedia project (e.g., wikipedia)",
"default": "wikipedia"
},
"language": {
"type": "string",
"description": "Language code (e.g., en)",
"default": "en"
}
},
"required": []
},
"parameters": {
"type": "object",
"properties": {
"date": {
"type": "string",
"description": "Date in YYYY-MM-DD format (defaults to current date)",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"type": {
"type": "string",
"description": "Type of historical events to fetch",
"enum": ["all", "events", "births", "deaths", "holidays"],
"default": "all"
}
},
"required": ["date"]
},
"result": {
"type": "object",
"properties": {
"events": {
"type": "object",
"properties": {
"selected_date": {"type": "string"},
"events": {
"type": "array",
"items": {
"type": "object",
"properties": {
"text": {"type": "string"},
"year": {"type": "string"},
"links": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {"type": "string"},
"url": {"type": "string"}
},
"required": ["title", "url"]
}
},
"required": ["text", "year", "links"]
}
}
},
"births": {"$ref": "#/result/properties/events/properties/events"},
"deaths": {"$ref": "#/result/properties/events/properties/events"},
"holidays": {"$ref": "#/result/properties/events/properties/events"}
},
"required": ["selected_date", "events", "births", "deaths", "holidays"]
}
},
"required": ["events"]
}
}
3 changes: 3 additions & 0 deletions tools/wikimedia-historical-events/store.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"categoryId": "cc6ba888-3987-4e2a-af7e-3b137d997262"
}
115 changes: 115 additions & 0 deletions tools/wikimedia-historical-events/tool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import axios from 'npm:axios';

type Configurations = {
project?: string;
language?: string;
};

type Parameters = {
date?: string;
type?: 'all' | 'events' | 'births' | 'deaths' | 'holidays';
};

type HistoricalEvent = {
text: string;
year: string;
links: Array<{
title: string;
url: string;
}>;
};

type Result = {
events: {
selected_date: string;
events?: HistoricalEvent[];
births?: HistoricalEvent[];
deaths?: HistoricalEvent[];
holidays?: HistoricalEvent[];
};
};

export type Run<C extends Record<string, any>, I extends Record<string, any>, R extends Record<string, any>> = (
config: C,
inputs: I
) => Promise<R>;

export const run: Run<Configurations, Parameters, Result> = async (
configurations: Configurations,
params: Parameters
): Promise<Result> => {
try {
const project = configurations?.project || 'wikipedia';
const language = configurations?.language || 'en';
const type = params.type || 'all';

// Parse and format the date
let month: string;
let day: string;

if (params.date) {
const d = new Date(params.date);
month = String(d.getMonth() + 1).padStart(2, '0');
day = String(d.getDate()).padStart(2, '0');
} else {
const d = new Date();
month = String(d.getMonth() + 1).padStart(2, '0');
day = String(d.getDate()).padStart(2, '0');
}

const api_url = `https://api.wikimedia.org/feed/v1/${project}/${language}/onthisday/${type}/${month}/${day}`;

const response = await axios.get(api_url, {
headers: {
'User-Agent': 'ShinkaiWikimediaHistoricalEvents/1.0',
'Accept': 'application/json',
'Api-User-Agent': 'ShinkaiWikimediaHistoricalEvents/1.0 (https://github.com/dcSpark/shinkai-tools)'
}
});

if (!response.data) {
throw new Error('No data received from Wikimedia API');
}

const formatEvents = (events: any[]): HistoricalEvent[] => {
if (!Array.isArray(events)) return [];
return events.map(event => ({
text: event.text || '',
year: (event.year || '').toString(),
links: (event.pages || []).map((page: any) => ({
title: page.title || '',
url: `https://${language}.${project}.org/wiki/${encodeURIComponent((page.title || '').replace(/ /g, '_'))}`
}))
}));
};

const result: Result = {
events: {
selected_date: params.date || new Date().toISOString().split('T')[0]
}
};

if (type === 'all' || type === 'events') {
result.events.events = formatEvents(response.data.events || []);
}
if (type === 'all' || type === 'births') {
result.events.births = formatEvents(response.data.births || []);
}
if (type === 'all' || type === 'deaths') {
result.events.deaths = formatEvents(response.data.deaths || []);
}
if (type === 'all' || type === 'holidays') {
result.events.holidays = formatEvents(response.data.holidays || []);
}

return result;
} catch (error) {
if (axios.isAxiosError(error)) {
if (error.response?.status === 404) {
throw new Error(`No historical events found for the specified date`);
}
throw new Error(`Failed to fetch historical events: ${error.response?.data?.detail || error.response?.data?.message || error.message}`);
}
throw error;
}
};

0 comments on commit 3edae50

Please sign in to comment.