drbinna commited on
Commit
e497516
Β·
verified Β·
1 Parent(s): ff5af61

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +603 -0
app.py ADDED
@@ -0,0 +1,603 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import boto3
3
+ import json
4
+ import os
5
+ from botocore.exceptions import ClientError, NoCredentialsError
6
+ import time
7
+
8
+ # Configuration - These will be set via Hugging Face Spaces environment variables
9
+ KNOWLEDGE_BASE_ID = os.environ.get("KNOWLEDGE_BASE_ID", "PLEASE_SET_IN_SPACES_SETTINGS")
10
+ AWS_REGION = os.environ.get("AWS_REGION", "us-east-1")
11
+ MODEL_ARN = f"arn:aws:bedrock:{AWS_REGION}::foundation-model/amazon.nova-pro-v1:0"
12
+
13
+ # Check if running in demo mode (no credentials set)
14
+ DEMO_MODE = KNOWLEDGE_BASE_ID == "PLEASE_SET_IN_SPACES_SETTINGS"
15
+
16
+ # Initialize AWS clients
17
+ bedrock_agent = None
18
+ initialization_error = None
19
+
20
+ if not DEMO_MODE:
21
+ try:
22
+ bedrock_agent = boto3.client(
23
+ 'bedrock-agent-runtime',
24
+ region_name=AWS_REGION,
25
+ aws_access_key_id=os.environ.get('AWS_ACCESS_KEY_ID'),
26
+ aws_secret_access_key=os.environ.get('AWS_SECRET_ACCESS_KEY')
27
+ )
28
+ print(f"βœ… AWS Bedrock client initialized in region: {AWS_REGION}")
29
+ except Exception as e:
30
+ print(f"❌ Error initializing AWS client: {e}")
31
+ initialization_error = str(e)
32
+ else:
33
+ print("🚧 Running in DEMO MODE - Configure environment variables to enable AWS integration")
34
+
35
+ def search_knowledge_base(query, search_type="generate"):
36
+ """
37
+ Search the ORU IT Knowledge Base using Amazon Bedrock
38
+ """
39
+
40
+ if not query.strip():
41
+ return "Please enter a question!", "", "error"
42
+
43
+ # Demo mode response
44
+ if DEMO_MODE:
45
+ demo_response = f"""
46
+ ## 🚧 Demo Mode Active
47
+
48
+ **Your Query:** "{query}"
49
+
50
+ **Demo Response:** This is a demonstration of the ORU IT Helpdesk Assistant interface.
51
+
52
+ To enable full functionality:
53
+ 1. Configure your Amazon Bedrock Knowledge Base
54
+ 2. Set up environment variables in Hugging Face Spaces settings
55
+ 3. Upload your ORU IT documentation to the knowledge base
56
+
57
+ **Expected Response:** Once configured, this system would search through ORU's IT knowledge base and provide accurate, contextual answers to questions like:
58
+ - Password reset procedures
59
+ - Software installation guides
60
+ - Network troubleshooting steps
61
+ - Campus system access instructions
62
+
63
+ **Cost Savings:** Using S3 Vectors provides up to 90% cost savings compared to traditional vector databases.
64
+ """
65
+
66
+ demo_sources = """
67
+ **Demo Sources:**
68
+ - password_authentication_001_student_password_change.txt
69
+ - mobile_applications_002_oru_app_experience_fix.txt
70
+ - software_applications_003_word_mac_view_only_fix.txt
71
+
72
+ *These would be the actual ORU IT knowledge base documents that contain the answer.*
73
+ """
74
+
75
+ return demo_response, demo_sources, "demo"
76
+
77
+ if not bedrock_agent:
78
+ error_msg = f"❌ AWS Bedrock client not initialized."
79
+ if initialization_error:
80
+ error_msg += f" Error: {initialization_error}"
81
+ return error_msg, "", "error"
82
+
83
+ try:
84
+ if search_type == "generate":
85
+ # Use RetrieveAndGenerate for full responses
86
+ response = bedrock_agent.retrieve_and_generate(
87
+ input={
88
+ 'text': query
89
+ },
90
+ retrieveAndGenerateConfiguration={
91
+ 'type': 'KNOWLEDGE_BASE',
92
+ 'knowledgeBaseConfiguration': {
93
+ 'knowledgeBaseId': KNOWLEDGE_BASE_ID,
94
+ 'modelArn': MODEL_ARN,
95
+ 'retrievalConfiguration': {
96
+ 'vectorSearchConfiguration': {
97
+ 'numberOfResults': 5
98
+ }
99
+ }
100
+ }
101
+ }
102
+ )
103
+
104
+ # Extract the generated response
105
+ generated_text = response.get('output', {}).get('text', 'No response generated.')
106
+
107
+ # Extract sources/citations
108
+ sources_info = []
109
+ citations = response.get('citations', [])
110
+
111
+ for i, citation in enumerate(citations, 1):
112
+ retrieved_refs = citation.get('retrievedReferences', [])
113
+ for j, ref in enumerate(retrieved_refs, 1):
114
+ content = ref.get('content', {}).get('text', 'No content available')
115
+ location = ref.get('location', {}).get('s3Location', {}).get('uri', 'Unknown source')
116
+ sources_info.append(f"**Source {i}.{j}:**\n{content[:300]}{'...' if len(content) > 300 else ''}\n*From: {location}*\n")
117
+
118
+ sources_text = "\n".join(sources_info) if sources_info else "No sources found."
119
+
120
+ return generated_text, sources_text, "success"
121
+
122
+ else: # retrieve only
123
+ # Use Retrieve for sources only
124
+ response = bedrock_agent.retrieve(
125
+ knowledgeBaseId=KNOWLEDGE_BASE_ID,
126
+ retrievalQuery={
127
+ 'text': query
128
+ },
129
+ retrievalConfiguration={
130
+ 'vectorSearchConfiguration': {
131
+ 'numberOfResults': 5
132
+ }
133
+ }
134
+ )
135
+
136
+ # Extract retrieved results
137
+ retrieval_results = response.get('retrievalResults', [])
138
+
139
+ if not retrieval_results:
140
+ return "No relevant sources found.", "", "warning"
141
+
142
+ sources_info = []
143
+ for i, result in enumerate(retrieval_results, 1):
144
+ content = result.get('content', {}).get('text', 'No content available')
145
+ score = result.get('score', 0)
146
+ location = result.get('location', {}).get('s3Location', {}).get('uri', 'Unknown source')
147
+
148
+ sources_info.append(
149
+ f"**Source {i} (Confidence: {score:.2f}):**\n"
150
+ f"{content[:400]}{'...' if len(content) > 400 else ''}\n"
151
+ f"*From: {location}*\n"
152
+ )
153
+
154
+ sources_text = "\n".join(sources_info)
155
+ response_text = f"Found {len(retrieval_results)} relevant sources from the ORU IT Knowledge Base:"
156
+
157
+ return response_text, sources_text, "success"
158
+
159
+ except ClientError as e:
160
+ error_code = e.response['Error']['Code']
161
+ error_message = e.response['Error']['Message']
162
+ return f"❌ AWS Error ({error_code}): {error_message}", "", "error"
163
+
164
+ except NoCredentialsError:
165
+ return "❌ AWS credentials not found. Please configure your credentials in Spaces settings.", "", "error"
166
+
167
+ except Exception as e:
168
+ return f"❌ Unexpected error: {str(e)}", "", "error"
169
+
170
+ def format_response(query, search_type):
171
+ """Process the query and return formatted response"""
172
+
173
+ if not query.strip():
174
+ return (
175
+ "Please enter your IT question above and click 'Get AI Answer' or 'Show Sources'.",
176
+ "",
177
+ "Enter a question to get started!"
178
+ )
179
+
180
+ # Perform the search
181
+ response_text, sources_text, status = search_knowledge_base(query, search_type)
182
+
183
+ # Format the final response based on search type and status
184
+ if status == "demo":
185
+ formatted_response = response_text
186
+ status_msg = "🚧 Demo Mode - Configure AWS credentials to enable full functionality"
187
+ elif search_type == "generate":
188
+ if status == "success":
189
+ formatted_response = f"## πŸ€– AI Assistant Response\n\n{response_text}"
190
+ status_msg = "βœ… Response generated successfully from ORU IT Knowledge Base!"
191
+ else:
192
+ formatted_response = response_text
193
+ status_msg = "❌ Error generating response"
194
+ else:
195
+ if status == "success":
196
+ formatted_response = f"## πŸ“š Retrieved Sources\n\n{response_text}"
197
+ status_msg = "βœ… Sources retrieved successfully from ORU IT Knowledge Base!"
198
+ else:
199
+ formatted_response = response_text
200
+ status_msg = "❌ Error retrieving sources"
201
+
202
+ return formatted_response, sources_text, status_msg
203
+
204
+ # Sample queries for ORU IT scenarios
205
+ SAMPLE_QUERIES = [
206
+ "How do I change my student password?",
207
+ "My ORU app isn't showing the right tiles",
208
+ "Word is showing view only mode on my Mac",
209
+ "How do I set up multi-factor authentication?",
210
+ "I can't edit Microsoft Word documents",
211
+ "How do I connect to ORU WiFi network?",
212
+ "My ORU email isn't syncing to my phone",
213
+ "How do I access Vision portal from off-campus?",
214
+ "VPN connection keeps dropping",
215
+ "Can't print to campus printers from my laptop",
216
+ "How do I reset my Z-number password?",
217
+ "Microsoft Teams isn't working properly"
218
+ ]
219
+
220
+ # Custom CSS with ORU Brand Colors
221
+ custom_css = """
222
+ :root {
223
+ --oru-primary-blue: #041E41;
224
+ --oru-primary-tan: #C4B282;
225
+ --oru-secondary-tan: #E9DFBB;
226
+ --oru-accent-blue: #7BAFD4;
227
+ --oru-accent-tan: #C39236;
228
+ }
229
+
230
+ .gradio-container {
231
+ max-width: 1200px !important;
232
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
233
+ }
234
+
235
+ /* Header styling */
236
+ .oru-header {
237
+ background: linear-gradient(135deg, var(--oru-primary-blue) 0%, var(--oru-accent-blue) 100%);
238
+ color: white;
239
+ padding: 30px;
240
+ text-align: center;
241
+ border-radius: 15px;
242
+ margin-bottom: 25px;
243
+ box-shadow: 0 8px 25px rgba(4, 30, 65, 0.2);
244
+ }
245
+
246
+ .oru-header h1 {
247
+ font-size: 2.5rem;
248
+ margin-bottom: 10px;
249
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
250
+ }
251
+
252
+ .oru-header p {
253
+ font-size: 1.1rem;
254
+ opacity: 0.95;
255
+ margin: 8px 0;
256
+ }
257
+
258
+ /* Button styling */
259
+ .gradio-button {
260
+ border-radius: 8px !important;
261
+ font-weight: 600 !important;
262
+ transition: all 0.3s ease !important;
263
+ border: none !important;
264
+ }
265
+
266
+ .gradio-button.primary {
267
+ background: linear-gradient(45deg, var(--oru-primary-blue), var(--oru-accent-blue)) !important;
268
+ color: white !important;
269
+ }
270
+
271
+ .gradio-button.primary:hover {
272
+ transform: translateY(-2px) !important;
273
+ box-shadow: 0 6px 20px rgba(4, 30, 65, 0.3) !important;
274
+ }
275
+
276
+ .gradio-button.secondary {
277
+ background: linear-gradient(45deg, var(--oru-accent-tan), var(--oru-primary-tan)) !important;
278
+ color: white !important;
279
+ }
280
+
281
+ .gradio-button.secondary:hover {
282
+ transform: translateY(-2px) !important;
283
+ box-shadow: 0 6px 20px rgba(195, 146, 54, 0.3) !important;
284
+ }
285
+
286
+ /* Small sample buttons */
287
+ .gradio-button[size="sm"] {
288
+ background: var(--oru-secondary-tan) !important;
289
+ color: var(--oru-primary-blue) !important;
290
+ border: 1px solid var(--oru-primary-tan) !important;
291
+ font-size: 14px !important;
292
+ padding: 8px 12px !important;
293
+ }
294
+
295
+ .gradio-button[size="sm"]:hover {
296
+ background: var(--oru-primary-tan) !important;
297
+ color: white !important;
298
+ transform: translateY(-1px) !important;
299
+ }
300
+
301
+ /* Input styling */
302
+ .gradio-textbox textarea, .gradio-textbox input {
303
+ border: 2px solid var(--oru-secondary-tan) !important;
304
+ border-radius: 8px !important;
305
+ font-size: 16px !important;
306
+ }
307
+
308
+ .gradio-textbox textarea:focus, .gradio-textbox input:focus {
309
+ border-color: var(--oru-accent-blue) !important;
310
+ box-shadow: 0 0 0 3px rgba(123, 175, 212, 0.2) !important;
311
+ }
312
+
313
+ /* Output styling */
314
+ .output-markdown h2 {
315
+ color: var(--oru-primary-blue) !important;
316
+ border-bottom: 3px solid var(--oru-accent-blue) !important;
317
+ padding-bottom: 10px !important;
318
+ margin-top: 20px !important;
319
+ }
320
+
321
+ .output-markdown h3 {
322
+ color: var(--oru-accent-tan) !important;
323
+ }
324
+
325
+ .output-markdown {
326
+ line-height: 1.6 !important;
327
+ }
328
+
329
+ /* Status messages */
330
+ .status-success {
331
+ background: linear-gradient(45deg, #d4edda, var(--oru-secondary-tan)) !important;
332
+ border: 2px solid var(--oru-primary-tan) !important;
333
+ color: var(--oru-primary-blue) !important;
334
+ padding: 15px !important;
335
+ border-radius: 10px !important;
336
+ font-weight: 600 !important;
337
+ }
338
+
339
+ .status-error {
340
+ background: linear-gradient(45deg, #f8d7da, #fde2e4) !important;
341
+ border: 2px solid #dc3545 !important;
342
+ color: #721c24 !important;
343
+ padding: 15px !important;
344
+ border-radius: 10px !important;
345
+ font-weight: 600 !important;
346
+ }
347
+
348
+ /* Demo mode styling */
349
+ .status-demo {
350
+ background: linear-gradient(45deg, #fff3cd, var(--oru-secondary-tan)) !important;
351
+ border: 2px solid var(--oru-accent-tan) !important;
352
+ color: var(--oru-primary-blue) !important;
353
+ padding: 15px !important;
354
+ border-radius: 10px !important;
355
+ font-weight: 600 !important;
356
+ }
357
+
358
+ /* Configuration panel */
359
+ .config-panel {
360
+ background: linear-gradient(45deg, var(--oru-secondary-tan), #f8f9fa) !important;
361
+ padding: 20px !important;
362
+ border-radius: 10px !important;
363
+ border: 1px solid var(--oru-primary-tan) !important;
364
+ }
365
+
366
+ /* Accordion styling */
367
+ .gradio-accordion {
368
+ border: 1px solid var(--oru-primary-tan) !important;
369
+ border-radius: 10px !important;
370
+ }
371
+
372
+ .gradio-accordion summary {
373
+ background: var(--oru-secondary-tan) !important;
374
+ color: var(--oru-primary-blue) !important;
375
+ font-weight: 600 !important;
376
+ padding: 15px !important;
377
+ }
378
+
379
+ /* Sample queries section */
380
+ .sample-queries {
381
+ background: linear-gradient(45deg, var(--oru-secondary-tan), #ffffff) !important;
382
+ padding: 20px !important;
383
+ border-radius: 10px !important;
384
+ border: 1px solid var(--oru-primary-tan) !important;
385
+ margin-top: 15px !important;
386
+ }
387
+
388
+ .sample-queries h3 {
389
+ color: var(--oru-primary-blue) !important;
390
+ margin-bottom: 15px !important;
391
+ font-size: 1.2rem !important;
392
+ }
393
+
394
+ /* Source citations styling */
395
+ .output-markdown strong {
396
+ color: var(--oru-accent-tan) !important;
397
+ }
398
+
399
+ .output-markdown em {
400
+ color: var(--oru-primary-blue) !important;
401
+ font-style: italic !important;
402
+ }
403
+ """
404
+
405
+ # Create the Gradio interface
406
+ with gr.Blocks(css=custom_css, title="ORU IT Helpdesk Assistant") as app:
407
+
408
+ # Header with ORU Branding
409
+ gr.HTML("""
410
+ <div class="oru-header">
411
+ <h1>πŸ›οΈ Oral Roberts University</h1>
412
+ <h2 style="font-size: 2rem; margin: 15px 0; font-weight: 600;">IT Helpdesk Assistant</h2>
413
+ <p style="font-size: 18px; margin: 10px 0;">Powered by Amazon Bedrock Knowledge Bases & S3 Vectors</p>
414
+ <p style="font-size: 16px; opacity: 0.95; margin: 5px 0;">Get instant answers to your IT questions β€’ Available 24/7</p>
415
+ <div style="margin-top: 20px; padding: 10px; background: rgba(255,255,255,0.1); border-radius: 8px; display: inline-block;">
416
+ <span style="font-size: 14px; opacity: 0.9;">πŸ” Search β€’ πŸ“š Retrieve Sources β€’ ⚑ Instant Responses</span>
417
+ </div>
418
+ </div>
419
+ """)
420
+
421
+ with gr.Row():
422
+ with gr.Column(scale=2):
423
+ # Input section
424
+ query_input = gr.Textbox(
425
+ label="πŸ” Ask your IT question:",
426
+ placeholder="e.g., How do I change my password?",
427
+ lines=2,
428
+ max_lines=4
429
+ )
430
+
431
+ with gr.Row():
432
+ search_btn = gr.Button(
433
+ "πŸ€– Get AI Answer",
434
+ variant="primary",
435
+ scale=2,
436
+ elem_classes=["primary"]
437
+ )
438
+ retrieve_btn = gr.Button(
439
+ "πŸ“š Show Sources",
440
+ variant="secondary",
441
+ scale=1,
442
+ elem_classes=["secondary"]
443
+ )
444
+
445
+ # Sample queries with ORU styling
446
+ gr.HTML("""
447
+ <div class="sample-queries">
448
+ <h3>πŸ’‘ Try These Common ORU IT Questions:</h3>
449
+ <p style="color: #041E41; margin-bottom: 15px; font-size: 14px;">
450
+ Click any question below to auto-fill the search box ⬆️
451
+ </p>
452
+ </div>
453
+ """)
454
+
455
+ with gr.Column():
456
+ for i in range(0, len(SAMPLE_QUERIES), 2):
457
+ with gr.Row():
458
+ if i < len(SAMPLE_QUERIES):
459
+ sample_btn1 = gr.Button(
460
+ SAMPLE_QUERIES[i],
461
+ size="sm",
462
+ elem_classes=["sample-query-btn"]
463
+ )
464
+ sample_btn1.click(lambda x=SAMPLE_QUERIES[i]: x, outputs=query_input)
465
+ if i + 1 < len(SAMPLE_QUERIES):
466
+ sample_btn2 = gr.Button(
467
+ SAMPLE_QUERIES[i + 1],
468
+ size="sm",
469
+ elem_classes=["sample-query-btn"]
470
+ )
471
+ sample_btn2.click(lambda x=SAMPLE_QUERIES[i + 1]: x, outputs=query_input)
472
+
473
+ with gr.Column(scale=3):
474
+ # Output section
475
+ status_output = gr.HTML(label="Status")
476
+ response_output = gr.Markdown(label="Response")
477
+ sources_output = gr.Markdown(label="Sources", visible=True)
478
+
479
+ # Configuration info with ORU branding
480
+ with gr.Accordion("πŸ”§ System Configuration", open=False):
481
+ gr.HTML(f"""
482
+ <div class="config-panel">
483
+ <h3 style="color: #041E41; margin-bottom: 15px; font-size: 1.3rem;">πŸ“Š Knowledge Base Configuration</h3>
484
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
485
+ <div>
486
+ <p><strong style="color: #C39236;">Knowledge Base ID:</strong><br>
487
+ <code style="background: #E9DFBB; padding: 5px; border-radius: 3px; color: #041E41;">{KNOWLEDGE_BASE_ID}</code></p>
488
+ <p><strong style="color: #C39236;">AWS Region:</strong><br>
489
+ <code style="background: #E9DFBB; padding: 5px; border-radius: 3px; color: #041E41;">{AWS_REGION}</code></p>
490
+ </div>
491
+ <div>
492
+ <p><strong style="color: #C39236;">AI Model:</strong><br>
493
+ <span style="color: #041E41;">Amazon Nova Pro</span></p>
494
+ <p><strong style="color: #C39236;">Connection Status:</strong><br>
495
+ <span style="color: {'#28a745' if bedrock_agent else ('#f39c12' if DEMO_MODE else '#dc3545')}; font-weight: 600;">
496
+ {'βœ… Connected & Ready' if bedrock_agent else ('🚧 Demo Mode - Configure AWS' if DEMO_MODE else '❌ Connection Error')}
497
+ </span></p>
498
+ </div>
499
+ </div>
500
+ <div style="margin-top: 15px; padding: 10px; background: rgba(123, 175, 212, 0.1); border-radius: 5px; border-left: 4px solid #7BAFD4;">
501
+ <small style="color: #041E41;"><strong>πŸ’‘ Tip:</strong> This system uses ORU's IT knowledge base to provide accurate, up-to-date answers to common technical questions.</small>
502
+ </div>
503
+ </div>
504
+ """)
505
+
506
+ # Setup instructions for Hugging Face Spaces
507
+ with gr.Accordion("πŸ“‹ Hugging Face Spaces Configuration", open=False):
508
+ gr.Markdown(f"""
509
+ ## πŸš€ Configure This Space for ORU IT:
510
+
511
+ ### Current Status:
512
+ - **Demo Mode:** {'🚧 Active' if DEMO_MODE else 'βœ… Disabled - AWS configured'}
513
+ - **Knowledge Base ID:** `{KNOWLEDGE_BASE_ID}`
514
+ - **AWS Region:** `{AWS_REGION}`
515
+
516
+ ### βš™οΈ Required Environment Variables:
517
+ To enable full functionality, add these in your **Space Settings > Variables and secrets**:
518
+
519
+ ```bash
520
+ KNOWLEDGE_BASE_ID=YOUR_ACTUAL_KNOWLEDGE_BASE_ID
521
+ AWS_REGION=us-east-1
522
+ AWS_ACCESS_KEY_ID=your_aws_access_key
523
+ AWS_SECRET_ACCESS_KEY=your_aws_secret_key
524
+ ```
525
+
526
+ ### πŸ“ Setup Steps:
527
+
528
+ 1. **Get Your Knowledge Base ID:**
529
+ - Go to AWS Bedrock Console
530
+ - Navigate to Knowledge Bases
531
+ - Find your "ORU IT Helpdesk Knowledge Base"
532
+ - Copy the Knowledge Base ID
533
+
534
+ 2. **Configure AWS Credentials:**
535
+ - Use an IAM user with Bedrock permissions
536
+ - Required permissions: `bedrock:InvokeModel`, `bedrock:Retrieve`, `bedrock:RetrieveAndGenerate`
537
+
538
+ 3. **Add to Hugging Face Spaces:**
539
+ - Go to your Space settings
540
+ - Click "Variables and secrets"
541
+ - Add each environment variable as a "Secret"
542
+ - The Space will automatically restart with new configuration
543
+
544
+ 4. **Test the Integration:**
545
+ - Once configured, the "🚧 Demo Mode" status will change to "βœ… Connected"
546
+ - Test with sample queries to verify everything works
547
+
548
+ ### πŸ”’ Security Best Practices:
549
+ - βœ… Use IAM user with minimal required permissions
550
+ - βœ… Store credentials as Secrets (not Variables) in Spaces
551
+ - βœ… Monitor AWS CloudTrail for API usage
552
+ - βœ… Regularly rotate access keys
553
+
554
+ ### πŸ’° Cost Optimization:
555
+ - S3 Vectors provides up to 90% cost savings vs traditional vector databases
556
+ - Monitor your AWS Bedrock usage in the AWS console
557
+ - Consider setting up billing alerts
558
+ """)
559
+
560
+ # Event handlers
561
+ search_btn.click(
562
+ fn=lambda query: format_response(query, "generate"),
563
+ inputs=[query_input],
564
+ outputs=[response_output, sources_output, status_output]
565
+ )
566
+
567
+ retrieve_btn.click(
568
+ fn=lambda query: format_response(query, "retrieve"),
569
+ inputs=[query_input],
570
+ outputs=[response_output, sources_output, status_output]
571
+ )
572
+
573
+ # Allow Enter key to trigger search
574
+ query_input.submit(
575
+ fn=lambda query: format_response(query, "generate"),
576
+ inputs=[query_input],
577
+ outputs=[response_output, sources_output, status_output]
578
+ )
579
+
580
+ # Launch configuration
581
+ if __name__ == "__main__":
582
+ print("πŸ›οΈ Starting ORU IT Helpdesk Assistant...")
583
+ print("πŸŽ“ Oral Roberts University - Information Technology")
584
+ print(f"πŸ“š Knowledge Base ID: {KNOWLEDGE_BASE_ID}")
585
+ print(f"🌍 AWS Region: {AWS_REGION}")
586
+ print(f"🚧 Demo Mode: {'Active' if DEMO_MODE else 'Disabled'}")
587
+ print("=" * 50)
588
+ if DEMO_MODE:
589
+ print("πŸ”§ Configuration needed:")
590
+ print(" β–‘ Set KNOWLEDGE_BASE_ID environment variable")
591
+ print(" β–‘ Set AWS_ACCESS_KEY_ID environment variable")
592
+ print(" β–‘ Set AWS_SECRET_ACCESS_KEY environment variable")
593
+ print(" β–‘ Verify Bedrock model access is enabled")
594
+ else:
595
+ print("βœ… Configuration looks good!")
596
+ print("πŸ”§ Checklist:")
597
+ print(" βœ… Environment variables configured")
598
+ print(" β–‘ Test with sample queries")
599
+ print(" β–‘ Verify knowledge base content")
600
+ print("=" * 50)
601
+ print("πŸš€ Ready to serve ORU students, faculty, and staff!")
602
+
603
+ app.launch()