Skip to content

Commit

Permalink
Merge pull request #138 from dcSpark/feature/add-wikimedia-featured-c…
Browse files Browse the repository at this point in the history
…ontent-tool

feat: add wikimedia-featured-content tool
  • Loading branch information
guillevalin authored Feb 4, 2025
2 parents 5ddf199 + bb9e17a commit b5d35db
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 0 deletions.
Binary file added tools/wikimedia-featured-content/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-featured-content/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 55 additions & 0 deletions tools/wikimedia-featured-content/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { expect } from '@jest/globals';
import { getToolTestClient } from '../../src/test/utils';
import * as path from 'path';

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

it('fetches featured content with default parameters', async () => {
const response = await client.executeToolFromFile(toolPath, {}, {});

console.log("Response: ", response);

expect(response).toHaveProperty('featured');
expect(response.featured).toHaveProperty('tfa');
expect(response.featured).toHaveProperty('image');
expect(response.featured).toHaveProperty('news');

expect(response.featured.tfa).toHaveProperty('title');
expect(response.featured.tfa).toHaveProperty('extract');
expect(response.featured.tfa).toHaveProperty('url');
expect(response.featured.tfa.url).toMatch(/^https:\/\/en\.wikipedia\.org\/wiki\//);

expect(response.featured.image).toHaveProperty('title');
expect(response.featured.image).toHaveProperty('description');
expect(response.featured.image).toHaveProperty('url');

expect(Array.isArray(response.featured.news)).toBe(true);
if (response.featured.news.length > 0) {
const firstNews = response.featured.news[0];
expect(firstNews).toHaveProperty('story');
expect(firstNews).toHaveProperty('links');
expect(Array.isArray(firstNews.links)).toBe(true);
}
}, 30000);

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

expect(response.featured.tfa).toBeTruthy();
expect(response.featured.image).toBeTruthy();
expect(Array.isArray(response.featured.news)).toBe(true);
}, 30000);

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

expect(response.featured.tfa.url).toMatch(/^https:\/\/fr\.wikipedia\.org\/wiki\//);
}, 30000);
});
89 changes: 89 additions & 0 deletions tools/wikimedia-featured-content/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"id": "wikimedia-featured-content",
"version": "1.0.0",
"name": "Wikimedia Featured Content",
"description": "Get featured content including article, image, and news from Wikimedia",
"author": "Shinkai",
"keywords": [
"wikimedia",
"featured",
"wikipedia",
"content",
"articles",
"images",
"news"
],
"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}$"
}
}
},
"result": {
"type": "object",
"properties": {
"featured": {
"type": "object",
"properties": {
"tfa": {
"type": "object",
"properties": {
"title": {"type": "string"},
"extract": {"type": "string"},
"url": {"type": "string"}
}
},
"image": {
"type": "object",
"properties": {
"title": {"type": "string"},
"description": {"type": "string"},
"url": {"type": "string"}
}
},
"news": {
"type": "array",
"items": {
"type": "object",
"properties": {
"story": {"type": "string"},
"links": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {"type": "string"},
"url": {"type": "string"}
}
}
}
}
}
}
},
"required": ["tfa", "image", "news"]
}
},
"required": ["featured"]
}
}
3 changes: 3 additions & 0 deletions tools/wikimedia-featured-content/store.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"categoryId": "cc6ba888-3987-4e2a-af7e-3b137d997262"
}
107 changes: 107 additions & 0 deletions tools/wikimedia-featured-content/tool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import axios from 'npm:axios';

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

type Parameters = {
date?: string;
};

type Result = {
featured: {
tfa: {
title: string;
extract: string;
url: string;
};
image: {
title: string;
description: string;
url: string;
};
news: Array<{
story: string;
links: Array<{
title: string;
url: string;
}>;
}>;
};
};

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';

// Format date as YYYY/MM/DD
let date: string;
if (params.date) {
const d = new Date(params.date);
date = `${d.getFullYear()}/${String(d.getMonth() + 1).padStart(2, '0')}/${String(d.getDate()).padStart(2, '0')}`;
} else {
const d = new Date();
date = `${d.getFullYear()}/${String(d.getMonth() + 1).padStart(2, '0')}/${String(d.getDate()).padStart(2, '0')}`;
}

const api_url = `https://api.wikimedia.org/feed/v1/${project}/${language}/featured/${date}`;

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

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

const { tfa, image, news } = response.data;

if (!tfa || !image) {
throw new Error('Required data missing from API response');
}

return {
featured: {
tfa: {
title: tfa.title,
extract: tfa.extract || tfa.description || '',
url: `https://${language}.${project}.org/wiki/${encodeURIComponent(tfa.title.replace(/ /g, '_'))}`
},
image: {
title: image.title,
description: image.description?.text || '',
url: image.image?.source || image.thumbnail?.source || ''
},
news: (news || []).map((item: any) => ({
story: item.story || '',
links: (item.links || []).map((link: any) => ({
title: link.title || '',
url: `https://${language}.${project}.org/wiki/${encodeURIComponent((link.title || '').replace(/ /g, '_'))}`
}))
}))
}
};
} catch (error) {
if (axios.isAxiosError(error)) {
if (error.response?.status === 404) {
throw new Error(`No featured content found for the specified date`);
}
throw new Error(`Failed to fetch featured content: ${error.response?.data?.detail || error.response?.data?.message || error.message}`);
}
throw error;
}
};

0 comments on commit b5d35db

Please sign in to comment.