Commit
·
bc3c7d8
1
Parent(s):
0bbea4b
Add images and updates with proper LFS tracking
Browse files- README.md +2 -1
- app.py +56 -44
- banner.jpg +3 -0
- bot-meetup.png +3 -0
- design/1.png +3 -0
- design/2.png +3 -0
- design/3.png +3 -0
README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
---
|
| 2 |
title: Text Transformation Model
|
| 3 |
-
emoji: 🚀
|
| 4 |
colorFrom: purple
|
| 5 |
colorTo: pink
|
| 6 |
sdk: gradio
|
|
@@ -12,6 +11,8 @@ short_description: Single turn text transformation pattern
|
|
| 12 |
|
| 13 |
# Text Transformation Model
|
| 14 |
|
|
|
|
|
|
|
| 15 |
Pattern Space for in-out single-turn text transformation workflows based on a system prompt.
|
| 16 |
|
| 17 |
Mode of operation: user-defined system prompt + single-turn workflow definition concatenate to an enriched system prompt ensuring reliable single turn adherence.
|
|
|
|
| 1 |
---
|
| 2 |
title: Text Transformation Model
|
|
|
|
| 3 |
colorFrom: purple
|
| 4 |
colorTo: pink
|
| 5 |
sdk: gradio
|
|
|
|
| 11 |
|
| 12 |
# Text Transformation Model
|
| 13 |
|
| 14 |
+

|
| 15 |
+
|
| 16 |
Pattern Space for in-out single-turn text transformation workflows based on a system prompt.
|
| 17 |
|
| 18 |
Mode of operation: user-defined system prompt + single-turn workflow definition concatenate to an enriched system prompt ensuring reliable single turn adherence.
|
app.py
CHANGED
|
@@ -4,17 +4,6 @@ import os
|
|
| 4 |
from typing import Optional, Tuple
|
| 5 |
|
| 6 |
def transform_text(input_text: str, system_prompt: str, api_key: str) -> Tuple[str, str]:
|
| 7 |
-
"""
|
| 8 |
-
Transform input text using OpenAI API with the provided system prompt.
|
| 9 |
-
|
| 10 |
-
Args:
|
| 11 |
-
input_text: The text to transform
|
| 12 |
-
system_prompt: User-defined system prompt
|
| 13 |
-
api_key: OpenAI API key
|
| 14 |
-
|
| 15 |
-
Returns:
|
| 16 |
-
Tuple of (output_text, cleared_input_text)
|
| 17 |
-
"""
|
| 18 |
if not api_key.strip():
|
| 19 |
return "Error: Please provide your OpenAI API key.", input_text
|
| 20 |
|
|
@@ -25,17 +14,14 @@ def transform_text(input_text: str, system_prompt: str, api_key: str) -> Tuple[s
|
|
| 25 |
return "Error: Please provide a system prompt.", input_text
|
| 26 |
|
| 27 |
try:
|
| 28 |
-
# Initialize OpenAI client with user's API key
|
| 29 |
client = openai.OpenAI(api_key=api_key.strip())
|
| 30 |
|
| 31 |
-
# Append workflow instruction to user's system prompt
|
| 32 |
enhanced_system_prompt = f"""{system_prompt.strip()}
|
| 33 |
|
| 34 |
IMPORTANT: This is a single-turn text transformation workflow interface. You must respond with the complete transformed text only, without any additional commentary, explanations, or formatting before or after the content."""
|
| 35 |
|
| 36 |
-
# Make API call
|
| 37 |
response = client.chat.completions.create(
|
| 38 |
-
model="gpt-4o-mini",
|
| 39 |
messages=[
|
| 40 |
{"role": "system", "content": enhanced_system_prompt},
|
| 41 |
{"role": "user", "content": input_text.strip()}
|
|
@@ -45,8 +31,6 @@ IMPORTANT: This is a single-turn text transformation workflow interface. You mus
|
|
| 45 |
)
|
| 46 |
|
| 47 |
output_text = response.choices[0].message.content
|
| 48 |
-
|
| 49 |
-
# Return output and clear input for next use
|
| 50 |
return output_text, ""
|
| 51 |
|
| 52 |
except openai.AuthenticationError:
|
|
@@ -59,10 +43,8 @@ IMPORTANT: This is a single-turn text transformation workflow interface. You mus
|
|
| 59 |
return f"Error: {str(e)}", input_text
|
| 60 |
|
| 61 |
def copy_to_clipboard(text: str) -> str:
|
| 62 |
-
"""Return the text for copying (Gradio handles the clipboard functionality)"""
|
| 63 |
return text
|
| 64 |
|
| 65 |
-
# Custom CSS for better styling
|
| 66 |
custom_css = """
|
| 67 |
.main-container {
|
| 68 |
max-width: 1200px;
|
|
@@ -122,25 +104,31 @@ with gr.Blocks(css=custom_css, title="Text Transformation Model", theme=gr.theme
|
|
| 122 |
Single-Turn Text Transformer (In, Out)
|
| 123 |
</h1>
|
| 124 |
<p style="font-size: 1.2em; color: #666; margin-bottom: 20px;">
|
| 125 |
-
A pattern for simple system prompt defined single turn text
|
| 126 |
</p>
|
| 127 |
</div>
|
| 128 |
""")
|
| 129 |
|
| 130 |
with gr.Tabs():
|
| 131 |
with gr.Tab("Transform Text"):
|
| 132 |
-
# API Key Section
|
| 133 |
with gr.Row():
|
| 134 |
-
with gr.Column():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
api_key_input = gr.Textbox(
|
| 136 |
label="OpenAI API Key",
|
| 137 |
placeholder="Enter your OpenAI API key (sk-...)",
|
| 138 |
type="password",
|
| 139 |
info="Your API key is stored locally in your browser for this session."
|
| 140 |
)
|
| 141 |
-
|
| 142 |
-
with gr.Row():
|
| 143 |
-
with gr.Column():
|
| 144 |
system_prompt_input = gr.Textbox(
|
| 145 |
label="System Prompt",
|
| 146 |
placeholder="Enter your system prompt here (e.g., 'Translate the following text to French', 'Summarize this text in bullet points', etc.)",
|
|
@@ -148,7 +136,6 @@ with gr.Blocks(css=custom_css, title="Text Transformation Model", theme=gr.theme
|
|
| 148 |
info="Define how the AI should transform your input text. This prompt will be enhanced automatically for single-turn processing."
|
| 149 |
)
|
| 150 |
|
| 151 |
-
# Input/Output Section
|
| 152 |
with gr.Row():
|
| 153 |
with gr.Column(scale=1):
|
| 154 |
input_text = gr.Textbox(
|
|
@@ -179,11 +166,10 @@ with gr.Blocks(css=custom_css, title="Text Transformation Model", theme=gr.theme
|
|
| 179 |
elem_classes=["copy-button"]
|
| 180 |
)
|
| 181 |
|
| 182 |
-
# Event handlers
|
| 183 |
transform_btn.click(
|
| 184 |
fn=transform_text,
|
| 185 |
inputs=[input_text, system_prompt_input, api_key_input],
|
| 186 |
-
outputs=[output_text, input_text]
|
| 187 |
)
|
| 188 |
|
| 189 |
copy_btn.click(
|
|
@@ -194,46 +180,72 @@ with gr.Blocks(css=custom_css, title="Text Transformation Model", theme=gr.theme
|
|
| 194 |
|
| 195 |
with gr.Tab("About"):
|
| 196 |
gr.Markdown("""
|
| 197 |
-
|
| 198 |
|
| 199 |
- By: [Daniel Rosehill](https://danielrosehill.com) (11-Sep-2025)
|
| 200 |
|
| 201 |
-
This Space provides a simple implementation of an extremely foundational but effective use for large language models (LLMs): taking a text and transforming it into something else using a
|
| 202 |
|
| 203 |
-
I call this Space a "model" of a "pattern" because an almost limitless variety of simple UIs can be developed around this
|
| 204 |
|
| 205 |
-
I call tools like these the great forgotten gems of the AI landscape: just as this AI use-case reached a high degree of stability, maturity, and cost-
|
| 206 |
|
| 207 |
## What Do You Call An Assistant That's Not An Agent?
|
| 208 |
|
| 209 |
Single turn text transformation tools like this (which lack, I argue, even a proper name!) are stateless and non-agentic and thus locked out of the glamorous agent landscape. They are single turn and non-conversational so are clearly not chatbots. At best, they might be described as "assistants" - to the extent that agents have not already usurped the term. But as assistants now connote something much more agentic, they might lack no matter name than "using AI to transform text."
|
| 210 |
|
| 211 |
-
Text transformers have vast application: they can be used to change the person or level of formality of text; to
|
| 212 |
|
| 213 |
## "Lived Experience"
|
| 214 |
|
| 215 |
I have implemented plenty of these.
|
| 216 |
|
| 217 |
-
To provide one pedestrian example: I have an agent like this whose task is to depersonalise system prompts so that I can open source them without random users getting addressed as "Daniel" or assumed to also live in Jerusalem. The system prompt asks the agent to take my system prompt and remove it of any details unique to my life - replace 'Daniel' with 'the user', etc. It's a simple in-out workflow that can (of course) be scripted and run in batches and
|
| 218 |
|
| 219 |
Other reasons why I love these tools:
|
| 220 |
|
| 221 |
-
- They leverage a very foundational and intended use of LLMs. This is not a frontier use or
|
| 222 |
-
- They are forgiving. You don't need a model branded as having PhD level reasoning to get these to work reliably well. Hence, they are cheap. And a huge advantage of
|
| 223 |
-
- They are great, too, for just demonstrating the utility of AI away from the hype cycle. They do something that even the most advanced RegEx patterns
|
| 224 |
- You just need a prompt: No tooling, no MCP integrations. Unless you're trying to transform encyclopedias in one go, they won't challenge the context window of modern models. In, out.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
|
| 231 |
-
# Add JavaScript for clipboard functionality and local storage
|
| 232 |
gr.HTML("""
|
| 233 |
<script>
|
| 234 |
-
// Local storage for API key and system prompt
|
| 235 |
document.addEventListener('DOMContentLoaded', function() {
|
| 236 |
-
// Load saved API key and system prompt
|
| 237 |
const savedApiKey = localStorage.getItem('openai_api_key');
|
| 238 |
const savedSystemPrompt = localStorage.getItem('system_prompt');
|
| 239 |
|
|
|
|
| 4 |
from typing import Optional, Tuple
|
| 5 |
|
| 6 |
def transform_text(input_text: str, system_prompt: str, api_key: str) -> Tuple[str, str]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
if not api_key.strip():
|
| 8 |
return "Error: Please provide your OpenAI API key.", input_text
|
| 9 |
|
|
|
|
| 14 |
return "Error: Please provide a system prompt.", input_text
|
| 15 |
|
| 16 |
try:
|
|
|
|
| 17 |
client = openai.OpenAI(api_key=api_key.strip())
|
| 18 |
|
|
|
|
| 19 |
enhanced_system_prompt = f"""{system_prompt.strip()}
|
| 20 |
|
| 21 |
IMPORTANT: This is a single-turn text transformation workflow interface. You must respond with the complete transformed text only, without any additional commentary, explanations, or formatting before or after the content."""
|
| 22 |
|
|
|
|
| 23 |
response = client.chat.completions.create(
|
| 24 |
+
model="gpt-4o-mini",
|
| 25 |
messages=[
|
| 26 |
{"role": "system", "content": enhanced_system_prompt},
|
| 27 |
{"role": "user", "content": input_text.strip()}
|
|
|
|
| 31 |
)
|
| 32 |
|
| 33 |
output_text = response.choices[0].message.content
|
|
|
|
|
|
|
| 34 |
return output_text, ""
|
| 35 |
|
| 36 |
except openai.AuthenticationError:
|
|
|
|
| 43 |
return f"Error: {str(e)}", input_text
|
| 44 |
|
| 45 |
def copy_to_clipboard(text: str) -> str:
|
|
|
|
| 46 |
return text
|
| 47 |
|
|
|
|
| 48 |
custom_css = """
|
| 49 |
.main-container {
|
| 50 |
max-width: 1200px;
|
|
|
|
| 104 |
Single-Turn Text Transformer (In, Out)
|
| 105 |
</h1>
|
| 106 |
<p style="font-size: 1.2em; color: #666; margin-bottom: 20px;">
|
| 107 |
+
A pattern for simple form-based, system prompt defined, single turn text transformation UIs.
|
| 108 |
</p>
|
| 109 |
</div>
|
| 110 |
""")
|
| 111 |
|
| 112 |
with gr.Tabs():
|
| 113 |
with gr.Tab("Transform Text"):
|
|
|
|
| 114 |
with gr.Row():
|
| 115 |
+
with gr.Column(scale=1):
|
| 116 |
+
gr.Image(
|
| 117 |
+
value="banner.jpg",
|
| 118 |
+
show_label=False,
|
| 119 |
+
show_download_button=False,
|
| 120 |
+
interactive=False,
|
| 121 |
+
container=False
|
| 122 |
+
)
|
| 123 |
+
|
| 124 |
+
with gr.Column(scale=2):
|
| 125 |
api_key_input = gr.Textbox(
|
| 126 |
label="OpenAI API Key",
|
| 127 |
placeholder="Enter your OpenAI API key (sk-...)",
|
| 128 |
type="password",
|
| 129 |
info="Your API key is stored locally in your browser for this session."
|
| 130 |
)
|
| 131 |
+
|
|
|
|
|
|
|
| 132 |
system_prompt_input = gr.Textbox(
|
| 133 |
label="System Prompt",
|
| 134 |
placeholder="Enter your system prompt here (e.g., 'Translate the following text to French', 'Summarize this text in bullet points', etc.)",
|
|
|
|
| 136 |
info="Define how the AI should transform your input text. This prompt will be enhanced automatically for single-turn processing."
|
| 137 |
)
|
| 138 |
|
|
|
|
| 139 |
with gr.Row():
|
| 140 |
with gr.Column(scale=1):
|
| 141 |
input_text = gr.Textbox(
|
|
|
|
| 166 |
elem_classes=["copy-button"]
|
| 167 |
)
|
| 168 |
|
|
|
|
| 169 |
transform_btn.click(
|
| 170 |
fn=transform_text,
|
| 171 |
inputs=[input_text, system_prompt_input, api_key_input],
|
| 172 |
+
outputs=[output_text, input_text]
|
| 173 |
)
|
| 174 |
|
| 175 |
copy_btn.click(
|
|
|
|
| 180 |
|
| 181 |
with gr.Tab("About"):
|
| 182 |
gr.Markdown("""
|
| 183 |
+
## Single Turn Text Transformer
|
| 184 |
|
| 185 |
- By: [Daniel Rosehill](https://danielrosehill.com) (11-Sep-2025)
|
| 186 |
|
| 187 |
+
This Space provides a simple implementation of an extremely foundational but effective use for large language models (LLMs): taking a text and transforming it into something else using a system prompt for guidance!
|
| 188 |
|
| 189 |
+
I call this Space a "model" of a "pattern" because an almost limitless variety of simple UIs can be developed around this principle by simply alternating the underlying system prompt (which in this demo is made editable with a short concatenated element).
|
| 190 |
|
| 191 |
+
I call tools like these the great forgotten gems of the AI landscape: just as this AI use-case reached a high degree of stability, maturity, and cost-effectiveness it has already been lumped into the bucket of legacy tech.
|
| 192 |
|
| 193 |
## What Do You Call An Assistant That's Not An Agent?
|
| 194 |
|
| 195 |
Single turn text transformation tools like this (which lack, I argue, even a proper name!) are stateless and non-agentic and thus locked out of the glamorous agent landscape. They are single turn and non-conversational so are clearly not chatbots. At best, they might be described as "assistants" - to the extent that agents have not already usurped the term. But as assistants now connote something much more agentic, they might lack no matter name than "using AI to transform text."
|
| 196 |
|
| 197 |
+
Text transformers have vast application: they can be used to change the person or level of formality of text; to restructure text from free-flowing formats into defined templates; or to clean up voice captured text, received from speech to text models, for downstream use in other systems. The model is very simple: the user prompt provides the text to be transformed and the system prompt provides the model with the desired transformation. The system prompt can also encapsulate few-shot examples to boost reliability. However, these workflows tend to execute well without even this safeguard.
|
| 198 |
|
| 199 |
## "Lived Experience"
|
| 200 |
|
| 201 |
I have implemented plenty of these.
|
| 202 |
|
| 203 |
+
To provide one pedestrian example: I have an agent like this whose task is to depersonalise system prompts so that I can open source them without random users getting addressed as "Daniel" or assumed to also live in Jerusalem. The system prompt asks the agent to take my system prompt and remove it of any details unique to my life - replace 'Daniel' with 'the user', etc. It's a simple in-out workflow that can (of course) be scripted and run in batches and programmatically but which is just as often more useful through a simple browser UI. And it doesn't get much simpler than a form in and form out!
|
| 204 |
|
| 205 |
Other reasons why I love these tools:
|
| 206 |
|
| 207 |
+
- They leverage a very foundational and intended use of LLMs. This is not a frontier use or cajoling LLMs into doing something we hope might work. It was what they were designed for. If you share my conviction that tools usually are best at what they were built for, this one's a winner.
|
| 208 |
+
- They are forgiving. You don't need a model branded as having PhD level reasoning to get these to work reliably well. Hence, they are cheap. And a huge advantage of affordability: you can spend plenty of time working on great system prompting until you achieve the perfect desired type of text reformatting.
|
| 209 |
+
- They are great, too, for just demonstrating the utility of AI away from the hype cycle. They do something that even the most advanced RegEx patterns can't. They work great locally, too.
|
| 210 |
- You just need a prompt: No tooling, no MCP integrations. Unless you're trying to transform encyclopedias in one go, they won't challenge the context window of modern models. In, out.
|
| 211 |
+
""")
|
| 212 |
+
|
| 213 |
+
with gr.Tab("Design"):
|
| 214 |
+
gr.Markdown("""
|
| 215 |
+
## Prompt Design for Single Turn Adherence
|
| 216 |
+
|
| 217 |
+
Effective prompt design patterns for non-JSON constrained prompting systems to ensure reliable single-turn text transformation workflows.
|
| 218 |
|
| 219 |
+
Instruction here: *IMPORTANT: This is a single-turn text transformation workflow interface. You must respond with the complete transformed text only, without any additional commentary, explanations, or formatting before or after the content.*
|
| 220 |
+
""")
|
| 221 |
+
|
| 222 |
+
gr.Image(
|
| 223 |
+
value="design/1.png",
|
| 224 |
+
show_label=False,
|
| 225 |
+
show_download_button=False,
|
| 226 |
+
interactive=False,
|
| 227 |
+
width=600
|
| 228 |
+
)
|
| 229 |
+
|
| 230 |
+
gr.Image(
|
| 231 |
+
value="design/2.png",
|
| 232 |
+
show_label=False,
|
| 233 |
+
show_download_button=False,
|
| 234 |
+
interactive=False,
|
| 235 |
+
width=600
|
| 236 |
+
)
|
| 237 |
+
|
| 238 |
+
gr.Image(
|
| 239 |
+
value="design/3.png",
|
| 240 |
+
show_label=False,
|
| 241 |
+
show_download_button=False,
|
| 242 |
+
interactive=False,
|
| 243 |
+
width=600
|
| 244 |
+
)
|
| 245 |
|
|
|
|
| 246 |
gr.HTML("""
|
| 247 |
<script>
|
|
|
|
| 248 |
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
| 249 |
const savedApiKey = localStorage.getItem('openai_api_key');
|
| 250 |
const savedSystemPrompt = localStorage.getItem('system_prompt');
|
| 251 |
|
banner.jpg
ADDED
|
Git LFS Details
|
bot-meetup.png
ADDED
|
Git LFS Details
|
design/1.png
ADDED
|
Git LFS Details
|
design/2.png
ADDED
|
Git LFS Details
|
design/3.png
ADDED
|
Git LFS Details
|