mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-08 22:48:14 -05:00
Added translate block, added ability to add default value during block definition
This commit is contained in:
@@ -15,6 +15,10 @@ interface SubBlockProps {
|
||||
}
|
||||
|
||||
export function SubBlock({ blockId, config, isConnecting }: SubBlockProps) {
|
||||
if (config.hidden) {
|
||||
return null
|
||||
}
|
||||
|
||||
const handleMouseDown = (e: React.MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
}
|
||||
|
||||
110
blocks/blocks/translate.ts
Normal file
110
blocks/blocks/translate.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { TranslateIcon } from '@/components/icons'
|
||||
import { BlockConfig } from '../types'
|
||||
import { ChatResponse } from '@/tools/openai/chat'
|
||||
|
||||
const MODEL_TOOLS = {
|
||||
'gpt-4o': 'openai.chat',
|
||||
'o1': 'openai.chat',
|
||||
'o1-mini': 'openai.chat',
|
||||
'claude-3-5-sonnet-20241022': 'anthropic.chat',
|
||||
'gemini-pro': 'google.chat',
|
||||
} as const
|
||||
|
||||
const getTranslationPrompt = (targetLanguage: string) => `You are a highly skilled translator. Your task is to translate the given text into ${targetLanguage || 'English'} while:
|
||||
1. Preserving the original meaning and nuance
|
||||
2. Maintaining appropriate formality levels
|
||||
3. Adapting idioms and cultural references appropriately
|
||||
4. Preserving formatting and special characters
|
||||
5. Handling technical terms accurately
|
||||
|
||||
Only return the translated text without any explanations or notes. The translation should be natural and fluent in ${targetLanguage || 'English'}.`
|
||||
|
||||
export const TranslateBlock: BlockConfig<ChatResponse> = {
|
||||
type: 'translate',
|
||||
toolbar: {
|
||||
title: 'Translate',
|
||||
description: 'Translate text to any language',
|
||||
bgColor: '#FF4B4B',
|
||||
icon: TranslateIcon,
|
||||
category: 'basic',
|
||||
},
|
||||
tools: {
|
||||
access: ['openai.chat', 'anthropic.chat', 'google.chat'],
|
||||
config: {
|
||||
tool: (params: Record<string, any>) => {
|
||||
const model = params.model || 'gpt-4o'
|
||||
|
||||
if (!model) {
|
||||
throw new Error('No model selected')
|
||||
}
|
||||
|
||||
const tool = MODEL_TOOLS[model as keyof typeof MODEL_TOOLS]
|
||||
|
||||
if (!tool) {
|
||||
throw new Error(`Invalid model selected: ${model}`)
|
||||
}
|
||||
|
||||
return tool
|
||||
}
|
||||
}
|
||||
},
|
||||
workflow: {
|
||||
inputs: {
|
||||
context: { type: 'string', required: true },
|
||||
targetLanguage: { type: 'string', required: true },
|
||||
apiKey: { type: 'string', required: true },
|
||||
systemPrompt: { type: 'string', required: true }
|
||||
},
|
||||
outputs: {
|
||||
response: {
|
||||
type: {
|
||||
content: 'string',
|
||||
model: 'string',
|
||||
tokens: 'any'
|
||||
}
|
||||
}
|
||||
},
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'context',
|
||||
title: 'Text to Translate',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter the text you want to translate'
|
||||
},
|
||||
{
|
||||
id: 'targetLanguage',
|
||||
title: 'Translate To',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter language (e.g. Spanish, French, etc.)'
|
||||
},
|
||||
{
|
||||
id: 'model',
|
||||
title: 'Model',
|
||||
type: 'dropdown',
|
||||
layout: 'half',
|
||||
options: Object.keys(MODEL_TOOLS)
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: "API Key",
|
||||
type: "short-input",
|
||||
layout: "full",
|
||||
placeholder: "Enter your API key",
|
||||
password: true,
|
||||
connectionDroppable: false
|
||||
},
|
||||
{
|
||||
id: 'systemPrompt',
|
||||
title: 'System Prompt',
|
||||
type: 'code',
|
||||
layout: 'full',
|
||||
hidden: true,
|
||||
value: (params: Record<string, any>) => {
|
||||
return getTranslationPrompt(params.targetLanguage || 'English')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { FunctionBlock } from './blocks/function'
|
||||
import { CrewAIVisionBlock } from './blocks/crewai'
|
||||
import { FirecrawlScrapeBlock } from './blocks/firecrawl'
|
||||
import { JinaBlock } from './blocks/jina'
|
||||
import { TranslateBlock } from './blocks/translate'
|
||||
|
||||
// Export blocks for ease of use
|
||||
export {
|
||||
@@ -15,7 +16,8 @@ export {
|
||||
FunctionBlock,
|
||||
CrewAIVisionBlock,
|
||||
FirecrawlScrapeBlock,
|
||||
JinaBlock
|
||||
JinaBlock,
|
||||
TranslateBlock
|
||||
}
|
||||
|
||||
// Registry of all block configurations
|
||||
@@ -25,7 +27,8 @@ const blocks: Record<string, BlockConfig> = {
|
||||
function: FunctionBlock,
|
||||
crewai_vision: CrewAIVisionBlock,
|
||||
firecrawl_scrape: FirecrawlScrapeBlock,
|
||||
jina_reader: JinaBlock
|
||||
jina_reader: JinaBlock,
|
||||
translate: TranslateBlock
|
||||
}
|
||||
|
||||
// Build a reverse mapping of tools to block types
|
||||
|
||||
@@ -46,6 +46,8 @@ export interface SubBlockConfig {
|
||||
placeholder?: string
|
||||
password?: boolean
|
||||
connectionDroppable?: boolean
|
||||
hidden?: boolean
|
||||
value?: (params: Record<string, any>) => string
|
||||
}
|
||||
|
||||
export interface BlockConfig<T extends ToolResponse = ToolResponse> {
|
||||
|
||||
@@ -956,3 +956,25 @@ export function JinaAIIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export const TranslateIcon = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path d="m5 8 6 6" />
|
||||
<path d="m4 14 6-6 2-3" />
|
||||
<path d="M2 5h12" />
|
||||
<path d="M7 2h1" />
|
||||
<path d="m22 22-5-10-5 10" />
|
||||
<path d="M14 18h6" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
@@ -58,10 +58,27 @@ export class Serializer {
|
||||
}
|
||||
|
||||
private extractParams(block: BlockState): Record<string, any> {
|
||||
const blockConfig = getBlock(block.type)
|
||||
if (!blockConfig) {
|
||||
throw new Error(`Invalid block type: ${block.type}`)
|
||||
}
|
||||
|
||||
const params: Record<string, any> = {}
|
||||
|
||||
// First collect all current values from subBlocks
|
||||
Object.entries(block.subBlocks).forEach(([id, subBlock]) => {
|
||||
params[id] = subBlock.value
|
||||
})
|
||||
|
||||
// Then check for any subBlocks with default values
|
||||
blockConfig.workflow.subBlocks.forEach(subBlockConfig => {
|
||||
const id = subBlockConfig.id
|
||||
if (params[id] === null && subBlockConfig.value) {
|
||||
// If the value is null and there's a default value function, use it
|
||||
params[id] = subBlockConfig.value(params)
|
||||
}
|
||||
})
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user