Skip to main content
Glama
external-apis.ts15.8 kB
import { GeminiHelper } from '../utils/gemini-helper.js'; // API integrations for external services and platforms export interface APIIntegration { name: string; baseUrl: string; authMethod: 'api-key' | 'oauth' | 'bearer' | 'basic'; rateLimit: number; generateTailwindComponents(prompt: string): Promise<APIResponse>; analyzeDesign(html: string): Promise<DesignAnalysis>; optimizeCSS(css: string): Promise<OptimizationResult>; } export interface APIResponse { success: boolean; data: any; error?: string; usage?: { tokens: number; cost: number; }; } export interface DesignAnalysis { score: number; suggestions: string[]; accessibility: AccessibilityScore; performance: PerformanceScore; responsive: ResponsiveScore; } export interface AccessibilityScore { score: number; issues: string[]; compliance: 'WCAG-A' | 'WCAG-AA' | 'WCAG-AAA'; } export interface PerformanceScore { score: number; bundleSize: number; loadTime: number; optimizations: string[]; } export interface ResponsiveScore { score: number; breakpoints: string[]; issues: string[]; } export interface OptimizationResult { original: string; optimized: string; suggestions: string[]; removed: string[]; savings: { size: number; percentage: number; }; changes: string[]; } // Gemini AI Integration export class GeminiAIIntegration implements APIIntegration { name = 'Gemini AI'; baseUrl = 'https://generativelanguage.googleapis.com/v1beta'; authMethod: 'api-key' = 'api-key'; rateLimit = 60; // requests per minute private gemini: GeminiHelper; constructor(apiKey: string) { this.gemini = new GeminiHelper({ apiKey }); } async generateTailwindComponents(prompt: string): Promise<APIResponse> { try { const component = await this.gemini.generateContent(prompt); return { success: true, data: { component, framework: 'html', styling: 'tailwind' }, usage: { tokens: prompt.length + component.length, cost: 0.001 } }; } catch (error) { return { success: false, data: null, error: error instanceof Error ? error.message : 'Unknown error' }; } } async analyzeDesign(html: string): Promise<DesignAnalysis> { try { const analysis = await this.gemini.analyzeDesign(html, { checkAccessibility: true, checkPerformance: true, checkResponsive: true }); return { score: analysis.overallScore || 75, suggestions: analysis.suggestions || [], accessibility: { score: analysis.accessibilityScore || 80, issues: analysis.accessibilityIssues || [], compliance: 'WCAG-AA' }, performance: { score: analysis.performanceScore || 70, bundleSize: 45000, // bytes loadTime: 1200, // ms optimizations: analysis.performanceOptimizations || [] }, responsive: { score: analysis.responsiveScore || 85, breakpoints: ['mobile', 'tablet', 'desktop'], issues: analysis.responsiveIssues || [] } }; } catch (error) { // Fallback analysis return { score: 60, suggestions: ['Unable to perform AI analysis'], accessibility: { score: 60, issues: ['Analysis unavailable'], compliance: 'WCAG-A' }, performance: { score: 60, bundleSize: 0, loadTime: 0, optimizations: [] }, responsive: { score: 60, breakpoints: [], issues: [] } }; } } async optimizeCSS(css: string): Promise<OptimizationResult> { try { const optimized = await this.gemini.optimizeClasses(css); const originalSize = css.length; const optimizedSize = optimized.optimized.length; const savings = originalSize - optimizedSize; return { original: css, optimized: optimized.optimized, suggestions: optimized.suggestions, removed: optimized.removed, savings: { size: savings, percentage: Math.round((savings / originalSize) * 100) }, changes: [ 'Removed duplicate classes', 'Optimized spacing utilities', 'Merged shorthand properties' ] }; } catch (error) { return { original: css, optimized: css, suggestions: [], removed: [], savings: { size: 0, percentage: 0 }, changes: ['Optimization failed'] }; } } } // OpenAI Integration export class OpenAIIntegration implements APIIntegration { name = 'OpenAI'; baseUrl = 'https://api.openai.com/v1'; authMethod: 'bearer' = 'bearer'; rateLimit = 200; // requests per minute constructor(private apiKey: string) {} async generateTailwindComponents(prompt: string): Promise<APIResponse> { try { const response = await fetch(`${this.baseUrl}/chat/completions`, { method: 'POST', headers: { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'gpt-4', messages: [ { role: 'system', content: 'You are a Tailwind CSS expert. Generate modern, responsive components with proper accessibility.' }, { role: 'user', content: prompt } ], max_tokens: 2000, temperature: 0.7 }) }); const data = await response.json() as any; if (!response.ok) { throw new Error(data.error?.message || 'OpenAI API error'); } return { success: true, data: { component: data.choices[0].message.content, framework: 'html', styling: 'tailwind' }, usage: { tokens: data.usage.total_tokens, cost: data.usage.total_tokens * 0.00002 // GPT-4 pricing } }; } catch (error) { return { success: false, data: null, error: error instanceof Error ? error.message : 'Unknown error' }; } } async analyzeDesign(html: string): Promise<DesignAnalysis> { try { const response = await fetch(`${this.baseUrl}/chat/completions`, { method: 'POST', headers: { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'gpt-4', messages: [ { role: 'system', content: 'Analyze this HTML/Tailwind design for accessibility, performance, and responsive design. Provide scores and specific suggestions.' }, { role: 'user', content: `Analyze this design:\n\n${html}` } ], max_tokens: 1500 }) }); const data = await response.json() as any; const analysis = data.choices[0].message.content; // Parse the analysis (simplified - would need more sophisticated parsing) return { score: 75, suggestions: [analysis], accessibility: { score: 80, issues: [], compliance: 'WCAG-AA' }, performance: { score: 70, bundleSize: 0, loadTime: 0, optimizations: [] }, responsive: { score: 85, breakpoints: [], issues: [] } }; } catch (error) { throw error; } } async optimizeCSS(css: string): Promise<OptimizationResult> { try { const response = await fetch(`${this.baseUrl}/chat/completions`, { method: 'POST', headers: { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'gpt-4', messages: [ { role: 'system', content: 'Optimize these Tailwind CSS classes by removing duplicates, conflicts, and suggesting improvements.' }, { role: 'user', content: css } ], max_tokens: 1000 }) }); const data = await response.json() as any; const optimized = data.choices[0].message.content; return { original: css, optimized: optimized, savings: { size: css.length - optimized.length, percentage: Math.round(((css.length - optimized.length) / css.length) * 100) }, changes: ['AI-optimized classes'], suggestions: ['Optimized for better performance'], removed: [] }; } catch (error) { throw error; } } } // Claude Integration (Anthropic) export class ClaudeIntegration implements APIIntegration { name = 'Claude'; baseUrl = 'https://api.anthropic.com/v1'; authMethod: 'api-key' = 'api-key'; rateLimit = 100; constructor(private apiKey: string) {} async generateTailwindComponents(prompt: string): Promise<APIResponse> { try { const response = await fetch(`${this.baseUrl}/messages`, { method: 'POST', headers: { 'x-api-key': this.apiKey, 'Content-Type': 'application/json', 'anthropic-version': '2023-06-01' }, body: JSON.stringify({ model: 'claude-3-sonnet-20240229', max_tokens: 2000, messages: [ { role: 'user', content: `Generate a Tailwind CSS component for: ${prompt}` } ] }) }); const data = await response.json() as any; return { success: true, data: { component: data.content[0].text, framework: 'html', styling: 'tailwind' }, usage: { tokens: data.usage.input_tokens + data.usage.output_tokens, cost: 0.003 // Claude pricing } }; } catch (error) { return { success: false, data: null, error: error instanceof Error ? error.message : 'Unknown error' }; } } async analyzeDesign(html: string): Promise<DesignAnalysis> { // Similar implementation to OpenAI return { score: 75, suggestions: [], accessibility: { score: 80, issues: [], compliance: 'WCAG-AA' }, performance: { score: 70, bundleSize: 0, loadTime: 0, optimizations: [] }, responsive: { score: 85, breakpoints: [], issues: [] } }; } async optimizeCSS(css: string): Promise<OptimizationResult> { // Similar implementation to OpenAI return { original: css, optimized: css, savings: { size: 0, percentage: 0 }, changes: [], suggestions: ['No optimization needed'], removed: [] }; } } // Design Tools Integration export class FigmaIntegration { name = 'Figma'; baseUrl = 'https://api.figma.com/v1'; constructor(private accessToken: string) {} async getDesignTokens(fileId: string): Promise<any> { try { const response = await fetch(`${this.baseUrl}/files/${fileId}`, { headers: { 'X-Figma-Token': this.accessToken } }); const data = await response.json(); return this.extractDesignTokens(data); } catch (error) { throw error; } } async convertToTailwind(fileId: string, nodeId: string): Promise<string> { try { const response = await fetch(`${this.baseUrl}/files/${fileId}/nodes?ids=${nodeId}`, { headers: { 'X-Figma-Token': this.accessToken } }); const data = await response.json() as any; return this.convertFigmaToTailwind(data.nodes[nodeId]); } catch (error) { throw error; } } private extractDesignTokens(figmaData: any): any { // Extract colors, typography, spacing from Figma data return { colors: {}, typography: {}, spacing: {} }; } private convertFigmaToTailwind(node: any): string { // Convert Figma node to Tailwind classes const classes: string[] = []; // Width and height if (node.absoluteBoundingBox) { classes.push(`w-[${node.absoluteBoundingBox.width}px]`); classes.push(`h-[${node.absoluteBoundingBox.height}px]`); } // Background color if (node.fills && node.fills[0]) { const fill = node.fills[0]; if (fill.type === 'SOLID') { const { r, g, b } = fill.color; const hex = this.rgbToHex(r * 255, g * 255, b * 255); classes.push(`bg-[${hex}]`); } } // Border radius if (node.cornerRadius) { classes.push(`rounded-[${node.cornerRadius}px]`); } return classes.join(' '); } private rgbToHex(r: number, g: number, b: number): string { return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); } } // Integration Manager export class IntegrationManager { private integrations: Map<string, APIIntegration> = new Map(); private designTools: Map<string, any> = new Map(); constructor() { // Initialize default integrations if API keys are available const geminiKey = process.env.GEMINI_API_KEY; const openaiKey = process.env.OPENAI_API_KEY; const claudeKey = process.env.CLAUDE_API_KEY; const figmaToken = process.env.FIGMA_ACCESS_TOKEN; if (geminiKey) { this.integrations.set('gemini', new GeminiAIIntegration(geminiKey)); } if (openaiKey) { this.integrations.set('openai', new OpenAIIntegration(openaiKey)); } if (claudeKey) { this.integrations.set('claude', new ClaudeIntegration(claudeKey)); } if (figmaToken) { this.designTools.set('figma', new FigmaIntegration(figmaToken)); } } getIntegration(name: string): APIIntegration | null { return this.integrations.get(name.toLowerCase()) || null; } getDesignTool(name: string): any { return this.designTools.get(name.toLowerCase()) || null; } addIntegration(name: string, integration: APIIntegration): void { this.integrations.set(name.toLowerCase(), integration); } addDesignTool(name: string, tool: any): void { this.designTools.set(name.toLowerCase(), tool); } getAvailableIntegrations(): string[] { return Array.from(this.integrations.keys()); } getAvailableDesignTools(): string[] { return Array.from(this.designTools.keys()); } async generateWithBestAvailable(prompt: string): Promise<APIResponse> { // Try integrations in order of preference const preferredOrder = ['gemini', 'openai', 'claude']; for (const name of preferredOrder) { const integration = this.integrations.get(name); if (integration) { try { return await integration.generateTailwindComponents(prompt); } catch (error) { console.warn(`${name} integration failed, trying next...`); continue; } } } throw new Error('No AI integrations available'); } async analyzeWithBestAvailable(html: string): Promise<DesignAnalysis> { const preferredOrder = ['gemini', 'openai', 'claude']; for (const name of preferredOrder) { const integration = this.integrations.get(name); if (integration) { try { return await integration.analyzeDesign(html); } catch (error) { console.warn(`${name} integration failed, trying next...`); continue; } } } throw new Error('No AI integrations available for analysis'); } }

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/Tai-DT/mcp-tailwind-gemini'

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