@agentdao/core
Version:
Core functionality, skills, and ready-made UI components for AgentDAO - Web3 subscriptions, content generation, social media, help support, live chat, RSS fetching, web search, and agent pricing integration
392 lines (391 loc) • 15.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PhotoSkill = void 0;
class PhotoSkill {
constructor(config) {
if (config.providers?.unsplash?.enabled && !config.providers.unsplash.accessKey) {
throw new Error('No Unsplash API key provided. Please add your key in Settings > API Keys.');
}
this.config = config;
}
/**
* Search for stock photos
*/
async searchPhotos(request) {
const { query, provider = this.config.search.defaultProvider, size = this.config.search.defaultSize, orientation, color, category, maxResults = this.config.search.maxResults, page = 1 } = request;
try {
// Validate request
if (!query || query.trim().length === 0) {
throw new Error('Search query is required');
}
let photos = [];
// Search based on provider
if (provider === 'all' || provider === 'unsplash') {
if (this.config.providers.unsplash?.enabled) {
const unsplashPhotos = await this.searchUnsplash(query, {
size,
orientation,
color,
maxResults,
page
});
photos.push(...unsplashPhotos);
}
}
if (provider === 'all' || provider === 'pexels') {
if (this.config.providers.pexels?.enabled) {
const pexelsPhotos = await this.searchPexels(query, {
size,
orientation,
color,
maxResults,
page
});
photos.push(...pexelsPhotos);
}
}
if (provider === 'all' || provider === 'pixabay') {
if (this.config.providers.pixabay?.enabled) {
const pixabayPhotos = await this.searchPixabay(query, {
size,
orientation,
color,
maxResults,
page
});
photos.push(...pixabayPhotos);
}
}
// Limit results
photos = photos.slice(0, maxResults);
// Track analytics if enabled
if (this.config.analytics?.enabled) {
await this.trackSearch(query, photos.length, provider || 'all');
}
return photos;
}
catch (error) {
throw new Error(`Photo search failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Get trending photos
*/
async getTrendingPhotos(options) {
const { provider = 'unsplash', category, maxResults = 10 } = options || {};
try {
const trendingQueries = ['nature', 'business', 'technology', 'travel', 'food'];
const randomQuery = trendingQueries[Math.floor(Math.random() * trendingQueries.length)];
return await this.searchPhotos({
query: category || randomQuery,
provider,
maxResults
});
}
catch (error) {
throw new Error(`Failed to get trending photos: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Get photo collections
*/
async getCollections(options) {
const { provider = 'unsplash', maxResults = 10 } = options || {};
try {
// For now, return empty array as collections require specific API implementations
// TODO: Implement real collection APIs for each provider
const collections = [];
return collections.slice(0, maxResults);
}
catch (error) {
throw new Error(`Failed to get collections: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Get photo by ID
*/
async getPhotoById(photoId, provider = 'unsplash') {
try {
// TODO: Implement real photo-by-ID APIs for each provider
throw new Error(`Photo by ID not yet implemented for ${provider}. Use searchPhotos() instead.`);
}
catch (error) {
throw new Error(`Failed to get photo: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Download photo
*/
async downloadPhoto(photoId, provider = 'unsplash') {
try {
const photo = await this.getPhotoById(photoId, provider);
return {
url: photo.downloadUrl,
filename: `${photoId}.${photo.format}`,
size: photo.size
};
}
catch (error) {
throw new Error(`Failed to download photo: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Get photo categories
*/
async getCategories() {
return [
{ id: 'nature', name: 'Nature', description: 'Landscapes, wildlife, and natural scenes', photoCount: 50000 },
{ id: 'business', name: 'Business', description: 'Professional business and office scenes', photoCount: 25000 },
{ id: 'technology', name: 'Technology', description: 'Computers, gadgets, and tech scenes', photoCount: 15000 },
{ id: 'travel', name: 'Travel', description: 'Destinations, landmarks, and travel scenes', photoCount: 30000 },
{ id: 'food', name: 'Food & Drink', description: 'Delicious food and beverage photography', photoCount: 20000 },
{ id: 'people', name: 'People', description: 'Portraits and people in various settings', photoCount: 40000 },
{ id: 'architecture', name: 'Architecture', description: 'Buildings, structures, and urban scenes', photoCount: 18000 },
{ id: 'abstract', name: 'Abstract', description: 'Abstract and artistic photography', photoCount: 12000 }
];
}
/**
* Search Unsplash photos
*/
async searchUnsplash(query, options) {
const accessKey = this.config.providers.unsplash?.accessKey;
if (!accessKey) {
throw new Error('Unsplash access key is required');
}
try {
const params = new URLSearchParams({
query: query,
per_page: Math.min(options.maxResults || 10, 30).toString(),
page: (options.page || 1).toString()
});
if (options.orientation) {
params.append('orientation', options.orientation);
}
const response = await fetch(`https://api.unsplash.com/search/photos?${params}`, {
headers: {
'Authorization': `Client-ID ${accessKey}`
}
});
if (!response.ok) {
throw new Error(`Unsplash API error: ${response.statusText}`);
}
const data = await response.json();
const photos = [];
for (const photo of data.results) {
const stockPhoto = {
id: photo.id,
url: photo.urls.regular,
thumbnailUrl: photo.urls.thumb,
previewUrl: photo.urls.small,
downloadUrl: photo.links.download,
title: photo.alt_description || `Photo by ${photo.user.name}`,
description: photo.description,
photographer: {
name: photo.user.name,
username: photo.user.username,
profileUrl: photo.user.links.html
},
dimensions: {
width: photo.width,
height: photo.height
},
size: 0, // Unsplash doesn't provide file size
format: 'jpeg',
tags: photo.tags?.map((tag) => tag.title) || [],
category: 'unsplash',
license: 'free',
provider: 'unsplash',
createdAt: new Date(photo.created_at),
metadata: {
likes: photo.likes,
downloads: photo.downloads,
views: photo.views,
color: photo.color
}
};
photos.push(stockPhoto);
}
return photos;
}
catch (error) {
console.error('Unsplash API error:', error);
throw new Error(`Failed to search Unsplash: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Search Pexels photos
*/
async searchPexels(query, options) {
const apiKey = this.config.providers.pexels?.apiKey;
if (!apiKey) {
throw new Error('Pexels API key is required');
}
try {
const params = new URLSearchParams({
query: query,
per_page: Math.min(options.maxResults || 10, 80).toString(),
page: (options.page || 1).toString()
});
if (options.orientation) {
params.append('orientation', options.orientation);
}
const response = await fetch(`https://api.pexels.com/v1/search?${params}`, {
headers: {
'Authorization': apiKey
}
});
if (!response.ok) {
throw new Error(`Pexels API error: ${response.statusText}`);
}
const data = await response.json();
const photos = [];
for (const photo of data.photos) {
const stockPhoto = {
id: photo.id.toString(),
url: photo.src.large,
thumbnailUrl: photo.src.small,
previewUrl: photo.src.medium,
downloadUrl: photo.src.original,
title: photo.alt || `Photo by ${photo.photographer}`,
description: photo.alt,
photographer: {
name: photo.photographer,
username: photo.photographer_id.toString(),
profileUrl: photo.photographer_url
},
dimensions: {
width: photo.width,
height: photo.height
},
size: 0, // Pexels doesn't provide file size
format: 'jpeg',
tags: [],
category: 'pexels',
license: 'free',
provider: 'pexels',
createdAt: new Date(),
metadata: {
likes: 0,
downloads: 0,
views: 0,
color: photo.avg_color
}
};
photos.push(stockPhoto);
}
return photos;
}
catch (error) {
console.error('Pexels API error:', error);
throw new Error(`Failed to search Pexels: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Search Pixabay photos
*/
async searchPixabay(query, options) {
const apiKey = this.config.providers.pixabay?.apiKey;
if (!apiKey) {
throw new Error('Pixabay API key is required');
}
try {
const params = new URLSearchParams({
key: apiKey,
q: query,
per_page: Math.min(options.maxResults || 10, 200).toString(),
page: (options.page || 1).toString(),
image_type: 'photo'
});
if (options.orientation) {
params.append('orientation', options.orientation);
}
const response = await fetch(`https://pixabay.com/api/?${params}`);
if (!response.ok) {
throw new Error(`Pixabay API error: ${response.statusText}`);
}
const data = await response.json();
const photos = [];
for (const photo of data.hits) {
const stockPhoto = {
id: photo.id.toString(),
url: photo.largeImageURL,
thumbnailUrl: photo.previewURL,
previewUrl: photo.webformatURL,
downloadUrl: photo.largeImageURL,
title: photo.tags || `Photo by ${photo.user}`,
description: photo.tags,
photographer: {
name: photo.user,
username: photo.user_id.toString(),
profileUrl: `https://pixabay.com/users/${photo.user}-${photo.user_id}/`
},
dimensions: {
width: photo.imageWidth,
height: photo.imageHeight
},
size: 0, // Pixabay doesn't provide file size
format: 'jpeg',
tags: photo.tags.split(', '),
category: 'pixabay',
license: 'free',
provider: 'pixabay',
createdAt: new Date(),
metadata: {
likes: photo.likes,
downloads: photo.downloads,
views: photo.views,
color: photo.dominantColor
}
};
photos.push(stockPhoto);
}
return photos;
}
catch (error) {
console.error('Pixabay API error:', error);
throw new Error(`Failed to search Pixabay: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Get a sample photo for testing
*/
async getSamplePhoto(provider = 'unsplash') {
// This method is deprecated - use searchPhotos() for real photos
throw new Error('getSamplePhoto is deprecated. Use searchPhotos() for real photos.');
}
/**
* Track search analytics
*/
async trackSearch(query, resultCount, provider) {
if (!this.config.analytics?.enabled)
return;
if (!this.config.database || !this.config.database.endpoint) {
throw new Error('No database endpoint configured for tracking analytics. Please configure a database endpoint to use this feature.');
}
try {
const analyticsData = {
agentId: this.config.agentId,
agentName: this.config.agentName,
query,
resultCount,
provider,
timestamp: new Date().toISOString()
};
await fetch(this.config.database.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(this.config.database.apiKey ? { 'Authorization': `Bearer ${this.config.database.apiKey}` } : {})
},
body: JSON.stringify({
type: 'photo_search_analytics',
data: analyticsData
})
});
}
catch (error) {
throw new Error(`Failed to track photo search analytics: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
}
exports.PhotoSkill = PhotoSkill;