diff --git a/apps/docs/content/docs/tools/huggingface.mdx b/apps/docs/content/docs/tools/huggingface.mdx new file mode 100644 index 00000000000..5b35a945dc4 --- /dev/null +++ b/apps/docs/content/docs/tools/huggingface.mdx @@ -0,0 +1,99 @@ +--- +title: Hugging Face +description: Use Hugging Face Inference API +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + + `} +/> + +{/* MANUAL-CONTENT-START:intro */} +[HuggingFace](https://huggingface.co/) is a leading AI platform that provides access to thousands of pre-trained machine learning models and powerful inference capabilities. With its extensive model hub and robust API, HuggingFace offers comprehensive tools for both research and production AI applications. +With HuggingFace, you can: + +Access pre-trained models: Utilize models for text generation, translation, image processing, and more +Generate AI completions: Create content using state-of-the-art language models through the Inference API +Natural language processing: Process and analyze text with specialized NLP models +Deploy at scale: Host and serve models for production applications +Customize models: Fine-tune existing models for specific use cases + +In Sim Studio, the HuggingFace integration enables your agents to programmatically generate completions using the HuggingFace Inference API. This allows for powerful automation scenarios such as content generation, text analysis, code completion, and creative writing. Your agents can generate completions with natural language prompts, access specialized models for different tasks, and integrate AI-generated content into workflows. This integration bridges the gap between your AI workflows and machine learning capabilities, enabling seamless AI-powered automation with one of the world's most comprehensive ML platforms. +{/* MANUAL-CONTENT-END */} + +## Usage Instructions + +Generate completions using Hugging Face Inference API with access to various open-source models. Leverage cutting-edge AI models for chat completions, content generation, and AI-powered conversations with customizable parameters. + + +## Tools + +### `huggingface_chat` + +Generate completions using Hugging Face Inference API + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hugging Face API token | +| `provider` | string | Yes | The provider to use for the API request \(e.g., novita, cerebras, etc.\) | +| `model` | string | Yes | Model to use for chat completions \(e.g., deepseek/deepseek-v3-0324\) | +| `content` | string | Yes | The user message content to send to the model | +| `systemPrompt` | string | No | System prompt to guide the model behavior | +| `maxTokens` | number | No | Maximum number of tokens to generate | +| `temperature` | number | No | Sampling temperature \(0-2\). Higher values make output more random | +| `stream` | boolean | No | Whether to stream the response | + +#### Output + +| Parameter | Type | +| --------- | ---- | +| `content` | string | +| `model` | string | +| `usage` | string | +| `completion_tokens` | string | +| `total_tokens` | string | + + + +## Block Configuration + +### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `systemPrompt` | string | No | System Prompt - Enter system prompt to guide the model behavior... | + + + +### Outputs + +| Output | Type | Description | +| ------ | ---- | ----------- | +| `response` | object | Output from response | +| ↳ `content` | string | content of the response | +| ↳ `model` | string | model of the response | +| ↳ `usage` | json | usage of the response | + + +## Notes + +- Category: `tools` +- Type: `huggingface` diff --git a/apps/docs/content/docs/tools/meta.json b/apps/docs/content/docs/tools/meta.json index 380fb990b8d..80332879640 100644 --- a/apps/docs/content/docs/tools/meta.json +++ b/apps/docs/content/docs/tools/meta.json @@ -19,6 +19,7 @@ "google_search", "google_sheets", "guesty", + "huggingface", "image_generator", "jina", "jira", diff --git a/apps/sim/blocks/blocks/huggingface.ts b/apps/sim/blocks/blocks/huggingface.ts new file mode 100644 index 00000000000..8aa50ec516d --- /dev/null +++ b/apps/sim/blocks/blocks/huggingface.ts @@ -0,0 +1,125 @@ +import { HuggingFaceIcon } from '@/components/icons' +import type { HuggingFaceChatResponse } from '@/tools/huggingface/types' +import type { BlockConfig } from '../types' + +export const HuggingFaceBlock: BlockConfig = { + type: 'huggingface', + name: 'Hugging Face', + description: 'Use Hugging Face Inference API', + longDescription: + 'Generate completions using Hugging Face Inference API with access to various open-source models. Leverage cutting-edge AI models for chat completions, content generation, and AI-powered conversations with customizable parameters.', + docsLink: 'https://docs.simstudio.ai/tools/huggingface', + category: 'tools', + bgColor: '#181C1E', + icon: HuggingFaceIcon, + subBlocks: [ + { + id: 'systemPrompt', + title: 'System Prompt', + type: 'long-input', + layout: 'full', + placeholder: 'Enter system prompt to guide the model behavior...', + rows: 3, + }, + { + id: 'content', + title: 'User Prompt', + type: 'long-input', + layout: 'full', + placeholder: 'Enter your message here...', + rows: 3, + }, + { + id: 'provider', + title: 'Provider', + type: 'dropdown', + layout: 'half', + options: [ + { label: 'Novita', id: 'novita' }, + { label: 'Cerebras', id: 'cerebras' }, + { label: 'Cohere', id: 'cohere' }, + { label: 'Fal AI', id: 'fal' }, + { label: 'Fireworks', id: 'fireworks' }, + { label: 'Hyperbolic', id: 'hyperbolic' }, + { label: 'HF Inference', id: 'hf-inference' }, + { label: 'Nebius', id: 'nebius' }, + { label: 'Nscale', id: 'nscale' }, + { label: 'Replicate', id: 'replicate' }, + { label: 'SambaNova', id: 'sambanova' }, + { label: 'Together', id: 'together' }, + ], + value: () => 'novita', + }, + { + id: 'model', + title: 'Model', + type: 'short-input', + layout: 'full', + placeholder: + 'e.g., deepseek/deepseek-v3-0324, llama3.1-8b, meta-llama/Llama-3.2-3B-Instruct-Turbo', + description: 'The model must be available for the selected provider.', + }, + { + id: 'temperature', + title: 'Temperature', + type: 'slider', + layout: 'half', + min: 0, + max: 2, + value: () => '0.7', + }, + { + id: 'maxTokens', + title: 'Max Tokens', + type: 'short-input', + layout: 'half', + placeholder: 'e.g., 1000', + }, + { + id: 'apiKey', + title: 'API Token', + type: 'short-input', + layout: 'full', + placeholder: 'Enter your Hugging Face API token', + password: true, + }, + ], + tools: { + access: ['huggingface_chat'], + config: { + tool: () => 'huggingface_chat', + params: (params) => { + const toolParams = { + apiKey: params.apiKey, + provider: params.provider, + model: params.model, + content: params.content, + systemPrompt: params.systemPrompt, + temperature: params.temperature ? Number.parseFloat(params.temperature) : undefined, + maxTokens: params.maxTokens ? Number.parseInt(params.maxTokens) : undefined, + stream: false, // Always false + } + + return toolParams + }, + }, + }, + inputs: { + systemPrompt: { type: 'string', required: false }, + content: { type: 'string', required: true }, + provider: { type: 'string', required: true }, + model: { type: 'string', required: true }, + temperature: { type: 'string', required: false }, + maxTokens: { type: 'string', required: false }, + apiKey: { type: 'string', required: true }, + }, + outputs: { + response: { + type: { + content: 'string', + model: 'string', + usage: 'json', + }, + }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index d758c9c6f6b..aab7f1419f9 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -25,6 +25,7 @@ import { GoogleCalendarBlock } from './blocks/google_calendar' import { GoogleDocsBlock } from './blocks/google_docs' import { GoogleDriveBlock } from './blocks/google_drive' import { GoogleSheetsBlock } from './blocks/google_sheets' +import { HuggingFaceBlock } from './blocks/huggingface' // import { GuestyBlock } from './blocks/guesty' import { ImageGeneratorBlock } from './blocks/image_generator' import { JinaBlock } from './blocks/jina' @@ -124,6 +125,7 @@ export const registry: Record = { whatsapp: WhatsAppBlock, x: XBlock, youtube: YouTubeBlock, + huggingface: HuggingFaceBlock, } // Helper functions to access the registry diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 2237b27e1e9..1f061476d34 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -2827,3 +2827,46 @@ export function PackageSearchIcon(props: SVGProps) { ) } +export function HuggingFaceIcon(props: SVGProps) { + return ( + + + + + + + + + ) +} diff --git a/apps/sim/tools/huggingface/chat.ts b/apps/sim/tools/huggingface/chat.ts new file mode 100644 index 00000000000..82438a4b12b --- /dev/null +++ b/apps/sim/tools/huggingface/chat.ts @@ -0,0 +1,193 @@ +import type { ToolConfig } from '../types' +import type { + HuggingFaceChatParams, + HuggingFaceChatResponse, + HuggingFaceMessage, + HuggingFaceRequestBody, +} from './types' + +export const chatTool: ToolConfig = { + id: 'huggingface_chat', + name: 'Hugging Face Chat', + description: 'Generate completions using Hugging Face Inference API', + version: '1.0', + + params: { + apiKey: { + type: 'string', + required: true, + requiredForToolCall: true, + description: 'Hugging Face API token', + }, + provider: { + type: 'string', + required: true, + description: 'The provider to use for the API request (e.g., novita, cerebras, etc.)', + }, + model: { + type: 'string', + required: true, + description: 'Model to use for chat completions (e.g., deepseek/deepseek-v3-0324)', + }, + content: { + type: 'string', + required: true, + description: 'The user message content to send to the model', + }, + systemPrompt: { + type: 'string', + required: false, + description: 'System prompt to guide the model behavior', + }, + maxTokens: { + type: 'number', + required: false, + description: 'Maximum number of tokens to generate', + }, + temperature: { + type: 'number', + required: false, + description: 'Sampling temperature (0-2). Higher values make output more random', + }, + stream: { + type: 'boolean', + required: false, + description: 'Whether to stream the response', + }, + }, + + request: { + method: 'POST', + url: (params) => { + // Provider-specific endpoint mapping + const endpointMap: Record = { + novita: '/v3/openai/chat/completions', + cerebras: '/v1/chat/completions', + cohere: '/v1/chat/completions', + fal: '/v1/chat/completions', + fireworks: '/v1/chat/completions', + hyperbolic: '/v1/chat/completions', + 'hf-inference': '/v1/chat/completions', + nebius: '/v1/chat/completions', + nscale: '/v1/chat/completions', + replicate: '/v1/chat/completions', + sambanova: '/v1/chat/completions', + together: '/v1/chat/completions', + } + + const endpoint = endpointMap[params.provider] || '/v1/chat/completions' + return `https://router.huggingface.co/${params.provider}${endpoint}` + }, + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const messages: HuggingFaceMessage[] = [] + + // Add system prompt if provided + if (params.systemPrompt) { + messages.push({ + role: 'system', + content: params.systemPrompt, + }) + } + + // Add user message + messages.push({ + role: 'user', + content: params.content, + }) + + const body: HuggingFaceRequestBody = { + model: params.model, + messages: messages, + stream: params.stream || false, + } + + // Add optional parameters if provided + if (params.temperature !== undefined) { + body.temperature = Number(params.temperature) + } + + if (params.maxTokens !== undefined) { + body.max_tokens = Number(params.maxTokens) + } + + return body + }, + }, + + transformResponse: async (response, params) => { + try { + // Check if the response was successful + if (!response.ok) { + const errorData = await response.json().catch(() => null) + console.error('Hugging Face API error:', { + status: response.status, + statusText: response.statusText, + errorData, + url: response.url, + }) + + const errorMessage = errorData + ? `API error: ${response.status} ${response.statusText} - ${JSON.stringify(errorData)}` + : `API error: ${response.status} ${response.statusText}` + + throw new Error(errorMessage) + } + + const data = await response.json() + + // Validate response structure + if (!data.choices || !data.choices[0] || !data.choices[0].message) { + console.error('Invalid Hugging Face response format:', data) + throw new Error('Invalid response format from Hugging Face API') + } + + return { + success: true, + output: { + content: data.choices[0].message.content, + model: data.model || params?.model || 'unknown', + usage: data.usage + ? { + prompt_tokens: data.usage.prompt_tokens || 0, + completion_tokens: data.usage.completion_tokens || 0, + total_tokens: data.usage.total_tokens || 0, + } + : { + prompt_tokens: 0, + completion_tokens: 0, + total_tokens: 0, + }, + }, + } + } catch (error: any) { + console.error('Failed to process Hugging Face response:', error) + throw error + } + }, + + transformError: (error) => { + let errorMessage = 'Unknown error occurred' + + if (error) { + if (typeof error === 'string') { + errorMessage = error + } else if (error.message) { + errorMessage = error.message + } else if (error.error) { + errorMessage = error.error + } else { + try { + errorMessage = JSON.stringify(error) + } catch (e) { + errorMessage = 'Error occurred but could not be serialized' + } + } + } + + return `Hugging Face chat completion failed: ${errorMessage}` + }, +} diff --git a/apps/sim/tools/huggingface/index.ts b/apps/sim/tools/huggingface/index.ts new file mode 100644 index 00000000000..fdef0ced657 --- /dev/null +++ b/apps/sim/tools/huggingface/index.ts @@ -0,0 +1,3 @@ +import { chatTool } from './chat' + +export const huggingfaceChatTool = chatTool diff --git a/apps/sim/tools/huggingface/types.ts b/apps/sim/tools/huggingface/types.ts new file mode 100644 index 00000000000..a3025bca898 --- /dev/null +++ b/apps/sim/tools/huggingface/types.ts @@ -0,0 +1,39 @@ +import type { ToolResponse } from '../types' + +export interface HuggingFaceUsage { + prompt_tokens: number + completion_tokens: number + total_tokens: number +} + +export interface HuggingFaceMessage { + role: 'user' | 'assistant' | 'system' + content: string +} + +export interface HuggingFaceRequestBody { + model: string + messages: HuggingFaceMessage[] + stream: boolean + temperature?: number + max_tokens?: number +} + +export interface HuggingFaceChatParams { + apiKey: string + provider: string + model: string + content: string + systemPrompt?: string + maxTokens?: number + temperature?: number + stream?: boolean +} + +export interface HuggingFaceChatResponse extends ToolResponse { + output: { + content: string + model: string + usage: HuggingFaceUsage + } +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 00bd7aed5f5..6909ff94ae5 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -50,6 +50,7 @@ import { import { guestyGuestTool, guestyReservationTool } from './guesty' import { requestTool as httpRequest } from './http' import { contactsTool as hubspotContacts } from './hubspot/contacts' +import { huggingfaceChatTool } from './huggingface' import { readUrlTool } from './jina' import { jiraBulkRetrieveTool, jiraRetrieveTool, jiraUpdateTool, jiraWriteTool } from './jira' import { knowledgeSearchTool, knowledgeUploadChunkTool } from './knowledge' @@ -104,6 +105,7 @@ export const tools: Record = { autoblocks_prompt_manager: autoblocksPromptManagerTool, openai_embeddings: openAIEmbeddings, http_request: httpRequest, + huggingface_chat: huggingfaceChatTool, hubspot_contacts: hubspotContacts, salesforce_opportunities: salesforceOpportunities, function_execute: functionExecuteTool,