milwright commited on
Commit
5bebe3e
·
verified ·
1 Parent(s): aa05c72

Push helper assets

Browse files
Files changed (2) hide show
  1. app.py +450 -0
  2. requirements.txt +2 -0
app.py ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import zipfile
4
+ import io
5
+ import os
6
+ from datetime import datetime
7
+
8
+ # Template for generated space app (based on mvp_simple.py)
9
+ SPACE_TEMPLATE = '''import gradio as gr
10
+ import os
11
+ import requests
12
+ import json
13
+
14
+ # Configuration
15
+ SPACE_NAME = "{name}"
16
+ SPACE_DESCRIPTION = "{description}"
17
+ SYSTEM_PROMPT = """{system_prompt}"""
18
+ MODEL = "{model}"
19
+
20
+ # Get API key from environment - customizable variable name
21
+ API_KEY = os.environ.get("{api_key_var}")
22
+
23
+ def generate_response(message, history):
24
+ """Generate response using OpenRouter API"""
25
+
26
+ if not API_KEY:
27
+ return "Please set your {api_key_var} in the Space settings."
28
+
29
+ # Build messages array for the API
30
+ messages = [{{"role": "system", "content": SYSTEM_PROMPT}}]
31
+
32
+ # Add conversation history - compatible with Gradio 5.x format
33
+ for chat in history:
34
+ if isinstance(chat, dict):
35
+ # New format: {{"role": "user", "content": "..."}} or {{"role": "assistant", "content": "..."}}
36
+ messages.append(chat)
37
+ else:
38
+ # Legacy format: ("user msg", "bot msg")
39
+ user_msg, bot_msg = chat
40
+ messages.append({{"role": "user", "content": user_msg}})
41
+ if bot_msg:
42
+ messages.append({{"role": "assistant", "content": bot_msg}})
43
+
44
+ # Add current message
45
+ messages.append({{"role": "user", "content": message}})
46
+
47
+ # Make API request
48
+ try:
49
+ response = requests.post(
50
+ url="https://openrouter.ai/api/v1/chat/completions",
51
+ headers={{
52
+ "Authorization": f"Bearer {{API_KEY}}",
53
+ "Content-Type": "application/json"
54
+ }},
55
+ json={{
56
+ "model": MODEL,
57
+ "messages": messages,
58
+ "temperature": {temperature},
59
+ "max_tokens": {max_tokens}
60
+ }}
61
+ )
62
+
63
+ if response.status_code == 200:
64
+ return response.json()['choices'][0]['message']['content']
65
+ else:
66
+ return f"Error: {{response.status_code}} - {{response.text}}"
67
+
68
+ except Exception as e:
69
+ return f"Error: {{str(e)}}"
70
+
71
+ # Create simple Gradio interface using ChatInterface
72
+ demo = gr.ChatInterface(
73
+ fn=generate_response,
74
+ title=SPACE_NAME,
75
+ description=SPACE_DESCRIPTION,
76
+ examples={examples}
77
+ )
78
+
79
+ if __name__ == "__main__":
80
+ demo.launch()
81
+ '''
82
+
83
+ # Available models
84
+ MODELS = [
85
+ "google/gemma-2-9b-it",
86
+ "google/gemma-2-27b-it",
87
+ "meta-llama/llama-3.1-8b-instruct",
88
+ "meta-llama/llama-3.1-70b-instruct",
89
+ "anthropic/claude-3-haiku",
90
+ "anthropic/claude-3-sonnet",
91
+ "anthropic/claude-3.5-sonnet",
92
+ "openai/gpt-3.5-turbo",
93
+ "openai/gpt-4o-mini",
94
+ "openai/gpt-4o",
95
+ "mistralai/mistral-7b-instruct",
96
+ "mistralai/mixtral-8x7b-instruct"
97
+ ]
98
+
99
+ def create_readme(config):
100
+ """Generate README with deployment instructions"""
101
+ return f"""# {config['name']}
102
+
103
+ {config['description']}
104
+
105
+ ## Quick Deploy to HuggingFace Spaces
106
+
107
+ ### Step 1: Create the Space
108
+ 1. Go to https://huggingface.co/spaces
109
+ 2. Click "Create new Space"
110
+ 3. Choose a name for your Space
111
+ 4. Select **Gradio** as the SDK
112
+ 5. Set visibility (Public/Private)
113
+ 6. Click "Create Space"
114
+
115
+ ### Step 2: Upload Files
116
+ 1. In your new Space, click "Files" tab
117
+ 2. Upload these files from the zip:
118
+ - `app.py`
119
+ - `requirements.txt`
120
+ 3. Wait for "Building" to complete
121
+
122
+ ### Step 3: Add API Key
123
+ 1. Go to Settings (gear icon)
124
+ 2. Click "Variables and secrets"
125
+ 3. Click "New secret"
126
+ 4. Name: `{config['api_key_var']}`
127
+ 5. Value: Your OpenRouter API key
128
+ 6. Click "Add"
129
+
130
+ ### Step 4: Get Your API Key
131
+ 1. Go to https://openrouter.ai/keys
132
+ 2. Sign up/login if needed
133
+ 3. Click "Create Key"
134
+ 4. Copy the key (starts with `sk-or-`)
135
+
136
+ ### Step 5: Test Your Space
137
+ - Go back to "App" tab
138
+ - Your Space should be running!
139
+ - Try the example prompts or ask a question
140
+
141
+ ## Configuration
142
+
143
+ - **Model**: {config['model']}
144
+ - **Temperature**: {config['temperature']}
145
+ - **Max Tokens**: {config['max_tokens']}
146
+ - **API Key Variable**: {config['api_key_var']}
147
+
148
+ ## Cost Information
149
+
150
+ OpenRouter charges per token used:
151
+ - Gemma 2 9B: ~$0.20 per million tokens
152
+ - Claude Haiku: ~$0.25 per million tokens
153
+ - GPT-4o-mini: ~$0.60 per million tokens
154
+
155
+ Typical conversation: ~300 tokens (cost: $0.00006 - $0.0018)
156
+
157
+ Check current pricing: https://openrouter.ai/models
158
+
159
+ ## Customization
160
+
161
+ To modify your Space:
162
+ 1. Edit `app.py` in your Space
163
+ 2. Update configuration variables at the top
164
+ 3. Changes deploy automatically
165
+
166
+ ## Troubleshooting
167
+
168
+ - **"Please set your {config['api_key_var']}"**: Add the secret in Space settings
169
+ - **Error 401**: Invalid API key or no credits
170
+ - **Error 429**: Rate limit - wait and try again
171
+ - **Build failed**: Check requirements.txt formatting
172
+
173
+ ## More Help
174
+
175
+ - HuggingFace Spaces: https://huggingface.co/docs/hub/spaces
176
+ - OpenRouter Docs: https://openrouter.ai/docs
177
+ - Gradio Docs: https://gradio.app/docs
178
+
179
+ ---
180
+
181
+ Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} with Chat U/I Helper
182
+ """
183
+
184
+ def create_requirements():
185
+ """Generate requirements.txt"""
186
+ return "gradio==5.34.0\nrequests==2.31.0"
187
+
188
+ def generate_zip(name, description, system_prompt, model, api_key_var, temperature, max_tokens, examples_text):
189
+ """Generate deployable zip file"""
190
+
191
+ # Process examples
192
+ if examples_text and examples_text.strip():
193
+ examples_list = [ex.strip() for ex in examples_text.split('\n') if ex.strip()]
194
+ examples_json = json.dumps(examples_list)
195
+ else:
196
+ examples_json = json.dumps([
197
+ "Hello! How can you help me?",
198
+ "Tell me something interesting",
199
+ "What can you do?"
200
+ ])
201
+
202
+ # Create config
203
+ config = {
204
+ 'name': name,
205
+ 'description': description,
206
+ 'system_prompt': system_prompt,
207
+ 'model': model,
208
+ 'api_key_var': api_key_var,
209
+ 'temperature': temperature,
210
+ 'max_tokens': int(max_tokens),
211
+ 'examples': examples_json
212
+ }
213
+
214
+ # Generate files
215
+ app_content = SPACE_TEMPLATE.format(**config)
216
+ readme_content = create_readme(config)
217
+ requirements_content = create_requirements()
218
+
219
+ # Create zip file with clean naming
220
+ filename = f"{name.lower().replace(' ', '_').replace('-', '_')}.zip"
221
+
222
+ # Create zip in memory and save to disk
223
+ zip_buffer = io.BytesIO()
224
+ with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
225
+ zip_file.writestr('app.py', app_content)
226
+ zip_file.writestr('requirements.txt', requirements_content)
227
+ zip_file.writestr('README.md', readme_content)
228
+ zip_file.writestr('config.json', json.dumps(config, indent=2))
229
+
230
+ # Write zip to file
231
+ zip_buffer.seek(0)
232
+ with open(filename, 'wb') as f:
233
+ f.write(zip_buffer.getvalue())
234
+
235
+ return filename
236
+
237
+ # Define callback functions outside the interface
238
+ def on_generate(name, description, system_prompt, model, api_key_var, temperature, max_tokens, examples_text):
239
+ if not name or not name.strip():
240
+ return gr.update(value="Error: Please provide a Space Title", visible=True), gr.update(visible=False)
241
+
242
+ if not system_prompt or not system_prompt.strip():
243
+ return gr.update(value="Error: Please provide a System Prompt", visible=True), gr.update(visible=False)
244
+
245
+ try:
246
+ filename = generate_zip(name, description, system_prompt, model, api_key_var, temperature, max_tokens, examples_text)
247
+
248
+ success_msg = f"""**Deployment package ready!**
249
+
250
+ **File**: `{filename}`
251
+
252
+ **What's included:**
253
+ - `app.py` - Ready-to-deploy chat interface
254
+ - `requirements.txt` - Dependencies
255
+ - `README.md` - Step-by-step deployment guide
256
+ - `config.json` - Configuration backup
257
+
258
+ **Next steps:**
259
+ 1. Download the zip file below
260
+ 2. Follow the README instructions to deploy on HuggingFace Spaces
261
+ 3. Set your `{api_key_var}` secret in Space settings
262
+
263
+ **Your Space will be live in minutes!**"""
264
+
265
+ return gr.update(value=success_msg, visible=True), gr.update(value=filename, visible=True)
266
+
267
+ except Exception as e:
268
+ return gr.update(value=f"Error: {str(e)}", visible=True), gr.update(visible=False)
269
+
270
+ def respond(message, chat_history):
271
+ # Make actual API request to OpenRouter
272
+ import os
273
+ import requests
274
+
275
+ # Get API key from environment
276
+ api_key = os.environ.get("OPENROUTER_API_KEY")
277
+
278
+ if not api_key:
279
+ response = "Please set your OPENROUTER_API_KEY in the Space settings to use the chat support."
280
+ chat_history.append({"role": "user", "content": message})
281
+ chat_history.append({"role": "assistant", "content": response})
282
+ return "", chat_history
283
+
284
+ # Build conversation history for API
285
+ messages = [{
286
+ "role": "system",
287
+ "content": """You are a helpful assistant specializing in creating chat UIs for HuggingFace Spaces. You help users configure assistants for education and research. Provide concise, practical advice about:
288
+ - System prompts for different use cases (courses, research, tutoring)
289
+ - Model selection (recommending google/gemma-2-27b-it as a great balance)
290
+ - HuggingFace Space deployment tips
291
+ - Customization options
292
+
293
+ Keep responses brief and actionable. Focus on what the user is specifically asking about."""
294
+ }]
295
+
296
+ # Add conversation history
297
+ for chat in chat_history:
298
+ messages.append(chat)
299
+
300
+ # Add current message
301
+ messages.append({"role": "user", "content": message})
302
+
303
+ try:
304
+ # Make API request to OpenRouter
305
+ response = requests.post(
306
+ url="https://openrouter.ai/api/v1/chat/completions",
307
+ headers={
308
+ "Authorization": f"Bearer {api_key}",
309
+ "Content-Type": "application/json"
310
+ },
311
+ json={
312
+ "model": "google/gemma-2-27b-it",
313
+ "messages": messages,
314
+ "temperature": 0.7,
315
+ "max_tokens": 500
316
+ }
317
+ )
318
+
319
+ if response.status_code == 200:
320
+ assistant_response = response.json()['choices'][0]['message']['content']
321
+ else:
322
+ assistant_response = f"Error: {response.status_code} - {response.text}"
323
+
324
+ except Exception as e:
325
+ assistant_response = f"Error: {str(e)}"
326
+
327
+ chat_history.append({"role": "user", "content": message})
328
+ chat_history.append({"role": "assistant", "content": assistant_response})
329
+ return "", chat_history
330
+
331
+ def clear_chat():
332
+ return "", []
333
+
334
+ # Create Gradio interface with proper tab structure
335
+ with gr.Blocks(title="Chat U/I Helper") as demo:
336
+ with gr.Tabs():
337
+ with gr.Tab("Spaces Configuration"):
338
+ gr.Markdown("# Spaces Configuration")
339
+ gr.Markdown("Convert custom assistants from HuggingChat into chat interfaces with HuggingFace Spaces. Configure and download everything needed to deploy a simple HF space using Gradio.")
340
+
341
+ with gr.Column():
342
+ name = gr.Textbox(
343
+ label="Space Title",
344
+ placeholder="My Course Helper",
345
+ value="My Custom Space"
346
+ )
347
+
348
+ description = gr.Textbox(
349
+ label="Space Description",
350
+ placeholder="A customizable AI chat interface for...",
351
+ lines=2,
352
+ value="A customizable AI chat interface for your specific needs"
353
+ )
354
+
355
+ model = gr.Dropdown(
356
+ label="Model",
357
+ choices=MODELS,
358
+ value=MODELS[0],
359
+ info="Choose based on your needs and budget"
360
+ )
361
+
362
+ api_key_var = gr.Textbox(
363
+ label="API Key Variable Name",
364
+ value="OPENROUTER_API_KEY",
365
+ info="Name for the secret in HuggingFace Space settings"
366
+ )
367
+
368
+ system_prompt = gr.Textbox(
369
+ label="System Prompt",
370
+ placeholder="You are a research assistant...",
371
+ lines=4,
372
+ value="You are a clear and concise research assistant. Provide accurate, succinct, and responsive support."
373
+ )
374
+
375
+ examples_text = gr.Textbox(
376
+ label="Example Prompts (one per line)",
377
+ placeholder="Hello! How can you help me?\nWhat's the weather like?\nExplain quantum computing",
378
+ lines=3,
379
+ info="These will appear as clickable examples in the chat interface"
380
+ )
381
+
382
+ with gr.Row():
383
+ temperature = gr.Slider(
384
+ label="Temperature",
385
+ minimum=0,
386
+ maximum=2,
387
+ value=0.7,
388
+ step=0.1,
389
+ info="Higher = more creative, Lower = more focused"
390
+ )
391
+
392
+ max_tokens = gr.Slider(
393
+ label="Max Response Tokens",
394
+ minimum=50,
395
+ maximum=4096,
396
+ value=1024,
397
+ step=50
398
+ )
399
+
400
+ generate_btn = gr.Button("Generate Deployment Package", variant="primary")
401
+
402
+ status = gr.Markdown(visible=False)
403
+ download_file = gr.File(label="Download your zip package", visible=False)
404
+
405
+ # Connect the generate button
406
+ generate_btn.click(
407
+ on_generate,
408
+ inputs=[name, description, system_prompt, model, api_key_var, temperature, max_tokens, examples_text],
409
+ outputs=[status, download_file]
410
+ )
411
+
412
+ with gr.Tab("Chat Support"):
413
+ gr.Markdown("# Chat Support")
414
+ gr.Markdown("Get personalized guidance on configuring chat UIs as HuggingFace Spaces for educational and research purposes.")
415
+
416
+ # Meta chat interface
417
+ with gr.Column():
418
+ chatbot = gr.Chatbot(
419
+ value=[],
420
+ label="Chat Support Assistant",
421
+ height=400,
422
+ type="messages"
423
+ )
424
+ msg = gr.Textbox(
425
+ label="Ask about configuring chat UIs for courses, research, or custom HuggingFace Spaces",
426
+ placeholder="How can I configure a chat UI for my senior seminar?",
427
+ lines=2
428
+ )
429
+ with gr.Row():
430
+ submit = gr.Button("Send", variant="primary")
431
+ clear = gr.Button("Clear")
432
+
433
+ gr.Examples(
434
+ examples=[
435
+ "How do I make a math tutor bot?",
436
+ "What's a good system prompt?",
437
+ "Which model should I use?",
438
+ "Can I add file uploads?",
439
+ "Help me build a course assistant"
440
+ ],
441
+ inputs=msg
442
+ )
443
+
444
+ # Connect the chat functionality
445
+ submit.click(respond, [msg, chatbot], [msg, chatbot])
446
+ msg.submit(respond, [msg, chatbot], [msg, chatbot])
447
+ clear.click(clear_chat, outputs=[msg, chatbot])
448
+
449
+ if __name__ == "__main__":
450
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio==5.34.0
2
+ requests==2.31.0