import gradio as gr import re import json import os import requests SYSTEM_INSTRUCTIONS = ( "Your task is to lightly edit system prompts for AI tools to comply with a specific stylistic convention.\n\n" "## Workflow\n\n" "You will receive the prompt from the user which will contain the system prompt to be edited. Upon receiving it, you must apply the edits and return the edited system prompt back to the user.\n\n" "## Editing Instructions\n\n" "- The system prompts should be written in the second person, instructing the assistant (use 'you'/'your').\n" "- Organize with brief paragraphs and use markdown headers when helpful.\n" "- Make the prompt ecosystem-agnostic. For example: if it includes 'you are a custom GPT', replace with 'you are an assistant'.\n" "- Make the prompt suitable for any user. If you encounter language specific to one user, generalize it. For example: rewrite 'your purpose is to help Daniel find restaurant recommendations' as 'your purpose is to help the user find restaurant recommendations'.\n\n" "## Additional Outputs\n\n" "In addition to the edited system prompt, also provide:\n\n" "- A name for the assistant encapsulating its main functionality.\n" "- A short single-sentence description describing the assistant's function (you don't need to mention that it's an AI tool).\n\n" "## Output Format (JSON only)\n\n" "Return a JSON object ONLY with the following exact keys and types. Do not include explanations, code fences, or any extra text.\n\n" "{\n" " \"reformatted\": string // the edited system prompt as plain text (no backticks/code fences)\n" " ,\n" " \"name\": string // assistant name\n" " ,\n" " \"description\": string // single-sentence description\n" "}\n" ) def reformat_system_prompt_offline(input_text): """ Reformats system prompts according to the specified guidelines """ if not input_text.strip(): return "Please provide a system prompt to reformat.", "", "" # Apply reformatting logic reformatted = input_text.strip() # Convert first person to second person reformatted = re.sub(r'\bI am\b', 'You are', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'\bI will\b', 'You will', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'\bI should\b', 'You should', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'\bI can\b', 'You can', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'\bI must\b', 'You must', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'\bmy task\b', 'your task', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'\bmy role\b', 'your role', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'\bmy purpose\b', 'your purpose', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'\bmy job\b', 'your job', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'\bmy goal\b', 'your goal', reformatted, flags=re.IGNORECASE) # Make ecosystem-agnostic reformatted = re.sub(r'custom GPT', 'assistant', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'ChatGPT', 'assistant', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'GPT-4', 'assistant', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'GPT model', 'assistant', reformatted, flags=re.IGNORECASE) reformatted = re.sub(r'OpenAI', 'AI', reformatted, flags=re.IGNORECASE) # Generalize user-specific language reformatted = re.sub(r'help [A-Z][a-z]+ ', 'help the user ', reformatted) reformatted = re.sub(r'assist [A-Z][a-z]+ ', 'assist the user ', reformatted) reformatted = re.sub(r'for [A-Z][a-z]+\'s', 'for the user\'s', reformatted) # Generate assistant name (extract main functionality) name = extract_assistant_name(reformatted) # Generate description description = extract_description(reformatted) return reformatted, name, description def reformat_system_prompt_llm(input_text: str, api_key: str): """ Use an LLM (OpenAI-compatible chat.completions) to reformat the prompt and produce name + description. Returns (reformatted_md, name, description). - api_key: user-provided OpenAI API key (not stored). Uses gpt-4o-mini. """ if not input_text.strip(): return "Please provide a system prompt to reformat.", "", "" if not api_key: # Try environment fallback (Space secret) before giving up api_key = os.environ.get("OPENAI_API_KEY", "").strip() if not api_key: # Fallback to offline if key still missing return reformat_system_prompt_offline(input_text) base_url = (os.environ.get("OPENAI_BASE_URL") or "https://api.openai.com/v1").rstrip("/") url = f"{base_url}/chat/completions" messages = [ {"role": "system", "content": SYSTEM_INSTRUCTIONS}, {"role": "user", "content": input_text.strip()}, ] payload = { "model": "gpt-4o-mini", "messages": messages, "temperature": 0.2, "response_format": {"type": "json_object"}, } headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} try: resp = requests.post(url, headers=headers, data=json.dumps(payload), timeout=30) if resp.status_code != 200: # Graceful fallback return reformat_system_prompt_offline(input_text) data = resp.json() content = data["choices"][0]["message"]["content"] parsed = json.loads(content) reformatted = parsed.get("reformatted", "").strip() name = parsed.get("name", "AI Assistant").strip() description = parsed.get("description", "Provides AI assistance for various tasks.").strip() if not reformatted: return reformat_system_prompt_offline(input_text) return reformatted, name, description except Exception: # Any parsing/network error → fallback return reformat_system_prompt_offline(input_text) def reformat_system_prompt(input_text, api_key): """ Use LLM if an API key is provided (or available via OPENAI_API_KEY), otherwise use the offline heuristic. """ live_key = api_key or os.environ.get("OPENAI_API_KEY", "").strip() if live_key: return reformat_system_prompt_llm(input_text, live_key) else: return reformat_system_prompt_offline(input_text) def extract_assistant_name(text): """ Extract a name for the assistant based on its functionality """ # Look for key phrases that indicate functionality if 'travel' in text.lower() and 'quiet' in text.lower(): return "Quiet Study Finder" elif 'system prompt' in text.lower() and 'reformat' in text.lower(): return "System Prompt Reformatter" elif 'code' in text.lower() and 'review' in text.lower(): return "Code Reviewer" elif 'writing' in text.lower() and 'assistant' in text.lower(): return "Writing Assistant" elif 'travel' in text.lower(): return "Travel Assistant" elif 'restaurant' in text.lower(): return "Restaurant Finder" elif 'recipe' in text.lower() or 'cooking' in text.lower(): return "Recipe Assistant" elif 'learning' in text.lower() or 'tutor' in text.lower(): return "Learning Assistant" elif 'email' in text.lower(): return "Email Assistant" elif 'schedule' in text.lower() or 'calendar' in text.lower(): return "Schedule Assistant" else: return "AI Assistant" def extract_description(text): """ Generate a single-sentence description of the assistant's function """ # Try to find purpose statements if 'purpose' in text.lower(): match = re.search(r'purpose is to ([^.]+)', text.lower()) if match: return f"Helps users {match.group(1).strip()}." if 'help' in text.lower(): match = re.search(r'help.*?users?.*?(?:to )?([^.]+)', text.lower()) if match: return f"Helps users {match.group(1).strip()}." if 'assist' in text.lower(): match = re.search(r'assist.*?users?.*?(?:with|in) ([^.]+)', text.lower()) if match: return f"Assists users with {match.group(1).strip()}." # Fallback generic description return "Provides AI assistance for various tasks." # Create the Gradio interface with gr.Blocks(title="System Prompt Reformatter", theme=gr.themes.Soft(primary_hue="indigo", radius_size="lg")) as demo: gr.HTML("
Transform system prompts to second person and make them ecosystem-agnostic
") # Light monospace styling for text areas gr.HTML( """ """ ) # API key beneath subtitle within an Advanced accordion with gr.Accordion("Advanced", open=False): api_key = gr.Textbox( label="OpenAI API Key (optional)", placeholder="sk-... Leave blank to use offline reformatter", type="password", info="Tip: Set Space Secret OPENAI_API_KEY to avoid typing your key. The key is only used for this session." ) with gr.Tabs(): with gr.Tab("App"): with gr.Row(): with gr.Column(scale=1): input_text = gr.Textbox( label="Original System Prompt", placeholder="Paste your system prompt here...", lines=10, max_lines=20 ) submit_btn = gr.Button("Reformat Prompt", variant="primary") status_info = gr.Markdown(visible=False) with gr.Column(scale=1): # Output order: Name -> Description -> System Prompt assistant_name_md = gr.Markdown() assistant_name_copy = gr.Textbox( label="Name", interactive=False, show_copy_button=True ) description = gr.Textbox( label="Description", interactive=False, show_copy_button=True, elem_classes=["monospace"], ) output_text = gr.Textbox( label="Reformatted System Prompt", lines=10, max_lines=20, interactive=False, show_copy_button=True, elem_classes=["monospace"], ) export_md = gr.Textbox( label="Export (Markdown)", lines=10, max_lines=20, interactive=False, show_copy_button=True, elem_classes=["monospace"], ) export_json = gr.Textbox( label="Export (JSON)", lines=10, max_lines=20, interactive=False, show_copy_button=True, elem_classes=["monospace"], ) clear_btn = gr.Button("Clear") # Wrapper to format outputs for UI ordering and bold name def reformat_system_prompt_for_ui(input_text_val, api_key_val): reformatted, name, desc = reformat_system_prompt(input_text_val, api_key_val) name_md = f"**{name}**" if name else "" export_markdown = ( f"## NAME\n\n{name}\n\n" f"## DESCRIPTION\n\n{desc}\n\n" f"## SYSTEM PROMPT\n\n{reformatted}" ) export_json_str = json.dumps({ "name": name, "description": desc, "reformatted": reformatted, }, indent=2) # Status: show offline note if no API key provided using_key = bool((api_key_val or "").strip() or os.environ.get("OPENAI_API_KEY", "").strip()) status = gr.update(visible=not using_key, value=("Using offline reformatter (no API key provided)." if not using_key else "")) return name_md, name, desc, reformatted, export_markdown, export_json_str, status submit_btn.click( fn=reformat_system_prompt_for_ui, inputs=[input_text, api_key], outputs=[assistant_name_md, assistant_name_copy, description, output_text, export_md, export_json, status_info] ) # Submit on Enter input_text.submit( fn=reformat_system_prompt_for_ui, inputs=[input_text, api_key], outputs=[assistant_name_md, assistant_name_copy, description, output_text, export_md, export_json, status_info] ) # Clear button resets input and outputs def clear_all(): return "", "", "", "", "", "", "", gr.update(visible=False, value="") clear_btn.click( fn=clear_all, inputs=None, outputs=[input_text, assistant_name_md, assistant_name_copy, description, output_text, export_md, export_json, status_info] ) # Add quick input example (fills the App input) gr.Examples( examples=[ ["I am a travel assistant. My purpose is to help Daniel find quiet places to study in busy cities. I should provide recommendations for libraries, cafes, and other quiet spaces."] ], inputs=input_text, label="Example" ) with gr.Tab("About"): gr.Markdown(""" # System Prompt Reformatter This tool reformats system prompts for AI assistants to follow specific stylistic conventions. ## The System Prompt Used by This Tool """) gr.Textbox( label="System Prompt (copyable)", value=SYSTEM_INSTRUCTIONS.strip(), lines=20, max_lines=40, interactive=False, show_copy_button=True ) gr.Markdown(""" ## How It Works - Converts first-person language ("I am", "my task") to second-person ("You are", "your task"). - Replaces platform-specific terms like "custom GPT" with generic "assistant". - Generalizes user-specific references to "the user". - Generates an assistant name and single-sentence description. Copy buttons are available for all output fields. """) with gr.Tab("Example"): gr.Markdown("### End-to-End Example (voice-captured input)") example_before_text = ( "I would like to create an AI assistant whose purpose is taking a list of different agents that I'll provide as a document, describing the list of agents and a short summary of the functionality of each. and it should return a document which suggests how they could be deployed into a multi-agent framework with specific patterns of delegation. In other words, it will take the list I provided and, if possible, identify the agent that could serve as the primary orchestrator, sub-orchestrators, and within under them, individual agents. It can present this information as it wishes, so long as the output is in readable markdown. That might take the format of basic diagrams showing the nesting, or it could use narrative or it could do both, but I'll provide the first and then it should return that as an output." ) gr.Textbox( label="Before", value=example_before_text, lines=10, max_lines=20, interactive=False, show_copy_button=True, elem_classes=["monospace"], ) example_after_text = ( "## NAME\n\n" "Multi-Agent Framework Advisor\n\n" "## DESCRIPTION\n\n" "This assistant helps organize and deploy agents within a multi-agent framework.\n\n" "## SYSTEM PROMPT\n\n" "You are an assistant designed to analyze a list of different agents provided in a document. Your task is to summarize the functionality of each agent and suggest how they could be deployed within a multi-agent framework, including specific patterns of delegation.\n\n" "You will identify the agent that could serve as the primary orchestrator, sub-orchestrators, and the individual agents beneath them. Present this information in a readable markdown format, which may include basic diagrams to illustrate the nesting or a narrative description, or both, based on the information you receive." ) gr.Textbox( label="After", value=example_after_text, lines=18, max_lines=36, interactive=False, show_copy_button=True, elem_classes=["monospace"], ) load_btn = gr.Button("Load 'Before' into App") load_btn.click(lambda: example_before_text, inputs=None, outputs=input_text) if __name__ == "__main__": demo.launch()