diff --git a/examples/streaming_web/READMD-zh-tw.md b/examples/streaming_web/READMD-zh-tw.md index be27e28..74e44b3 100644 --- a/examples/streaming_web/READMD-zh-tw.md +++ b/examples/streaming_web/READMD-zh-tw.md @@ -3,115 +3,71 @@ # 即時串流網頁範例 -此部分提供一個即時串流網頁應用程式的實作範例,設計目的是為了實現即時的攝影機串流畫面更新。本指南提供如何使用、配置及瞭解此應用程式的特點與功能。 +本節提供了一個 Streaming Web 應用程序的範例實作,旨在促進即時相機畫面傳輸和更新。此指南提供有關如何使用、配置和了解該應用程序功能的信息。 -## 使用方法 +## 使用方式 1. **啟動伺服器:** ```sh python app.py ``` - 或者使用 Gunicorn 啟動應用程式,並設定非同步工作執行緒: + 或是 + ```sh - gunicorn -w 1 -k eventlet -b 127.0.0.1:8000 "examples.streaming_web.app:app" + uvicorn examples.streaming_web.app:sio_app --host 127.0.0.1 --port 8000 ``` -2. **訪問應用程式:** - 打開網頁瀏覽器,並導向以下網址: +2. **打開您的網頁瀏覽器並導航至:** ```sh http://localhost:8000 ``` ## 功能 -- **即時串流**:顯示即時的攝影機畫面,每 5 秒自動更新。 -- **WebSocket 整合**:使用 WebSocket 進行高效的即時通訊。 -- **動態內容加載**:自動更新攝影機圖片,無需重新整理頁面。 -- **響應式設計**:適應不同螢幕尺寸,提供無縫的使用者體驗。 -- **可自定義的佈局**:透過 CSS 調整佈局和樣式,以符合個人需求。 +- **即時流媒體**:顯示即時相機畫面,每5秒自動更新一次。 +- **WebSocket 整合**:利用 WebSocket 進行高效的即時通信。 +- **動態內容加載**:無需刷新頁面即可自動更新相機圖像。 +- **響應式設計**:適應各種屏幕尺寸,提供無縫的用戶體驗。 +- **可定制的佈局**:使用 CSS 調整佈局和樣式。 -## 配置和檔案概覽 +## 配置 -此應用程式可透過以下關鍵檔案進行自訂和配置: +可以通過以下文件配置應用程序: -- **app.py**:啟動伺服器並定義路由的主要應用程式檔案。 -- **routes.py**:定義網頁路由及其相應的處理器。 +- **app.py**:啟動伺服器並定義路由的主要應用文件。 +- **routes.py**:定義網頁路由及其相應的處理程序。 - **sockets.py**:管理 WebSocket 連接和事件。 -- **utils.py**:包含應用程式使用的實用工具函式。 -- **index.js**:處理主頁面中攝影機圖片的動態更新。 -- **camera.js**:管理攝影機畫面的更新。 -- **label.js**:處理 WebSocket 通訊和基於標籤的更新。 -- **styles.css**:包含網頁應用程式的樣式,確保響應式和可存取的設計。 - -請務必根據環境需求檢查並調整這些檔案中的配置設定。 - -## Nginx 配置範例 - -若要使用 Nginx 作為此 FastAPI 應用程式的反向代理,可以參考以下關鍵配置部分。完整的範例配置檔案請參見 `config/` 目錄中的 `nginx_config_example.conf`。 - -1. **HTTP 重定向至 HTTPS**:將所有 HTTP 請求重定向到 HTTPS,確保安全通訊。 - ```nginx - server { - listen 80; - server_name yourdomain.com; - location / { - return 301 https://$server_name$request_uri; - } - } - ``` +- **utils.py**:應用程序中使用的實用函數。 +- **index.js**:處理主頁面動態圖像更新。 +- **camera.js**:管理相機圖像更新。 +- **label.js**:處理基於標籤的 WebSocket 通信和更新。 +- **styles.css**:包含網頁應用程序的樣式,確保響應式和無障礙設計。 -2. **HTTPS 配置**:啟用 SSL 憑證並代理靜態文件和 WebSocket 請求。 - ```nginx - server { - listen 443 ssl; - server_name yourdomain.com; - - # SSL 憑證路徑 - ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; - - # 靜態文件 - location /upload/ { - alias /home/youruser/Documents/Construction-Hazard-Detection/static/uploads/; - autoindex on; - allow all; - } - - # WebSocket 配置 - location /ws/ { - proxy_pass http://127.0.0.1:8000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_buffering off; - # 傳遞額外的客戶端資訊標頭 - } - - # 一般 HTTP 代理 - location / { - proxy_pass http://127.0.0.1:8000; - # 傳遞客戶端及 SSL 狀態的標頭 - } - } - ``` +## 文件概述 + +### app.py +啟動伺服器並設置路由的應用程序主入口。 + +### routes.py +定義各種網頁路由及其相應的請求處理程序。 + +### sockets.py +管理 WebSocket 連接,處理連接、重新連接和更新事件。 -3. **SSL 憑證設定** +### utils.py +包含應用程序中使用的實用函數。 - 若要使用 SSL 保護伺服器,可以使用 Let's Encrypt 提供的免費 SSL 憑證。建議步驟如下: +### index.js +使用 jQuery 定期更新主頁面的相機圖像。 - - **安裝 Certbot**:使用 Certbot 來自動處理 SSL 憑證的安裝和續期。 - - **取得 SSL 憑證**:使用您的網域名稱運行 Certbot 以創建 SSL 憑證: - ```sh - sudo certbot --nginx -d yourdomain.com - ``` - - **設置自動續期**:Certbot 會自動處理憑證的續期,您可以新增 Cron 排程定期檢查: - ```sh - 0 12 * * * /usr/bin/certbot renew --quiet - ``` +### camera.js +通過刷新圖像源每5秒更新頁面上的相機圖像。 -此配置確保 Nginx 伺服器的安全性,並自動管理 SSL 憑證。 +### label.js +管理 WebSocket 連接,處理當前頁面標籤顯示的更新。 -## 其他注意事項 +### styles.css +定義應用程序的樣式,包括響應式設計、強制顏色調整以確保無障礙性以及平滑的圖像過渡效果。 -欲進一步自訂應用程式,請參考 `examples/streaming_web` 資料夾並根據專案需求調整檔案。此程式碼具有模組化設計,允許您更新或替換組件,以適應擴展性和維護性需求。 +請確保檢查並調整相應文件中的配置設置以適應您的具體需求。 diff --git a/examples/streaming_web/README.md b/examples/streaming_web/README.md index 92df657..c1720d3 100644 --- a/examples/streaming_web/README.md +++ b/examples/streaming_web/README.md @@ -12,106 +12,62 @@ This section provides an example implementation of a Streaming Web application, python app.py ``` - Alternatively, use Gunicorn to start the application with an asynchronous worker: + or + ```sh - gunicorn -w 1 -k eventlet -b 127.0.0.1:8000 "examples.streaming_web.app:app" + uvicorn examples.streaming_web.app:sio_app --host 127.0.0.1 --port 8000 ``` -2. **Access the application:** - Open your web browser and navigate to: +2. **Open your web browser and navigate to:** ```sh http://localhost:8000 ``` ## Features -- **Real-Time Streaming**: Displays real-time camera feeds with automatic updates every 5 seconds. +- **Real-Time Streaming**: Display real-time camera feeds with automatic updates every 5 seconds. - **WebSocket Integration**: Utilises WebSocket for efficient real-time communication. -- **Dynamic Content Loading**: Automatically updates camera images without page refresh. +- **Dynamic Content Loading**: Automatically updates camera images without refreshing the page. - **Responsive Design**: Adapts to various screen sizes for a seamless user experience. -- **Customisable Layout**: Modify layout and styles using CSS for a tailored appearance. +- **Customisable Layout**: Adjust layout and styles using CSS. -## Configuration and File Overview +## Configuration -The application can be customised and configured via the following key files: +The application can be configured through the following files: - **app.py**: Main application file that starts the server and defines the routes. -- **routes.py**: Defines web routes and their respective handlers. +- **routes.py**: Defines the web routes and their respective handlers. - **sockets.py**: Manages WebSocket connections and events. -- **utils.py**: Contains utility functions for the application. -- **index.js**: Handles dynamic image updates on the main page. +- **utils.py**: Utility functions for the application. +- **index.js**: Handles dynamic image updates for the main page. - **camera.js**: Manages the camera image updates. -- **label.js**: Handles WebSocket communication and label-based updates. -- **styles.css**: Contains the styles for the web application, ensuring responsive and accessible design. - -Ensure to review and adjust configuration settings in these files as necessary for your environment. +- **label.js**: Handles WebSocket communication and updates based on labels. +- **styles.css**: Contains the styles for the web application, ensuring a responsive and accessible design. -## Nginx Configuration Example +## File Overview -To use Nginx as a reverse proxy for this FastAPI application, you may refer to the following key configuration parts. For a complete example configuration file, see `nginx_config_example.conf` in the `config/` directory. +### app.py +The main entry point of the application that starts the server and sets up routes. -1. **HTTP Redirect to HTTPS**: Redirect all HTTP requests to HTTPS for secure communication. - ```nginx - server { - listen 80; - server_name yourdomain.com; - location / { - return 301 https://$server_name$request_uri; - } - } - ``` +### routes.py +Defines the various web routes and their respective request handlers. -2. **HTTPS Configuration**: Enables SSL certificates and proxies static files and WebSocket requests. - ```nginx - server { - listen 443 ssl; - server_name yourdomain.com; - - # SSL certificate paths - ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; - - # Static files - location /upload/ { - alias /home/youruser/Documents/Construction-Hazard-Detection/static/uploads/; - autoindex on; - allow all; - } - - # WebSocket configuration - location /ws/ { - proxy_pass http://127.0.0.1:8000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_buffering off; - # Additional headers to forward client information - } - - # General HTTP proxy - location / { - proxy_pass http://127.0.0.1:8000; - # Forward headers for client and SSL status - } - } - ``` +### sockets.py +Manages WebSocket connections, handling events such as connection, reconnection, and updates. -3. **SSL Certificate Setup** +### utils.py +Contains utility functions used across the application for various tasks. - To secure the server with SSL, a free SSL certificate from Let's Encrypt can be used. Here are the recommended steps: +### index.js +Handles the periodic update of camera images on the main page using jQuery. - - **Install Certbot**: Use Certbot to handle automatic SSL certificate installation and renewal. - - **Obtain SSL Certificates**: Run Certbot with your domain name to create SSL certificates: - ```sh - sudo certbot --nginx -d yourdomain.com - ``` - - **Set Up Automatic Renewal**: Certbot handles automatic renewal; however, you can add a Cron job to check periodically: - ```sh - 0 12 * * * /usr/bin/certbot renew --quiet - ``` +### camera.js +Updates the camera images on the page by refreshing the image source every 5 seconds. -This setup ensures secure, automatic SSL management for the Nginx server. +### label.js +Manages WebSocket connections, handling updates based on the current label displayed on the page. -## Additional Notes +### styles.css +Defines the styling for the application, including responsive design, forced color adjustments for accessibility, and smooth image transitions. -For further customisation, refer to the `examples/streaming_web` folder and adjust files as per project needs. The code is modular, allowing you to update or replace components for scalability and maintenance. +Ensure to review and adjust the configuration settings in the respective files to suit your specific requirements. diff --git a/examples/streaming_web/app.py b/examples/streaming_web/app.py index 334e6a4..3bce52d 100644 --- a/examples/streaming_web/app.py +++ b/examples/streaming_web/app.py @@ -1,42 +1,73 @@ from __future__ import annotations -import os +from collections.abc import AsyncGenerator +from contextlib import asynccontextmanager -import redis -from dotenv import load_dotenv -from flask import Flask -from flask_cors import CORS -from flask_limiter import Limiter -from flask_limiter.util import get_remote_address -from flask_socketio import SocketIO +import socketio +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +from fastapi.staticfiles import StaticFiles +from fastapi_limiter import FastAPILimiter from .routes import register_routes from .sockets import register_sockets +from .utils import redis_manager -load_dotenv() -# Redis configuration -redis_host: str = os.getenv('redis_host') or 'localhost' -redis_port: int = int(os.getenv('redis_port') or 6379) -redis_password: str | None = os.getenv('redis_password') or None +@asynccontextmanager +async def lifespan(app: FastAPI) -> AsyncGenerator[None]: + """ + Initialises resources at startup and performs cleanup on shutdown. -# Connect to Redis -r = redis.StrictRedis( - host=redis_host, - port=redis_port, - password=redis_password, - decode_responses=False, + Args: + app (FastAPI): The FastAPI application instance. + + Yields: + None + """ + # Initialises rate limiter with the Redis client + await FastAPILimiter.init(redis_manager.client) + try: + yield + finally: + # Cleanup code: Closes the Redis connection after application shutdown + await redis_manager.client.close() + print('Redis connection closed.') + + +# Create the FastAPI application with a lifespan manager for setup and cleanup +app = FastAPI(lifespan=lifespan) + +# Add CORS middleware to allow cross-origin requests +app.add_middleware( + CORSMiddleware, + allow_origins=['*'], + allow_credentials=True, + allow_methods=['*'], + allow_headers=['*'], ) -app = Flask(__name__) -CORS(app) # Allow cross-origin requests from any domain -# Allow all origins for WebSocket connections -socketio = SocketIO(app, cors_allowed_origins='*') -limiter = Limiter(key_func=get_remote_address) +# Mount the static files directory to serve static assets +app.mount( + '/static', + StaticFiles(directory='examples/streaming_web/static'), + name='static', +) +# Initialise Socket.IO server with ASGI support +sio = socketio.AsyncServer(async_mode='asgi') +sio_app = socketio.ASGIApp(sio, app) -register_routes(app, limiter, r) -register_sockets(socketio, r) +# Register application routes and Socket.IO events +register_routes(app) +register_sockets(sio, redis_manager) +# Run the application using Uvicorn ASGI server if __name__ == '__main__': - socketio.run(app, host='127.0.0.1', port=8000, debug=False) + import uvicorn + uvicorn.run( + 'examples.streaming_web.app:sio_app', + host='127.0.0.1', + port=8000, + log_level='info', + ) diff --git a/examples/streaming_web/routes.py b/examples/streaming_web/routes.py index 684beec..7dd8b43 100644 --- a/examples/streaming_web/routes.py +++ b/examples/streaming_web/routes.py @@ -1,86 +1,201 @@ from __future__ import annotations -from flask import abort -from flask import Flask -from flask import make_response -from flask import render_template -from flask import Response -from flask_limiter import Limiter - -from .utils import get_image_data -from .utils import get_labels - - -def register_routes(app: Flask, limiter: Limiter, r) -> None: - @app.route('/') - @limiter.limit('60 per minute') - def index() -> str: - """ - Serve the index page with a dynamic list of labels from Redis. - - Returns: - str: The rendered 'index.html' page. - """ - labels = get_labels(r) - return render_template('index.html', labels=labels) - - @app.route('/label/