ZENLLC commited on
Commit
f55ced2
·
verified ·
1 Parent(s): 32b5e7b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +134 -82
app.py CHANGED
@@ -5,85 +5,116 @@ import openai
5
  # --------------- PRESETS ---------------
6
 
7
  PRESETS = {
8
- "Executive Summary":
9
- {
10
- "system": (
11
- "You are an executive briefing assistant. "
12
- "Turn complex text into a concise 3–5 bullet executive summary "
13
- "with clear insights and recommendations."
14
- ),
15
- "user": "Paste a long report, transcript, or document here and I'll summarize it."
16
- },
17
- "Polished Email Reply":
18
- {
19
- "system": (
20
- "You are a professional communications assistant. "
21
- "Write clear, concise, and friendly emails suitable for executives. "
22
- "Preserve tone and key details."
23
- ),
24
- "user": "Paste the email you received and a few notes on how you want to respond."
25
- },
26
- "Meeting Notes Action Plan":
27
- {
28
- "system": (
29
- "You convert messy meeting notes into a clear action-oriented summary. "
30
- "Always include: 1) Key decisions, 2) Action items with owners and timelines, "
31
- "3) Risks or next steps."
32
- ),
33
- "user": "Paste your rough meeting notes or bullet points and I'll structure them."
34
- },
35
- "Idea Generator / Brainstorm":
36
- {
37
- "system": (
38
- "You are a creative strategist. Generate structured ideas with titles, "
39
- "descriptions, and next steps."
40
- ),
41
- "user": "Describe what you want to build, improve, or launch. I'll propose ideas."
42
- },
43
  }
44
 
 
45
  # --------------- CORE CHAT LOGIC ---------------
46
 
47
- def run_completion(api_key, model, system_prompt, user_prompt, temperature, history):
 
 
 
 
 
 
 
 
 
 
 
48
  if not api_key:
49
- raise gr.Error("🔑 Please save your API key first.")
 
 
 
50
 
51
  if not user_prompt.strip():
52
- raise gr.Error("✏️ Add a prompt or select a preset before running.")
 
 
 
 
 
53
 
54
- openai.api_key = api_key
55
  messages = []
56
  if system_prompt.strip():
57
  messages.append({"role": "system", "content": system_prompt.strip()})
58
  messages.append({"role": "user", "content": user_prompt.strip()})
59
 
60
- # GPT-5 models use max_completion_tokens instead of max_tokens
61
- response = openai.chat.completions.create(
62
- model=model,
63
- messages=messages,
64
- temperature=float(temperature),
65
- max_completion_tokens=1200,
66
- )
 
 
 
 
 
67
 
68
- answer = response.choices[0].message.content.strip()
69
- history = history or []
70
  history.append(("You", user_prompt))
71
  history.append(("Assistant", answer))
 
72
  return history, answer
73
 
74
 
75
  # --------------- HELPERS ---------------
76
 
77
- def save_api_key(raw_key):
78
- cleaned = raw_key.strip()
 
 
 
 
 
79
  if not cleaned:
80
- raise gr.Error("🔐 Please paste a valid API key.")
 
81
  if not cleaned.startswith("sk-"):
82
  gr.Info("Key saved, but it doesn’t start with 'sk-'. Double-check your provider format.")
 
 
83
  return cleaned, gr.update(value="", placeholder="API key saved ✔")
84
 
85
 
86
- def load_preset(preset_name):
 
 
 
87
  if not preset_name or preset_name not in PRESETS:
88
  return gr.update(), gr.update()
89
  preset = PRESETS[preset_name]
@@ -96,21 +127,21 @@ CUSTOM_CSS = """
96
  #zen-root {
97
  background: radial-gradient(circle at top left, #111827, #020617 65%);
98
  color: #f3f4f6;
99
- font-family: 'Inter', system-ui, sans-serif;
100
  min-height: 100vh;
101
  }
102
  .zen-card {
103
  border-radius: 20px;
104
- background: rgba(17, 24, 39, 0.6);
105
- border: 1px solid rgba(255,255,255,0.08);
106
- backdrop-filter: blur(16px);
107
- box-shadow: 0 0 40px rgba(0,0,0,0.35);
108
- padding: 1.75rem;
109
  }
110
  .zen-pill {
111
  border-radius: 9999px;
112
- padding: 0.3rem 0.9rem;
113
- border: 1px solid rgba(255,255,255,0.15);
114
  color: #a5b4fc;
115
  font-size: 0.75rem;
116
  text-transform: uppercase;
@@ -119,18 +150,29 @@ CUSTOM_CSS = """
119
  .zen-title {
120
  font-size: 1.9rem;
121
  font-weight: 700;
122
- letter-spacing: -0.02em;
 
 
 
 
123
  }
124
  """
125
 
126
- with gr.Blocks(css=CUSTOM_CSS, elem_id="zen-root", fill_height=True, title="ZEN Promptboard — GPT-5") as demo:
 
 
 
 
 
 
 
127
  gr.Markdown(
128
  """
129
  <div class="zen-card">
130
  <div class="zen-pill">ZEN VANGUARD • GPT-5 CONSOLE</div>
131
  <div class="zen-title" style="margin-top: 0.8rem;">Professional AI Promptboard</div>
132
- <div style="margin-top: 0.5rem; color:#9ca3af;">
133
- Transform unstructured content into polished professional outputs — with GPT-5 as your assistant.
134
  </div>
135
  </div>
136
  """
@@ -139,14 +181,17 @@ with gr.Blocks(css=CUSTOM_CSS, elem_id="zen-root", fill_height=True, title="ZEN
139
  api_key_state = gr.State("")
140
 
141
  with gr.Row(equal_height=True):
 
142
  with gr.Column(scale=1):
143
  with gr.Group():
144
- gr.Markdown("### 🔐 Connect")
 
145
  api_key_input = gr.Textbox(
146
  label="API Key",
147
- placeholder="Paste your GPT-5 key here (not stored on server)",
148
  type="password",
149
  )
 
150
  with gr.Row():
151
  save_btn = gr.Button("Save Key", variant="primary")
152
  key_status = gr.Markdown("Key not saved yet.")
@@ -154,40 +199,49 @@ with gr.Blocks(css=CUSTOM_CSS, elem_id="zen-root", fill_height=True, title="ZEN
154
  model_name = gr.Textbox(
155
  label="Model ID",
156
  value="gpt-5",
157
- info="Default: GPT-5. You may switch to gpt-4o or gpt-4.1-mini if needed.",
158
- )
159
- temperature = gr.Slider(
160
- 0.0, 1.2, 0.5, 0.05, label="Creativity"
161
  )
162
 
163
  with gr.Group():
164
- gr.Markdown("### ⚡ Presets")
 
165
  preset_radio = gr.Radio(
166
  label="Quick workflows",
167
  choices=list(PRESETS.keys()),
168
  interactive=True,
169
  )
170
 
 
171
  with gr.Column(scale=2):
172
  system_box = gr.Textbox(
173
  label="System / Role Instructions",
174
- placeholder="How should the AI behave?",
175
  lines=4,
176
  )
 
177
  user_box = gr.Textbox(
178
  label="Your Prompt or Notes",
179
- placeholder="Paste text, meeting notes, or raw input...",
180
  lines=8,
181
  )
 
182
  run_btn = gr.Button("Run Prompt", variant="primary")
 
183
  output_md = gr.Markdown("Output will appear here.")
184
- history_chat = gr.Chatbot(label="History", height=300)
185
 
186
- # --- Wiring ---
 
 
 
 
 
 
 
187
 
188
- def _save_and_ack(key):
189
  stored_key, placeholder_update = save_api_key(key)
190
- return stored_key, "✅ API key stored for this session.", placeholder_update
 
191
 
192
  save_btn.click(
193
  _save_and_ack,
@@ -201,20 +255,18 @@ with gr.Blocks(css=CUSTOM_CSS, elem_id="zen-root", fill_height=True, title="ZEN
201
  outputs=[system_box, user_box],
202
  )
203
 
204
- def _run(api_state, model, system, user, temp, history):
205
- history, answer = run_completion(
206
  api_key=api_state,
207
  model=model,
208
  system_prompt=system,
209
  user_prompt=user,
210
- temperature=temp,
211
  history=history,
212
  )
213
- return history, answer
214
 
215
  run_btn.click(
216
  _run,
217
- inputs=[api_key_state, model_name, system_box, user_box, temperature, history_chat],
218
  outputs=[history_chat, output_md],
219
  )
220
 
 
5
  # --------------- PRESETS ---------------
6
 
7
  PRESETS = {
8
+ "Executive Summary": {
9
+ "system": (
10
+ "You are an executive briefing assistant. "
11
+ "Turn complex text into a concise 3–5 bullet executive summary "
12
+ "with clear insights and recommendations."
13
+ ),
14
+ "user": "Paste a long report, transcript, or document here and I'll summarize it.",
15
+ },
16
+ "Polished Email Reply": {
17
+ "system": (
18
+ "You are a professional communications assistant. "
19
+ "Write clear, concise, and friendly emails suitable for executives. "
20
+ "Preserve tone and key details."
21
+ ),
22
+ "user": "Paste the email you received and a few notes on how you want to respond.",
23
+ },
24
+ "Meeting Notes Action Plan": {
25
+ "system": (
26
+ "You convert messy meeting notes into a clear action-oriented summary. "
27
+ "Always include: 1) Key decisions, 2) Action items with owners and timelines, "
28
+ "3) Risks or next steps."
29
+ ),
30
+ "user": "Paste your rough meeting notes or bullet points and I'll structure them.",
31
+ },
32
+ "Idea Generator / Brainstorm": {
33
+ "system": (
34
+ "You are a creative strategist. Generate structured ideas with titles, "
35
+ "descriptions, and next steps."
36
+ ),
37
+ "user": "Describe what you want to build, improve, or launch. I'll propose ideas.",
38
+ },
 
 
 
 
39
  }
40
 
41
+
42
  # --------------- CORE CHAT LOGIC ---------------
43
 
44
+ def run_completion(api_key, model, system_prompt, user_prompt, history):
45
+ """
46
+ Core call to the OpenAI Chat Completions API.
47
+
48
+ IMPORTANT:
49
+ - Does NOT raise errors for missing API key; returns a friendly message instead.
50
+ - Does NOT send temperature or max_tokens/max_completion_tokens, to avoid
51
+ model-specific 400 errors like you saw with GPT-5.
52
+ """
53
+
54
+ history = history or []
55
+
56
  if not api_key:
57
+ # No exception; just return a message in the output area
58
+ msg = "❌ No API key found. Paste your key in the API Key field and click **Save Key** first."
59
+ history.append(("System", msg))
60
+ return history, msg
61
 
62
  if not user_prompt.strip():
63
+ msg = "⚠️ Please enter a prompt or paste some content before running."
64
+ history.append(("System", msg))
65
+ return history, msg
66
+
67
+ # Configure OpenAI
68
+ openai.api_key = api_key.strip()
69
 
70
+ # Build messages for the chat completion
71
  messages = []
72
  if system_prompt.strip():
73
  messages.append({"role": "system", "content": system_prompt.strip()})
74
  messages.append({"role": "user", "content": user_prompt.strip()})
75
 
76
+ try:
77
+ # Minimal, model-agnostic call: no temperature / max_* params
78
+ response = openai.chat.completions.create(
79
+ model=model.strip(),
80
+ messages=messages,
81
+ )
82
+ answer = (response.choices[0].message.content or "").strip()
83
+ if not answer:
84
+ answer = "⚠️ The model returned an empty response. Try again with more context."
85
+
86
+ except Exception as e:
87
+ answer = f"❌ Error while calling the model:\n\n`{e}`"
88
 
 
 
89
  history.append(("You", user_prompt))
90
  history.append(("Assistant", answer))
91
+
92
  return history, answer
93
 
94
 
95
  # --------------- HELPERS ---------------
96
 
97
+ def save_api_key(raw_key: str):
98
+ """
99
+ Save the API key for this session.
100
+
101
+ We still allow non 'sk-' prefixes so people can drop in OpenRouter or other provider keys.
102
+ """
103
+ cleaned = (raw_key or "").strip()
104
  if not cleaned:
105
+ raise gr.Error("🔐 Please paste a valid API key before saving.")
106
+
107
  if not cleaned.startswith("sk-"):
108
  gr.Info("Key saved, but it doesn’t start with 'sk-'. Double-check your provider format.")
109
+
110
+ # Return key for State + clear textbox with a new placeholder
111
  return cleaned, gr.update(value="", placeholder="API key saved ✔")
112
 
113
 
114
+ def load_preset(preset_name: str):
115
+ """
116
+ Load system + user text for a selected preset.
117
+ """
118
  if not preset_name or preset_name not in PRESETS:
119
  return gr.update(), gr.update()
120
  preset = PRESETS[preset_name]
 
127
  #zen-root {
128
  background: radial-gradient(circle at top left, #111827, #020617 65%);
129
  color: #f3f4f6;
130
+ font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
131
  min-height: 100vh;
132
  }
133
  .zen-card {
134
  border-radius: 20px;
135
+ background: rgba(15, 23, 42, 0.82);
136
+ border: 1px solid rgba(148, 163, 184, 0.35);
137
+ backdrop-filter: blur(18px);
138
+ box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
139
+ padding: 1.8rem;
140
  }
141
  .zen-pill {
142
  border-radius: 9999px;
143
+ padding: 0.28rem 0.9rem;
144
+ border: 1px solid rgba(129, 140, 248, 0.65);
145
  color: #a5b4fc;
146
  font-size: 0.75rem;
147
  text-transform: uppercase;
 
150
  .zen-title {
151
  font-size: 1.9rem;
152
  font-weight: 700;
153
+ letter-spacing: -0.025em;
154
+ }
155
+ .zen-subtitle {
156
+ font-size: 0.9rem;
157
+ color: #9ca3af;
158
  }
159
  """
160
 
161
+ with gr.Blocks(
162
+ css=CUSTOM_CSS,
163
+ elem_id="zen-root",
164
+ fill_height=True,
165
+ title="ZEN Promptboard — GPT-5",
166
+ ) as demo:
167
+
168
+ # Header
169
  gr.Markdown(
170
  """
171
  <div class="zen-card">
172
  <div class="zen-pill">ZEN VANGUARD • GPT-5 CONSOLE</div>
173
  <div class="zen-title" style="margin-top: 0.8rem;">Professional AI Promptboard</div>
174
+ <div class="zen-subtitle" style="margin-top: 0.5rem;">
175
+ Transform unstructured content into polished, ready-to-send executive artifacts.
176
  </div>
177
  </div>
178
  """
 
181
  api_key_state = gr.State("")
182
 
183
  with gr.Row(equal_height=True):
184
+ # LEFT COLUMN: API + model + presets
185
  with gr.Column(scale=1):
186
  with gr.Group():
187
+ gr.Markdown("### 🔐 1. Connect")
188
+
189
  api_key_input = gr.Textbox(
190
  label="API Key",
191
+ placeholder="Paste your GPT-style key here (not stored on server)",
192
  type="password",
193
  )
194
+
195
  with gr.Row():
196
  save_btn = gr.Button("Save Key", variant="primary")
197
  key_status = gr.Markdown("Key not saved yet.")
 
199
  model_name = gr.Textbox(
200
  label="Model ID",
201
  value="gpt-5",
202
+ info="Default: gpt-5. You can switch to gpt-4o, gpt-4.1-mini, etc. if needed.",
 
 
 
203
  )
204
 
205
  with gr.Group():
206
+ gr.Markdown("### ⚡ 2. Presets")
207
+
208
  preset_radio = gr.Radio(
209
  label="Quick workflows",
210
  choices=list(PRESETS.keys()),
211
  interactive=True,
212
  )
213
 
214
+ # RIGHT COLUMN: prompts + output
215
  with gr.Column(scale=2):
216
  system_box = gr.Textbox(
217
  label="System / Role Instructions",
218
+ placeholder="How should the AI behave? (e.g., 'You are my executive assistant...')",
219
  lines=4,
220
  )
221
+
222
  user_box = gr.Textbox(
223
  label="Your Prompt or Notes",
224
+ placeholder="Paste content, meeting notes, or a draft you want rewritten...",
225
  lines=8,
226
  )
227
+
228
  run_btn = gr.Button("Run Prompt", variant="primary")
229
+
230
  output_md = gr.Markdown("Output will appear here.")
 
231
 
232
+ history_chat = gr.Chatbot(
233
+ label="History",
234
+ height=300,
235
+ type="tuples", # explicit to avoid the deprecation warning
236
+ show_copy_button=True,
237
+ )
238
+
239
+ # --------------- WIRES / EVENTS ---------------
240
 
241
+ def _save_and_ack(key: str):
242
  stored_key, placeholder_update = save_api_key(key)
243
+ status_msg = "✅ API key stored for this session."
244
+ return stored_key, status_msg, placeholder_update
245
 
246
  save_btn.click(
247
  _save_and_ack,
 
255
  outputs=[system_box, user_box],
256
  )
257
 
258
+ def _run(api_state, model, system, user, history):
259
+ return run_completion(
260
  api_key=api_state,
261
  model=model,
262
  system_prompt=system,
263
  user_prompt=user,
 
264
  history=history,
265
  )
 
266
 
267
  run_btn.click(
268
  _run,
269
+ inputs=[api_key_state, model_name, system_box, user_box, history_chat],
270
  outputs=[history_chat, output_md],
271
  )
272