Svngoku commited on
Commit
d7ea2f7
·
verified ·
1 Parent(s): 189d757

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +183 -262
app.py CHANGED
@@ -1,8 +1,6 @@
1
- import gradio as gr
2
- from dotenv import load_dotenv
3
  import os
4
- import logging
5
- from typing import Dict, Any, Optional
6
  from proctor import (
7
  CompositeTechnique,
8
  RolePrompting,
@@ -10,60 +8,51 @@ from proctor import (
10
  ChainOfVerification,
11
  SelfAsk,
12
  EmotionPrompting,
13
- ZeroShotCoT,
14
  list_techniques,
15
  )
16
 
17
- # Configure logging
18
- logging.basicConfig(level=logging.INFO)
19
- logger = logging.getLogger(__name__)
20
-
21
- # Load environment variables
22
  load_dotenv()
23
-
24
- # Check for OpenRouter API key
25
  openrouter_key = os.environ.get("OPENROUTER_API_KEY")
26
- if not openrouter_key:
27
- raise ValueError("OPENROUTER_API_KEY not set. Please set it in your .env file.")
28
 
29
- # Available models and techniques
30
- MODELS = {
31
- "Google Gemini 2.5 Flash": "openrouter/google/gemini-2.5-flash-preview-05-20",
32
- "Claude 4 Sonnet": "openrouter/anthropic/claude-sonnet-4",
33
- "DeepSeek R1": "openrouter/deepseek/deepseek-r1-0528",
34
- "Llama 4 Scout": "openrouter/meta-llama/llama-4-scout",
35
- "Mistral Small 3.1 24B": "openrouter/mistralai/mistral-small-3.1-24b-instruct",
36
- }
37
-
38
- TECHNIQUES = list_techniques()
39
 
40
- # Model configurations with optimized parameters
41
  MODEL_CONFIGS = {
42
- "openrouter/google/gemini-2.5-flash-preview-05-20": {
 
43
  "api_base": "https://openrouter.ai/api/v1",
44
  "api_key": openrouter_key,
45
  "temperature": 0.3,
46
- "max_tokens": 15000,
47
  },
48
- "openrouter/anthropic/claude-sonnet-4": {
 
49
  "api_base": "https://openrouter.ai/api/v1",
50
  "api_key": openrouter_key,
51
  "temperature": 0.7,
52
- "max_tokens": 12000,
53
  },
54
- "openrouter/deepseek/deepseek-r1-0528": {
 
55
  "api_base": "https://openrouter.ai/api/v1",
56
  "api_key": openrouter_key,
57
  "temperature": 0.6,
58
- "max_tokens": 8000,
59
  },
60
- "openrouter/meta-llama/llama-4-scout": {
 
61
  "api_base": "https://openrouter.ai/api/v1",
62
  "api_key": openrouter_key,
63
  "temperature": 0.6,
64
- "max_tokens": 12500,
65
  },
66
- "openrouter/mistralai/mistral-small-3.1-24b-instruct": {
 
67
  "api_base": "https://openrouter.ai/api/v1",
68
  "api_key": openrouter_key,
69
  "temperature": 0.8,
@@ -71,251 +60,183 @@ MODEL_CONFIGS = {
71
  },
72
  }
73
 
74
- # Composite technique definitions
75
- TECHNIQUE_CONFIGS = {
76
- "Expert Chain-of-Thought": CompositeTechnique(
 
 
 
 
77
  name="Expert Chain-of-Thought",
78
  identifier="custom-expert-cot",
79
- techniques=[RolePrompting(), ChainOfThought(), ChainOfVerification()],
80
- ),
81
- "Deep Reasoning Analysis": CompositeTechnique(
82
- name="Deep Reasoning Analysis",
83
- identifier="deep-reasoning",
84
- techniques=[ChainOfThought(), SelfAsk(), ChainOfVerification()],
85
- ),
86
- "ChainOfThought": ChainOfThought(),
87
- "EmotionPrompting": EmotionPrompting(),
88
- "RolePrompting": RolePrompting(),
89
- "SelfAsk": SelfAsk(),
90
- "ZeroShotCoT": ZeroShotCoT(),
91
- }
 
 
 
92
 
93
- def format_as_markdown(response: str) -> str:
94
  """
95
- Format the response as Markdown for better readability.
96
-
97
- Args:
98
- response: The raw response text to format
99
-
100
- Returns:
101
- Formatted markdown string
102
  """
103
- if not response:
104
- return ""
105
-
106
- lines = response.split("\n")
107
- formatted_lines = []
108
- in_list = False
109
-
110
- for line in lines:
111
- line = line.strip()
112
- if not line:
113
- in_list = False
114
- formatted_lines.append("")
115
- continue
116
-
117
- # Check for headings (e.g., "Target Market:")
118
- if line.endswith(":") and not line.startswith("-") and len(line) < 100:
119
- formatted_lines.append(f"### {line}")
120
- continue
121
-
122
- # Check for list items (e.g., "- Item" or "1. Item")
123
- if line.startswith("-") or (line and line[0].isdigit() and len(line) > 2 and line[1:3] in [". ", ".("]):
124
- in_list = True
125
- formatted_lines.append(line)
126
- continue
127
-
128
- # If not a heading or list item, treat as a paragraph
129
- if in_list:
130
- in_list = False
131
- formatted_lines.append("")
132
- formatted_lines.append(line)
133
-
134
- return "\n".join(formatted_lines)
135
 
136
- def validate_inputs(problem: str, technique_name: str, model_name: str) -> Optional[str]:
137
  """
138
- Validate user inputs and return error message if invalid.
139
-
140
- Args:
141
- problem: The problem statement
142
- technique_name: Selected technique name
143
- model_name: Selected model name
144
-
145
- Returns:
146
- Error message if validation fails, None otherwise
147
  """
148
- if not problem or not problem.strip():
149
- return "Please enter a problem statement."
150
-
151
- if technique_name not in TECHNIQUE_CONFIGS:
152
- return f"Technique '{technique_name}' not found."
153
-
154
- if model_name not in MODELS:
155
- return f"Model '{model_name}' not found."
156
-
157
- return None
 
 
 
 
 
158
 
159
- def process_problem(
160
- problem: str,
161
- technique_name: str,
162
- model_name: str,
163
- role: str = "",
164
- emotion: str = ""
165
- ) -> str:
166
  """
167
- Process the problem using the selected technique and model.
168
-
169
- Args:
170
- problem: The problem statement to solve
171
- technique_name: Name of the prompting technique to use
172
- model_name: Name of the model to use
173
- role: Role for role prompting (optional)
174
- emotion: Emotion for emotion prompting (optional)
175
-
176
- Returns:
177
- Formatted response or error message
178
  """
179
- # Validate inputs
180
- validation_error = validate_inputs(problem, technique_name, model_name)
181
- if validation_error:
182
- return f"**Error**: {validation_error}"
183
-
184
- technique = TECHNIQUE_CONFIGS[technique_name]
185
- model_id = MODELS[model_name]
186
- llm_config = MODEL_CONFIGS[model_id]
187
-
188
- try:
189
- # Prepare kwargs for technique execution
190
- kwargs = {"llm_config": llm_config}
191
-
192
- # Add technique-specific parameters
193
- if technique_name == "RolePrompting":
194
- kwargs["role"] = role.strip() or "Expert"
195
- elif technique_name == "EmotionPrompting":
196
- kwargs["emotion"] = emotion.strip() or "thoughtful and methodical"
197
- elif technique_name == "Expert Chain-of-Thought":
198
- kwargs["role"] = role.strip() or "Expert"
199
-
200
- logger.info(f"Processing problem with {technique_name} using {model_name}")
201
- response = technique.execute(problem.strip(), **kwargs)
202
-
203
- # Format and return the response
204
- markdown_response = format_as_markdown(response)
205
- logger.info("Successfully processed problem")
206
- return markdown_response
207
-
208
- except Exception as e:
209
- error_msg = f"Error processing request: {str(e)}"
210
- logger.error(error_msg)
211
- return f"**Error**: {error_msg}"
212
 
213
- def update_input_visibility(technique: str) -> Dict[str, Any]:
214
  """
215
- Update visibility of role and emotion inputs based on selected technique.
216
-
217
- Args:
218
- technique: Selected technique name
219
-
220
- Returns:
221
- Dictionary with visibility updates for inputs
222
  """
223
- show_role = technique in ["RolePrompting", "Expert Chain-of-Thought"]
224
- show_emotion = technique == "EmotionPrompting"
225
-
 
 
 
226
  return {
227
- role_input: gr.update(visible=show_role),
228
- emotion_input: gr.update(visible=show_emotion)
 
229
  }
230
 
231
- # Create Gradio interface with improved styling
232
- with gr.Blocks(
233
- title="Proctor AI Prompt Engineering App",
234
- theme=gr.themes.Soft(),
235
- css="""
236
- .gradio-container {
237
- max-width: 1200px !important;
238
- margin: auto !important;
239
- }
240
  """
241
- ) as interface:
242
- gr.Markdown(
243
- """
244
- # 🤖 Proctor AI Prompt Engineering App
245
-
246
- **Enhance your problem-solving with advanced AI prompting techniques**
247
-
248
- Enter a problem, select a technique and model, and get intelligent responses powered by OpenRouter.
249
- """
250
- )
251
-
252
- with gr.Row():
253
- with gr.Column(scale=2):
254
- problem_input = gr.Textbox(
255
- label="Problem Statement",
256
- placeholder="e.g., How to build a sustainable house for a family of 4?",
257
- lines=3,
258
- max_lines=5
259
- )
260
-
261
- with gr.Row():
262
- technique_dropdown = gr.Dropdown(
263
- choices=list(TECHNIQUE_CONFIGS.keys()),
264
- label="Prompting Technique",
265
- value=list(TECHNIQUE_CONFIGS.keys())[0] if TECHNIQUE_CONFIGS else None
266
- )
267
- model_dropdown = gr.Dropdown(
268
- choices=list(MODELS.keys()),
269
- label="Model",
270
- value=list(MODELS.keys())[0] if MODELS else None
271
- )
272
-
273
- role_input = gr.Textbox(
274
- label="Role (for RolePrompting or Expert CoT)",
275
- placeholder="e.g., Expert Architect",
276
- visible=False
277
- )
278
- emotion_input = gr.Textbox(
279
- label="Emotion (for EmotionPrompting)",
280
- placeholder="e.g., thoughtful and methodical",
281
- visible=False
282
- )
283
-
284
- submit_button = gr.Button(
285
- "🚀 Generate Response",
286
- variant="primary",
287
- size="lg"
288
- )
289
-
290
- with gr.Column(scale=3):
291
- output = gr.Markdown(
292
- label="Response",
293
- value="*Your response will appear here...*"
294
- )
295
-
296
- # Event handlers
297
- technique_dropdown.change(
298
- fn=update_input_visibility,
299
- inputs=technique_dropdown,
300
- outputs=[role_input, emotion_input]
301
- )
302
-
303
- submit_button.click(
304
- fn=process_problem,
305
- inputs=[problem_input, technique_dropdown, model_dropdown, role_input, emotion_input],
306
- outputs=output
307
- )
308
-
309
- # Add examples
310
- gr.Examples(
311
- examples=[
312
- ["How can I improve team productivity in a remote work environment?", "Expert Chain-of-Thought", "Claude 4 Sonnet", "Management Consultant", ""],
313
- ["What are the key factors to consider when starting a tech startup?", "Deep Reasoning Analysis", "Google Gemini 2.5 Flash", "", ""],
314
- ["How do I create a sustainable garden in a small urban space?", "RolePrompting", "DeepSeek R1", "Urban Gardening Expert", ""],
315
- ],
316
- inputs=[problem_input, technique_dropdown, model_dropdown, role_input, emotion_input],
317
- )
 
318
 
319
- # Launch the app
320
  if __name__ == "__main__":
321
- interface.launch(mcp_server=True)
 
 
 
1
  import os
2
+ from dotenv import load_dotenv
3
+ import gradio as gr
4
  from proctor import (
5
  CompositeTechnique,
6
  RolePrompting,
 
8
  ChainOfVerification,
9
  SelfAsk,
10
  EmotionPrompting,
 
11
  list_techniques,
12
  )
13
 
14
+ # Load environment variables (.env should contain OPENROUTER_API_KEY)
 
 
 
 
15
  load_dotenv()
 
 
16
  openrouter_key = os.environ.get("OPENROUTER_API_KEY")
 
 
17
 
18
+ # Check API key
19
+ if not openrouter_key:
20
+ raise RuntimeError(
21
+ " OPENROUTER_API_KEY not set. Please set it in your .env file."
22
+ )
 
 
 
 
 
23
 
24
+ # ----- Model Configs -----
25
  MODEL_CONFIGS = {
26
+ "gemini": {
27
+ "model": "openrouter/google/gemini-2.5-flash-preview-05-20",
28
  "api_base": "https://openrouter.ai/api/v1",
29
  "api_key": openrouter_key,
30
  "temperature": 0.3,
31
+ "max_tokens": 1500,
32
  },
33
+ "claude": {
34
+ "model": "openrouter/anthropic/claude-sonnet-4",
35
  "api_base": "https://openrouter.ai/api/v1",
36
  "api_key": openrouter_key,
37
  "temperature": 0.7,
38
+ "max_tokens": 2000,
39
  },
40
+ "deepseek": {
41
+ "model": "openrouter/deepseek/deepseek-r1-0528",
42
  "api_base": "https://openrouter.ai/api/v1",
43
  "api_key": openrouter_key,
44
  "temperature": 0.6,
45
+ "max_tokens": 3000,
46
  },
47
+ "llama": {
48
+ "model": "openrouter/meta-llama/llama-4-scout",
49
  "api_base": "https://openrouter.ai/api/v1",
50
  "api_key": openrouter_key,
51
  "temperature": 0.6,
52
+ "max_tokens": 2500,
53
  },
54
+ "mistral": {
55
+ "model": "openrouter/mistralai/mistral-small-3.1-24b-instruct",
56
  "api_base": "https://openrouter.ai/api/v1",
57
  "api_key": openrouter_key,
58
  "temperature": 0.8,
 
60
  },
61
  }
62
 
63
+ # ----- Tool Functions -----
64
+
65
+ def proctor_expert_cot(problem: str) -> dict:
66
+ """
67
+ Chain-of-Thought, Verification, and Role Prompting on Gemini.
68
+ """
69
+ technique = CompositeTechnique(
70
  name="Expert Chain-of-Thought",
71
  identifier="custom-expert-cot",
72
+ techniques=[
73
+ RolePrompting(),
74
+ ChainOfThought(),
75
+ ChainOfVerification(),
76
+ ],
77
+ )
78
+ response = technique.execute(
79
+ problem,
80
+ llm_config=MODEL_CONFIGS["gemini"],
81
+ role="Expert House Builder and Construction Manager"
82
+ )
83
+ return {
84
+ "model": "Google Gemini 2.5 Flash",
85
+ "technique": "Expert Chain-of-Thought",
86
+ "response": response
87
+ }
88
 
89
+ def proctor_claude_cot(problem: str) -> dict:
90
  """
91
+ Chain-of-Thought with Claude 4 Sonnet.
 
 
 
 
 
 
92
  """
93
+ technique = ChainOfThought()
94
+ response = technique.execute(problem, llm_config=MODEL_CONFIGS["claude"])
95
+ return {
96
+ "model": "Claude 4 Sonnet",
97
+ "technique": "Chain-of-Thought",
98
+ "response": response
99
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
+ def proctor_deepseek_reasoning(problem: str) -> dict:
102
  """
103
+ Deep reasoning with DeepSeek R1: CoT, SelfAsk, Verification.
 
 
 
 
 
 
 
 
104
  """
105
+ technique = CompositeTechnique(
106
+ name="Deep Reasoning Analysis",
107
+ identifier="deep-reasoning",
108
+ techniques=[
109
+ ChainOfThought(),
110
+ SelfAsk(),
111
+ ChainOfVerification(),
112
+ ],
113
+ )
114
+ response = technique.execute(problem, llm_config=MODEL_CONFIGS["deepseek"])
115
+ return {
116
+ "model": "DeepSeek R1",
117
+ "technique": "Deep Reasoning Analysis",
118
+ "response": response
119
+ }
120
 
121
+ def proctor_llama_emotion(problem: str) -> dict:
 
 
 
 
 
 
122
  """
123
+ Emotion Prompting with Llama 4 Scout.
 
 
 
 
 
 
 
 
 
 
124
  """
125
+ technique = EmotionPrompting()
126
+ response = technique.execute(
127
+ problem,
128
+ llm_config=MODEL_CONFIGS["llama"],
129
+ emotion="thoughtful and methodical"
130
+ )
131
+ return {
132
+ "model": "Llama 4 Scout",
133
+ "technique": "Emotion Prompting",
134
+ "response": response
135
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
+ def proctor_mistral_tips(problem: str) -> dict:
138
  """
139
+ Fast Role Prompting with Mistral Small (for quick suggestions).
 
 
 
 
 
 
140
  """
141
+ technique = RolePrompting()
142
+ response = technique.execute(
143
+ problem,
144
+ llm_config=MODEL_CONFIGS["mistral"],
145
+ role="Construction Project Manager"
146
+ )
147
  return {
148
+ "model": "Mistral Small 3.1 24B",
149
+ "technique": "Role Prompting",
150
+ "response": response
151
  }
152
 
153
+ # Optionally, expose a unified tool for arbitrary model/technique selection:
154
+ def proctor_flexible(
155
+ problem: str,
156
+ model: str = "gemini",
157
+ technique: str = "ChainOfThought",
158
+ role: str = "",
159
+ emotion: str = ""
160
+ ) -> dict:
 
161
  """
162
+ Flexible interface for any model/technique combo.
163
+ """
164
+ technique_map = {
165
+ "ChainOfThought": ChainOfThought,
166
+ "RolePrompting": RolePrompting,
167
+ "EmotionPrompting": EmotionPrompting,
168
+ "SelfAsk": SelfAsk,
169
+ "ChainOfVerification": ChainOfVerification,
170
+ }
171
+ if technique == "CompositeExpert":
172
+ tech = CompositeTechnique(
173
+ name="Expert Chain-of-Thought",
174
+ identifier="custom-expert-cot",
175
+ techniques=[
176
+ RolePrompting(),
177
+ ChainOfThought(),
178
+ ChainOfVerification(),
179
+ ],
180
+ )
181
+ response = tech.execute(problem, llm_config=MODEL_CONFIGS[model], role=role)
182
+ elif technique == "DeepReasoning":
183
+ tech = CompositeTechnique(
184
+ name="Deep Reasoning Analysis",
185
+ identifier="deep-reasoning",
186
+ techniques=[
187
+ ChainOfThought(),
188
+ SelfAsk(),
189
+ ChainOfVerification(),
190
+ ],
191
+ )
192
+ response = tech.execute(problem, llm_config=MODEL_CONFIGS[model])
193
+ else:
194
+ tech_cls = technique_map.get(technique, ChainOfThought)
195
+ if technique == "RolePrompting":
196
+ response = tech_cls().execute(problem, llm_config=MODEL_CONFIGS[model], role=role)
197
+ elif technique == "EmotionPrompting":
198
+ response = tech_cls().execute(problem, llm_config=MODEL_CONFIGS[model], emotion=emotion)
199
+ else:
200
+ response = tech_cls().execute(problem, llm_config=MODEL_CONFIGS[model])
201
+ return {
202
+ "model": MODEL_CONFIGS[model]["model"],
203
+ "technique": technique,
204
+ "response": response
205
+ }
206
+
207
+ # ----- Gradio/MCP Interface -----
208
+
209
+ with gr.Blocks() as demo:
210
+ gr.Markdown("# 🏗️ Proctor AI MCP Server\nAdvanced prompt engineering tools via OpenRouter and Proctor AI.\n\n*Try from an MCP-compatible client or the web UI below!*")
211
+ with gr.Tab("Gemini (Expert CoT)"):
212
+ gr.Interface(fn=proctor_expert_cot, inputs=gr.Textbox(label="Problem"), outputs=gr.JSON(), allow_flagging="never")
213
+ with gr.Tab("Claude 4 (Chain-of-Thought)"):
214
+ gr.Interface(fn=proctor_claude_cot, inputs=gr.Textbox(label="Problem"), outputs=gr.JSON(), allow_flagging="never")
215
+ with gr.Tab("DeepSeek R1 (Deep Reasoning)"):
216
+ gr.Interface(fn=proctor_deepseek_reasoning, inputs=gr.Textbox(label="Problem"), outputs=gr.JSON(), allow_flagging="never")
217
+ with gr.Tab("Llama 4 (Emotion Prompting)"):
218
+ gr.Interface(fn=proctor_llama_emotion, inputs=gr.Textbox(label="Problem"), outputs=gr.JSON(), allow_flagging="never")
219
+ with gr.Tab("Mistral (Quick Tips)"):
220
+ gr.Interface(fn=proctor_mistral_tips, inputs=gr.Textbox(label="Problem (tips request)"), outputs=gr.JSON(), allow_flagging="never")
221
+ with gr.Tab("Flexible (Advanced)"):
222
+ model_dropdown = gr.Dropdown(choices=list(MODEL_CONFIGS.keys()), value="gemini", label="Model")
223
+ technique_dropdown = gr.Dropdown(
224
+ choices=["ChainOfThought", "RolePrompting", "EmotionPrompting", "SelfAsk", "ChainOfVerification", "CompositeExpert", "DeepReasoning"],
225
+ value="ChainOfThought",
226
+ label="Technique"
227
+ )
228
+ role_input = gr.Textbox(label="Role (optional)", value="")
229
+ emotion_input = gr.Textbox(label="Emotion (optional)", value="")
230
+ flexible_iface = gr.Interface(
231
+ fn=proctor_flexible,
232
+ inputs=[gr.Textbox(label="Problem"),
233
+ model_dropdown,
234
+ technique_dropdown,
235
+ role_input,
236
+ emotion_input],
237
+ outputs=gr.JSON(),
238
+ allow_flagging="never"
239
+ )
240
 
 
241
  if __name__ == "__main__":
242
+ demo.launch(mcp_server=True)