Davidtran99
commited on
Commit
·
3718c84
1
Parent(s):
eef3d60
chore: sync with main repo
Browse files- Dockerfile +63 -1
- HUONG_DAN_LAY_CLOUDFLARE_TUNNEL.md +110 -0
- README_khoidongDB.md +89 -0
- README_ngrok_fix.md +99 -0
- SETUP_CLOUDFLARE_TUNNEL_POSTGRES.md +88 -0
- __pycache__/start_ngrok_and_set_db.cpython-310.pyc +0 -0
- backend/hue_portal/chatbot/chatbot.py +1 -1
- backend/hue_portal/chatbot/tests/__pycache__/test_smoke.cpython-310.pyc +0 -0
- backend/hue_portal/core/management/commands/__pycache__/retry_ingestion_job.cpython-310.pyc +0 -0
- check_tunnel_unraid.sh +106 -0
- entrypoint.sh +48 -13
- fix_ngrok_postgres.sh +173 -0
- khoidongDB.sh +243 -0
- monitor_space.py +150 -0
- set_hf_space_env_qwen.py +99 -0
- test_cloudflare_tunnel.py +172 -0
- test_ngrok.sh +206 -0
- test_ngrok_simple.sh +114 -0
- test_postgres_quick.sh +76 -0
- test_tunnel.sh +139 -0
Dockerfile
CHANGED
|
@@ -54,11 +54,73 @@ fi
|
|
| 54 |
echo "[Docker] Collecting static files..."
|
| 55 |
python /app/hue_portal/manage.py collectstatic --noinput || echo "[Docker] Collectstatic failed, continuing..."
|
| 56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
echo "[Docker] Starting gunicorn..."
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
| 59 |
EOF
|
| 60 |
|
| 61 |
RUN chmod +x /entrypoint.sh
|
| 62 |
|
| 63 |
EXPOSE 7860
|
| 64 |
CMD ["/entrypoint.sh"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
echo "[Docker] Collecting static files..."
|
| 55 |
python /app/hue_portal/manage.py collectstatic --noinput || echo "[Docker] Collectstatic failed, continuing..."
|
| 56 |
|
| 57 |
+
echo "[Docker] Preloading all models to avoid first-request timeout..."
|
| 58 |
+
python -c "
|
| 59 |
+
import os
|
| 60 |
+
import sys
|
| 61 |
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hue_portal.hue_portal.settings')
|
| 62 |
+
import django
|
| 63 |
+
django.setup()
|
| 64 |
+
|
| 65 |
+
print('[Docker] 🔄 Starting model preload...', flush=True)
|
| 66 |
+
|
| 67 |
+
# 1. Preload Embedding Model (BGE-M3)
|
| 68 |
+
try:
|
| 69 |
+
print('[Docker] 📦 Preloading embedding model (BGE-M3)...', flush=True)
|
| 70 |
+
from hue_portal.core.embeddings import get_embedding_model
|
| 71 |
+
embedding_model = get_embedding_model()
|
| 72 |
+
if embedding_model:
|
| 73 |
+
print('[Docker] ✅ Embedding model preloaded successfully', flush=True)
|
| 74 |
+
else:
|
| 75 |
+
print('[Docker] ⚠️ Embedding model not loaded', flush=True)
|
| 76 |
+
except Exception as e:
|
| 77 |
+
print(f'[Docker] ⚠️ Embedding model preload failed: {e}', flush=True)
|
| 78 |
+
|
| 79 |
+
# 2. Preload LLM Model (llama.cpp)
|
| 80 |
+
llm_provider = os.environ.get('DEFAULT_LLM_PROVIDER') or os.environ.get('LLM_PROVIDER', '')
|
| 81 |
+
if llm_provider.lower() == 'llama_cpp':
|
| 82 |
+
try:
|
| 83 |
+
print('[Docker] 📦 Preloading LLM model (llama.cpp)...', flush=True)
|
| 84 |
+
from hue_portal.chatbot.llm_integration import get_llm_generator
|
| 85 |
+
llm_gen = get_llm_generator()
|
| 86 |
+
if llm_gen and hasattr(llm_gen, 'llama_cpp') and llm_gen.llama_cpp:
|
| 87 |
+
print('[Docker] ✅ LLM model preloaded successfully', flush=True)
|
| 88 |
+
else:
|
| 89 |
+
print('[Docker] ⚠️ LLM model not loaded (may load on first request)', flush=True)
|
| 90 |
+
except Exception as e:
|
| 91 |
+
print(f'[Docker] ⚠️ LLM model preload failed: {e} (will load on first request)', flush=True)
|
| 92 |
+
else:
|
| 93 |
+
print(f'[Docker] ⏭️ Skipping LLM preload (provider is {llm_provider or \"not set\"}, not llama_cpp)', flush=True)
|
| 94 |
+
|
| 95 |
+
# 3. Preload Reranker Model
|
| 96 |
+
try:
|
| 97 |
+
print('[Docker] 📦 Preloading reranker model...', flush=True)
|
| 98 |
+
from hue_portal.core.reranker import get_reranker
|
| 99 |
+
reranker = get_reranker()
|
| 100 |
+
if reranker:
|
| 101 |
+
print('[Docker] ✅ Reranker model preloaded successfully', flush=True)
|
| 102 |
+
else:
|
| 103 |
+
print('[Docker] ⚠️ Reranker model not loaded (may load on first request)', flush=True)
|
| 104 |
+
except Exception as e:
|
| 105 |
+
print(f'[Docker] ⚠️ Reranker preload failed: {e} (will load on first request)', flush=True)
|
| 106 |
+
|
| 107 |
+
print('[Docker] ✅ Model preload completed', flush=True)
|
| 108 |
+
" || echo "[Docker] ⚠️ Model preload had errors (models will load on first request)"
|
| 109 |
+
|
| 110 |
echo "[Docker] Starting gunicorn..."
|
| 111 |
+
# Reduce tokenizers parallelism warnings and risk of fork deadlocks
|
| 112 |
+
export TOKENIZERS_PARALLELISM=false
|
| 113 |
+
# Shorter timeouts to avoid long hangs; adjust if needed
|
| 114 |
+
cd /app/backend && export PYTHONPATH="/app/backend:${PYTHONPATH}" && exec gunicorn -b 0.0.0.0:7860 --timeout 600 --graceful-timeout 600 --worker-class sync --config python:hue_portal.hue_portal.gunicorn_app hue_portal.hue_portal.gunicorn_app:application
|
| 115 |
EOF
|
| 116 |
|
| 117 |
RUN chmod +x /entrypoint.sh
|
| 118 |
|
| 119 |
EXPOSE 7860
|
| 120 |
CMD ["/entrypoint.sh"]
|
| 121 |
+
|
| 122 |
+
EXPOSE 7860
|
| 123 |
+
CMD ["/entrypoint.sh"]
|
| 124 |
+
|
| 125 |
+
EXPOSE 7860
|
| 126 |
+
CMD ["/entrypoint.sh"]
|
HUONG_DAN_LAY_CLOUDFLARE_TUNNEL.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hướng dẫn lấy Cloudflare Tunnel URL từ Unraid
|
| 2 |
+
|
| 3 |
+
## Cách 1: Xem Logs của Container (Dễ nhất)
|
| 4 |
+
|
| 5 |
+
1. **Vào Unraid Web UI**
|
| 6 |
+
- Mở trình duyệt, truy cập Unraid dashboard
|
| 7 |
+
|
| 8 |
+
2. **Vào Docker tab**
|
| 9 |
+
- Click vào tab "Docker" ở menu trên
|
| 10 |
+
|
| 11 |
+
3. **Tìm container "Hue-DB-Tunnel"**
|
| 12 |
+
- Scroll xuống tìm container có tên "Hue-DB-Tunnel"
|
| 13 |
+
- Hoặc tìm container có image `figro/unraid-cloudflared-tunnel` hoặc `cloudflare/cloudflared`
|
| 14 |
+
|
| 15 |
+
4. **Click vào container → Logs**
|
| 16 |
+
- Click vào tên container
|
| 17 |
+
- Click tab "Logs" hoặc icon logs
|
| 18 |
+
- Tìm dòng có chứa:
|
| 19 |
+
- `https://` hoặc `tcp://`
|
| 20 |
+
- `trycloudflare.com` hoặc `cfargotunnel.com`
|
| 21 |
+
- Hoặc dòng có format: `Connection established: tcp://...`
|
| 22 |
+
|
| 23 |
+
5. **Copy URL**
|
| 24 |
+
- URL thường có dạng:
|
| 25 |
+
- `xyz-abc-123.trycloudflare.com:5432`
|
| 26 |
+
- `xyz-abc-123.cfargotunnel.com:5432`
|
| 27 |
+
- Hoặc chỉ có hostname: `xyz-abc-123.trycloudflare.com`
|
| 28 |
+
|
| 29 |
+
## Cách 2: Xem Config của Container
|
| 30 |
+
|
| 31 |
+
1. **Vào container "Hue-DB-Tunnel"**
|
| 32 |
+
- Click vào container trong Docker tab
|
| 33 |
+
|
| 34 |
+
2. **Xem "Edit" hoặc "Show more settings"**
|
| 35 |
+
- Tìm phần "Extra Parameters" hoặc "Post Arguments"
|
| 36 |
+
- Hoặc xem "Environment Variables"
|
| 37 |
+
- Tìm các biến như:
|
| 38 |
+
- `TUNNEL_URL`
|
| 39 |
+
- `TUNNEL_HOST`
|
| 40 |
+
- `TUNNEL_PORT`
|
| 41 |
+
|
| 42 |
+
## Cách 3: SSH vào Unraid và xem logs
|
| 43 |
+
|
| 44 |
+
1. **SSH vào Unraid**
|
| 45 |
+
```bash
|
| 46 |
+
ssh root@192.168.1.212
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
2. **Xem logs của container**
|
| 50 |
+
```bash
|
| 51 |
+
docker logs Hue-DB-Tunnel
|
| 52 |
+
# hoặc
|
| 53 |
+
docker logs 944286801b0d
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
3. **Tìm URL trong logs**
|
| 57 |
+
```bash
|
| 58 |
+
docker logs Hue-DB-Tunnel | grep -E "trycloudflare|cfargotunnel|Connection established|tcp://"
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
## Cách 4: Kiểm tra qua Cloudflare Dashboard
|
| 62 |
+
|
| 63 |
+
1. **Đăng nhập Cloudflare Dashboard**
|
| 64 |
+
- Vào https://dash.cloudflare.com
|
| 65 |
+
- Chọn account của bạn
|
| 66 |
+
|
| 67 |
+
2. **Vào Zero Trust → Tunnels**
|
| 68 |
+
- Menu bên trái: "Zero Trust" → "Networks" → "Tunnels"
|
| 69 |
+
- Tìm tunnel có tên liên quan đến "Hue" hoặc "DB"
|
| 70 |
+
|
| 71 |
+
3. **Xem Public Hostname**
|
| 72 |
+
- Click vào tunnel
|
| 73 |
+
- Xem phần "Public Hostname" hoặc "Private Network"
|
| 74 |
+
- Copy URL
|
| 75 |
+
|
| 76 |
+
## Thông tin cần lấy
|
| 77 |
+
|
| 78 |
+
Sau khi có URL, bạn cần:
|
| 79 |
+
|
| 80 |
+
1. **Hostname**: Ví dụ `xyz-abc-123.trycloudflare.com`
|
| 81 |
+
2. **Port**: Thường là `5432` (PostgreSQL port)
|
| 82 |
+
3. **Full URL**: `xyz-abc-123.trycloudflare.com:5432`
|
| 83 |
+
|
| 84 |
+
## Test kết nối
|
| 85 |
+
|
| 86 |
+
Sau khi có URL, chạy script test:
|
| 87 |
+
|
| 88 |
+
```bash
|
| 89 |
+
cd /Users/davidtran/Downloads/TryHarDemNayProject
|
| 90 |
+
python3 hue-portal-backend/test_cloudflare_tunnel.py
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
Nhập:
|
| 94 |
+
- Host: `xyz-abc-123.trycloudflare.com`
|
| 95 |
+
- Port: `5432`
|
| 96 |
+
- User: `hue_remote`
|
| 97 |
+
- Password: `huepass123`
|
| 98 |
+
- Database: `hue_portal`
|
| 99 |
+
|
| 100 |
+
## Lưu ý
|
| 101 |
+
|
| 102 |
+
- Cloudflare Tunnel URL có thể thay đổi mỗi lần restart container
|
| 103 |
+
- Nếu dùng Cloudflare Zero Trust (có account), URL sẽ ổn định hơn
|
| 104 |
+
- Nếu dùng `cloudflared` free (trycloudflare.com), URL sẽ thay đổi mỗi lần chạy
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
|
README_khoidongDB.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Script khởi động Database (khoidongDB.sh)
|
| 2 |
+
|
| 3 |
+
Script tự động khởi động PostgreSQL và ngrok tunnel với port và URL cố định.
|
| 4 |
+
|
| 5 |
+
## Cách sử dụng
|
| 6 |
+
|
| 7 |
+
```bash
|
| 8 |
+
cd hue-portal-backend
|
| 9 |
+
./khoidongDB.sh
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
## Chức năng
|
| 13 |
+
|
| 14 |
+
1. **Kiểm tra PostgreSQL**: Kiểm tra PostgreSQL có đang chạy trên port 5543 không
|
| 15 |
+
2. **Khởi động ngrok**:
|
| 16 |
+
- Kiểm tra ngrok đã chạy chưa
|
| 17 |
+
- Nếu chưa, khởi động ngrok tunnel forward đến localhost:5543
|
| 18 |
+
3. **Lưu thông tin tunnel**: Lưu ngrok URL vào `ops/.env.tunnel`
|
| 19 |
+
4. **Cập nhật Hugging Face Space**: Tự động cập nhật DATABASE_URL lên Space
|
| 20 |
+
|
| 21 |
+
## Cấu hình
|
| 22 |
+
|
| 23 |
+
Script sử dụng các biến môi trường sau (có thể set trong `.env`):
|
| 24 |
+
|
| 25 |
+
- `POSTGRES_PORT`: Port PostgreSQL (mặc định: 5543)
|
| 26 |
+
- `POSTGRES_USER`: PostgreSQL user (mặc định: hue_remote)
|
| 27 |
+
- `POSTGRES_PASSWORD`: PostgreSQL password (mặc định: huepass123)
|
| 28 |
+
- `POSTGRES_DB`: Database name (mặc định: hue_portal)
|
| 29 |
+
- `NGROK_REGION`: Ngrok region (mặc định: ap)
|
| 30 |
+
- `HF_SPACE_ID`: Hugging Face Space ID (mặc định: davidtran999/hue-portal-backend)
|
| 31 |
+
|
| 32 |
+
## Output
|
| 33 |
+
|
| 34 |
+
Script sẽ:
|
| 35 |
+
- Hiển thị trạng thái PostgreSQL
|
| 36 |
+
- Hiển thị ngrok tunnel URL
|
| 37 |
+
- Lưu thông tin vào `ops/.env.tunnel`
|
| 38 |
+
- Cập nhật DATABASE_URL lên Hugging Face Space
|
| 39 |
+
|
| 40 |
+
## Ví dụ output
|
| 41 |
+
|
| 42 |
+
```
|
| 43 |
+
[DB-START] ============================================================
|
| 44 |
+
[DB-START] Khởi động PostgreSQL và ngrok tunnel
|
| 45 |
+
[DB-START] ============================================================
|
| 46 |
+
[DB-START] Kiểm tra PostgreSQL trên port 5543...
|
| 47 |
+
[DB-START] ✅ PostgreSQL đang chạy trên port 5543
|
| 48 |
+
[DB-START] Khởi động ngrok tunnel...
|
| 49 |
+
[DB-START] ✅ Ngrok đã chạy sẵn: tcp://0.tcp.ap.ngrok.io:15028
|
| 50 |
+
[DB-START] Lưu thông tin tunnel...
|
| 51 |
+
[DB-START] ✅ Đã lưu tunnel info vào ops/.env.tunnel
|
| 52 |
+
[DB-START] Cập nhật DATABASE_URL lên Hugging Face Space...
|
| 53 |
+
[DB-START] ============================================================
|
| 54 |
+
[DB-START] ✅ Hoàn tất!
|
| 55 |
+
[DB-START] PostgreSQL: localhost:5543
|
| 56 |
+
[DB-START] Ngrok tunnel: tcp://0.tcp.ap.ngrok.io:15028
|
| 57 |
+
[DB-START] DATABASE_URL: postgres://hue_remote:***@0.tcp.ap.ngrok.io:15028/hue_portal
|
| 58 |
+
[DB-START] ============================================================
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
## Lưu ý
|
| 62 |
+
|
| 63 |
+
- PostgreSQL phải đang chạy trước khi chạy script
|
| 64 |
+
- Ngrok phải được cài đặt và cấu hình (API key)
|
| 65 |
+
- Script sẽ tự động kill ngrok process cũ nếu có
|
| 66 |
+
- Thông tin tunnel được lưu vào `ops/.env.tunnel` để sử dụng sau
|
| 67 |
+
|
| 68 |
+
## Troubleshooting
|
| 69 |
+
|
| 70 |
+
### PostgreSQL không chạy
|
| 71 |
+
```bash
|
| 72 |
+
# Kiểm tra PostgreSQL
|
| 73 |
+
psql -h localhost -p 5543 -U hue_remote -d hue_portal -c "SELECT 1;"
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
### Ngrok không khởi động được
|
| 77 |
+
```bash
|
| 78 |
+
# Kiểm tra ngrok API
|
| 79 |
+
curl http://127.0.0.1:4040/api/tunnels
|
| 80 |
+
|
| 81 |
+
# Xem ngrok logs
|
| 82 |
+
cat ops/ngrok.log
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
### Không kết nối được qua ngrok
|
| 86 |
+
- Kiểm tra PostgreSQL có accept connection từ ngrok không
|
| 87 |
+
- Kiểm tra firewall/network settings
|
| 88 |
+
- Test kết nối từ local machine trước
|
| 89 |
+
|
README_ngrok_fix.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Fix Ngrok Tunnel với PostgreSQL
|
| 2 |
+
|
| 3 |
+
## Vấn đề
|
| 4 |
+
|
| 5 |
+
Ngrok TCP tunnel không kết nối được PostgreSQL trong Docker container mặc dù:
|
| 6 |
+
- ✅ PostgreSQL đang listen trên `*` (tất cả interfaces)
|
| 7 |
+
- ✅ pg_hba.conf đã có rule cho `0.0.0.0/0`
|
| 8 |
+
- ✅ Docker port mapping đúng (`0.0.0.0:5543->5432`)
|
| 9 |
+
- ✅ Ngrok tunnel đang chạy và forward đến `localhost:5543`
|
| 10 |
+
|
| 11 |
+
## Nguyên nhân có thể
|
| 12 |
+
|
| 13 |
+
1. **Ngrok TCP tunnel không forward đúng PostgreSQL protocol handshake**
|
| 14 |
+
2. **Docker network isolation** - PostgreSQL trong container không accept connection từ ngrok IP range
|
| 15 |
+
3. **PostgreSQL trong Docker chỉ bind đến localhost bên trong container**
|
| 16 |
+
|
| 17 |
+
## Giải pháp đã thử
|
| 18 |
+
|
| 19 |
+
### 1. Fix PostgreSQL config
|
| 20 |
+
- ✅ Set `listen_addresses = '*'`
|
| 21 |
+
- ✅ Thêm rule vào `pg_hba.conf`: `host all all 0.0.0.0/0 md5`
|
| 22 |
+
- ✅ Restart PostgreSQL container
|
| 23 |
+
|
| 24 |
+
### 2. Fix Docker config
|
| 25 |
+
- ✅ Set port mapping: `0.0.0.0:5543:5432`
|
| 26 |
+
- ✅ Thêm command: `postgres -c listen_addresses='*'`
|
| 27 |
+
|
| 28 |
+
### 3. Scripts đã tạo
|
| 29 |
+
- ✅ `khoidongDB.sh` - Khởi động ngrok và update DATABASE_URL
|
| 30 |
+
- ✅ `fix_ngrok_postgres.sh` - Fix và test ngrok tunnel
|
| 31 |
+
|
| 32 |
+
## Giải pháp thay thế
|
| 33 |
+
|
| 34 |
+
### Option 1: SSH Tunnel (Khuyến nghị)
|
| 35 |
+
```bash
|
| 36 |
+
# Trên server có PostgreSQL
|
| 37 |
+
ssh -N -L 5543:localhost:5543 user@your-server
|
| 38 |
+
|
| 39 |
+
# Hoặc reverse SSH tunnel
|
| 40 |
+
ssh -R 5543:localhost:5543 user@your-server
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
### Option 2: Cloudflare Tunnel
|
| 44 |
+
```bash
|
| 45 |
+
# Cài đặt cloudflared
|
| 46 |
+
brew install cloudflared # macOS
|
| 47 |
+
# hoặc
|
| 48 |
+
sudo apt install cloudflared # Linux
|
| 49 |
+
|
| 50 |
+
# Tạo tunnel
|
| 51 |
+
cloudflared tunnel --url tcp://localhost:5543
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
### Option 3: Tailscale
|
| 55 |
+
```bash
|
| 56 |
+
# Cài đặt Tailscale
|
| 57 |
+
# Tạo mesh network
|
| 58 |
+
# PostgreSQL sẽ accessible qua Tailscale IP
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
### Option 4: Docker network_mode: host
|
| 62 |
+
```yaml
|
| 63 |
+
# docker-compose.yml
|
| 64 |
+
db:
|
| 65 |
+
network_mode: host
|
| 66 |
+
# ... config khác
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
**Lưu ý:** `network_mode: host` chỉ hoạt động trên Linux, không hoạt động trên macOS/Windows.
|
| 70 |
+
|
| 71 |
+
## Workaround hiện tại
|
| 72 |
+
|
| 73 |
+
Space đang dùng **SQLite fallback**:
|
| 74 |
+
- ✅ App chạy được
|
| 75 |
+
- ✅ Migration pass
|
| 76 |
+
- ✅ Chatbot hoạt động (không có data)
|
| 77 |
+
- ⚠️ Không có data để trả lời câu hỏi phức tạp
|
| 78 |
+
|
| 79 |
+
## Next Steps
|
| 80 |
+
|
| 81 |
+
1. **Test SSH tunnel** thay vì ngrok
|
| 82 |
+
2. **Hoặc dùng Cloudflare Tunnel** (miễn phí, ổn định hơn)
|
| 83 |
+
3. **Hoặc chấp nhận SQLite fallback** cho Space (chỉ để test)
|
| 84 |
+
|
| 85 |
+
## Scripts
|
| 86 |
+
|
| 87 |
+
- `khoidongDB.sh` - Khởi động ngrok và update DATABASE_URL
|
| 88 |
+
- `fix_ngrok_postgres.sh` - Fix và test ngrok tunnel (chưa fix được)
|
| 89 |
+
|
| 90 |
+
## Cách sử dụng
|
| 91 |
+
|
| 92 |
+
```bash
|
| 93 |
+
# Khởi động ngrok và update DATABASE_URL
|
| 94 |
+
./hue-portal-backend/khoidongDB.sh
|
| 95 |
+
|
| 96 |
+
# Fix và test ngrok tunnel
|
| 97 |
+
./hue-portal-backend/fix_ngrok_postgres.sh
|
| 98 |
+
```
|
| 99 |
+
|
SETUP_CLOUDFLARE_TUNNEL_POSTGRES.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hướng dẫn Setup Cloudflare Tunnel cho PostgreSQL
|
| 2 |
+
|
| 3 |
+
## Bước 1: Kiểm tra Cloudflare Tunnel hiện tại
|
| 4 |
+
|
| 5 |
+
Trên Unraid terminal:
|
| 6 |
+
|
| 7 |
+
```bash
|
| 8 |
+
docker ps | grep -i cloudflare
|
| 9 |
+
docker ps | grep -i tunnel
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
## Bước 2: Setup Cloudflare Tunnel cho PostgreSQL
|
| 13 |
+
|
| 14 |
+
### Option A: Thêm route vào tunnel hiện có (nếu có Cloudflare Zero Trust)
|
| 15 |
+
|
| 16 |
+
1. **Vào Cloudflare Dashboard**
|
| 17 |
+
- https://dash.cloudflare.com
|
| 18 |
+
- Zero Trust → Networks → Tunnels
|
| 19 |
+
|
| 20 |
+
2. **Chọn tunnel hiện có**
|
| 21 |
+
- Click vào tunnel name
|
| 22 |
+
|
| 23 |
+
3. **Thêm Public Hostname**
|
| 24 |
+
- Click "Public Hostname" tab
|
| 25 |
+
- Click "Add a public hostname"
|
| 26 |
+
- Configure:
|
| 27 |
+
- **Subdomain**: `postgres` (hoặc tên bạn muốn)
|
| 28 |
+
- **Domain**: Chọn domain của bạn (ví dụ: `aliss.io.vn`)
|
| 29 |
+
- **Service Type**: `TCP`
|
| 30 |
+
- **URL**: `192.168.1.212:5432`
|
| 31 |
+
- Save
|
| 32 |
+
|
| 33 |
+
4. **Lấy URL**
|
| 34 |
+
- URL sẽ là: `postgres.aliss.io.vn:5432` (hoặc domain bạn chọn)
|
| 35 |
+
|
| 36 |
+
### Option B: Tạo tunnel mới với cloudflared (Free, URL thay đổi)
|
| 37 |
+
|
| 38 |
+
Trên Unraid terminal:
|
| 39 |
+
|
| 40 |
+
```bash
|
| 41 |
+
# 1. Tạo tunnel mới
|
| 42 |
+
docker run -d \
|
| 43 |
+
--name cloudflare-postgres \
|
| 44 |
+
--network host \
|
| 45 |
+
cloudflare/cloudflared:latest \
|
| 46 |
+
tunnel --url tcp://192.168.1.212:5432
|
| 47 |
+
|
| 48 |
+
# 2. Đợi vài giây
|
| 49 |
+
sleep 5
|
| 50 |
+
|
| 51 |
+
# 3. Lấy URL từ logs
|
| 52 |
+
docker logs cloudflare-postgres | grep -oE "trycloudflare.com:[0-9]+" | head -1
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
## Bước 3: Test kết nối
|
| 56 |
+
|
| 57 |
+
Từ máy local:
|
| 58 |
+
|
| 59 |
+
```bash
|
| 60 |
+
cd /Users/davidtran/Downloads/TryHarDemNayProject
|
| 61 |
+
./hue-portal-backend/test_ngrok_simple.sh [CLOUDFLARE_HOST] [PORT]
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
Hoặc:
|
| 65 |
+
|
| 66 |
+
```bash
|
| 67 |
+
PGPASSWORD=huepass123 psql -h [CLOUDFLARE_HOST] -p [PORT] -U hue_remote -d hue_portal -c "SELECT 1;"
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
## Bước 4: Update DATABASE_URL
|
| 71 |
+
|
| 72 |
+
```
|
| 73 |
+
postgres://hue_remote:huepass123@[CLOUDFLARE_HOST]:[PORT]/hue_portal
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
Update trên Hugging Face Space:
|
| 77 |
+
- Settings → Variables → DATABASE_URL
|
| 78 |
+
|
| 79 |
+
## Lưu ý
|
| 80 |
+
|
| 81 |
+
- **Cloudflare Zero Trust (paid)**: URL cố định, ổn định
|
| 82 |
+
- **cloudflared free (trycloudflare.com)**: URL thay đổi mỗi lần restart
|
| 83 |
+
- **Ngrok free**: Không tương thích tốt với PostgreSQL TCP
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
|
__pycache__/start_ngrok_and_set_db.cpython-310.pyc
ADDED
|
Binary file (7.71 kB). View file
|
|
|
backend/hue_portal/chatbot/chatbot.py
CHANGED
|
@@ -136,7 +136,7 @@ class Chatbot(CoreChatbot):
|
|
| 136 |
# tránh trả lại các câu trả lời cũ không có options.
|
| 137 |
cached_response = None
|
| 138 |
if intent != "search_legal":
|
| 139 |
-
|
| 140 |
if cached_response:
|
| 141 |
cached_response["_cache"] = "exact_match"
|
| 142 |
cached_response["_source"] = cached_response.get("_source", "cache")
|
|
|
|
| 136 |
# tránh trả lại các câu trả lời cũ không có options.
|
| 137 |
cached_response = None
|
| 138 |
if intent != "search_legal":
|
| 139 |
+
cached_response = EXACT_MATCH_CACHE.get(query, intent)
|
| 140 |
if cached_response:
|
| 141 |
cached_response["_cache"] = "exact_match"
|
| 142 |
cached_response["_source"] = cached_response.get("_source", "cache")
|
backend/hue_portal/chatbot/tests/__pycache__/test_smoke.cpython-310.pyc
ADDED
|
Binary file (1.71 kB). View file
|
|
|
backend/hue_portal/core/management/commands/__pycache__/retry_ingestion_job.cpython-310.pyc
ADDED
|
Binary file (1.41 kB). View file
|
|
|
check_tunnel_unraid.sh
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Script để kiểm tra và fix Cloudflare Tunnel trên Unraid
|
| 4 |
+
|
| 5 |
+
echo "============================================================"
|
| 6 |
+
echo "🔍 Kiểm tra Cloudflare Tunnel cho PostgreSQL"
|
| 7 |
+
echo "============================================================"
|
| 8 |
+
echo ""
|
| 9 |
+
|
| 10 |
+
TUNNEL_NAME="mystifying_bassi"
|
| 11 |
+
POSTGRES_CONTAINER="postgres-hue"
|
| 12 |
+
POSTGRES_HOST="192.168.1.212"
|
| 13 |
+
POSTGRES_PORT="5432"
|
| 14 |
+
|
| 15 |
+
# 1. Check tunnel container
|
| 16 |
+
echo "1️⃣ Kiểm tra tunnel container..."
|
| 17 |
+
if docker ps | grep -q "$TUNNEL_NAME"; then
|
| 18 |
+
echo "✅ Tunnel container đang chạy"
|
| 19 |
+
docker ps | grep "$TUNNEL_NAME"
|
| 20 |
+
else
|
| 21 |
+
echo "❌ Tunnel container KHÔNG chạy!"
|
| 22 |
+
exit 1
|
| 23 |
+
fi
|
| 24 |
+
|
| 25 |
+
# 2. Check PostgreSQL container
|
| 26 |
+
echo ""
|
| 27 |
+
echo "2️⃣ Kiểm tra PostgreSQL container..."
|
| 28 |
+
if docker ps | grep -q "$POSTGRES_CONTAINER"; then
|
| 29 |
+
echo "✅ PostgreSQL container đang chạy"
|
| 30 |
+
docker ps | grep "$POSTGRES_CONTAINER"
|
| 31 |
+
else
|
| 32 |
+
echo "❌ PostgreSQL container KHÔNG chạy!"
|
| 33 |
+
exit 1
|
| 34 |
+
fi
|
| 35 |
+
|
| 36 |
+
# 3. Test PostgreSQL locally
|
| 37 |
+
echo ""
|
| 38 |
+
echo "3️⃣ Test PostgreSQL từ trong Unraid..."
|
| 39 |
+
if docker exec "$POSTGRES_CONTAINER" psql -U hue_remote -d hue_portal -c "SELECT 1;" > /dev/null 2>&1; then
|
| 40 |
+
echo "✅ PostgreSQL hoạt động OK"
|
| 41 |
+
else
|
| 42 |
+
echo "❌ PostgreSQL KHÔNG hoạt động!"
|
| 43 |
+
exit 1
|
| 44 |
+
fi
|
| 45 |
+
|
| 46 |
+
# 4. Check tunnel logs for postgres config
|
| 47 |
+
echo ""
|
| 48 |
+
echo "4️⃣ Kiểm tra tunnel config..."
|
| 49 |
+
if docker logs "$TUNNEL_NAME" --tail 50 | grep -q "postgres.aliss.io.vn.*tcp://$POSTGRES_HOST:$POSTGRES_PORT"; then
|
| 50 |
+
echo "✅ Tunnel config có postgres.aliss.io.vn → tcp://$POSTGRES_HOST:$POSTGRES_PORT"
|
| 51 |
+
else
|
| 52 |
+
echo "⚠️ KHÔNG tìm thấy config postgres trong logs"
|
| 53 |
+
echo " Xem logs:"
|
| 54 |
+
docker logs "$TUNNEL_NAME" --tail 10 | grep -i "postgres\|tcp\|5432"
|
| 55 |
+
fi
|
| 56 |
+
|
| 57 |
+
# 5. Check tunnel connection status
|
| 58 |
+
echo ""
|
| 59 |
+
echo "5️⃣ Kiểm tra tunnel connection status..."
|
| 60 |
+
if docker logs "$TUNNEL_NAME" --tail 20 | grep -q "Registered tunnel connection"; then
|
| 61 |
+
echo "✅ Tunnel đã connected"
|
| 62 |
+
docker logs "$TUNNEL_NAME" --tail 5 | grep "Registered tunnel connection"
|
| 63 |
+
else
|
| 64 |
+
echo "⚠️ Không thấy tunnel connection"
|
| 65 |
+
fi
|
| 66 |
+
|
| 67 |
+
# 6. Check for any connection attempts
|
| 68 |
+
echo ""
|
| 69 |
+
echo "6️⃣ Kiểm tra connection attempts (nếu có)..."
|
| 70 |
+
RECENT_LOGS=$(docker logs "$TUNNEL_NAME" --tail 100 | grep -i "request\|connection\|postgres\|5432" | tail -5)
|
| 71 |
+
if [ -n "$RECENT_LOGS" ]; then
|
| 72 |
+
echo "📋 Recent logs:"
|
| 73 |
+
echo "$RECENT_LOGS"
|
| 74 |
+
else
|
| 75 |
+
echo "⚠️ Không có connection attempts gần đây"
|
| 76 |
+
fi
|
| 77 |
+
|
| 78 |
+
# 7. Suggestions
|
| 79 |
+
echo ""
|
| 80 |
+
echo "============================================================"
|
| 81 |
+
echo "💡 Gợi ý:"
|
| 82 |
+
echo "============================================================"
|
| 83 |
+
echo ""
|
| 84 |
+
echo "Nếu kết nối vẫn không hoạt động:"
|
| 85 |
+
echo ""
|
| 86 |
+
echo "1. Restart tunnel:"
|
| 87 |
+
echo " docker restart $TUNNEL_NAME"
|
| 88 |
+
echo ""
|
| 89 |
+
echo "2. Đợi 30 giây và check logs:"
|
| 90 |
+
echo " sleep 30"
|
| 91 |
+
echo " docker logs $TUNNEL_NAME --tail 20"
|
| 92 |
+
echo ""
|
| 93 |
+
echo "3. Kiểm tra Cloudflare Dashboard:"
|
| 94 |
+
echo " https://dash.cloudflare.com → Zero Trust → Networks → Tunnels"
|
| 95 |
+
echo " - Xem tunnel status phải là 'Healthy'"
|
| 96 |
+
echo " - Xem config có postgres.aliss.io.vn → tcp://$POSTGRES_HOST:$POSTGRES_PORT"
|
| 97 |
+
echo ""
|
| 98 |
+
echo "4. Test từ máy local:"
|
| 99 |
+
echo " PGPASSWORD=huepass123 psql -h postgres.aliss.io.vn -p 5432 -U hue_remote -d hue_portal -c 'SELECT 1;'"
|
| 100 |
+
echo ""
|
| 101 |
+
echo "============================================================"
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
|
entrypoint.sh
CHANGED
|
@@ -31,26 +31,61 @@ log "Ensuring cache table exists..."
|
|
| 31 |
python hue_portal/manage.py createcachetable
|
| 32 |
log "Cache table ready."
|
| 33 |
|
| 34 |
-
log "
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
log "Preloading llama.cpp model to avoid first-request timeout..."
|
| 38 |
-
python -c "
|
| 39 |
import os
|
|
|
|
| 40 |
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hue_portal.hue_portal.settings')
|
| 41 |
import django
|
| 42 |
django.setup()
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
| 44 |
try:
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
|
|
|
|
|
|
| 48 |
else:
|
| 49 |
-
print('[ENTRYPOINT] ⚠️
|
| 50 |
except Exception as e:
|
| 51 |
-
print(f'[ENTRYPOINT] ⚠️
|
| 52 |
-
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
exec gunicorn hue_portal.hue_portal.wsgi:application \
|
| 56 |
--bind 0.0.0.0:${PORT:-7860} \
|
|
|
|
| 31 |
python hue_portal/manage.py createcachetable
|
| 32 |
log "Cache table ready."
|
| 33 |
|
| 34 |
+
log "Preloading all models to avoid first-request timeout..."
|
| 35 |
+
|
| 36 |
+
python -c "
|
|
|
|
|
|
|
| 37 |
import os
|
| 38 |
+
import sys
|
| 39 |
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hue_portal.hue_portal.settings')
|
| 40 |
import django
|
| 41 |
django.setup()
|
| 42 |
+
|
| 43 |
+
print('[ENTRYPOINT] 🔄 Starting model preload...', flush=True)
|
| 44 |
+
|
| 45 |
+
# 1. Preload Embedding Model (BGE-M3)
|
| 46 |
try:
|
| 47 |
+
print('[ENTRYPOINT] 📦 Preloading embedding model (BGE-M3)...', flush=True)
|
| 48 |
+
from hue_portal.core.embeddings import get_embedding_model
|
| 49 |
+
embedding_model = get_embedding_model()
|
| 50 |
+
if embedding_model:
|
| 51 |
+
print('[ENTRYPOINT] ✅ Embedding model preloaded successfully', flush=True)
|
| 52 |
else:
|
| 53 |
+
print('[ENTRYPOINT] ⚠️ Embedding model not loaded', flush=True)
|
| 54 |
except Exception as e:
|
| 55 |
+
print(f'[ENTRYPOINT] ⚠️ Embedding model preload failed: {e}', flush=True)
|
| 56 |
+
|
| 57 |
+
# 2. Preload LLM Model (llama.cpp)
|
| 58 |
+
llm_provider = os.environ.get('DEFAULT_LLM_PROVIDER') or os.environ.get('LLM_PROVIDER', '')
|
| 59 |
+
if llm_provider.lower() == 'llama_cpp':
|
| 60 |
+
try:
|
| 61 |
+
print('[ENTRYPOINT] 📦 Preloading LLM model (llama.cpp)...', flush=True)
|
| 62 |
+
from hue_portal.chatbot.llm_integration import get_llm_generator
|
| 63 |
+
llm_gen = get_llm_generator()
|
| 64 |
+
if llm_gen and hasattr(llm_gen, 'llama_cpp') and llm_gen.llama_cpp:
|
| 65 |
+
print('[ENTRYPOINT] ✅ LLM model preloaded successfully', flush=True)
|
| 66 |
+
else:
|
| 67 |
+
print('[ENTRYPOINT] ⚠️ LLM model not loaded (may load on first request)', flush=True)
|
| 68 |
+
except Exception as e:
|
| 69 |
+
print(f'[ENTRYPOINT] ⚠️ LLM model preload failed: {e} (will load on first request)', flush=True)
|
| 70 |
+
else:
|
| 71 |
+
print(f'[ENTRYPOINT] ⏭️ Skipping LLM preload (provider is {llm_provider or \"not set\"}, not llama_cpp)', flush=True)
|
| 72 |
+
|
| 73 |
+
# 3. Preload Reranker Model (lazy, but trigger import)
|
| 74 |
+
try:
|
| 75 |
+
print('[ENTRYPOINT] 📦 Preloading reranker model...', flush=True)
|
| 76 |
+
from hue_portal.core.reranker import get_reranker
|
| 77 |
+
reranker = get_reranker()
|
| 78 |
+
if reranker:
|
| 79 |
+
print('[ENTRYPOINT] ✅ Reranker model preloaded successfully', flush=True)
|
| 80 |
+
else:
|
| 81 |
+
print('[ENTRYPOINT] ⚠️ Reranker model not loaded (may load on first request)', flush=True)
|
| 82 |
+
except Exception as e:
|
| 83 |
+
print(f'[ENTRYPOINT] ⚠️ Reranker preload failed: {e} (will load on first request)', flush=True)
|
| 84 |
+
|
| 85 |
+
print('[ENTRYPOINT] ✅ Model preload completed', flush=True) # v2.0-preload-all
|
| 86 |
+
" || log "⚠️ Model preload had errors (models will load on first request)"
|
| 87 |
+
|
| 88 |
+
log "Starting Gunicorn on port ${PORT:-7860}..."
|
| 89 |
|
| 90 |
exec gunicorn hue_portal.hue_portal.wsgi:application \
|
| 91 |
--bind 0.0.0.0:${PORT:-7860} \
|
fix_ngrok_postgres.sh
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Script để fix và test ngrok tunnel với PostgreSQL
|
| 3 |
+
# Sử dụng: ./fix_ngrok_postgres.sh
|
| 4 |
+
|
| 5 |
+
set -e
|
| 6 |
+
|
| 7 |
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 8 |
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
| 9 |
+
OPS_DIR="$PROJECT_ROOT/ops"
|
| 10 |
+
ENV_TUNNEL="$OPS_DIR/.env.tunnel"
|
| 11 |
+
|
| 12 |
+
# Colors
|
| 13 |
+
GREEN='\033[0;32m'
|
| 14 |
+
YELLOW='\033[1;33m'
|
| 15 |
+
RED='\033[0;31m'
|
| 16 |
+
NC='\033[0m'
|
| 17 |
+
|
| 18 |
+
log() {
|
| 19 |
+
echo -e "${GREEN}[FIX-NGROK]${NC} $1"
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
warn() {
|
| 23 |
+
echo -e "${YELLOW}[FIX-NGROK]${NC} $1"
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
error() {
|
| 27 |
+
echo -e "${RED}[FIX-NGROK]${NC} $1"
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# Default values
|
| 31 |
+
POSTGRES_PORT=${POSTGRES_PORT:-5543}
|
| 32 |
+
POSTGRES_USER=${POSTGRES_USER:-hue_remote}
|
| 33 |
+
POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-huepass123}
|
| 34 |
+
POSTGRES_DB=${POSTGRES_DB:-hue_portal}
|
| 35 |
+
NGROK_REGION=${NGROK_REGION:-ap}
|
| 36 |
+
|
| 37 |
+
log "============================================================"
|
| 38 |
+
log "Fix và test ngrok tunnel với PostgreSQL"
|
| 39 |
+
log "============================================================"
|
| 40 |
+
|
| 41 |
+
# Step 1: Check PostgreSQL
|
| 42 |
+
log "Bước 1: Kiểm tra PostgreSQL..."
|
| 43 |
+
export PGPASSWORD="$POSTGRES_PASSWORD"
|
| 44 |
+
if psql -h localhost -p "$POSTGRES_PORT" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT 1;" &>/dev/null; then
|
| 45 |
+
log "✅ PostgreSQL đang chạy trên localhost:$POSTGRES_PORT"
|
| 46 |
+
else
|
| 47 |
+
error "❌ PostgreSQL không chạy trên localhost:$POSTGRES_PORT"
|
| 48 |
+
exit 1
|
| 49 |
+
fi
|
| 50 |
+
|
| 51 |
+
# Step 2: Check PostgreSQL listen addresses
|
| 52 |
+
log "Bước 2: Kiểm tra PostgreSQL config..."
|
| 53 |
+
LISTEN_ADDR=$(psql -h localhost -p "$POSTGRES_PORT" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -t -c "SHOW listen_addresses;" 2>/dev/null | xargs)
|
| 54 |
+
if [ "$LISTEN_ADDR" = "*" ]; then
|
| 55 |
+
log "✅ PostgreSQL đang listen trên tất cả interfaces (*)"
|
| 56 |
+
else
|
| 57 |
+
warn "⚠️ PostgreSQL listen trên: $LISTEN_ADDR (cần là *)"
|
| 58 |
+
fi
|
| 59 |
+
|
| 60 |
+
# Step 3: Check Docker container
|
| 61 |
+
log "Bước 3: Kiểm tra Docker container..."
|
| 62 |
+
if docker ps | grep -q "tryhardemnayproject-db-1\|postgres.*5543"; then
|
| 63 |
+
CONTAINER_NAME=$(docker ps | grep -E "tryhardemnayproject-db-1|postgres.*5543" | awk '{print $NF}' | head -1)
|
| 64 |
+
log "✅ Tìm thấy PostgreSQL container: $CONTAINER_NAME"
|
| 65 |
+
|
| 66 |
+
# Check pg_hba.conf
|
| 67 |
+
log "Bước 4: Kiểm tra pg_hba.conf..."
|
| 68 |
+
if docker exec "$CONTAINER_NAME" grep -q "0.0.0.0/0" /var/lib/postgresql/data/pg_hba.conf 2>/dev/null; then
|
| 69 |
+
log "✅ pg_hba.conf đã có rule cho 0.0.0.0/0"
|
| 70 |
+
else
|
| 71 |
+
warn "⚠️ pg_hba.conf chưa có rule cho 0.0.0.0/0, đang thêm..."
|
| 72 |
+
docker exec "$CONTAINER_NAME" bash -c "echo 'host all all 0.0.0.0/0 md5' >> /var/lib/postgresql/data/pg_hba.conf" 2>/dev/null || true
|
| 73 |
+
log "✅ Đã thêm rule vào pg_hba.conf (cần restart container để apply)"
|
| 74 |
+
fi
|
| 75 |
+
else
|
| 76 |
+
warn "⚠️ Không tìm thấy PostgreSQL container"
|
| 77 |
+
fi
|
| 78 |
+
|
| 79 |
+
# Step 5: Restart ngrok
|
| 80 |
+
log "Bước 5: Khởi động lại ngrok tunnel..."
|
| 81 |
+
pkill -f "ngrok tcp" 2>/dev/null || true
|
| 82 |
+
sleep 2
|
| 83 |
+
|
| 84 |
+
# Start ngrok
|
| 85 |
+
nohup ngrok tcp "$POSTGRES_PORT" --region "$NGROK_REGION" --log=stdout > "$OPS_DIR/ngrok.log" 2>&1 &
|
| 86 |
+
NGROK_PID=$!
|
| 87 |
+
|
| 88 |
+
# Wait for ngrok
|
| 89 |
+
for i in {1..10}; do
|
| 90 |
+
sleep 1
|
| 91 |
+
if curl -s http://127.0.0.1:4040/api/tunnels &>/dev/null; then
|
| 92 |
+
NGROK_URL=$(curl -s http://127.0.0.1:4040/api/tunnels | python3 -c "
|
| 93 |
+
import sys, json
|
| 94 |
+
try:
|
| 95 |
+
data = json.load(sys.stdin)
|
| 96 |
+
for tunnel in data.get('tunnels', []):
|
| 97 |
+
if tunnel.get('proto') == 'tcp':
|
| 98 |
+
print(tunnel.get('public_url', '').replace('tcp://', ''))
|
| 99 |
+
sys.exit(0)
|
| 100 |
+
except:
|
| 101 |
+
pass
|
| 102 |
+
" 2>/dev/null)
|
| 103 |
+
if [ -n "$NGROK_URL" ]; then
|
| 104 |
+
NGROK_HOST=$(echo "$NGROK_URL" | cut -d':' -f1)
|
| 105 |
+
NGROK_PORT=$(echo "$NGROK_URL" | cut -d':' -f2)
|
| 106 |
+
log "✅ Ngrok đã sẵn sàng: tcp://$NGROK_HOST:$NGROK_PORT"
|
| 107 |
+
break
|
| 108 |
+
fi
|
| 109 |
+
fi
|
| 110 |
+
done
|
| 111 |
+
|
| 112 |
+
if [ -z "$NGROK_HOST" ] || [ -z "$NGROK_PORT" ]; then
|
| 113 |
+
error "❌ Không thể khởi động ngrok"
|
| 114 |
+
exit 1
|
| 115 |
+
fi
|
| 116 |
+
|
| 117 |
+
# Step 6: Test connection
|
| 118 |
+
log "Bước 6: Test kết nối PostgreSQL qua ngrok..."
|
| 119 |
+
sleep 3
|
| 120 |
+
|
| 121 |
+
# Test với psql
|
| 122 |
+
if timeout 10 psql -h "$NGROK_HOST" -p "$NGROK_PORT" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT 1;" &>/dev/null; then
|
| 123 |
+
log "✅✅✅ KẾT NỐI THÀNH CÔNG QUA NGROK!"
|
| 124 |
+
|
| 125 |
+
# Get document count
|
| 126 |
+
DOC_COUNT=$(psql -h "$NGROK_HOST" -p "$NGROK_PORT" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -t -c "SELECT COUNT(*) FROM core_legaldocument;" 2>/dev/null | xargs)
|
| 127 |
+
log " Số lượng documents: $DOC_COUNT"
|
| 128 |
+
|
| 129 |
+
# Save tunnel info
|
| 130 |
+
log "Bước 7: Lưu thông tin tunnel..."
|
| 131 |
+
mkdir -p "$OPS_DIR"
|
| 132 |
+
cat > "$ENV_TUNNEL" << EOF
|
| 133 |
+
# Ngrok tunnel info - Generated by fix_ngrok_postgres.sh
|
| 134 |
+
# Last updated: $(date -u +"%Y-%m-%dT%H:%M:%S")
|
| 135 |
+
|
| 136 |
+
PG_TUNNEL_HOST=$NGROK_HOST
|
| 137 |
+
PG_TUNNEL_PORT=$NGROK_PORT
|
| 138 |
+
PG_TUNNEL_LOCAL_PORT=$POSTGRES_PORT
|
| 139 |
+
PG_TUNNEL_USER=$POSTGRES_USER
|
| 140 |
+
PG_TUNNEL_PASSWORD=$POSTGRES_PASSWORD
|
| 141 |
+
PG_TUNNEL_DB=$POSTGRES_DB
|
| 142 |
+
DATABASE_URL=postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@$NGROK_HOST:$NGROK_PORT/$POSTGRES_DB
|
| 143 |
+
HF_SPACE_ID=${HF_SPACE_ID:-davidtran999/hue-portal-backend}
|
| 144 |
+
POSTGRES_HOST=${POSTGRES_HOST:-localhost}
|
| 145 |
+
POSTGRES_PORT=$POSTGRES_PORT
|
| 146 |
+
POSTGRES_USER=$POSTGRES_USER
|
| 147 |
+
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
|
| 148 |
+
POSTGRES_DB=$POSTGRES_DB
|
| 149 |
+
PG_TUNNEL_LAST_UPDATED=$(date -u +"%Y-%m-%dT%H:%M:%S")
|
| 150 |
+
EOF
|
| 151 |
+
log "✅ Đã lưu tunnel info vào $ENV_TUNNEL"
|
| 152 |
+
|
| 153 |
+
# Update Hugging Face Space
|
| 154 |
+
log "Bước 8: Cập nhật DATABASE_URL lên Hugging Face Space..."
|
| 155 |
+
if [ -f "$PROJECT_ROOT/backend/venv/bin/python" ]; then
|
| 156 |
+
"$PROJECT_ROOT/backend/venv/bin/python" "$SCRIPT_DIR/start_ngrok_and_set_db.py" 2>&1 | grep -E "(✅|❌|📌)" || true
|
| 157 |
+
fi
|
| 158 |
+
|
| 159 |
+
log "============================================================"
|
| 160 |
+
log "✅✅✅ HOÀN TẤT!"
|
| 161 |
+
log " PostgreSQL: localhost:$POSTGRES_PORT"
|
| 162 |
+
log " Ngrok tunnel: tcp://$NGROK_HOST:$NGROK_PORT"
|
| 163 |
+
log " DATABASE_URL: postgres://$POSTGRES_USER:***@$NGROK_HOST:$NGROK_PORT/$POSTGRES_DB"
|
| 164 |
+
log "============================================================"
|
| 165 |
+
else
|
| 166 |
+
error "❌ Vẫn không kết nối được qua ngrok"
|
| 167 |
+
error " Có thể cần:"
|
| 168 |
+
error " 1. Restart PostgreSQL container để apply pg_hba.conf"
|
| 169 |
+
error " 2. Hoặc dùng SSH tunnel thay vì ngrok"
|
| 170 |
+
error " 3. Hoặc expose PostgreSQL với network_mode: host"
|
| 171 |
+
exit 1
|
| 172 |
+
fi
|
| 173 |
+
|
khoidongDB.sh
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Script khởi động PostgreSQL và ngrok tunnel với port và URL cố định
|
| 3 |
+
# Sử dụng: ./khoidongDB.sh
|
| 4 |
+
|
| 5 |
+
set -e
|
| 6 |
+
|
| 7 |
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 8 |
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
| 9 |
+
OPS_DIR="$PROJECT_ROOT/ops"
|
| 10 |
+
ENV_TUNNEL="$OPS_DIR/.env.tunnel"
|
| 11 |
+
|
| 12 |
+
# Colors
|
| 13 |
+
GREEN='\033[0;32m'
|
| 14 |
+
YELLOW='\033[1;33m'
|
| 15 |
+
RED='\033[0;31m'
|
| 16 |
+
NC='\033[0m' # No Color
|
| 17 |
+
|
| 18 |
+
log() {
|
| 19 |
+
echo -e "${GREEN}[DB-START]${NC} $1"
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
warn() {
|
| 23 |
+
echo -e "${YELLOW}[DB-START]${NC} $1"
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
error() {
|
| 27 |
+
echo -e "${RED}[DB-START]${NC} $1"
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# Load config
|
| 31 |
+
if [ -f "$PROJECT_ROOT/.env" ]; then
|
| 32 |
+
source "$PROJECT_ROOT/.env"
|
| 33 |
+
fi
|
| 34 |
+
|
| 35 |
+
# Default values
|
| 36 |
+
POSTGRES_PORT=${POSTGRES_PORT:-5543}
|
| 37 |
+
NGROK_REGION=${NGROK_REGION:-ap}
|
| 38 |
+
NGROK_API_URL="http://127.0.0.1:4040"
|
| 39 |
+
|
| 40 |
+
# Create ops directory if not exists
|
| 41 |
+
mkdir -p "$OPS_DIR"
|
| 42 |
+
|
| 43 |
+
# Function to check if PostgreSQL is running
|
| 44 |
+
check_postgres() {
|
| 45 |
+
log "Kiểm tra PostgreSQL trên port $POSTGRES_PORT..."
|
| 46 |
+
|
| 47 |
+
if command -v psql &> /dev/null; then
|
| 48 |
+
if PGPASSWORD="${POSTGRES_PASSWORD:-huepass123}" psql -h localhost -p "$POSTGRES_PORT" -U "${POSTGRES_USER:-hue_remote}" -d "${POSTGRES_DB:-hue_portal}" -c "SELECT 1;" &> /dev/null; then
|
| 49 |
+
log "✅ PostgreSQL đang chạy trên port $POSTGRES_PORT"
|
| 50 |
+
return 0
|
| 51 |
+
fi
|
| 52 |
+
fi
|
| 53 |
+
|
| 54 |
+
# Try Python connection
|
| 55 |
+
if [ -f "$PROJECT_ROOT/backend/venv/bin/python" ]; then
|
| 56 |
+
if "$PROJECT_ROOT/backend/venv/bin/python" -c "
|
| 57 |
+
import psycopg2
|
| 58 |
+
try:
|
| 59 |
+
conn = psycopg2.connect(
|
| 60 |
+
host='localhost',
|
| 61 |
+
port=$POSTGRES_PORT,
|
| 62 |
+
database='${POSTGRES_DB:-hue_portal}',
|
| 63 |
+
user='${POSTGRES_USER:-hue_remote}',
|
| 64 |
+
password='${POSTGRES_PASSWORD:-huepass123}',
|
| 65 |
+
connect_timeout=2
|
| 66 |
+
)
|
| 67 |
+
conn.close()
|
| 68 |
+
exit(0)
|
| 69 |
+
except:
|
| 70 |
+
exit(1)
|
| 71 |
+
" 2>/dev/null; then
|
| 72 |
+
log "✅ PostgreSQL đang chạy trên port $POSTGRES_PORT"
|
| 73 |
+
return 0
|
| 74 |
+
fi
|
| 75 |
+
fi
|
| 76 |
+
|
| 77 |
+
warn "⚠️ PostgreSQL không chạy trên port $POSTGRES_PORT"
|
| 78 |
+
return 1
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
# Function to get ngrok tunnel URL
|
| 82 |
+
get_ngrok_url() {
|
| 83 |
+
local host port
|
| 84 |
+
if command -v curl &> /dev/null && command -v python3 &> /dev/null; then
|
| 85 |
+
response=$(curl -s "$NGROK_API_URL/api/tunnels" 2>/dev/null || echo "")
|
| 86 |
+
if [ -n "$response" ]; then
|
| 87 |
+
# Use Python to parse JSON properly
|
| 88 |
+
ngrok_url=$(echo "$response" | python3 -c "
|
| 89 |
+
import sys, json
|
| 90 |
+
try:
|
| 91 |
+
data = json.load(sys.stdin)
|
| 92 |
+
for tunnel in data.get('tunnels', []):
|
| 93 |
+
if tunnel.get('proto') == 'tcp':
|
| 94 |
+
public_url = tunnel.get('public_url', '')
|
| 95 |
+
if public_url.startswith('tcp://'):
|
| 96 |
+
url = public_url.replace('tcp://', '')
|
| 97 |
+
print(url)
|
| 98 |
+
sys.exit(0)
|
| 99 |
+
except:
|
| 100 |
+
pass
|
| 101 |
+
" 2>/dev/null)
|
| 102 |
+
if [ -n "$ngrok_url" ]; then
|
| 103 |
+
echo "$ngrok_url"
|
| 104 |
+
return 0
|
| 105 |
+
fi
|
| 106 |
+
fi
|
| 107 |
+
fi
|
| 108 |
+
return 1
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
# Function to start ngrok
|
| 112 |
+
start_ngrok() {
|
| 113 |
+
log "Khởi động ngrok tunnel..." >&2
|
| 114 |
+
|
| 115 |
+
# Check if ngrok is already running
|
| 116 |
+
if curl -s "$NGROK_API_URL/api/tunnels" &> /dev/null; then
|
| 117 |
+
ngrok_url=$(get_ngrok_url)
|
| 118 |
+
if [ -n "$ngrok_url" ]; then
|
| 119 |
+
log "✅ Ngrok đã chạy sẵn: tcp://$ngrok_url" >&2
|
| 120 |
+
echo "$ngrok_url"
|
| 121 |
+
return 0
|
| 122 |
+
fi
|
| 123 |
+
fi
|
| 124 |
+
|
| 125 |
+
# Kill existing ngrok processes
|
| 126 |
+
pkill -f "ngrok tcp" 2>/dev/null || true
|
| 127 |
+
sleep 1
|
| 128 |
+
|
| 129 |
+
# Start ngrok
|
| 130 |
+
log "Đang start ngrok (ngrok tcp $POSTGRES_PORT --region $NGROK_REGION)..." >&2
|
| 131 |
+
nohup ngrok tcp "$POSTGRES_PORT" --region "$NGROK_REGION" --log=stdout > "$OPS_DIR/ngrok.log" 2>&1 &
|
| 132 |
+
NGROK_PID=$!
|
| 133 |
+
|
| 134 |
+
# Wait for ngrok to start
|
| 135 |
+
for i in {1..10}; do
|
| 136 |
+
sleep 1
|
| 137 |
+
if curl -s "$NGROK_API_URL/api/tunnels" &> /dev/null; then
|
| 138 |
+
ngrok_url=$(get_ngrok_url)
|
| 139 |
+
if [ -n "$ngrok_url" ]; then
|
| 140 |
+
log "✅ Ngrok đã sẵn sàng: tcp://$ngrok_url" >&2
|
| 141 |
+
echo "$ngrok_url"
|
| 142 |
+
return 0
|
| 143 |
+
fi
|
| 144 |
+
fi
|
| 145 |
+
done
|
| 146 |
+
|
| 147 |
+
error "❌ Không thể khởi động ngrok" >&2
|
| 148 |
+
return 1
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
# Function to update DATABASE_URL on Hugging Face Space
|
| 152 |
+
update_hf_space() {
|
| 153 |
+
local host=$1
|
| 154 |
+
local port=$2
|
| 155 |
+
|
| 156 |
+
if [ -z "$host" ] || [ -z "$port" ]; then
|
| 157 |
+
warn "⚠️ Không có ngrok URL, bỏ qua cập nhật HF Space"
|
| 158 |
+
return 1
|
| 159 |
+
fi
|
| 160 |
+
|
| 161 |
+
log "Cập nhật DATABASE_URL lên Hugging Face Space..."
|
| 162 |
+
|
| 163 |
+
if [ -f "$PROJECT_ROOT/backend/venv/bin/python" ]; then
|
| 164 |
+
"$PROJECT_ROOT/backend/venv/bin/python" "$SCRIPT_DIR/start_ngrok_and_set_db.py" 2>&1 | grep -E "(✅|❌|📌)" || true
|
| 165 |
+
else
|
| 166 |
+
warn "⚠️ Không tìm thấy Python venv, bỏ qua cập nhật HF Space"
|
| 167 |
+
fi
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
# Function to save tunnel info
|
| 171 |
+
save_tunnel_info() {
|
| 172 |
+
local host=$1
|
| 173 |
+
local port=$2
|
| 174 |
+
|
| 175 |
+
if [ -z "$host" ] || [ -z "$port" ]; then
|
| 176 |
+
return 1
|
| 177 |
+
fi
|
| 178 |
+
|
| 179 |
+
log "Lưu thông tin tunnel..."
|
| 180 |
+
|
| 181 |
+
cat > "$ENV_TUNNEL" << EOF
|
| 182 |
+
# Ngrok tunnel info - Generated by khoidongDB.sh
|
| 183 |
+
# Last updated: $(date -u +"%Y-%m-%dT%H:%M:%S")
|
| 184 |
+
|
| 185 |
+
PG_TUNNEL_HOST=$host
|
| 186 |
+
PG_TUNNEL_PORT=$port
|
| 187 |
+
PG_TUNNEL_LOCAL_PORT=$POSTGRES_PORT
|
| 188 |
+
PG_TUNNEL_USER=${POSTGRES_USER:-hue_remote}
|
| 189 |
+
PG_TUNNEL_PASSWORD=${POSTGRES_PASSWORD:-huepass123}
|
| 190 |
+
PG_TUNNEL_DB=${POSTGRES_DB:-hue_portal}
|
| 191 |
+
DATABASE_URL=postgres://${POSTGRES_USER:-hue_remote}:${POSTGRES_PASSWORD:-huepass123}@$host:$port/${POSTGRES_DB:-hue_portal}
|
| 192 |
+
HF_SPACE_ID=${HF_SPACE_ID:-davidtran999/hue-portal-backend}
|
| 193 |
+
POSTGRES_HOST=${POSTGRES_HOST:-localhost}
|
| 194 |
+
POSTGRES_PORT=$POSTGRES_PORT
|
| 195 |
+
POSTGRES_USER=${POSTGRES_USER:-hue_remote}
|
| 196 |
+
POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-huepass123}
|
| 197 |
+
POSTGRES_DB=${POSTGRES_DB:-hue_portal}
|
| 198 |
+
PG_TUNNEL_LAST_UPDATED=$(date -u +"%Y-%m-%dT%H:%M:%S")
|
| 199 |
+
EOF
|
| 200 |
+
|
| 201 |
+
log "✅ Đã lưu tunnel info vào $ENV_TUNNEL"
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
# Main execution
|
| 205 |
+
main() {
|
| 206 |
+
log "============================================================"
|
| 207 |
+
log "Khởi động PostgreSQL và ngrok tunnel"
|
| 208 |
+
log "============================================================"
|
| 209 |
+
|
| 210 |
+
# Check PostgreSQL
|
| 211 |
+
if ! check_postgres; then
|
| 212 |
+
error "❌ PostgreSQL không chạy trên port $POSTGRES_PORT"
|
| 213 |
+
error " Vui lòng khởi động PostgreSQL trước"
|
| 214 |
+
exit 1
|
| 215 |
+
fi
|
| 216 |
+
|
| 217 |
+
# Start ngrok
|
| 218 |
+
ngrok_url=$(start_ngrok)
|
| 219 |
+
if [ $? -ne 0 ] || [ -z "$ngrok_url" ]; then
|
| 220 |
+
error "❌ Không thể khởi động ngrok"
|
| 221 |
+
exit 1
|
| 222 |
+
fi
|
| 223 |
+
|
| 224 |
+
ngrok_host=$(echo "$ngrok_url" | cut -d':' -f1)
|
| 225 |
+
ngrok_port=$(echo "$ngrok_url" | cut -d':' -f2)
|
| 226 |
+
|
| 227 |
+
# Save tunnel info
|
| 228 |
+
save_tunnel_info "$ngrok_host" "$ngrok_port"
|
| 229 |
+
|
| 230 |
+
# Update Hugging Face Space
|
| 231 |
+
update_hf_space "$ngrok_host" "$ngrok_port"
|
| 232 |
+
|
| 233 |
+
log "============================================================"
|
| 234 |
+
log "✅ Hoàn tất!"
|
| 235 |
+
log " PostgreSQL: localhost:$POSTGRES_PORT"
|
| 236 |
+
log " Ngrok tunnel: tcp://$ngrok_host:$ngrok_port"
|
| 237 |
+
log " DATABASE_URL: postgres://${POSTGRES_USER:-hue_remote}:***@$ngrok_host:$ngrok_port/${POSTGRES_DB:-hue_portal}"
|
| 238 |
+
log "============================================================"
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
# Run main
|
| 242 |
+
main "$@"
|
| 243 |
+
|
monitor_space.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Utility script to monitor Hugging Face Space status + logs.
|
| 4 |
+
|
| 5 |
+
Features:
|
| 6 |
+
- Fetch latest build/runtime info using huggingface_hub
|
| 7 |
+
- Download logs via HF REST API and persist to logs/hf_space/
|
| 8 |
+
- Highlight errors (Traceback/SyntaxError) directly in console
|
| 9 |
+
- Optional --watch mode to poll every N seconds
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
from __future__ import annotations
|
| 13 |
+
|
| 14 |
+
import argparse
|
| 15 |
+
import json
|
| 16 |
+
import os
|
| 17 |
+
import sys
|
| 18 |
+
import time
|
| 19 |
+
from datetime import datetime
|
| 20 |
+
from pathlib import Path
|
| 21 |
+
from typing import Any, Dict, Optional
|
| 22 |
+
|
| 23 |
+
import requests
|
| 24 |
+
from huggingface_hub import HfApi
|
| 25 |
+
|
| 26 |
+
DEFAULT_SPACE_ID = "davidtran999/hue-portal-backend"
|
| 27 |
+
LOG_ROOT = Path(__file__).resolve().parent / "logs" / "hf_space"
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def get_hf_token() -> str:
|
| 31 |
+
"""Return Hugging Face token from env or cached file."""
|
| 32 |
+
token = os.getenv("HF_TOKEN") or os.getenv("HUGGINGFACE_HUB_TOKEN")
|
| 33 |
+
if token:
|
| 34 |
+
return token.strip()
|
| 35 |
+
|
| 36 |
+
cache_file = Path.home() / ".cache" / "huggingface" / "token"
|
| 37 |
+
if cache_file.exists():
|
| 38 |
+
return cache_file.read_text(encoding="utf-8").strip()
|
| 39 |
+
return ""
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def fetch_space_logs(space_id: str, token: str, limit: int) -> str:
|
| 43 |
+
"""Fetch the latest logs, trying both repo path and subdomain API."""
|
| 44 |
+
candidates = []
|
| 45 |
+
if "/" in space_id:
|
| 46 |
+
owner, name = space_id.split("/", 1)
|
| 47 |
+
candidates.append(f"https://huggingface.co/api/spaces/{owner}/{name}/logs?limit={limit}")
|
| 48 |
+
subdomain = f"{owner}-{name}"
|
| 49 |
+
else:
|
| 50 |
+
subdomain = space_id
|
| 51 |
+
candidates.append(f"https://huggingface.co/api/spaces/{subdomain}/logs?limit={limit}")
|
| 52 |
+
|
| 53 |
+
headers = {"Accept": "application/json"}
|
| 54 |
+
if token:
|
| 55 |
+
headers["Authorization"] = f"Bearer {token}"
|
| 56 |
+
|
| 57 |
+
last_error = None
|
| 58 |
+
for url in candidates:
|
| 59 |
+
try:
|
| 60 |
+
response = requests.get(url, headers=headers, timeout=30)
|
| 61 |
+
if response.status_code == 401:
|
| 62 |
+
raise RuntimeError("Không có quyền đọc logs. Hãy đặt HF_TOKEN với quyền write.")
|
| 63 |
+
if response.status_code == 404:
|
| 64 |
+
last_error = f"404 for {url}"
|
| 65 |
+
continue
|
| 66 |
+
response.raise_for_status()
|
| 67 |
+
data = response.json()
|
| 68 |
+
logs = data.get("logs") or data.get("log")
|
| 69 |
+
if isinstance(logs, list):
|
| 70 |
+
return "\n".join(logs)
|
| 71 |
+
if isinstance(logs, str):
|
| 72 |
+
return logs
|
| 73 |
+
return json.dumps(data, ensure_ascii=False)
|
| 74 |
+
except Exception as exc:
|
| 75 |
+
last_error = str(exc)
|
| 76 |
+
continue
|
| 77 |
+
raise RuntimeError(f"Không thể lấy logs. Nguyên nhân gần nhất: {last_error}")
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def write_log(space_id: str, space_info: Dict[str, Any], logs: str) -> Path:
|
| 81 |
+
"""Persist logs + status info to disk."""
|
| 82 |
+
LOG_ROOT.mkdir(parents=True, exist_ok=True)
|
| 83 |
+
timestamp = datetime.utcnow().strftime("%Y%m%d-%H%M%S")
|
| 84 |
+
safe_space = space_id.replace("/", "__")
|
| 85 |
+
log_path = LOG_ROOT / f"{safe_space}-{timestamp}.log"
|
| 86 |
+
|
| 87 |
+
with log_path.open("w", encoding="utf-8") as fp:
|
| 88 |
+
fp.write(f"# Space: {space_id}\n")
|
| 89 |
+
fp.write(f"# Timestamp: {timestamp} UTC\n")
|
| 90 |
+
fp.write(f"# Runtime: {space_info.get('runtime', {}).get('stage')}\n")
|
| 91 |
+
fp.write(f"# Hardware: {space_info.get('runtime', {}).get('hardware', 'unknown')}\n")
|
| 92 |
+
fp.write("# --- Logs ---\n")
|
| 93 |
+
fp.write(logs)
|
| 94 |
+
|
| 95 |
+
return log_path
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def monitor(space_id: str, watch: bool, interval: int, limit: int) -> None:
|
| 99 |
+
token = get_hf_token()
|
| 100 |
+
if not token:
|
| 101 |
+
print("⚠️ Không tìm thấy HF token – chỉ có thể đọc log public.")
|
| 102 |
+
|
| 103 |
+
api = HfApi(token=token or None)
|
| 104 |
+
|
| 105 |
+
def _single_cycle() -> None:
|
| 106 |
+
info = api.space_info(space_id)
|
| 107 |
+
logs = fetch_space_logs(space_id, token, limit)
|
| 108 |
+
log_path = write_log(space_id, info, logs)
|
| 109 |
+
|
| 110 |
+
runtime = info.runtime if hasattr(info, "runtime") else getattr(info, "runtime", {})
|
| 111 |
+
stage = (runtime or {}).get("stage") if isinstance(runtime, dict) else runtime
|
| 112 |
+
hardware = (runtime or {}).get("hardware") if isinstance(runtime, dict) else "unknown"
|
| 113 |
+
|
| 114 |
+
print(f"\n📡 Space: {space_id}")
|
| 115 |
+
print(f" Stage: {stage}, Hardware: {hardware}")
|
| 116 |
+
print(f" Updated: {datetime.utcnow().isoformat()}Z")
|
| 117 |
+
print(f" Logs saved to: {log_path}")
|
| 118 |
+
|
| 119 |
+
alert_keywords = ["Traceback", "SyntaxError", "ModuleNotFoundError"]
|
| 120 |
+
if any(keyword in logs for keyword in alert_keywords):
|
| 121 |
+
print(" 🚨 Detected errors in log (Traceback/SyntaxError). Check file above.")
|
| 122 |
+
else:
|
| 123 |
+
print(" ✅ No critical errors detected in latest log.")
|
| 124 |
+
|
| 125 |
+
_single_cycle()
|
| 126 |
+
while watch:
|
| 127 |
+
time.sleep(interval)
|
| 128 |
+
_single_cycle()
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
def parse_args(argv: Optional[list[str]] = None) -> argparse.Namespace:
|
| 132 |
+
parser = argparse.ArgumentParser(description="Monitor Hugging Face Space build/logs.")
|
| 133 |
+
parser.add_argument("--space-id", default=DEFAULT_SPACE_ID, help="Ví dụ: owner/space-name")
|
| 134 |
+
parser.add_argument("--interval", type=int, default=30, help="Số giây giữa các l���n kiểm tra (watch mode)")
|
| 135 |
+
parser.add_argument("--limit", type=int, default=200, help="Số dòng log lấy về (max 400)")
|
| 136 |
+
parser.add_argument("--watch", action="store_true", help="Bật chế độ theo dõi liên tục")
|
| 137 |
+
return parser.parse_args(argv)
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
def main() -> None:
|
| 141 |
+
args = parse_args()
|
| 142 |
+
try:
|
| 143 |
+
monitor(space_id=args.space_id, watch=args.watch, interval=args.interval, limit=args.limit)
|
| 144 |
+
except KeyboardInterrupt:
|
| 145 |
+
print("\n⏹️ Dừng theo dõi theo yêu cầu người dùng.")
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
if __name__ == "__main__":
|
| 149 |
+
main()
|
| 150 |
+
|
set_hf_space_env_qwen.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Script to set Qwen2.5-7B-Instruct Q4_K_M on Hugging Face Space.
|
| 4 |
+
Upgrade from Gemma 2-2B-it for better Vietnamese legal understanding.
|
| 5 |
+
|
| 6 |
+
Usage:
|
| 7 |
+
python3 set_hf_space_env_qwen.py
|
| 8 |
+
"""
|
| 9 |
+
import os
|
| 10 |
+
import sys
|
| 11 |
+
from pathlib import Path
|
| 12 |
+
|
| 13 |
+
try:
|
| 14 |
+
from huggingface_hub import HfApi
|
| 15 |
+
except ImportError:
|
| 16 |
+
print("❌ huggingface_hub not installed. Install with: pip install huggingface_hub")
|
| 17 |
+
sys.exit(1)
|
| 18 |
+
|
| 19 |
+
# Space configuration
|
| 20 |
+
SPACE_ID = "davidtran999/hue-portal-backend"
|
| 21 |
+
|
| 22 |
+
# Environment variables for Qwen2.5-7B-Instruct Q4_K_M
|
| 23 |
+
# Optimized for 2 vCPU + 16GB RAM free tier
|
| 24 |
+
ENV_VARS = {
|
| 25 |
+
"DEFAULT_LLM_PROVIDER": "llama_cpp",
|
| 26 |
+
"LLM_PROVIDER": "llama_cpp",
|
| 27 |
+
# Qwen2.5-7B-Instruct Q4_K_M (~4GB, best balance for free tier)
|
| 28 |
+
"LLAMA_CPP_MODEL_REPO": "bartowski/Qwen2.5-7B-Instruct-GGUF",
|
| 29 |
+
"LLAMA_CPP_MODEL_FILE": "Qwen2.5-7B-Instruct-Q4_K_M.gguf",
|
| 30 |
+
# Context: 2048 tokens (reduced from 4096 to speed up inference on free tier CPU)
|
| 31 |
+
# Qwen2.5-7B Q4_K_M supports up to 8192, but 2048 is optimal for 2 vCPU free tier
|
| 32 |
+
"LLAMA_CPP_CONTEXT": "2048",
|
| 33 |
+
"LLAMA_CPP_THREADS": "2",
|
| 34 |
+
"LLAMA_CPP_BATCH": "512", # Increased to 512 for faster prompt eval (was 256)
|
| 35 |
+
"LLAMA_CPP_MAX_TOKENS": "512",
|
| 36 |
+
"LLAMA_CPP_TEMPERATURE": "0.35",
|
| 37 |
+
"LLAMA_CPP_TOP_P": "0.85",
|
| 38 |
+
"LLAMA_CPP_REPEAT_PENALTY": "1.1",
|
| 39 |
+
"LLAMA_CPP_USE_MMAP": "true",
|
| 40 |
+
"LLAMA_CPP_USE_MLOCK": "true",
|
| 41 |
+
"RUN_HEAVY_STARTUP_TASKS": "0",
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
def main():
|
| 45 |
+
# Get HF token
|
| 46 |
+
hf_token = os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_HUB_TOKEN")
|
| 47 |
+
if not hf_token:
|
| 48 |
+
token_file = Path.home() / ".cache" / "huggingface" / "token"
|
| 49 |
+
if token_file.exists():
|
| 50 |
+
hf_token = token_file.read_text(encoding="utf-8").strip()
|
| 51 |
+
if not hf_token:
|
| 52 |
+
print("❌ HF_TOKEN not found.")
|
| 53 |
+
print("\n💡 Option 1: Set token as environment variable")
|
| 54 |
+
print(" export HF_TOKEN=your_token_here")
|
| 55 |
+
print(" python3 set_hf_space_env_qwen.py")
|
| 56 |
+
print("\n💡 Option 2: Login with Hugging Face CLI")
|
| 57 |
+
print(" huggingface-cli login")
|
| 58 |
+
print(" python3 set_hf_space_env_qwen.py")
|
| 59 |
+
sys.exit(1)
|
| 60 |
+
|
| 61 |
+
# Initialize API
|
| 62 |
+
api = HfApi(token=hf_token)
|
| 63 |
+
|
| 64 |
+
print(f"🚀 Upgrading to Qwen2.5-7B-Instruct Q4_K_M on Space: {SPACE_ID}")
|
| 65 |
+
print("=" * 60)
|
| 66 |
+
print("📊 Model specs:")
|
| 67 |
+
print(" - Size: ~4GB (downloads from HF, no storage limit)")
|
| 68 |
+
print(" - RAM: ~6-8GB (fits 16GB free tier)")
|
| 69 |
+
print(" - Expected latency: 7-9s on 2 vCPU")
|
| 70 |
+
print(" - Vietnamese legal: Excellent")
|
| 71 |
+
print("=" * 60)
|
| 72 |
+
|
| 73 |
+
for key, value in ENV_VARS.items():
|
| 74 |
+
try:
|
| 75 |
+
print(f"Setting {key}={value}...", end=" ")
|
| 76 |
+
api.delete_space_variable(repo_id=SPACE_ID, key=key)
|
| 77 |
+
except Exception:
|
| 78 |
+
pass # Ignore if variable doesn't exist yet
|
| 79 |
+
try:
|
| 80 |
+
api.add_space_variable(repo_id=SPACE_ID, key=key, value=str(value))
|
| 81 |
+
print("✅")
|
| 82 |
+
except Exception as exc:
|
| 83 |
+
print(f"❌ {exc}")
|
| 84 |
+
|
| 85 |
+
print("=" * 60)
|
| 86 |
+
print("✅ Config updated! Restarting Space...")
|
| 87 |
+
|
| 88 |
+
try:
|
| 89 |
+
api.restart_space(repo_id=SPACE_ID)
|
| 90 |
+
print("✅ Space restarted. Wait 2-3 minutes for model download & load.")
|
| 91 |
+
print("\n💡 Monitor logs at:")
|
| 92 |
+
print(f" https://huggingface.co/spaces/{SPACE_ID}/logs")
|
| 93 |
+
except Exception as exc:
|
| 94 |
+
print(f"⚠️ Config saved but restart failed: {exc}")
|
| 95 |
+
print(" Please restart Space manually from HF dashboard.")
|
| 96 |
+
|
| 97 |
+
if __name__ == "__main__":
|
| 98 |
+
main()
|
| 99 |
+
|
test_cloudflare_tunnel.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Script để test Cloudflare Tunnel URL và kiểm tra dữ liệu PostgreSQL
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import sys
|
| 7 |
+
import psycopg2
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
# Colors
|
| 11 |
+
GREEN = '\033[0;32m'
|
| 12 |
+
YELLOW = '\033[1;33m'
|
| 13 |
+
RED = '\033[0;31m'
|
| 14 |
+
BLUE = '\033[0;34m'
|
| 15 |
+
NC = '\033[0m' # No Color
|
| 16 |
+
|
| 17 |
+
def log(msg):
|
| 18 |
+
print(f"{BLUE}[TEST]{NC} {msg}")
|
| 19 |
+
|
| 20 |
+
def success(msg):
|
| 21 |
+
print(f"{GREEN}✅{NC} {msg}")
|
| 22 |
+
|
| 23 |
+
def warn(msg):
|
| 24 |
+
print(f"{YELLOW}⚠️{NC} {msg}")
|
| 25 |
+
|
| 26 |
+
def error(msg):
|
| 27 |
+
print(f"{RED}❌{NC} {msg}")
|
| 28 |
+
|
| 29 |
+
def test_connection(host, port, database, user, password):
|
| 30 |
+
"""Test kết nối PostgreSQL"""
|
| 31 |
+
log(f"Đang test kết nối: {host}:{port}/{database}")
|
| 32 |
+
|
| 33 |
+
try:
|
| 34 |
+
conn = psycopg2.connect(
|
| 35 |
+
host=host,
|
| 36 |
+
port=port,
|
| 37 |
+
database=database,
|
| 38 |
+
user=user,
|
| 39 |
+
password=password,
|
| 40 |
+
connect_timeout=10
|
| 41 |
+
)
|
| 42 |
+
success("Kết nối thành công!")
|
| 43 |
+
|
| 44 |
+
cursor = conn.cursor()
|
| 45 |
+
|
| 46 |
+
# Test 1: PostgreSQL version
|
| 47 |
+
cursor.execute("SELECT version();")
|
| 48 |
+
version = cursor.fetchone()[0]
|
| 49 |
+
log(f"PostgreSQL version: {version[:50]}...")
|
| 50 |
+
|
| 51 |
+
# Test 2: Kiểm tra database
|
| 52 |
+
cursor.execute("SELECT current_database();")
|
| 53 |
+
db_name = cursor.fetchone()[0]
|
| 54 |
+
success(f"Đang kết nối database: {db_name}")
|
| 55 |
+
|
| 56 |
+
# Test 3: Kiểm tra số lượng tables
|
| 57 |
+
cursor.execute("""
|
| 58 |
+
SELECT COUNT(*)
|
| 59 |
+
FROM information_schema.tables
|
| 60 |
+
WHERE table_schema = 'public'
|
| 61 |
+
""")
|
| 62 |
+
table_count = cursor.fetchone()[0]
|
| 63 |
+
success(f"Số lượng tables: {table_count}")
|
| 64 |
+
|
| 65 |
+
# Test 4: Kiểm tra dữ liệu trong các bảng chính
|
| 66 |
+
tables_to_check = [
|
| 67 |
+
'core_legaldocument',
|
| 68 |
+
'core_fine',
|
| 69 |
+
'core_procedure',
|
| 70 |
+
'core_office',
|
| 71 |
+
'core_advisory',
|
| 72 |
+
]
|
| 73 |
+
|
| 74 |
+
print(f"\n{BLUE}📊 Kiểm tra dữ liệu:{NC}")
|
| 75 |
+
print("=" * 60)
|
| 76 |
+
|
| 77 |
+
total_docs = 0
|
| 78 |
+
for table in tables_to_check:
|
| 79 |
+
try:
|
| 80 |
+
cursor.execute(f"SELECT COUNT(*) FROM {table};")
|
| 81 |
+
count = cursor.fetchone()[0]
|
| 82 |
+
total_docs += count
|
| 83 |
+
if count > 0:
|
| 84 |
+
success(f"{table}: {count:,} records")
|
| 85 |
+
else:
|
| 86 |
+
warn(f"{table}: 0 records (trống)")
|
| 87 |
+
except Exception as e:
|
| 88 |
+
error(f"{table}: Lỗi - {e}")
|
| 89 |
+
|
| 90 |
+
print("=" * 60)
|
| 91 |
+
success(f"Tổng số documents: {total_docs:,}")
|
| 92 |
+
|
| 93 |
+
# Test 5: Kiểm tra một vài records mẫu
|
| 94 |
+
if total_docs > 0:
|
| 95 |
+
print(f"\n{BLUE}📄 Sample records:{NC}")
|
| 96 |
+
try:
|
| 97 |
+
cursor.execute("""
|
| 98 |
+
SELECT id, title, created_at
|
| 99 |
+
FROM core_legaldocument
|
| 100 |
+
ORDER BY created_at DESC
|
| 101 |
+
LIMIT 5
|
| 102 |
+
""")
|
| 103 |
+
records = cursor.fetchall()
|
| 104 |
+
for idx, (doc_id, title, created_at) in enumerate(records, 1):
|
| 105 |
+
title_short = (title[:50] + "...") if title and len(title) > 50 else (title or "N/A")
|
| 106 |
+
print(f" {idx}. [{doc_id}] {title_short}")
|
| 107 |
+
print(f" Created: {created_at}")
|
| 108 |
+
except Exception as e:
|
| 109 |
+
warn(f"Không thể lấy sample records: {e}")
|
| 110 |
+
|
| 111 |
+
cursor.close()
|
| 112 |
+
conn.close()
|
| 113 |
+
|
| 114 |
+
return True, total_docs
|
| 115 |
+
|
| 116 |
+
except psycopg2.OperationalError as e:
|
| 117 |
+
error(f"Lỗi kết nối: {e}")
|
| 118 |
+
return False, 0
|
| 119 |
+
except Exception as e:
|
| 120 |
+
error(f"Lỗi: {e}")
|
| 121 |
+
return False, 0
|
| 122 |
+
|
| 123 |
+
def main():
|
| 124 |
+
print(f"{BLUE}{'='*60}{NC}")
|
| 125 |
+
print(f"{BLUE}Test Cloudflare Tunnel và kiểm tra dữ liệu PostgreSQL{NC}")
|
| 126 |
+
print(f"{BLUE}{'='*60}{NC}\n")
|
| 127 |
+
|
| 128 |
+
# Lấy thông tin từ user
|
| 129 |
+
print("Nhập thông tin Cloudflare Tunnel:")
|
| 130 |
+
tunnel_host = input(" Host (ví dụ: xyz.trycloudflare.com hoặc xyz.cfargotunnel.com): ").strip()
|
| 131 |
+
tunnel_port = input(" Port (ví dụ: 5432): ").strip() or "5432"
|
| 132 |
+
|
| 133 |
+
# Database credentials
|
| 134 |
+
db_user = input(" Database user (mặc định: hue_remote): ").strip() or "hue_remote"
|
| 135 |
+
db_password = input(" Database password (mặc định: huepass123): ").strip() or "huepass123"
|
| 136 |
+
db_name = input(" Database name (mặc định: hue_portal): ").strip() or "hue_portal"
|
| 137 |
+
|
| 138 |
+
print(f"\n{BLUE}🔍 Đang test kết nối...{NC}\n")
|
| 139 |
+
|
| 140 |
+
# Test connection
|
| 141 |
+
success_conn, doc_count = test_connection(
|
| 142 |
+
tunnel_host,
|
| 143 |
+
int(tunnel_port),
|
| 144 |
+
db_name,
|
| 145 |
+
db_user,
|
| 146 |
+
db_password
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
if success_conn:
|
| 150 |
+
print(f"\n{BLUE}{'='*60}{NC}")
|
| 151 |
+
success("KẾT NỐI THÀNH CÔNG!")
|
| 152 |
+
if doc_count > 0:
|
| 153 |
+
success(f"Có {doc_count:,} documents trong database")
|
| 154 |
+
print(f"\n{BLUE}📝 DATABASE_URL đ�� dùng:{NC}")
|
| 155 |
+
print(f"postgres://{db_user}:{db_password}@{tunnel_host}:{tunnel_port}/{db_name}")
|
| 156 |
+
else:
|
| 157 |
+
warn("Database trống, chưa có dữ liệu")
|
| 158 |
+
print(f"{BLUE}{'='*60}{NC}")
|
| 159 |
+
else:
|
| 160 |
+
print(f"\n{BLUE}{'='*60}{NC}")
|
| 161 |
+
error("KHÔNG KẾT NỐI ĐƯỢC!")
|
| 162 |
+
print(f"\n{BLUE}💡 Kiểm tra:{NC}")
|
| 163 |
+
print(" 1. Cloudflare Tunnel URL có đúng không?")
|
| 164 |
+
print(" 2. Tunnel có đang chạy trên server không?")
|
| 165 |
+
print(" 3. PostgreSQL có đang chạy không?")
|
| 166 |
+
print(" 4. Firewall có block port không?")
|
| 167 |
+
print(f"{BLUE}{'='*60}{NC}")
|
| 168 |
+
sys.exit(1)
|
| 169 |
+
|
| 170 |
+
if __name__ == "__main__":
|
| 171 |
+
main()
|
| 172 |
+
|
test_ngrok.sh
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Script test ngrok tunnel và kiểm tra PostgreSQL connection
|
| 3 |
+
# Usage: ./test_ngrok.sh [ngrok_host] [ngrok_port]
|
| 4 |
+
|
| 5 |
+
set -e
|
| 6 |
+
|
| 7 |
+
# Colors
|
| 8 |
+
GREEN='\033[0;32m'
|
| 9 |
+
YELLOW='\033[1;33m'
|
| 10 |
+
RED='\033[0;31m'
|
| 11 |
+
BLUE='\033[0;34m'
|
| 12 |
+
NC='\033[0m'
|
| 13 |
+
|
| 14 |
+
log() {
|
| 15 |
+
echo -e "${BLUE}[TEST]${NC} $1"
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
success() {
|
| 19 |
+
echo -e "${GREEN}✅${NC} $1"
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
warn() {
|
| 23 |
+
echo -e "${YELLOW}⚠️${NC} $1"
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
error() {
|
| 27 |
+
echo -e "${RED}❌${NC} $1"
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# Default values
|
| 31 |
+
NGROK_API="http://192.168.1.212:4040"
|
| 32 |
+
DB_USER="${POSTGRES_USER:-hue_remote}"
|
| 33 |
+
DB_PASSWORD="${POSTGRES_PASSWORD:-huepass123}"
|
| 34 |
+
DB_NAME="${POSTGRES_DB:-hue_portal}"
|
| 35 |
+
|
| 36 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 37 |
+
echo -e "${BLUE}Test Ngrok Tunnel và PostgreSQL Connection${NC}"
|
| 38 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 39 |
+
echo ""
|
| 40 |
+
|
| 41 |
+
# Step 1: Check ngrok API
|
| 42 |
+
log "Bước 1: Kiểm tra ngrok API ($NGROK_API)..."
|
| 43 |
+
if command -v curl &> /dev/null; then
|
| 44 |
+
if curl -s "$NGROK_API/api/tunnels" &> /dev/null; then
|
| 45 |
+
success "Ngrok API đang chạy"
|
| 46 |
+
else
|
| 47 |
+
error "Không thể kết nối ngrok API"
|
| 48 |
+
echo ""
|
| 49 |
+
echo "💡 Kiểm tra:"
|
| 50 |
+
echo " 1. Ngrok container có đang chạy không?"
|
| 51 |
+
echo " 2. Port 4040 có được expose không?"
|
| 52 |
+
echo " 3. Thử truy cập: http://192.168.1.212:4040"
|
| 53 |
+
exit 1
|
| 54 |
+
fi
|
| 55 |
+
else
|
| 56 |
+
warn "Không có curl, bỏ qua kiểm tra API"
|
| 57 |
+
fi
|
| 58 |
+
|
| 59 |
+
# Step 2: Get ngrok tunnel URL
|
| 60 |
+
log "Bước 2: Lấy ngrok tunnel URL..."
|
| 61 |
+
if command -v curl &> /dev/null && command -v python3 &> /dev/null; then
|
| 62 |
+
response=$(curl -s "$NGROK_API/api/tunnels" 2>/dev/null || echo "")
|
| 63 |
+
if [ -n "$response" ]; then
|
| 64 |
+
ngrok_url=$(echo "$response" | python3 -c "
|
| 65 |
+
import sys, json
|
| 66 |
+
try:
|
| 67 |
+
data = json.load(sys.stdin)
|
| 68 |
+
tunnels = data.get('tunnels', [])
|
| 69 |
+
if not tunnels:
|
| 70 |
+
print('NO_TUNNELS')
|
| 71 |
+
sys.exit(0)
|
| 72 |
+
for tunnel in tunnels:
|
| 73 |
+
if tunnel.get('proto') == 'tcp':
|
| 74 |
+
public_url = tunnel.get('public_url', '')
|
| 75 |
+
if public_url.startswith('tcp://'):
|
| 76 |
+
url = public_url.replace('tcp://', '')
|
| 77 |
+
print(url)
|
| 78 |
+
sys.exit(0)
|
| 79 |
+
print('NO_TCP_TUNNEL')
|
| 80 |
+
except Exception as e:
|
| 81 |
+
print('ERROR: ' + str(e))
|
| 82 |
+
" 2>/dev/null)
|
| 83 |
+
|
| 84 |
+
if [ "$ngrok_url" = "NO_TUNNELS" ]; then
|
| 85 |
+
error "Không tìm thấy tunnel nào!"
|
| 86 |
+
echo ""
|
| 87 |
+
echo "💡 Kiểm tra:"
|
| 88 |
+
echo " 1. Ngrok có đang chạy command 'tcp' không?"
|
| 89 |
+
echo " 2. Toggle switch có được BẬT (ON) không?"
|
| 90 |
+
echo " 3. Xem logs: docker logs ngrok"
|
| 91 |
+
exit 1
|
| 92 |
+
elif [ "$ngrok_url" = "NO_TCP_TUNNEL" ]; then
|
| 93 |
+
error "Không tìm thấy TCP tunnel!"
|
| 94 |
+
echo ""
|
| 95 |
+
echo "💡 Ngrok có thể đang chạy HTTP tunnel, cần TCP tunnel cho PostgreSQL"
|
| 96 |
+
exit 1
|
| 97 |
+
elif [[ "$ngrok_url" == ERROR* ]]; then
|
| 98 |
+
error "Lỗi parse JSON: $ngrok_url"
|
| 99 |
+
exit 1
|
| 100 |
+
else
|
| 101 |
+
ngrok_host=$(echo "$ngrok_url" | cut -d':' -f1)
|
| 102 |
+
ngrok_port=$(echo "$ngrok_url" | cut -d':' -f2)
|
| 103 |
+
success "Tìm thấy ngrok URL: tcp://$ngrok_host:$ngrok_port"
|
| 104 |
+
fi
|
| 105 |
+
else
|
| 106 |
+
error "Không thể lấy thông tin từ ngrok API"
|
| 107 |
+
exit 1
|
| 108 |
+
fi
|
| 109 |
+
else
|
| 110 |
+
# Manual input
|
| 111 |
+
if [ -n "$1" ] && [ -n "$2" ]; then
|
| 112 |
+
ngrok_host="$1"
|
| 113 |
+
ngrok_port="$2"
|
| 114 |
+
warn "Dùng ngrok URL từ tham số: tcp://$ngrok_host:$ngrok_port"
|
| 115 |
+
else
|
| 116 |
+
error "Cần cung cấp ngrok host và port"
|
| 117 |
+
echo ""
|
| 118 |
+
echo "Usage: $0 [ngrok_host] [ngrok_port]"
|
| 119 |
+
echo "Ví dụ: $0 0.tcp.ap.ngrok.io 13432"
|
| 120 |
+
exit 1
|
| 121 |
+
fi
|
| 122 |
+
fi
|
| 123 |
+
|
| 124 |
+
echo ""
|
| 125 |
+
log "Thông tin kết nối:"
|
| 126 |
+
echo " Ngrok Host: $ngrok_host"
|
| 127 |
+
echo " Ngrok Port: $ngrok_port"
|
| 128 |
+
echo " Database User: $DB_USER"
|
| 129 |
+
echo " Database Name: $DB_NAME"
|
| 130 |
+
echo ""
|
| 131 |
+
|
| 132 |
+
# Step 3: Test PostgreSQL connection
|
| 133 |
+
log "Bước 3: Test kết nối PostgreSQL qua ngrok..."
|
| 134 |
+
export PGPASSWORD="$DB_PASSWORD"
|
| 135 |
+
|
| 136 |
+
if command -v psql &> /dev/null; then
|
| 137 |
+
if psql -h "$ngrok_host" -p "$ngrok_port" -U "$DB_USER" -d "$DB_NAME" -c "SELECT 1;" &>/dev/null; then
|
| 138 |
+
success "Kết nối PostgreSQL thành công!"
|
| 139 |
+
echo ""
|
| 140 |
+
|
| 141 |
+
# Get PostgreSQL version
|
| 142 |
+
VERSION=$(psql -h "$ngrok_host" -p "$ngrok_port" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT version();" 2>/dev/null | head -1 | xargs)
|
| 143 |
+
log "PostgreSQL version: ${VERSION:0:60}..."
|
| 144 |
+
|
| 145 |
+
# Count tables
|
| 146 |
+
TABLE_COUNT=$(psql -h "$ngrok_host" -p "$ngrok_port" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';" 2>/dev/null | xargs)
|
| 147 |
+
success "Số lượng tables: $TABLE_COUNT"
|
| 148 |
+
echo ""
|
| 149 |
+
|
| 150 |
+
# Check data
|
| 151 |
+
echo -e "${BLUE}📊 Kiểm tra dữ liệu:${NC}"
|
| 152 |
+
echo "============================================================"
|
| 153 |
+
|
| 154 |
+
TOTAL_DOCS=0
|
| 155 |
+
|
| 156 |
+
for table in core_legaldocument core_fine core_procedure core_office core_advisory; do
|
| 157 |
+
COUNT=$(psql -h "$ngrok_host" -p "$ngrok_port" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM $table;" 2>/dev/null | xargs || echo "0")
|
| 158 |
+
if [ "$COUNT" != "0" ] && [ -n "$COUNT" ]; then
|
| 159 |
+
TOTAL_DOCS=$((TOTAL_DOCS + COUNT))
|
| 160 |
+
success "$table: $(printf "%'d" $COUNT) records"
|
| 161 |
+
else
|
| 162 |
+
warn "$table: 0 records (trống)"
|
| 163 |
+
fi
|
| 164 |
+
done
|
| 165 |
+
|
| 166 |
+
echo "============================================================"
|
| 167 |
+
success "Tổng số documents: $(printf "%'d" $TOTAL_DOCS)"
|
| 168 |
+
echo ""
|
| 169 |
+
|
| 170 |
+
# Show DATABASE_URL
|
| 171 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 172 |
+
success "✅ NGROK TUNNEL HOẠT ĐỘNG TỐT!"
|
| 173 |
+
if [ "$TOTAL_DOCS" -gt 0 ]; then
|
| 174 |
+
success "Có $(printf "%'d" $TOTAL_DOCS) documents trong database"
|
| 175 |
+
else
|
| 176 |
+
warn "Database trống, chưa có dữ liệu"
|
| 177 |
+
fi
|
| 178 |
+
echo ""
|
| 179 |
+
echo -e "${BLUE}📝 DATABASE_URL để dùng:${NC}"
|
| 180 |
+
echo "postgres://$DB_USER:$DB_PASSWORD@$ngrok_host:$ngrok_port/$DB_NAME"
|
| 181 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 182 |
+
|
| 183 |
+
else
|
| 184 |
+
error "KHÔNG KẾT NỐI ĐƯỢC PostgreSQL!"
|
| 185 |
+
echo ""
|
| 186 |
+
echo -e "${BLUE}💡 Kiểm tra:${NC}"
|
| 187 |
+
echo " 1. PostgreSQL có đang chạy trên 192.168.1.212:5432 không?"
|
| 188 |
+
echo " 2. Ngrok tunnel có đang chạy đúng command 'tcp 192.168.1.212:5432' không?"
|
| 189 |
+
echo " 3. Toggle switch có được BẬT (ON) không?"
|
| 190 |
+
echo " 4. Firewall có block không?"
|
| 191 |
+
echo ""
|
| 192 |
+
echo "Thử test trực tiếp:"
|
| 193 |
+
echo " psql -h $ngrok_host -p $ngrok_port -U $DB_USER -d $DB_NAME"
|
| 194 |
+
exit 1
|
| 195 |
+
fi
|
| 196 |
+
else
|
| 197 |
+
warn "Không có psql, bỏ qua test PostgreSQL"
|
| 198 |
+
echo ""
|
| 199 |
+
echo -e "${BLUE}📝 DATABASE_URL để dùng:${NC}"
|
| 200 |
+
echo "postgres://$DB_USER:$DB_PASSWORD@$ngrok_host:$ngrok_port/$DB_NAME"
|
| 201 |
+
fi
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
|
test_ngrok_simple.sh
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Script test ngrok tunnel đơn giản - không cần API
|
| 3 |
+
# Usage: ./test_ngrok_simple.sh <ngrok_host> <ngrok_port>
|
| 4 |
+
|
| 5 |
+
set -e
|
| 6 |
+
|
| 7 |
+
# Colors
|
| 8 |
+
GREEN='\033[0;32m'
|
| 9 |
+
YELLOW='\033[1;33m'
|
| 10 |
+
RED='\033[0;31m'
|
| 11 |
+
BLUE='\033[0;34m'
|
| 12 |
+
NC='\033[0m'
|
| 13 |
+
|
| 14 |
+
success() {
|
| 15 |
+
echo -e "${GREEN}✅${NC} $1"
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
warn() {
|
| 19 |
+
echo -e "${YELLOW}⚠️${NC} $1"
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
error() {
|
| 23 |
+
echo -e "${RED}❌${NC} $1"
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
log() {
|
| 27 |
+
echo -e "${BLUE}[TEST]${NC} $1"
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# Parse arguments
|
| 31 |
+
NGROK_HOST="${1:-}"
|
| 32 |
+
NGROK_PORT="${2:-}"
|
| 33 |
+
|
| 34 |
+
if [ -z "$NGROK_HOST" ] || [ -z "$NGROK_PORT" ]; then
|
| 35 |
+
error "Thiếu tham số!"
|
| 36 |
+
echo ""
|
| 37 |
+
echo "Usage: $0 <ngrok_host> <ngrok_port>"
|
| 38 |
+
echo ""
|
| 39 |
+
echo "Ví dụ:"
|
| 40 |
+
echo " $0 0.tcp.ap.ngrok.io 13432"
|
| 41 |
+
echo ""
|
| 42 |
+
echo "💡 Lấy ngrok URL từ:"
|
| 43 |
+
echo " 1. Docker logs: docker logs ngrok | grep tcp://"
|
| 44 |
+
echo " 2. Web interface: http://192.168.1.212:4040"
|
| 45 |
+
echo " 3. Hoặc xem trong Unraid Docker logs"
|
| 46 |
+
exit 1
|
| 47 |
+
fi
|
| 48 |
+
|
| 49 |
+
DB_USER="${POSTGRES_USER:-hue_remote}"
|
| 50 |
+
DB_PASSWORD="${POSTGRES_PASSWORD:-huepass123}"
|
| 51 |
+
DB_NAME="${POSTGRES_DB:-hue_portal}"
|
| 52 |
+
|
| 53 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 54 |
+
echo -e "${BLUE}Test Ngrok Tunnel: $NGROK_HOST:$NGROK_PORT${NC}"
|
| 55 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 56 |
+
echo ""
|
| 57 |
+
|
| 58 |
+
log "Đang test kết nối PostgreSQL..."
|
| 59 |
+
export PGPASSWORD="$DB_PASSWORD"
|
| 60 |
+
|
| 61 |
+
if command -v psql &> /dev/null; then
|
| 62 |
+
# Test với timeout 5 giây
|
| 63 |
+
if timeout 5 psql -h "$NGROK_HOST" -p "$NGROK_PORT" -U "$DB_USER" -d "$DB_NAME" -c "SELECT 1;" &>/dev/null; then
|
| 64 |
+
success "Kết nối thành công!"
|
| 65 |
+
echo ""
|
| 66 |
+
|
| 67 |
+
# Get version
|
| 68 |
+
VERSION=$(timeout 5 psql -h "$NGROK_HOST" -p "$NGROK_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT version();" 2>/dev/null | head -1 | xargs)
|
| 69 |
+
log "PostgreSQL: ${VERSION:0:50}..."
|
| 70 |
+
|
| 71 |
+
# Count tables
|
| 72 |
+
TABLE_COUNT=$(timeout 5 psql -h "$NGROK_HOST" -p "$NGROK_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';" 2>/dev/null | xargs)
|
| 73 |
+
success "Tables: $TABLE_COUNT"
|
| 74 |
+
echo ""
|
| 75 |
+
|
| 76 |
+
# Quick data check
|
| 77 |
+
TOTAL=$(timeout 5 psql -h "$NGROK_HOST" -p "$NGROK_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM core_legaldocument;" 2>/dev/null | xargs || echo "0")
|
| 78 |
+
if [ "$TOTAL" != "0" ]; then
|
| 79 |
+
success "Documents: $(printf "%'d" $TOTAL)"
|
| 80 |
+
else
|
| 81 |
+
warn "Database trống"
|
| 82 |
+
fi
|
| 83 |
+
|
| 84 |
+
echo ""
|
| 85 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 86 |
+
success "✅ NGROK TUNNEL HOẠT ĐỘNG!"
|
| 87 |
+
echo ""
|
| 88 |
+
echo -e "${BLUE}📝 DATABASE_URL:${NC}"
|
| 89 |
+
echo "postgres://$DB_USER:$DB_PASSWORD@$NGROK_HOST:$NGROK_PORT/$DB_NAME"
|
| 90 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 91 |
+
|
| 92 |
+
else
|
| 93 |
+
error "KHÔNG KẾT NỐI ĐƯỢC!"
|
| 94 |
+
echo ""
|
| 95 |
+
echo "💡 Kiểm tra:"
|
| 96 |
+
echo " 1. Ngrok URL có đúng không? (từ logs: docker logs ngrok)"
|
| 97 |
+
echo " 2. Toggle switch có ON không?"
|
| 98 |
+
echo " 3. PostgreSQL có chạy trên 192.168.1.212:5432 không?"
|
| 99 |
+
exit 1
|
| 100 |
+
fi
|
| 101 |
+
else
|
| 102 |
+
error "Không có psql để test!"
|
| 103 |
+
echo ""
|
| 104 |
+
echo "Cài đặt: brew install postgresql"
|
| 105 |
+
echo ""
|
| 106 |
+
echo "Hoặc dùng DATABASE_URL này:"
|
| 107 |
+
echo "postgres://$DB_USER:$DB_PASSWORD@$NGROK_HOST:$NGROK_PORT/$DB_NAME"
|
| 108 |
+
exit 1
|
| 109 |
+
fi
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
|
test_postgres_quick.sh
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Colors
|
| 4 |
+
GREEN='\033[0;32m'
|
| 5 |
+
RED='\033[0;31m'
|
| 6 |
+
YELLOW='\033[1;33m'
|
| 7 |
+
BLUE='\033[0;34m'
|
| 8 |
+
NC='\033[0m'
|
| 9 |
+
|
| 10 |
+
echo "============================================================"
|
| 11 |
+
echo "🔍 Quick Test PostgreSQL Connection"
|
| 12 |
+
echo "============================================================"
|
| 13 |
+
echo ""
|
| 14 |
+
|
| 15 |
+
HOST="postgres.aliss.io.vn"
|
| 16 |
+
PORT="5432"
|
| 17 |
+
USER="hue_remote"
|
| 18 |
+
PASSWORD="huepass123"
|
| 19 |
+
DB="hue_portal"
|
| 20 |
+
|
| 21 |
+
# Test 1: DNS Resolution
|
| 22 |
+
echo "1️⃣ Testing DNS resolution..."
|
| 23 |
+
if nslookup "$HOST" > /dev/null 2>&1; then
|
| 24 |
+
IP=$(dig +short "$HOST" | head -1)
|
| 25 |
+
echo -e "${GREEN}✅ DNS OK: $HOST → $IP${NC}"
|
| 26 |
+
else
|
| 27 |
+
echo -e "${RED}❌ DNS FAILED${NC}"
|
| 28 |
+
exit 1
|
| 29 |
+
fi
|
| 30 |
+
|
| 31 |
+
# Test 2: Port connectivity (timeout 5s)
|
| 32 |
+
echo ""
|
| 33 |
+
echo "2️⃣ Testing port connectivity (timeout 5s)..."
|
| 34 |
+
if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$HOST/$PORT" 2>/dev/null; then
|
| 35 |
+
echo -e "${GREEN}✅ Port $PORT is open${NC}"
|
| 36 |
+
else
|
| 37 |
+
echo -e "${YELLOW}⚠️ Port test failed (có thể do firewall hoặc tunnel chưa ready)${NC}"
|
| 38 |
+
fi
|
| 39 |
+
|
| 40 |
+
# Test 3: PostgreSQL connection
|
| 41 |
+
echo ""
|
| 42 |
+
echo "3️⃣ Testing PostgreSQL connection (timeout 10s)..."
|
| 43 |
+
export PGPASSWORD="$PASSWORD"
|
| 44 |
+
|
| 45 |
+
if timeout 10 psql -h "$HOST" -p "$PORT" -U "$USER" -d "$DB" -c "SELECT 1 as test;" 2>&1 | grep -q "test"; then
|
| 46 |
+
echo -e "${GREEN}✅ PostgreSQL connection SUCCESS!${NC}"
|
| 47 |
+
echo ""
|
| 48 |
+
echo "📝 DATABASE_URL:"
|
| 49 |
+
echo "postgres://$USER:$PASSWORD@$HOST:$PORT/$DB"
|
| 50 |
+
echo ""
|
| 51 |
+
|
| 52 |
+
# Quick data check
|
| 53 |
+
echo "4️⃣ Checking database data..."
|
| 54 |
+
COUNT=$(timeout 10 psql -h "$HOST" -p "$PORT" -U "$USER" -d "$DB" -t -c "SELECT COUNT(*) FROM core_legaldocument;" 2>/dev/null | xargs)
|
| 55 |
+
if [ -n "$COUNT" ]; then
|
| 56 |
+
echo -e "${GREEN}✅ Database has $COUNT legal documents${NC}"
|
| 57 |
+
else
|
| 58 |
+
echo -e "${YELLOW}⚠️ Could not check data count${NC}"
|
| 59 |
+
fi
|
| 60 |
+
|
| 61 |
+
exit 0
|
| 62 |
+
else
|
| 63 |
+
echo -e "${RED}❌ PostgreSQL connection FAILED${NC}"
|
| 64 |
+
echo ""
|
| 65 |
+
echo "💡 Troubleshooting:"
|
| 66 |
+
echo " 1. Check tunnel logs on Unraid: docker logs mystifying_bassi --tail 20"
|
| 67 |
+
echo " 2. Verify tunnel config has: postgres.aliss.io.vn → tcp://192.168.1.212:5432"
|
| 68 |
+
echo " 3. Check PostgreSQL is running: docker ps | grep postgres"
|
| 69 |
+
echo " 4. Try restart tunnel: docker restart mystifying_bassi"
|
| 70 |
+
exit 1
|
| 71 |
+
fi
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
|
test_tunnel.sh
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Script test Cloudflare Tunnel URL và kiểm tra dữ liệu PostgreSQL
|
| 3 |
+
# Usage: ./test_tunnel.sh <host> <port> [user] [password] [database]
|
| 4 |
+
|
| 5 |
+
set -e
|
| 6 |
+
|
| 7 |
+
# Colors
|
| 8 |
+
GREEN='\033[0;32m'
|
| 9 |
+
YELLOW='\033[1;33m'
|
| 10 |
+
RED='\033[0;31m'
|
| 11 |
+
BLUE='\033[0;34m'
|
| 12 |
+
NC='\033[0m'
|
| 13 |
+
|
| 14 |
+
log() {
|
| 15 |
+
echo -e "${BLUE}[TEST]${NC} $1"
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
success() {
|
| 19 |
+
echo -e "${GREEN}✅${NC} $1"
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
warn() {
|
| 23 |
+
echo -e "${YELLOW}⚠️${NC} $1"
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
error() {
|
| 27 |
+
echo -e "${RED}❌${NC} $1"
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# Parse arguments
|
| 31 |
+
TUNNEL_HOST="${1:-}"
|
| 32 |
+
TUNNEL_PORT="${2:-5432}"
|
| 33 |
+
DB_USER="${3:-hue_remote}"
|
| 34 |
+
DB_PASSWORD="${4:-huepass123}"
|
| 35 |
+
DB_NAME="${5:-hue_portal}"
|
| 36 |
+
|
| 37 |
+
if [ -z "$TUNNEL_HOST" ]; then
|
| 38 |
+
error "Thiếu tham số host!"
|
| 39 |
+
echo ""
|
| 40 |
+
echo "Usage: $0 <host> [port] [user] [password] [database]"
|
| 41 |
+
echo ""
|
| 42 |
+
echo "Ví dụ:"
|
| 43 |
+
echo " $0 nas.aliss.io.vn 5432"
|
| 44 |
+
echo " $0 xyz.trycloudflare.com 5432 hue_remote huepass123 hue_portal"
|
| 45 |
+
exit 1
|
| 46 |
+
fi
|
| 47 |
+
|
| 48 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 49 |
+
echo -e "${BLUE}Test Cloudflare Tunnel và kiểm tra dữ liệu PostgreSQL${NC}"
|
| 50 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 51 |
+
echo ""
|
| 52 |
+
log "Thông tin kết nối:"
|
| 53 |
+
echo " Host: $TUNNEL_HOST"
|
| 54 |
+
echo " Port: $TUNNEL_PORT"
|
| 55 |
+
echo " User: $DB_USER"
|
| 56 |
+
echo " Database: $DB_NAME"
|
| 57 |
+
echo ""
|
| 58 |
+
|
| 59 |
+
# Test connection
|
| 60 |
+
log "Đang test kết nối..."
|
| 61 |
+
export PGPASSWORD="$DB_PASSWORD"
|
| 62 |
+
|
| 63 |
+
if psql -h "$TUNNEL_HOST" -p "$TUNNEL_PORT" -U "$DB_USER" -d "$DB_NAME" -c "SELECT 1;" &>/dev/null; then
|
| 64 |
+
success "Kết nối thành công!"
|
| 65 |
+
echo ""
|
| 66 |
+
|
| 67 |
+
# Get PostgreSQL version
|
| 68 |
+
VERSION=$(psql -h "$TUNNEL_HOST" -p "$TUNNEL_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT version();" 2>/dev/null | head -1 | xargs)
|
| 69 |
+
log "PostgreSQL version: ${VERSION:0:50}..."
|
| 70 |
+
|
| 71 |
+
# Count tables
|
| 72 |
+
TABLE_COUNT=$(psql -h "$TUNNEL_HOST" -p "$TUNNEL_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';" 2>/dev/null | xargs)
|
| 73 |
+
success "Số lượng tables: $TABLE_COUNT"
|
| 74 |
+
echo ""
|
| 75 |
+
|
| 76 |
+
# Check data
|
| 77 |
+
echo -e "${BLUE}📊 Kiểm tra dữ liệu:${NC}"
|
| 78 |
+
echo "============================================================"
|
| 79 |
+
|
| 80 |
+
TOTAL_DOCS=0
|
| 81 |
+
|
| 82 |
+
for table in core_legaldocument core_fine core_procedure core_office core_advisory; do
|
| 83 |
+
COUNT=$(psql -h "$TUNNEL_HOST" -p "$TUNNEL_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM $table;" 2>/dev/null | xargs || echo "0")
|
| 84 |
+
if [ "$COUNT" != "0" ] && [ -n "$COUNT" ]; then
|
| 85 |
+
TOTAL_DOCS=$((TOTAL_DOCS + COUNT))
|
| 86 |
+
success "$table: $(printf "%'d" $COUNT) records"
|
| 87 |
+
else
|
| 88 |
+
warn "$table: 0 records (trống)"
|
| 89 |
+
fi
|
| 90 |
+
done
|
| 91 |
+
|
| 92 |
+
echo "============================================================"
|
| 93 |
+
success "Tổng số documents: $(printf "%'d" $TOTAL_DOCS)"
|
| 94 |
+
echo ""
|
| 95 |
+
|
| 96 |
+
# Show sample records
|
| 97 |
+
if [ "$TOTAL_DOCS" -gt 0 ]; then
|
| 98 |
+
echo -e "${BLUE}📄 Sample records (5 mới nhất):${NC}"
|
| 99 |
+
psql -h "$TUNNEL_HOST" -p "$TUNNEL_PORT" -U "$DB_USER" -d "$DB_NAME" -c "
|
| 100 |
+
SELECT id, LEFT(title, 50) as title, created_at
|
| 101 |
+
FROM core_legaldocument
|
| 102 |
+
ORDER BY created_at DESC
|
| 103 |
+
LIMIT 5;
|
| 104 |
+
" 2>/dev/null || warn "Không thể lấy sample records"
|
| 105 |
+
echo ""
|
| 106 |
+
fi
|
| 107 |
+
|
| 108 |
+
# Show DATABASE_URL
|
| 109 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 110 |
+
success "KẾT NỐI THÀNH CÔNG!"
|
| 111 |
+
if [ "$TOTAL_DOCS" -gt 0 ]; then
|
| 112 |
+
success "Có $(printf "%'d" $TOTAL_DOCS) documents trong database"
|
| 113 |
+
else
|
| 114 |
+
warn "Database trống, chưa có dữ liệu"
|
| 115 |
+
fi
|
| 116 |
+
echo ""
|
| 117 |
+
echo -e "${BLUE}📝 DATABASE_URL để dùng:${NC}"
|
| 118 |
+
echo "postgres://$DB_USER:$DB_PASSWORD@$TUNNEL_HOST:$TUNNEL_PORT/$DB_NAME"
|
| 119 |
+
echo -e "${BLUE}============================================================${NC}"
|
| 120 |
+
|
| 121 |
+
else
|
| 122 |
+
error "KHÔNG KẾT NỐI ĐƯỢC!"
|
| 123 |
+
echo ""
|
| 124 |
+
echo -e "${BLUE}💡 Kiểm tra:${NC}"
|
| 125 |
+
echo " 1. Cloudflare Tunnel URL có đúng không?"
|
| 126 |
+
echo " 2. Tunnel có đang chạy trên server không?"
|
| 127 |
+
echo " 3. PostgreSQL có đang chạy không?"
|
| 128 |
+
echo " 4. Firewall có block port không?"
|
| 129 |
+
echo ""
|
| 130 |
+
echo "Thử test với:"
|
| 131 |
+
echo " psql -h $TUNNEL_HOST -p $TUNNEL_PORT -U $DB_USER -d $DB_NAME"
|
| 132 |
+
exit 1
|
| 133 |
+
fi
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
|