| import gradio as gr |
| import openai |
| import os |
| from typing import Optional, Tuple |
|
|
| def transform_text(input_text: str, system_prompt: str, api_key: str) -> Tuple[str, str]: |
| """ |
| Transform input text using OpenAI API with the provided system prompt. |
| |
| Args: |
| input_text: The text to transform |
| system_prompt: User-defined system prompt |
| api_key: OpenAI API key |
| |
| Returns: |
| Tuple of (output_text, cleared_input_text) |
| """ |
| if not api_key.strip(): |
| return "Error: Please provide your OpenAI API key.", input_text |
| |
| if not input_text.strip(): |
| return "Error: Please provide input text to transform.", input_text |
| |
| if not system_prompt.strip(): |
| return "Error: Please provide a system prompt.", input_text |
| |
| try: |
| |
| client = openai.OpenAI(api_key=api_key.strip()) |
| |
| |
| enhanced_system_prompt = f"""{system_prompt.strip()} |
| |
| 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.""" |
| |
| |
| response = client.chat.completions.create( |
| model="gpt-4o-mini", |
| messages=[ |
| {"role": "system", "content": enhanced_system_prompt}, |
| {"role": "user", "content": input_text.strip()} |
| ], |
| temperature=0.7, |
| max_tokens=4000 |
| ) |
| |
| output_text = response.choices[0].message.content |
| |
| |
| return output_text, "" |
| |
| except openai.AuthenticationError: |
| return "Error: Invalid OpenAI API key. Please check your key and try again.", input_text |
| except openai.RateLimitError: |
| return "Error: Rate limit exceeded. Please try again later.", input_text |
| except openai.APIError as e: |
| return f"Error: OpenAI API error - {str(e)}", input_text |
| except Exception as e: |
| return f"Error: {str(e)}", input_text |
|
|
| def copy_to_clipboard(text: str) -> str: |
| """Return the text for copying (Gradio handles the clipboard functionality)""" |
| return text |
|
|
| |
| custom_css = """ |
| .main-container { |
| max-width: 1200px; |
| margin: 0 auto; |
| padding: 20px; |
| } |
| |
| .input-section, .output-section, .system-prompt-section { |
| margin-bottom: 20px; |
| } |
| |
| .api-key-section { |
| background-color: #f8f9fa; |
| padding: 15px; |
| border-radius: 8px; |
| margin-bottom: 20px; |
| border-left: 4px solid #007bff; |
| } |
| |
| .transform-button { |
| background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); |
| border: none; |
| color: white; |
| font-weight: bold; |
| font-size: 16px; |
| padding: 12px 24px; |
| border-radius: 8px; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| } |
| |
| .copy-button { |
| background: linear-gradient(45deg, #56ab2f 0%, #a8e6cf 100%); |
| border: none; |
| color: white; |
| font-weight: bold; |
| padding: 8px 16px; |
| border-radius: 6px; |
| cursor: pointer; |
| } |
| |
| .warning-text { |
| color: #856404; |
| background-color: #fff3cd; |
| border: 1px solid #ffeaa7; |
| padding: 10px; |
| border-radius: 6px; |
| margin-bottom: 15px; |
| } |
| """ |
|
|
| |
| with gr.Blocks(css=custom_css, title="Text Transformation Model", theme=gr.themes.Soft()) as app: |
| gr.HTML(""" |
| <div style="text-align: center; margin-bottom: 30px;"> |
| <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;"> |
| π Text Transformation Model |
| </h1> |
| <p style="font-size: 1.2em; color: #666; margin-bottom: 20px;"> |
| Transform your text using AI with custom system prompts and your own OpenAI API key |
| </p> |
| </div> |
| """) |
| |
| |
| with gr.Row(): |
| with gr.Column(): |
| 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>') |
| api_key_input = gr.Textbox( |
| label="π OpenAI API Key", |
| placeholder="Enter your OpenAI API key (sk-...)", |
| type="password", |
| info="Your API key is stored locally in your browser for this session." |
| ) |
| |
| |
| with gr.Row(): |
| with gr.Column(): |
| system_prompt_input = gr.Textbox( |
| label="π― System Prompt", |
| placeholder="Enter your system prompt here (e.g., 'Translate the following text to French', 'Summarize this text in bullet points', etc.)", |
| lines=4, |
| info="Define how the AI should transform your input text. This prompt will be enhanced automatically for single-turn processing." |
| ) |
| |
| |
| with gr.Row(): |
| with gr.Column(scale=1): |
| input_text = gr.Textbox( |
| label="π Input Text", |
| placeholder="Paste or type your text here...", |
| lines=10, |
| info="Enter the text you want to transform" |
| ) |
| |
| transform_btn = gr.Button( |
| "β¨ Transform Text", |
| variant="primary", |
| size="lg", |
| elem_classes=["transform-button"] |
| ) |
| |
| with gr.Column(scale=1): |
| output_text = gr.Textbox( |
| label="π€ Output Text", |
| lines=10, |
| info="Transformed text will appear here", |
| interactive=False |
| ) |
| |
| copy_btn = gr.Button( |
| "π Copy Output", |
| variant="secondary", |
| elem_classes=["copy-button"] |
| ) |
| |
| |
| transform_btn.click( |
| fn=transform_text, |
| inputs=[input_text, system_prompt_input, api_key_input], |
| outputs=[output_text, input_text] |
| ) |
| |
| copy_btn.click( |
| fn=copy_to_clipboard, |
| inputs=[output_text], |
| outputs=[] |
| ) |
| |
| |
| gr.HTML(""" |
| <script> |
| // Local storage for API key and system prompt |
| document.addEventListener('DOMContentLoaded', function() { |
| // Load saved API key and system prompt |
| const savedApiKey = localStorage.getItem('openai_api_key'); |
| const savedSystemPrompt = localStorage.getItem('system_prompt'); |
| |
| if (savedApiKey) { |
| const apiKeyInput = document.querySelector('input[type="password"]'); |
| if (apiKeyInput) apiKeyInput.value = savedApiKey; |
| } |
| |
| if (savedSystemPrompt) { |
| const systemPromptInputs = document.querySelectorAll('textarea'); |
| if (systemPromptInputs.length > 0) { |
| systemPromptInputs[0].value = savedSystemPrompt; |
| } |
| } |
| |
| // Save API key and system prompt on change |
| document.addEventListener('input', function(e) { |
| if (e.target.type === 'password') { |
| localStorage.setItem('openai_api_key', e.target.value); |
| } |
| if (e.target.tagName === 'TEXTAREA' && e.target.placeholder.includes('system prompt')) { |
| localStorage.setItem('system_prompt', e.target.value); |
| } |
| }); |
| |
| // Enhanced copy functionality |
| document.addEventListener('click', function(e) { |
| if (e.target.textContent.includes('Copy Output')) { |
| const outputTextarea = document.querySelectorAll('textarea'); |
| const outputText = outputTextarea[outputTextarea.length - 1].value; |
| |
| if (outputText && !outputText.startsWith('Error:')) { |
| navigator.clipboard.writeText(outputText).then(function() { |
| // Visual feedback |
| const originalText = e.target.textContent; |
| e.target.textContent = 'β
Copied!'; |
| e.target.style.background = 'linear-gradient(45deg, #28a745 0%, #20c997 100%)'; |
| |
| setTimeout(function() { |
| e.target.textContent = originalText; |
| e.target.style.background = 'linear-gradient(45deg, #56ab2f 0%, #a8e6cf 100%)'; |
| }, 2000); |
| }).catch(function(err) { |
| console.error('Could not copy text: ', err); |
| alert('Copy failed. Please select and copy the text manually.'); |
| }); |
| } else { |
| alert('No valid output text to copy.'); |
| } |
| } |
| }); |
| }); |
| </script> |
| """) |
| |
| |
| gr.HTML(""" |
| <div style="text-align: center; margin-top: 40px; padding: 20px; border-top: 1px solid #eee; color: #666;"> |
| <p>π‘ <strong>Tips:</strong></p> |
| <ul style="text-align: left; max-width: 600px; margin: 0 auto;"> |
| <li>Your API key and system prompt are saved locally in your browser</li> |
| <li>Each transformation is a single API call - the input form clears automatically</li> |
| <li>Use specific system prompts for better results (e.g., "Translate to Spanish", "Summarize in 3 bullet points")</li> |
| <li>The AI will respond with only the transformed text, no additional commentary</li> |
| </ul> |
| </div> |
| """) |
|
|
| if __name__ == "__main__": |
| app.launch() |
|
|