DJ-Goanna-Coding commited on
Commit
bed2f8d
·
verified ·
1 Parent(s): b6fd557

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +27 -567
app.py CHANGED
@@ -1,573 +1,33 @@
1
- """
2
- VAMGUARD TITAN - HuggingFace Space Manager
3
- Streamlit App with AI Agent Interface
4
- """
5
 
6
- import streamlit as st
7
  import os
8
- import yaml
9
- from pathlib import Path
10
- from datetime import datetime
11
- from typing import Optional
12
- from dotenv import load_dotenv
13
- import anthropic
14
- from hf_space_sync import HFSpaceSync
15
- from genesis_boiler import GenesisBoiler
16
- import json
17
-
18
- # Load environment variables
19
- load_dotenv()
20
-
21
- # Page configuration
22
- st.set_page_config(
23
- page_title="VAMGUARD TITAN - HF Space Manager",
24
- page_icon="🚀",
25
- layout="wide",
26
- initial_sidebar_state="expanded"
27
- )
28
-
29
-
30
- class AIAgent:
31
- """AI Agent powered by Claude for code and file management."""
32
-
33
- def __init__(self):
34
- api_key = os.getenv("ANTHROPIC_API_KEY")
35
- if not api_key:
36
- raise ValueError("ANTHROPIC_API_KEY not found in environment")
37
-
38
- self.client = anthropic.Anthropic(api_key=api_key)
39
- self.model = os.getenv("AGENT_MODEL", "claude-sonnet-4-5-20250929")
40
- self.max_tokens = int(os.getenv("MAX_TOKENS", "4096"))
41
-
42
- def process_request(self, user_message: str, context: str = "") -> str:
43
- """
44
- Process a user request using Claude AI.
45
-
46
- Args:
47
- user_message: The user's message/request
48
- context: Additional context for the agent
49
-
50
- Returns:
51
- Agent's response
52
- """
53
- system_prompt = f"""You are a helpful AI assistant managing HuggingFace Spaces and GitHub repositories.
54
- You can help with:
55
- - File management and organization
56
- - Code analysis and suggestions
57
- - Space deployment strategies
58
- - Automation workflows
59
- - Mapping and inventory management
60
-
61
- {context}"""
62
-
63
- try:
64
- message = self.client.messages.create(
65
- model=self.model,
66
- max_tokens=self.max_tokens,
67
- system=system_prompt,
68
- messages=[
69
- {"role": "user", "content": user_message}
70
- ]
71
- )
72
- return message.content[0].text
73
- except Exception as e:
74
- return f"Error communicating with AI agent: {str(e)}"
75
-
76
-
77
- def load_config():
78
- """Load application configuration."""
79
  try:
80
- with open("config.yaml", 'r') as f:
81
- return yaml.safe_load(f)
82
- except FileNotFoundError:
83
- st.error("config.yaml not found!")
84
- return {}
85
-
86
-
87
- def init_session_state():
88
- """Initialize Streamlit session state."""
89
- if 'messages' not in st.session_state:
90
- st.session_state.messages = []
91
- if 'agent' not in st.session_state:
92
- try:
93
- st.session_state.agent = AIAgent()
94
- except Exception as e:
95
- st.session_state.agent = None
96
- st.error(f"Failed to initialize AI agent: {e}")
97
- if 'hf_sync' not in st.session_state:
98
- try:
99
- st.session_state.hf_sync = HFSpaceSync()
100
- except Exception as e:
101
- st.session_state.hf_sync = None
102
- st.warning(f"HuggingFace sync not available: {e}")
103
-
104
-
105
- def main():
106
- """Main application."""
107
- init_session_state()
108
- config = load_config()
109
-
110
- # Sidebar
111
- with st.sidebar:
112
- st.title("🚀 VAMGUARD TITAN")
113
- st.markdown("---")
114
-
115
- page = st.radio(
116
- "Navigation",
117
- ["🏠 Dashboard", "🤖 AI Agent", "📁 File Manager",
118
- "🔄 Space Sync", "📊 Audit & Archive", "⚙️ Settings"]
119
  )
 
 
 
120
 
121
- st.markdown("---")
122
- st.markdown("### Quick Actions")
123
-
124
- if st.button("🔍 Run Audit"):
125
- with st.spinner("Running file audit..."):
126
- try:
127
- boiler = GenesisBoiler()
128
- results = boiler.run_full_audit()
129
- st.success(f"Audit complete! {results['file_count']} files processed")
130
- except Exception as e:
131
- st.error(f"Audit failed: {e}")
132
-
133
- if st.button("🔄 Sync All Spaces"):
134
- if st.session_state.hf_sync:
135
- with st.spinner("Syncing spaces..."):
136
- try:
137
- for space_name, space_config in config.get('spaces', {}).items():
138
- if space_config.get('auto_sync', False):
139
- result = st.session_state.hf_sync.sync_directory(
140
- space_config['name']
141
- )
142
- st.success(f"Synced {space_name}: {result['uploaded']} files")
143
- except Exception as e:
144
- st.error(f"Sync failed: {e}")
145
-
146
- # Main content area
147
- if page == "🏠 Dashboard":
148
- show_dashboard(config)
149
- elif page == "🤖 AI Agent":
150
- show_ai_agent(config)
151
- elif page == "📁 File Manager":
152
- show_file_manager(config)
153
- elif page == "🔄 Space Sync":
154
- show_space_sync(config)
155
- elif page == "📊 Audit & Archive":
156
- show_audit_archive(config)
157
- elif page == "⚙️ Settings":
158
- show_settings(config)
159
-
160
-
161
- def show_dashboard(config):
162
- """Display dashboard overview."""
163
- st.title("Dashboard")
164
- #!/usr/bin/env python3
165
- """
166
- 🧠 TIA-ARCHITECT-CORE (v25.0.OMNI++)
167
- T.I.A. - The Intelligence Architect
168
- Central Reasoning Hub for Q.G.T.N.L. Citadel Mesh
169
-
170
- Purpose: RAG-powered intelligence synthesis, model management, and worker orchestration
171
- """
172
-
173
- import os
174
- import sys
175
- import json
176
- import streamlit as st
177
- from pathlib import Path
178
- from datetime import datetime
179
- from typing import Dict, List, Optional
180
-
181
- # ═══════════════════════════════════════════════════════════════════
182
- # PAGE CONFIGURATION (must be called exactly once, before any other st calls)
183
- # ═══════════════════════════════════════════════════════════════════
184
-
185
- st.set_page_config(
186
- page_title="TIA-ARCHITECT-CORE",
187
- layout="wide",
188
- page_icon="🧠",
189
- initial_sidebar_state="expanded"
190
- )
191
-
192
- # ═══════════════════════════════════════════════════════════════════
193
- # IDENTITY & CONFIGURATION
194
- # ═══════════════════════════════════════════════════════════════════
195
-
196
- IDENTITY = {
197
- "name": "T.I.A.",
198
- "full_name": "The Intelligence Architect",
199
- "version": "25.0.OMNI++",
200
- "role": "Central Reasoning Hub",
201
- "github": "DJ-Goana-Coding",
202
- "huggingface": "DJ-Goanna-Coding"
203
- }
204
-
205
- # ═══════════════════════════════════════════════════════════════════
206
- # SIDEBAR - SYSTEM STATUS
207
- # ═══════════════════════════════════════════════════════════════════
208
-
209
- with st.sidebar:
210
- st.image("https://img.shields.io/badge/T.I.A.-ARCHITECT-blueviolet?style=for-the-badge", width=220)
211
- st.markdown(f"## 🧠 {IDENTITY['full_name']}")
212
- st.caption(f"Version {IDENTITY['version']}")
213
-
214
- st.divider()
215
-
216
- # System Status
217
- st.markdown("### 📊 System Status")
218
-
219
- # Check for environment variables
220
- env_status = {
221
- "HF_TOKEN": os.getenv("HF_TOKEN") is not None,
222
- "GITHUB_TOKEN": os.getenv("GITHUB_TOKEN") is not None,
223
- "GOOGLE_API_KEY": os.getenv("GOOGLE_API_KEY") is not None,
224
- }
225
-
226
- for key, status in env_status.items():
227
- icon = "✅" if status else "⚠️"
228
- st.markdown(f"{icon} **{key}**")
229
-
230
- st.divider()
231
-
232
- # Quick Stats
233
- st.markdown("### 📈 Quick Stats")
234
-
235
- # Check for data directories
236
- data_dir = Path("data")
237
- models_dir = data_dir / "models"
238
- workers_dir = data_dir / "workers"
239
-
240
- models_count = len(list(models_dir.glob("*"))) if models_dir.exists() else 0
241
- workers_count = len(list(workers_dir.glob("*.py"))) if workers_dir.exists() else 0
242
-
243
- st.metric("🤖 Models", models_count)
244
- st.metric("⚙️ Workers", workers_count)
245
- st.metric("🔗 Connections", len(env_status))
246
-
247
- st.divider()
248
-
249
- st.markdown("""
250
- ### Quick Links
251
- - [GitHub Repo](https://github.com/DJ-Goana-Coding/mapping-and-inventory)
252
- - [HF Space](https://huggingface.co/spaces/DJ-Goanna-Coding/TIA-ARCHITECT-CORE)
253
-
254
- ### Authority Hierarchy
255
- 1. Cloud Hubs (L4)
256
- 2. GitHub Repositories
257
- 3. GDrive Metadata
258
- 4. Local Nodes
259
- """)
260
-
261
- st.markdown("---")
262
- st.markdown("**Weld. Pulse. Ignite.** 🔥")
263
-
264
- # ═══════════════════════════════════════════════════════════════════
265
- # MAIN DASHBOARD
266
- # ═══���═══════════════════════════════════════════════════════════════
267
-
268
- st.title("🧠 TIA-ARCHITECT-CORE")
269
- st.markdown(f"**{IDENTITY['full_name']}** — Central Reasoning Hub")
270
- st.markdown("---")
271
-
272
- # Health check indicator
273
- st.success("✅ Space is operational - Build successful!")
274
-
275
- # Create tabs
276
- tab1, tab2, tab3, tab4, tab5 = st.tabs([
277
- "🏠 Dashboard",
278
- "🤖 Models",
279
- "⚙️ Workers",
280
- "📚 Knowledge Base",
281
- "🔧 Tools"
282
- ])
283
-
284
- # ═══════════════════════════════════════════════════════════════════
285
- # TAB 1: DASHBOARD
286
- # ═══════════════════════════════════════════════════════════════════
287
-
288
- with tab1:
289
- st.header("Welcome to T.I.A. Central")
290
-
291
- col1, col2, col3 = st.columns(3)
292
-
293
- with col1:
294
- st.markdown("### 🎯 Purpose")
295
- st.markdown("""
296
- - **RAG Intelligence** - Vector search & synthesis
297
- - **Model Management** - Deploy & monitor AI models
298
- - **Worker Orchestration** - Coordinate automation workers
299
- - **Knowledge Mesh** - Connect all Citadel nodes
300
- """)
301
-
302
- with col2:
303
- st.markdown("### 🌐 Connections")
304
- st.markdown("""
305
- - **GitHub** - DJ-Goana-Coding (single N)
306
- - **HuggingFace** - DJ-Goanna-Coding (double N)
307
- - **Mapping Hub** - Inventory & artifacts
308
- - **Districts** - D01-D12 data nodes
309
- """)
310
-
311
- with col3:
312
- st.markdown("### 📡 Status")
313
- st.success("✅ Core Systems Online")
314
- st.info(f"📅 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
315
- st.info(f"🔢 Python {sys.version.split()[0]}")
316
-
317
- st.divider()
318
-
319
- # District Topology Summary
320
- st.subheader("🗺️ District Topology")
321
- districts = {
322
- "D01": "Core Infrastructure",
323
- "D02": "Data Processing",
324
- "D03": "Security & Authentication",
325
- "D04": "ML Models & Training",
326
- "D05": "API & Integration",
327
- "D06": "Random Futures Trading",
328
- }
329
-
330
- district_cols = st.columns(3)
331
- for i, (district_id, description) in enumerate(districts.items()):
332
- with district_cols[i % 3]:
333
- st.markdown(f"**{district_id}**: {description}")
334
-
335
- # ═══════════════════════════════════════════════════════════════════
336
- # TAB 2: MODELS REGISTRY
337
- # ═══════════════════════════════════════════════════════════════════
338
-
339
- with tab2:
340
- st.header("🤖 AI Models Registry")
341
-
342
- # Check for models manifest
343
- models_manifest_path = Path("data/models/models_manifest.json")
344
-
345
- if models_manifest_path.exists():
346
- with open(models_manifest_path, 'r') as f:
347
- models_manifest = json.load(f)
348
-
349
- st.success(f"✅ Models Registry Loaded - {models_manifest.get('total_models', 0)} models")
350
-
351
- # Display categories
352
- categories = models_manifest.get("categories", {})
353
-
354
- if categories:
355
- for category, data in categories.items():
356
- with st.expander(f"📂 {category} ({data.get('count', 0)} models)"):
357
- models = data.get("models", [])
358
- if models:
359
- for model in models:
360
- st.markdown(f"- **{model.get('name', 'Unknown')}**")
361
- st.caption(model.get('description', ''))
362
- else:
363
- st.info("No models in this category yet")
364
- else:
365
- st.info("Models registry is empty. Use the deployment tools to add models.")
366
- else:
367
- st.warning("⚠️ Models manifest not found")
368
- st.info("Run the model downloader to populate the registry")
369
-
370
- st.divider()
371
-
372
- # Model Downloader Section
373
- st.subheader("📥 Download Models")
374
-
375
- with st.expander("🔮 Frontier Models Downloader (2026)"):
376
- st.markdown("""
377
- Download cutting-edge AI models discovered via web reconnaissance:
378
- - **Gemma 4** (2B, 4B) - Multimodal, edge-ready
379
- - **Qwen 3.5** (7B, 14B) - Multilingual code specialist
380
- - **DeepSeek V4** - Reasoning & code expert
381
- - **Phi-4** - Microsoft's compact powerhouse
382
- - **Ministral 8B** - Mistral's efficient model
383
- """)
384
-
385
- if st.button("🚀 Launch Downloader"):
386
- st.info("Downloader script available in `scripts/download_frontier_models_2026.py`")
387
- st.code("python scripts/download_frontier_models_2026.py", language="bash")
388
-
389
- # ═══════════════════════════════════════════════════════════════════
390
- # TAB 3: WORKERS CONSTELLATION
391
- # ═══════════════════════════════════════════════════════════════════
392
-
393
- with tab3:
394
- st.header("⚙️ Workers Constellation")
395
-
396
- st.markdown("""
397
- Worker constellation enables automated task execution across the Citadel Mesh.
398
- """)
399
-
400
- # Check for workers manifest
401
- workers_manifest_path = Path("data/workers/workers_manifest.json")
402
-
403
- if workers_manifest_path.exists():
404
- with open(workers_manifest_path, 'r') as f:
405
- workers_manifest = json.load(f)
406
-
407
- st.success(f"✅ Workers Registry Loaded - {workers_manifest.get('total_workers', 0)} workers")
408
-
409
- # Display worker categories
410
- categories = workers_manifest.get("categories", {})
411
-
412
- for category, data in categories.items():
413
- with st.expander(f"🔧 {category} ({data.get('count', 0)} workers)"):
414
- workers = data.get("workers", [])
415
- if workers:
416
- for worker in workers:
417
- st.markdown(f"**{worker.get('name', 'Unknown')}**")
418
- st.caption(worker.get('description', ''))
419
- else:
420
- st.info("No workers in this category yet")
421
- else:
422
- st.warning("⚠️ Workers manifest not found")
423
-
424
- st.divider()
425
-
426
- # Apps Script Integration
427
- st.subheader("📱 Apps Script Workers")
428
-
429
- with st.expander("🛠️ Apps Script Toolbox"):
430
- st.markdown("""
431
- Bridge between CITADEL workers and Google Sheets for automated reporting.
432
-
433
- **Features:**
434
- - Identity Strike Reports (Section 44 Audit)
435
- - Full Archive Audits (MD5 hashing, file inventory)
436
- - Worker Status Dashboards
437
-
438
- **Available in:** `workers/apps_script_toolbox.py`
439
- """)
440
-
441
- # ═══════════════════════════════════════════════════════════════════
442
- # TAB 4: KNOWLEDGE BASE (RAG)
443
- # ═══════════════════════════════════════════════════════════════════
444
-
445
- with tab4:
446
- st.header("📚 Knowledge Base & RAG")
447
-
448
- st.info("🔮 RAG (Retrieval-Augmented Generation) system coming soon")
449
-
450
- st.markdown("""
451
- The Knowledge Base will provide:
452
- - **Vector Search** - Semantic search across all Citadel documents
453
- - **Intelligence Synthesis** - Connect related information
454
- - **Context Retrieval** - Pull relevant data for queries
455
- - **Memory Mesh** - Persistent knowledge graph
456
- """)
457
-
458
- # RAG status
459
- rag_dir = Path("rag_store")
460
- if rag_dir.exists():
461
- st.success("✅ RAG store detected")
462
- rag_files = list(rag_dir.glob("*"))
463
- st.metric("📄 RAG Files", len(rag_files))
464
- else:
465
- st.warning("⚠️ RAG store not initialized")
466
-
467
- st.divider()
468
-
469
- st.subheader("🔮 Oracle Reasoning Engine")
470
- st.markdown("""
471
- The Oracle provides:
472
- - Multi-agent reasoning and coordination
473
- - Strategic planning and decision support
474
- - System orchestration and workflow generation
475
- - Citadel mesh coherence maintenance
476
- """)
477
-
478
- # Simple chat interface
479
- user_query = st.text_area("Ask the Oracle:", placeholder="Enter your query...")
480
- if st.button("Submit Query"):
481
- if user_query:
482
- st.success(f"Query received: {user_query}")
483
- st.info("Oracle reasoning engine processing... (Full implementation pending)")
484
- else:
485
- st.warning("Please enter a query")
486
-
487
- # ═══════════════════════════════════════════════════════════════════
488
- # TAB 5: TOOLS & UTILITIES
489
- # ═══════════════════════════════════════════════════════════════════
490
-
491
- with tab5:
492
- st.header("🔧 Tools & Utilities")
493
-
494
- # System Information
495
- with st.expander("💻 System Information"):
496
- st.markdown(f"""
497
- - **Python Version:** {sys.version}
498
- - **Platform:** {sys.platform}
499
- - **Working Directory:** {os.getcwd()}
500
- """)
501
-
502
- # Environment Variables
503
- with st.expander("🔐 Environment Variables"):
504
- env_vars = ["HF_TOKEN", "GITHUB_TOKEN", "GOOGLE_API_KEY", "SPACE_ID"]
505
- for var in env_vars:
506
- value = os.getenv(var)
507
- if value:
508
- st.success(f"✅ {var} - Configured")
509
- else:
510
- st.warning(f"⚠️ {var} - Not set")
511
-
512
- # Build Info
513
- with st.expander("📦 Build Information"):
514
- col1, col2, col3 = st.columns(3)
515
- with col1:
516
- st.metric("Build Status", "✅ Success", "Operational")
517
- st.metric("Dependencies", "✅ Installed", "All packages loaded")
518
- with col2:
519
- st.metric("Python Version", sys.version.split()[0], "Compatible")
520
- st.metric("Streamlit", "1.42+", "Compatible")
521
- with col3:
522
- st.metric("Space Status", "🟢 Running", "Healthy")
523
- st.metric("Port", "8501", "Active")
524
-
525
- # Quick Actions
526
- st.subheader("⚡ Quick Actions")
527
-
528
- col1, col2 = st.columns(2)
529
-
530
- with col1:
531
- if st.button("🔄 Refresh Data"):
532
- st.rerun()
533
-
534
- if st.button("📊 Generate Report"):
535
- st.info("Report generation available via workers")
536
-
537
- with col2:
538
- if st.button("🧹 Clear Cache"):
539
- st.cache_data.clear()
540
- st.success("Cache cleared")
541
-
542
- if st.button("💾 Export Config"):
543
- config = {
544
- "identity": IDENTITY,
545
- "timestamp": datetime.now().isoformat(),
546
- "env_status": {k: v for k, v in env_status.items()}
547
- }
548
- st.download_button(
549
- "⬇️ Download Config",
550
- data=json.dumps(config, indent=2),
551
- file_name="tia_config.json",
552
- mime="application/json"
553
- )
554
-
555
- st.divider()
556
-
557
- st.subheader("📋 Recent Updates")
558
- st.success("✅ Fixed Python 3.13 compatibility (numpy>=2.0.0, pandas>=2.2.0)")
559
- st.success("✅ Fixed invalid streamlit version (1.56.0 → >=1.42.0)")
560
- st.success("✅ Added setuptools>=75.0.0 to prevent pkg_resources errors")
561
- st.success("✅ Resolved 503 error with proper health check configuration")
562
- st.success("✅ Fixed duplicate st.set_page_config() error in app.py")
563
-
564
- # ═══════════════════════════════════════════════════════════════════
565
- # FOOTER
566
- # ═══════════════════════════════════════════════════════════════════
567
 
568
- st.markdown("---")
569
- st.caption(
570
- f"🧠 {IDENTITY['full_name']} v{IDENTITY['version']} | "
571
- f"GitHub: {IDENTITY['github']} | HF: {IDENTITY['huggingface']}"
572
- )
573
- st.caption("Double-N Rift: GitHub (DJ-Goana-Coding) ⟷ HuggingFace (DJ-Goanna-Coding)")
 
 
 
 
 
1
 
 
2
  import os
3
+ from flask import Flask, request, jsonify
4
+ from huggingface_hub import HfApi
5
+
6
+ app = Flask(__name__)
7
+ TOKEN = os.getenv("HF_TOKEN")
8
+ VAULT_ID = "DJ-Goanna-Coding/Mapping-and-Inventory-storage" # All feed the Librarian Vault
9
+ api = HfApi(token=TOKEN)
10
+
11
+ @app.route('/ignite_harvest', methods=['POST'])
12
+ def catch_payload():
13
+ if not TOKEN:
14
+ return jsonify({"status": "ERROR", "message": "HF_TOKEN missing"}), 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  try:
16
+ payload = request.json
17
+ filename = payload.get("fileName", "swarm_shard.9293")
18
+ api.upload_file(
19
+ path_or_fileobj=payload.get("content", "").encode('utf-8'),
20
+ path_in_repo=f"ingested_core/{filename}",
21
+ repo_id=VAULT_ID,
22
+ repo_type="dataset"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  )
24
+ return jsonify({"status": "CAUGHT_BY_SWARM", "file": filename}), 200
25
+ except Exception as e:
26
+ return jsonify({"status": "ERROR", "message": str(e)}), 500
27
 
28
+ @app.route('/', methods=['GET'])
29
+ def health_check():
30
+ return jsonify({"status": "SWARM_NODE_ONLINE"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ if __name__ == "__main__":
33
+ app.run(host="0.0.0.0", port=7860)