danielrosehill commited on
Commit
7391b54
Β·
1 Parent(s): 1f2abee
Files changed (3) hide show
  1. README.md +8 -2
  2. app.py +270 -0
  3. requirements.txt +2 -0
README.md CHANGED
@@ -7,7 +7,13 @@ sdk: gradio
7
  sdk_version: 5.45.0
8
  app_file: app.py
9
  pinned: false
10
- short_description: Template UI for simple "in-out" text transformation jobs
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
7
  sdk_version: 5.45.0
8
  app_file: app.py
9
  pinned: false
10
+ short_description: BYOK OpenAI-powered text transformation with custom system prompts
11
  ---
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.
18
+
19
+ Overwriting text box and clipboard button for efficient manual repeat operation.
app.py ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import openai
3
+ 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
+
21
+ if not input_text.strip():
22
+ return "Error: Please provide input text to transform.", input_text
23
+
24
+ if not system_prompt.strip():
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", # Using cost-effective model
39
+ messages=[
40
+ {"role": "system", "content": enhanced_system_prompt},
41
+ {"role": "user", "content": input_text.strip()}
42
+ ],
43
+ temperature=0.7,
44
+ max_tokens=4000
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:
53
+ return "Error: Invalid OpenAI API key. Please check your key and try again.", input_text
54
+ except openai.RateLimitError:
55
+ return "Error: Rate limit exceeded. Please try again later.", input_text
56
+ except openai.APIError as e:
57
+ return f"Error: OpenAI API error - {str(e)}", input_text
58
+ except Exception as e:
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;
69
+ margin: 0 auto;
70
+ padding: 20px;
71
+ }
72
+
73
+ .input-section, .output-section, .system-prompt-section {
74
+ margin-bottom: 20px;
75
+ }
76
+
77
+ .api-key-section {
78
+ background-color: #f8f9fa;
79
+ padding: 15px;
80
+ border-radius: 8px;
81
+ margin-bottom: 20px;
82
+ border-left: 4px solid #007bff;
83
+ }
84
+
85
+ .transform-button {
86
+ background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
87
+ border: none;
88
+ color: white;
89
+ font-weight: bold;
90
+ font-size: 16px;
91
+ padding: 12px 24px;
92
+ border-radius: 8px;
93
+ cursor: pointer;
94
+ transition: all 0.3s ease;
95
+ }
96
+
97
+ .copy-button {
98
+ background: linear-gradient(45deg, #56ab2f 0%, #a8e6cf 100%);
99
+ border: none;
100
+ color: white;
101
+ font-weight: bold;
102
+ padding: 8px 16px;
103
+ border-radius: 6px;
104
+ cursor: pointer;
105
+ }
106
+
107
+ .warning-text {
108
+ color: #856404;
109
+ background-color: #fff3cd;
110
+ border: 1px solid #ffeaa7;
111
+ padding: 10px;
112
+ border-radius: 6px;
113
+ margin-bottom: 15px;
114
+ }
115
+ """
116
+
117
+ # Create the Gradio interface
118
+ with gr.Blocks(css=custom_css, title="Text Transformation Model", theme=gr.themes.Soft()) as app:
119
+ gr.HTML("""
120
+ <div style="text-align: center; margin-bottom: 30px;">
121
+ <h1 style="background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 2.5em; margin-bottom: 10px;">
122
+ πŸš€ Text Transformation Model
123
+ </h1>
124
+ <p style="font-size: 1.2em; color: #666; margin-bottom: 20px;">
125
+ Transform your text using AI with custom system prompts and your own OpenAI API key
126
+ </p>
127
+ </div>
128
+ """)
129
+
130
+ # API Key Section
131
+ with gr.Row():
132
+ with gr.Column():
133
+ gr.HTML('<div class="warning-text">⚠️ <strong>Privacy Notice:</strong> Your API key is stored locally in your browser and never sent to our servers.</div>')
134
+ api_key_input = gr.Textbox(
135
+ label="πŸ”‘ OpenAI API Key",
136
+ placeholder="Enter your OpenAI API key (sk-...)",
137
+ type="password",
138
+ info="Your API key is stored locally in your browser for this session."
139
+ )
140
+
141
+ # System Prompt Section
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.)",
147
+ lines=4,
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(
155
+ label="πŸ“ Input Text",
156
+ placeholder="Paste or type your text here...",
157
+ lines=10,
158
+ info="Enter the text you want to transform"
159
+ )
160
+
161
+ transform_btn = gr.Button(
162
+ "✨ Transform Text",
163
+ variant="primary",
164
+ size="lg",
165
+ elem_classes=["transform-button"]
166
+ )
167
+
168
+ with gr.Column(scale=1):
169
+ output_text = gr.Textbox(
170
+ label="πŸ“€ Output Text",
171
+ lines=10,
172
+ info="Transformed text will appear here",
173
+ interactive=False
174
+ )
175
+
176
+ copy_btn = gr.Button(
177
+ "πŸ“‹ Copy Output",
178
+ variant="secondary",
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] # Clear input after transformation
187
+ )
188
+
189
+ copy_btn.click(
190
+ fn=copy_to_clipboard,
191
+ inputs=[output_text],
192
+ outputs=[]
193
+ )
194
+
195
+ # Add JavaScript for clipboard functionality and local storage
196
+ gr.HTML("""
197
+ <script>
198
+ // Local storage for API key and system prompt
199
+ document.addEventListener('DOMContentLoaded', function() {
200
+ // Load saved API key and system prompt
201
+ const savedApiKey = localStorage.getItem('openai_api_key');
202
+ const savedSystemPrompt = localStorage.getItem('system_prompt');
203
+
204
+ if (savedApiKey) {
205
+ const apiKeyInput = document.querySelector('input[type="password"]');
206
+ if (apiKeyInput) apiKeyInput.value = savedApiKey;
207
+ }
208
+
209
+ if (savedSystemPrompt) {
210
+ const systemPromptInputs = document.querySelectorAll('textarea');
211
+ if (systemPromptInputs.length > 0) {
212
+ systemPromptInputs[0].value = savedSystemPrompt;
213
+ }
214
+ }
215
+
216
+ // Save API key and system prompt on change
217
+ document.addEventListener('input', function(e) {
218
+ if (e.target.type === 'password') {
219
+ localStorage.setItem('openai_api_key', e.target.value);
220
+ }
221
+ if (e.target.tagName === 'TEXTAREA' && e.target.placeholder.includes('system prompt')) {
222
+ localStorage.setItem('system_prompt', e.target.value);
223
+ }
224
+ });
225
+
226
+ // Enhanced copy functionality
227
+ document.addEventListener('click', function(e) {
228
+ if (e.target.textContent.includes('Copy Output')) {
229
+ const outputTextarea = document.querySelectorAll('textarea');
230
+ const outputText = outputTextarea[outputTextarea.length - 1].value;
231
+
232
+ if (outputText && !outputText.startsWith('Error:')) {
233
+ navigator.clipboard.writeText(outputText).then(function() {
234
+ // Visual feedback
235
+ const originalText = e.target.textContent;
236
+ e.target.textContent = 'βœ… Copied!';
237
+ e.target.style.background = 'linear-gradient(45deg, #28a745 0%, #20c997 100%)';
238
+
239
+ setTimeout(function() {
240
+ e.target.textContent = originalText;
241
+ e.target.style.background = 'linear-gradient(45deg, #56ab2f 0%, #a8e6cf 100%)';
242
+ }, 2000);
243
+ }).catch(function(err) {
244
+ console.error('Could not copy text: ', err);
245
+ alert('Copy failed. Please select and copy the text manually.');
246
+ });
247
+ } else {
248
+ alert('No valid output text to copy.');
249
+ }
250
+ }
251
+ });
252
+ });
253
+ </script>
254
+ """)
255
+
256
+ # Footer
257
+ gr.HTML("""
258
+ <div style="text-align: center; margin-top: 40px; padding: 20px; border-top: 1px solid #eee; color: #666;">
259
+ <p>πŸ’‘ <strong>Tips:</strong></p>
260
+ <ul style="text-align: left; max-width: 600px; margin: 0 auto;">
261
+ <li>Your API key and system prompt are saved locally in your browser</li>
262
+ <li>Each transformation is a single API call - the input form clears automatically</li>
263
+ <li>Use specific system prompts for better results (e.g., "Translate to Spanish", "Summarize in 3 bullet points")</li>
264
+ <li>The AI will respond with only the transformed text, no additional commentary</li>
265
+ </ul>
266
+ </div>
267
+ """)
268
+
269
+ if __name__ == "__main__":
270
+ app.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio==5.45.0
2
+ openai>=1.0.0