mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-04 20:05:11 -05:00
Compare commits
11 Commits
release-v0
...
feat/text-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15bddcaf1e | ||
|
|
2eaa13b141 | ||
|
|
283b77e7e0 | ||
|
|
ac5aa0a5f4 | ||
|
|
0f300d7884 | ||
|
|
7dfc816280 | ||
|
|
378126e60f | ||
|
|
21a1d993b8 | ||
|
|
e0862e8086 | ||
|
|
b1259e0bdd | ||
|
|
5244bd94fc |
77
autogpt_platform/backend/backend/blocks/encoder_block.py
Normal file
77
autogpt_platform/backend/backend/blocks/encoder_block.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
"""Text encoding block for converting special characters to escape sequences."""
|
||||||
|
|
||||||
|
import codecs
|
||||||
|
|
||||||
|
from backend.data.block import (
|
||||||
|
Block,
|
||||||
|
BlockCategory,
|
||||||
|
BlockOutput,
|
||||||
|
BlockSchemaInput,
|
||||||
|
BlockSchemaOutput,
|
||||||
|
)
|
||||||
|
from backend.data.model import SchemaField
|
||||||
|
|
||||||
|
|
||||||
|
class TextEncoderBlock(Block):
|
||||||
|
"""
|
||||||
|
Encodes a string by converting special characters into escape sequences.
|
||||||
|
|
||||||
|
This block is the inverse of TextDecoderBlock. It takes text containing
|
||||||
|
special characters (like newlines, tabs, etc.) and converts them into
|
||||||
|
their escape sequence representations (e.g., newline becomes \\n).
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Input(BlockSchemaInput):
|
||||||
|
"""Input schema for TextEncoderBlock."""
|
||||||
|
|
||||||
|
text: str = SchemaField(
|
||||||
|
description="A string containing special characters to be encoded",
|
||||||
|
placeholder="Your text with newlines and quotes to encode",
|
||||||
|
)
|
||||||
|
|
||||||
|
class Output(BlockSchemaOutput):
|
||||||
|
"""Output schema for TextEncoderBlock."""
|
||||||
|
|
||||||
|
encoded_text: str = SchemaField(
|
||||||
|
description="The encoded text with special characters converted to escape sequences"
|
||||||
|
)
|
||||||
|
error: str = SchemaField(description="Error message if encoding fails")
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(
|
||||||
|
id="5185f32e-4b65-4ecf-8fbb-873f003f09d6",
|
||||||
|
description="Encodes a string by converting special characters into escape sequences",
|
||||||
|
categories={BlockCategory.TEXT},
|
||||||
|
input_schema=TextEncoderBlock.Input,
|
||||||
|
output_schema=TextEncoderBlock.Output,
|
||||||
|
test_input={
|
||||||
|
"text": """Hello
|
||||||
|
World!
|
||||||
|
This is a "quoted" string."""
|
||||||
|
},
|
||||||
|
test_output=[
|
||||||
|
(
|
||||||
|
"encoded_text",
|
||||||
|
"""Hello\\nWorld!\\nThis is a "quoted" string.""",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
async def run(self, input_data: Input, **kwargs) -> BlockOutput:
|
||||||
|
"""
|
||||||
|
Encode the input text by converting special characters to escape sequences.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
input_data: The input containing the text to encode.
|
||||||
|
**kwargs: Additional keyword arguments (unused).
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
The encoded text with escape sequences, or an error message if encoding fails.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
encoded_text = codecs.encode(input_data.text, "unicode_escape").decode(
|
||||||
|
"utf-8"
|
||||||
|
)
|
||||||
|
yield "encoded_text", encoded_text
|
||||||
|
except Exception as e:
|
||||||
|
yield "error", f"Encoding error: {str(e)}"
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from backend.blocks.encoder_block import TextEncoderBlock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_text_encoder_basic():
|
||||||
|
"""Test basic encoding of newlines and special characters."""
|
||||||
|
block = TextEncoderBlock()
|
||||||
|
result = []
|
||||||
|
async for output in block.run(TextEncoderBlock.Input(text="Hello\nWorld")):
|
||||||
|
result.append(output)
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0][0] == "encoded_text"
|
||||||
|
assert result[0][1] == "Hello\\nWorld"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_text_encoder_multiple_escapes():
|
||||||
|
"""Test encoding of multiple escape sequences."""
|
||||||
|
block = TextEncoderBlock()
|
||||||
|
result = []
|
||||||
|
async for output in block.run(
|
||||||
|
TextEncoderBlock.Input(text="Line1\nLine2\tTabbed\rCarriage")
|
||||||
|
):
|
||||||
|
result.append(output)
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0][0] == "encoded_text"
|
||||||
|
assert "\\n" in result[0][1]
|
||||||
|
assert "\\t" in result[0][1]
|
||||||
|
assert "\\r" in result[0][1]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_text_encoder_unicode():
|
||||||
|
"""Test that unicode characters are handled correctly."""
|
||||||
|
block = TextEncoderBlock()
|
||||||
|
result = []
|
||||||
|
async for output in block.run(TextEncoderBlock.Input(text="Hello 世界\n")):
|
||||||
|
result.append(output)
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0][0] == "encoded_text"
|
||||||
|
# Unicode characters should be escaped as \uXXXX sequences
|
||||||
|
assert "\\n" in result[0][1]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_text_encoder_empty_string():
|
||||||
|
"""Test encoding of an empty string."""
|
||||||
|
block = TextEncoderBlock()
|
||||||
|
result = []
|
||||||
|
async for output in block.run(TextEncoderBlock.Input(text="")):
|
||||||
|
result.append(output)
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0][0] == "encoded_text"
|
||||||
|
assert result[0][1] == ""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_text_encoder_error_handling():
|
||||||
|
"""Test that encoding errors are handled gracefully."""
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
block = TextEncoderBlock()
|
||||||
|
result = []
|
||||||
|
|
||||||
|
with patch("codecs.encode", side_effect=Exception("Mocked encoding error")):
|
||||||
|
async for output in block.run(TextEncoderBlock.Input(text="test")):
|
||||||
|
result.append(output)
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0][0] == "error"
|
||||||
|
assert "Mocked encoding error" in result[0][1]
|
||||||
@@ -26,20 +26,8 @@ export function buildCopilotChatUrl(prompt: string): string {
|
|||||||
|
|
||||||
export function getQuickActions(): string[] {
|
export function getQuickActions(): string[] {
|
||||||
return [
|
return [
|
||||||
"I don't know where to start, just ask me stuff",
|
"Show me what I can automate",
|
||||||
"I do the same thing every week and it's killing me",
|
"Design a custom workflow",
|
||||||
"Help me find where I'm wasting my time",
|
"Help me with content creation",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInputPlaceholder(width?: number) {
|
|
||||||
if (!width) return "What's your role and what eats up most of your day?";
|
|
||||||
|
|
||||||
if (width < 500) {
|
|
||||||
return "I'm a chef and I hate...";
|
|
||||||
}
|
|
||||||
if (width <= 1080) {
|
|
||||||
return "What's your role and what eats up most of your day?";
|
|
||||||
}
|
|
||||||
return "What's your role and what eats up most of your day? e.g. 'I'm a recruiter and I hate...'";
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import { Text } from "@/components/atoms/Text/Text";
|
|||||||
import { Chat } from "@/components/contextual/Chat/Chat";
|
import { Chat } from "@/components/contextual/Chat/Chat";
|
||||||
import { ChatInput } from "@/components/contextual/Chat/components/ChatInput/ChatInput";
|
import { ChatInput } from "@/components/contextual/Chat/components/ChatInput/ChatInput";
|
||||||
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useCopilotStore } from "./copilot-page-store";
|
import { useCopilotStore } from "./copilot-page-store";
|
||||||
import { getInputPlaceholder } from "./helpers";
|
|
||||||
import { useCopilotPage } from "./useCopilotPage";
|
import { useCopilotPage } from "./useCopilotPage";
|
||||||
|
|
||||||
export default function CopilotPage() {
|
export default function CopilotPage() {
|
||||||
@@ -16,25 +14,8 @@ export default function CopilotPage() {
|
|||||||
const isInterruptModalOpen = useCopilotStore((s) => s.isInterruptModalOpen);
|
const isInterruptModalOpen = useCopilotStore((s) => s.isInterruptModalOpen);
|
||||||
const confirmInterrupt = useCopilotStore((s) => s.confirmInterrupt);
|
const confirmInterrupt = useCopilotStore((s) => s.confirmInterrupt);
|
||||||
const cancelInterrupt = useCopilotStore((s) => s.cancelInterrupt);
|
const cancelInterrupt = useCopilotStore((s) => s.cancelInterrupt);
|
||||||
|
|
||||||
const [inputPlaceholder, setInputPlaceholder] = useState(
|
|
||||||
getInputPlaceholder(),
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleResize = () => {
|
|
||||||
setInputPlaceholder(getInputPlaceholder(window.innerWidth));
|
|
||||||
};
|
|
||||||
|
|
||||||
handleResize();
|
|
||||||
|
|
||||||
window.addEventListener("resize", handleResize);
|
|
||||||
return () => window.removeEventListener("resize", handleResize);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const { greetingName, quickActions, isLoading, hasSession, initialPrompt } =
|
const { greetingName, quickActions, isLoading, hasSession, initialPrompt } =
|
||||||
state;
|
state;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleQuickAction,
|
handleQuickAction,
|
||||||
startChatWithPrompt,
|
startChatWithPrompt,
|
||||||
@@ -92,7 +73,7 @@ export default function CopilotPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-1 items-center justify-center overflow-y-auto bg-[#f8f8f9] px-3 py-5 md:px-6 md:py-10">
|
<div className="flex h-full flex-1 items-center justify-center overflow-y-auto bg-[#f8f8f9] px-6 py-10">
|
||||||
<div className="w-full text-center">
|
<div className="w-full text-center">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="mx-auto max-w-2xl">
|
<div className="mx-auto max-w-2xl">
|
||||||
@@ -109,25 +90,25 @@ export default function CopilotPage() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="mx-auto max-w-3xl">
|
<div className="mx-auto max-w-2xl">
|
||||||
<Text
|
<Text
|
||||||
variant="h3"
|
variant="h3"
|
||||||
className="mb-1 !text-[1.375rem] text-zinc-700"
|
className="mb-3 !text-[1.375rem] text-zinc-700"
|
||||||
>
|
>
|
||||||
Hey, <span className="text-violet-600">{greetingName}</span>
|
Hey, <span className="text-violet-600">{greetingName}</span>
|
||||||
</Text>
|
</Text>
|
||||||
<Text variant="h3" className="mb-8 !font-normal">
|
<Text variant="h3" className="mb-8 !font-normal">
|
||||||
Tell me about your work — I'll find what to automate.
|
What do you want to automate?
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<ChatInput
|
<ChatInput
|
||||||
onSend={startChatWithPrompt}
|
onSend={startChatWithPrompt}
|
||||||
placeholder={inputPlaceholder}
|
placeholder='You can search or just ask - e.g. "create a blog post outline"'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap items-center justify-center gap-3 overflow-x-auto [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
|
<div className="flex flex-nowrap items-center justify-center gap-3 overflow-x-auto [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
|
||||||
{quickActions.map((action) => (
|
{quickActions.map((action) => (
|
||||||
<Button
|
<Button
|
||||||
key={action}
|
key={action}
|
||||||
@@ -135,7 +116,7 @@ export default function CopilotPage() {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => handleQuickAction(action)}
|
onClick={() => handleQuickAction(action)}
|
||||||
className="h-auto shrink-0 border-zinc-300 px-3 py-2 text-[.9rem] text-zinc-600"
|
className="h-auto shrink-0 border-zinc-600 !px-4 !py-2 text-[1rem] text-zinc-600"
|
||||||
>
|
>
|
||||||
{action}
|
{action}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { SessionDetailResponse } from "@/app/api/__generated__/models/sessi
|
|||||||
import { Button } from "@/components/atoms/Button/Button";
|
import { Button } from "@/components/atoms/Button/Button";
|
||||||
import { Text } from "@/components/atoms/Text/Text";
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
||||||
|
import { useBreakpoint } from "@/lib/hooks/useBreakpoint";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { GlobeHemisphereEastIcon } from "@phosphor-icons/react";
|
import { GlobeHemisphereEastIcon } from "@phosphor-icons/react";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
@@ -55,6 +56,10 @@ export function ChatContainer({
|
|||||||
onStreamingChange?.(isStreaming);
|
onStreamingChange?.(isStreaming);
|
||||||
}, [isStreaming, onStreamingChange]);
|
}, [isStreaming, onStreamingChange]);
|
||||||
|
|
||||||
|
const breakpoint = useBreakpoint();
|
||||||
|
const isMobile =
|
||||||
|
breakpoint === "base" || breakpoint === "sm" || breakpoint === "md";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -122,7 +127,11 @@ export function ChatContainer({
|
|||||||
disabled={isStreaming || !sessionId}
|
disabled={isStreaming || !sessionId}
|
||||||
isStreaming={isStreaming}
|
isStreaming={isStreaming}
|
||||||
onStop={stopStreaming}
|
onStop={stopStreaming}
|
||||||
placeholder="What else can I help with?"
|
placeholder={
|
||||||
|
isMobile
|
||||||
|
? "You can search or just ask"
|
||||||
|
: 'You can search or just ask — e.g. "create a blog post outline"'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -74,20 +74,19 @@ export function ChatInput({
|
|||||||
hasMultipleLines ? "rounded-xlarge" : "rounded-full",
|
hasMultipleLines ? "rounded-xlarge" : "rounded-full",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{!value && !isRecording && (
|
|
||||||
<div
|
|
||||||
className="pointer-events-none absolute inset-0 top-0.5 flex items-center justify-start pl-14 text-[1rem] text-zinc-400"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
{isTranscribing ? "Transcribing..." : placeholder}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<textarea
|
<textarea
|
||||||
id={inputId}
|
id={inputId}
|
||||||
aria-label="Chat message input"
|
aria-label="Chat message input"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
|
placeholder={
|
||||||
|
isTranscribing
|
||||||
|
? "Transcribing..."
|
||||||
|
: isRecording
|
||||||
|
? ""
|
||||||
|
: placeholder
|
||||||
|
}
|
||||||
disabled={isInputDisabled}
|
disabled={isInputDisabled}
|
||||||
rows={1}
|
rows={1}
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -123,14 +122,13 @@ export function ChatInput({
|
|||||||
size="icon"
|
size="icon"
|
||||||
aria-label={isRecording ? "Stop recording" : "Start recording"}
|
aria-label={isRecording ? "Stop recording" : "Start recording"}
|
||||||
onClick={toggleRecording}
|
onClick={toggleRecording}
|
||||||
disabled={disabled || isTranscribing || isStreaming}
|
disabled={disabled || isTranscribing}
|
||||||
className={cn(
|
className={cn(
|
||||||
isRecording
|
isRecording
|
||||||
? "animate-pulse border-red-500 bg-red-500 text-white hover:border-red-600 hover:bg-red-600"
|
? "animate-pulse border-red-500 bg-red-500 text-white hover:border-red-600 hover:bg-red-600"
|
||||||
: isTranscribing
|
: isTranscribing
|
||||||
? "border-zinc-300 bg-zinc-100 text-zinc-400"
|
? "border-zinc-300 bg-zinc-100 text-zinc-400"
|
||||||
: "border-zinc-300 bg-white text-zinc-500 hover:border-zinc-400 hover:bg-zinc-50 hover:text-zinc-700",
|
: "border-zinc-300 bg-white text-zinc-500 hover:border-zinc-400 hover:bg-zinc-50 hover:text-zinc-700",
|
||||||
isStreaming && "opacity-40",
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{isTranscribing ? (
|
{isTranscribing ? (
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ export function AudioWaveform({
|
|||||||
// Create audio context and analyser
|
// Create audio context and analyser
|
||||||
const audioContext = new AudioContext();
|
const audioContext = new AudioContext();
|
||||||
const analyser = audioContext.createAnalyser();
|
const analyser = audioContext.createAnalyser();
|
||||||
analyser.fftSize = 256;
|
analyser.fftSize = 512;
|
||||||
analyser.smoothingTimeConstant = 0.3;
|
analyser.smoothingTimeConstant = 0.8;
|
||||||
|
|
||||||
// Connect the stream to the analyser
|
// Connect the stream to the analyser
|
||||||
const source = audioContext.createMediaStreamSource(stream);
|
const source = audioContext.createMediaStreamSource(stream);
|
||||||
@@ -73,11 +73,10 @@ export function AudioWaveform({
|
|||||||
maxAmplitude = Math.max(maxAmplitude, amplitude);
|
maxAmplitude = Math.max(maxAmplitude, amplitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize amplitude (0-128 range) to 0-1
|
// Map amplitude (0-128) to bar height
|
||||||
const normalized = maxAmplitude / 128;
|
const normalized = (maxAmplitude / 128) * 255;
|
||||||
// Apply sensitivity boost (multiply by 4) and use sqrt curve to amplify quiet sounds
|
const height =
|
||||||
const boosted = Math.min(1, Math.sqrt(normalized) * 4);
|
minBarHeight + (normalized / 255) * (maxBarHeight - minBarHeight);
|
||||||
const height = minBarHeight + boosted * (maxBarHeight - minBarHeight);
|
|
||||||
newBars.push(height);
|
newBars.push(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ export function useVoiceRecording({
|
|||||||
[value, isTranscribing, toggleRecording, baseHandleKeyDown],
|
[value, isTranscribing, toggleRecording, baseHandleKeyDown],
|
||||||
);
|
);
|
||||||
|
|
||||||
const showMicButton = isSupported;
|
const showMicButton = isSupported && !isStreaming;
|
||||||
const isInputDisabled = disabled || isStreaming || isTranscribing;
|
const isInputDisabled = disabled || isStreaming || isTranscribing;
|
||||||
|
|
||||||
// Cleanup on unmount
|
// Cleanup on unmount
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ Below is a comprehensive list of all available blocks, categorized by their prim
|
|||||||
| [Get Current Time](block-integrations/text.md#get-current-time) | This block outputs the current time |
|
| [Get Current Time](block-integrations/text.md#get-current-time) | This block outputs the current time |
|
||||||
| [Match Text Pattern](block-integrations/text.md#match-text-pattern) | Matches text against a regex pattern and forwards data to positive or negative output based on the match |
|
| [Match Text Pattern](block-integrations/text.md#match-text-pattern) | Matches text against a regex pattern and forwards data to positive or negative output based on the match |
|
||||||
| [Text Decoder](block-integrations/text.md#text-decoder) | Decodes a string containing escape sequences into actual text |
|
| [Text Decoder](block-integrations/text.md#text-decoder) | Decodes a string containing escape sequences into actual text |
|
||||||
|
| [Text Encoder](block-integrations/text.md#text-encoder) | Encodes a string by converting special characters into escape sequences |
|
||||||
| [Text Replace](block-integrations/text.md#text-replace) | This block is used to replace a text with a new text |
|
| [Text Replace](block-integrations/text.md#text-replace) | This block is used to replace a text with a new text |
|
||||||
| [Text Split](block-integrations/text.md#text-split) | This block is used to split a text into a list of strings |
|
| [Text Split](block-integrations/text.md#text-split) | This block is used to split a text into a list of strings |
|
||||||
| [Word Character Count](block-integrations/text.md#word-character-count) | Counts the number of words and characters in a given text |
|
| [Word Character Count](block-integrations/text.md#word-character-count) | Counts the number of words and characters in a given text |
|
||||||
|
|||||||
@@ -380,6 +380,42 @@ This is useful when working with data from APIs or files where escape sequences
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Text Encoder
|
||||||
|
|
||||||
|
### What it is
|
||||||
|
Encodes a string by converting special characters into escape sequences
|
||||||
|
|
||||||
|
### How it works
|
||||||
|
<!-- MANUAL: how_it_works -->
|
||||||
|
The Text Encoder takes the input string and applies Python's `unicode_escape` encoding (equivalent to `codecs.encode(text, "unicode_escape").decode("utf-8")`) to transform special characters like newlines, tabs, and backslashes into their escaped forms.
|
||||||
|
|
||||||
|
The block relies on the input schema to ensure the value is a string; non-string inputs are rejected by validation, and any encoding failures surface as block errors. Non-ASCII characters are emitted as `\uXXXX` sequences, which is useful for ASCII-only payloads.
|
||||||
|
<!-- END MANUAL -->
|
||||||
|
|
||||||
|
### Inputs
|
||||||
|
|
||||||
|
| Input | Description | Type | Required |
|
||||||
|
|-------|-------------|------|----------|
|
||||||
|
| text | A string containing special characters to be encoded | str | Yes |
|
||||||
|
|
||||||
|
### Outputs
|
||||||
|
|
||||||
|
| Output | Description | Type |
|
||||||
|
|--------|-------------|------|
|
||||||
|
| error | Error message if encoding fails | str |
|
||||||
|
| encoded_text | The encoded text with special characters converted to escape sequences | str |
|
||||||
|
|
||||||
|
### Possible use case
|
||||||
|
<!-- MANUAL: use_case -->
|
||||||
|
**JSON Payload Preparation**: Encode multiline or quoted text before embedding it in JSON string fields to ensure proper escaping.
|
||||||
|
|
||||||
|
**Config/ENV Generation**: Convert template text into escaped strings for `.env` or YAML values that require special character handling.
|
||||||
|
|
||||||
|
**Snapshot Fixtures**: Produce stable escaped strings for golden files or API tests where consistent text representation is needed.
|
||||||
|
<!-- END MANUAL -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Text Replace
|
## Text Replace
|
||||||
|
|
||||||
### What it is
|
### What it is
|
||||||
|
|||||||
Reference in New Issue
Block a user