Skip to main content
Glama
actor-card.ts4.59 kB
import type { Actor } from 'apify-client'; import { APIFY_STORE_URL } from '../const.js'; import type { ExtendedActorStoreList, ExtendedPricingInfo } from '../types.js'; import { getCurrentPricingInfo, pricingInfoToString } from './pricing-info.js'; // Helper function to format categories from uppercase with underscores to proper case function formatCategories(categories?: string[]): string[] { if (!categories) return []; return categories.map((category) => { const formatted = category .toLowerCase() .split('_') .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(' '); // Special case for MCP server, AI, and SEO tools return formatted.replace('Mcp Server', 'MCP Server').replace('Ai', 'AI').replace('Seo', 'SEO'); }); } /** * Formats Actor details into an Actor card (Actor markdown representation). * @param actor - Actor information from the API * @returns Formatted actor card */ export function formatActorToActorCard( actor: Actor | ExtendedActorStoreList, ): string { // Format categories for display const formattedCategories = formatCategories('categories' in actor ? actor.categories : undefined); // Get pricing info let pricingInfo: string; if ('currentPricingInfo' in actor) { // ActorStoreList has currentPricingInfo pricingInfo = pricingInfoToString(actor.currentPricingInfo as ExtendedPricingInfo); } else { // Actor has pricingInfos array const currentPricingInfo = getCurrentPricingInfo(actor.pricingInfos || [], new Date()); pricingInfo = pricingInfoToString(currentPricingInfo as (ExtendedPricingInfo | null)); } const actorFullName = `${actor.username}/${actor.name}`; // Build the markdown lines const markdownLines = [ `# [${actor.title}](${APIFY_STORE_URL}/${actorFullName}) (${actorFullName})`, `**Developed by:** ${actor.username} ${actor.username === 'apify' ? '(Apify)' : '(community)'}`, `**Description:** ${actor.description || 'No description provided.'}`, `**Categories:** ${formattedCategories.length ? formattedCategories.join(', ') : 'Uncategorized'}`, `**Pricing:** ${pricingInfo}`, ]; // Add stats - handle different stat structures if ('stats' in actor) { const { stats } = actor; const statsParts = []; if ('totalUsers' in stats && 'totalUsers30Days' in stats) { // Both Actor and ActorStoreList have the same stats structure statsParts.push(`${stats.totalUsers.toLocaleString()} total users, ${stats.totalUsers30Days.toLocaleString()} monthly users`); } // Add success rate for last 30 days if available if ('publicActorRunStats30Days' in stats && stats.publicActorRunStats30Days) { const runStats = stats.publicActorRunStats30Days as { SUCCEEDED: number; TOTAL: number; }; if (runStats.TOTAL > 0) { const successRate = ((runStats.SUCCEEDED / runStats.TOTAL) * 100).toFixed(1); statsParts.push(`Runs succeeded: ${successRate}%`); } } // Add bookmark count if available (ActorStoreList only) if ('bookmarkCount' in actor && actor.bookmarkCount) { statsParts.push(`${actor.bookmarkCount} bookmarks`); } if (statsParts.length > 0) { markdownLines.push(`**Stats:** ${statsParts.join(', ')}`); } } // Add rating if available (ActorStoreList only) if ('actorReviewRating' in actor && actor.actorReviewRating) { markdownLines.push(`**Rating:** ${actor.actorReviewRating.toFixed(2)} out of 5`); } // Add modification date if available if ('modifiedAt' in actor) { markdownLines.push(`**Last modified:** ${actor.modifiedAt.toISOString()}`); } // Add deprecation warning if applicable if ('isDeprecated' in actor && actor.isDeprecated) { markdownLines.push('\n>This Actor is deprecated and may not be maintained anymore.'); } return markdownLines.join('\n'); } /** * Formats a list of Actors into Actor cards * @param actors - Array of Actor information * @returns Formatted markdown string */ export function formatActorsListToActorCard(actors: (Actor | ExtendedActorStoreList)[]): string[] { if (actors.length === 0) { return []; } return actors.map((actor) => { const card = formatActorToActorCard(actor); return `- ${card}`; }); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jirispilka/actors-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server