File size: 12,812 Bytes
e59d91d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
---
sidebar_position: 5
---

# Google Colab Setup Guide

Run Open Navigator data processing workflows in Google Colab with GPU/TPU acceleration and Google Drive storage.

## 🎯 When to Use Google Colab

- βœ… Process large datasets without local compute resources
- βœ… Access free GPU/TPU for ML tasks (Gemini AI analysis, embeddings)
- βœ… Bypass local disk space limitations
- βœ… Run long-running jobs without keeping laptop on
- βœ… Share notebooks with collaborators

## πŸ“‹ Prerequisites

- Google account
- Google Drive with available storage (15 GB free tier)
- GitHub account (for cloning repository)

## πŸš€ Quick Start

### Step 1: Create New Colab Notebook

1. Go to [Google Colab](https://colab.research.google.com/)
2. Click **File** β†’ **New Notebook**
3. Rename notebook: `open-navigator-processing.ipynb`

### Step 2: Mount Google Drive

```python
from google.colab import drive
drive.mount('/content/drive')

# Verify mount
!ls /content/drive/MyDrive/
```

**Authorization:**
1. Click the link that appears
2. Choose your Google account
3. Click "Allow" to give Colab access to Drive
4. Copy the authorization code
5. Paste into Colab input box

### Step 3: Clone Repository

```python
# Navigate to Google Drive
%cd /content/drive/MyDrive/

# Clone repository (only needed first time)
# Skip git hooks to avoid permission issues on Google Drive
!git clone --no-checkout https://github.com/getcommunityone/open-navigator.git
%cd open-navigator
!git config core.hooksPath /dev/null
!git checkout main

# Install Git LFS and pull large files (images, etc.)
!apt-get install -y git-lfs
!git lfs install
!git lfs pull

# Verify clone
!ls -lh
```

**Subsequent runs:**
```python
# Just navigate to existing directory
%cd /content/drive/MyDrive/open-navigator

# Pull latest changes (skip hooks)
!git config core.hooksPath /dev/null
!git pull origin main
!git lfs pull
```

**⚠️ Common Issues:**

**"Permission denied" on git hooks:**
```python
# Fix hook permissions
!git config core.hooksPath /dev/null
# This disables git hooks which don't work on Google Drive
```

**"Files should have been pointers" (Git LFS):**
```python
# Install Git LFS
!apt-get install -y git-lfs
!git lfs install

# Pull actual files (replaces pointers with real files)
!git lfs pull

# Verify images loaded correctly
!ls -lh frontend/public/*.png
```

### Step 4: Install Dependencies

```python
# Install Python packages
!pip install -q -r requirements.txt

# Verify installation
!pip list | grep pandas
!pip list | grep psycopg2
```

### Step 5: Configure Environment

```python
# Create .env file with secrets
import os

# Database connection
os.environ['NEON_DATABASE_URL_DEV'] = 'postgresql://user:pass@host:5432/dbname'

# API keys
os.environ['YOUTUBE_API_KEY'] = 'your_youtube_api_key_here'
os.environ['GEMINI_API_KEY'] = 'your_gemini_api_key_here'

# Verify
!echo "Environment configured"
```

**Or upload .env file:**
```python
from google.colab import files

# Upload .env from your computer
uploaded = files.upload()

# Move to project root
!mv .env /content/drive/MyDrive/open-navigator/
```

## πŸ“Š Common Workflows

### Load YouTube Videos to Bronze

```python
%cd /content/drive/MyDrive/open-navigator

# Load recent videos (last 180 days)
!python packages/scrapers/src/scrapers/youtube/load_youtube_events_to_postgres.py \
  --days 180 \
  --max-videos 200 \
  --skip-transcripts \
  --states AL,MA,WI,GA,IN,WA
```

### Process with Gemini AI

```python
%cd /content/drive/MyDrive/open-navigator

# Analyze meetings with Gemini (uses GPU if available)
!python scripts/datasources/gemini/load_meeting_transcripts.py \
  --meetings-per-channel 10 \
  --delay 3
```

### Run dbt Models

```python
%cd /content/drive/MyDrive/open-navigator/dbt_project

# Install dbt if needed
!pip install -q dbt-postgres

# Run models
!dbt run --select tag:bronze
!dbt run --select tag:ai-extraction
```

### Download YouTube Audio to Google Drive

```python
%cd /content/drive/MyDrive/CommunityOne/open-navigator

# Install yt-dlp if needed
!pip install -q yt-dlp

# Download audio from recent videos (last 30 days)
!python packages/scrapers/src/scrapers/youtube/download_audio_to_drive.py \
  --output-dir /content/drive/MyDrive/CommunityOne/youtube_audio \
  --days 30 \
  --limit 50

# Download from specific channels
!python packages/scrapers/src/scrapers/youtube/download_audio_to_drive.py \
  --output-dir /content/drive/MyDrive/CommunityOne/youtube_audio \
  --channels "City of Seattle,Portland" \
  --limit 100

# Download from specific states
!python packages/scrapers/src/scrapers/youtube/download_audio_to_drive.py \
  --output-dir /content/drive/MyDrive/CommunityOne/youtube_audio \
  --states AL,MA,WI \
  --limit 200
```

**Output Structure:**
```
youtube_audio/
β”œβ”€β”€ City-of-Seattle_UCxxx/
β”‚   β”œβ”€β”€ 2026-05-01_City Council Meeting.opus
β”‚   β”œβ”€β”€ 2026-04-28_Planning Commission.opus
β”‚   └── ...
β”œβ”€β”€ Portland-City-Hall_UCyyy/
β”‚   β”œβ”€β”€ 2026-05-02_Council Session.opus
β”‚   └── ...
```

**Audio Format:**
- Opus codec (best quality, smallest size ~10-20 MB/hour)
- Audio-only (no video)
- Organized by channel β†’ date_title.opus

### Export Data to Google Drive

```python
# Create output directory in Drive
!mkdir -p /content/drive/MyDrive/open-navigator-exports

# Export query results
import pandas as pd
from sqlalchemy import create_engine

engine = create_engine(os.environ['NEON_DATABASE_URL_DEV'])

df = pd.read_sql("""
    SELECT * FROM bronze.bronze_event_youtube
    WHERE event_date >= '2026-01-01'
""", engine)

# Save to Drive
df.to_parquet('/content/drive/MyDrive/open-navigator-exports/youtube_2026.parquet')
df.to_csv('/content/drive/MyDrive/open-navigator-exports/youtube_2026.csv', index=False)

print(f"βœ… Exported {len(df):,} rows to Google Drive")
```

## βš™οΈ Advanced Configuration

### Use GPU Runtime

1. Click **Runtime** β†’ **Change runtime type**
2. Select **GPU** from Hardware accelerator dropdown
3. Choose **T4** or **A100** (paid tier)
4. Click **Save**

**Verify GPU:**
```python
import torch
print(f"GPU available: {torch.cuda.is_available()}")
if torch.cuda.is_available():
    print(f"GPU name: {torch.cuda.get_device_name(0)}")
```

### Increase RAM

For large datasets:
1. **Runtime** β†’ **Change runtime type**
2. Select **High-RAM** from Runtime shape
3. Click **Save**

### Keep Session Alive

Colab disconnects after ~90 minutes of inactivity:

```python
# Add to notebook cell
import time
from IPython.display import clear_output

while True:
    print("❀️ Keeping session alive...")
    time.sleep(60)  # Ping every minute
    clear_output(wait=True)
```

**Or use browser extension:**
- [Colab Auto Reconnect](https://chrome.google.com/webstore/detail/colab-auto-reconnect)

### Monitor Progress

```python
# Install progress bars
!pip install -q tqdm

# Use in Python scripts
from tqdm import tqdm
import time

for i in tqdm(range(100), desc="Processing"):
    time.sleep(0.1)
```

## πŸ“ Organize Google Drive

**Recommended folder structure:**

```
MyDrive/
β”œβ”€β”€ open-navigator/              # Git repository
β”‚   β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ dbt_project/
β”‚   └── .env
β”œβ”€β”€ open-navigator-exports/      # Output files
β”‚   β”œβ”€β”€ youtube_2026.parquet
β”‚   └── reports/
└── open-navigator-cache/        # Large cache files
    └── gemini/
```

**Create structure:**
```python
!mkdir -p /content/drive/MyDrive/open-navigator-exports
!mkdir -p /content/drive/MyDrive/open-navigator-cache
```

## πŸ”’ Security Best Practices

### Don't Hardcode Secrets

❌ **Bad:**
```python
api_key = "AIzaSyABC123..."  # Visible in notebook history!
```

βœ… **Good:**
```python
from google.colab import userdata
api_key = userdata.get('GEMINI_API_KEY')
```

**Store secrets in Colab:**
1. Click πŸ”‘ (Secrets) in left sidebar
2. Click **Add new secret**
3. Name: `GEMINI_API_KEY`, Value: your key
4. Click **Save**

### Use Read-Only Database Credentials

For analytics/exports, use read-only credentials:

```python
# Read-only user (safer for Colab)
os.environ['DATABASE_URL_READONLY'] = 'postgresql://readonly:pass@host:5432/db'
```

## πŸ› Troubleshooting

### Git Hooks Permission Error

**Error:**
```
fatal: cannot exec '/content/drive/MyDrive/.../open-navigator/.git/hooks/post-checkout': Permission denied
```

**Fix:**
```python
%cd /content/drive/MyDrive/open-navigator

# Disable git hooks (they don't work on Google Drive FUSE filesystem)
!git config core.hooksPath /dev/null

# Verify
!git config --get core.hooksPath
# Should output: /dev/null
```

**Why this happens:**
- Google Drive FUSE filesystem doesn't preserve execute permissions
- Git hooks need executable permissions to run
- Solution: Disable hooks entirely (they're for pre-commit checks, not needed in Colab)

### Git LFS Files Missing (Image Pointers)

**Error:**
```
Encountered 20 file(s) that should have been pointers, but weren't:
    frontend/public/communityone_logo.jpg
    website/static/img/favicon.ico
    ...
```

**Fix:**
```python
# Install Git LFS
!apt-get update -qq
!apt-get install -y git-lfs

# Initialize Git LFS for this repository
%cd /content/drive/MyDrive/open-navigator
!git lfs install

# Pull actual files (replaces text pointers with real binary files)
!git lfs pull

# Verify images loaded correctly
!file frontend/public/communityone_logo.jpg
# Should say: "JPEG image data", not "ASCII text"
```

**Why this happens:**
- Repository uses Git LFS (Large File Storage) for images/binaries
- Plain `git clone` downloads text pointers instead of actual files
- Need `git lfs pull` to fetch the real files

**To avoid this in future clones:**
```python
# Install Git LFS BEFORE cloning
!apt-get install -y git-lfs
!git lfs install

# Then clone (will automatically fetch LFS files)
!git clone https://github.com/getcommunityone/open-navigator.git
```

### "No module named 'xyz'"

```python
# Install missing package
!pip install xyz

# Or reinstall all requirements
!pip install -q -r requirements.txt --force-reinstall
```

### "Permission denied" when writing to Drive

```python
# Remount Drive
from google.colab import drive
drive.flush_and_unmount()
drive.mount('/content/drive')
```

### "Runtime disconnected"

- Save work frequently: **Ctrl+S** or **File** β†’ **Save**
- Download important outputs: `files.download('output.csv')`
- Use checkpoints in long-running scripts

### "Out of memory"

```python
# Clear Python variables
import gc
gc.collect()

# Or restart runtime
# Runtime β†’ Restart runtime
```

## πŸ“ Example Notebook Template

```python
# ========================================
# Open Navigator - Google Colab Workflow
# ========================================

# 1. Mount Google Drive
from google.colab import drive
drive.mount('/content/drive')

# 2. Navigate to project
%cd /content/drive/MyDrive/open-navigator

# 3. Pull latest code (if repo exists)
!git pull origin main

# 4. Install dependencies
!pip install -q -r requirements.txt

# 5. Set environment variables
from google.colab import userdata
import os

os.environ['NEON_DATABASE_URL_DEV'] = userdata.get('DATABASE_URL')
os.environ['GEMINI_API_KEY'] = userdata.get('GEMINI_API_KEY')

# 6. Run data processing
print("πŸš€ Starting data load...")
!python packages/scrapers/src/scrapers/youtube/load_youtube_events_to_postgres.py \
  --days 30 \
  --max-videos 100 \
  --skip-transcripts

print("βœ… Data load complete!")

# 7. Export results
import pandas as pd
from sqlalchemy import create_engine

engine = create_engine(os.environ['NEON_DATABASE_URL_DEV'])

df = pd.read_sql("""
    SELECT COUNT(*) as total_videos, 
           MAX(event_date) as latest_date
    FROM bronze.bronze_event_youtube
""", engine)

print(df)
```

## πŸ”— Related Resources

- [Google Colab Documentation](https://colab.research.google.com/notebooks/intro.ipynb)
- [Colab Pro Features](https://colab.research.google.com/signup) - Faster GPUs, longer runtimes
- [Colab Tips & Tricks](https://medium.com/@oribarel/colab-tricks-7e8c07b9e4c6)

## πŸ’‘ Tips

- **Save notebooks in Drive** - File β†’ Save a copy in Drive
- **Use markdown cells** - Document your workflow
- **Share notebooks** - Click Share button, send link
- **Schedule runs** - Use [Colab Pro+](https://colab.research.google.com/signup/pricing) background execution
- **Download outputs** - `files.download('filename')` before session ends
- **Check quotas** - Free tier has usage limits, upgrade to Pro if needed

## πŸ†˜ Getting Help

If you encounter issues:

1. Check [Common Errors](#-troubleshooting) above
2. Search [Colab FAQ](https://research.google.com/colaboratory/faq.html)
3. Ask in [GitHub Discussions](https://github.com/getcommunityone/open-navigator/discussions)
4. File bug report with notebook link