From c6bffe5dc1494abaa79e36b2f6c9492cf42651d5 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 14:01:02 +0000 Subject: [PATCH] feat: Add video gallery and chat features This commit introduces two new community-oriented features: a video gallery and a real-time chat room. The video gallery is available at `/videos.html` and dynamically loads a list of videos from a new `/api/videos` endpoint. The chat room is available at `/chat.html` and uses WebSockets for real-time communication between users. The backend is powered by Flask-SocketIO. Both new pages are linked from a new "Community" section on the homepage. --- .gitignore | 1 + eco_project/backend/app.py | 125 +++++++++++++++---------- eco_project/backend/requirements.txt | 1 + eco_project/backend/static/chat.css | 23 +++++ eco_project/backend/static/chat.html | 32 +++++++ eco_project/backend/static/chat.js | 35 +++++++ eco_project/backend/static/index.html | 8 ++ eco_project/backend/static/videos.css | 23 +++++ eco_project/backend/static/videos.html | 30 ++++++ eco_project/backend/static/videos.js | 31 ++++++ 10 files changed, 258 insertions(+), 51 deletions(-) create mode 100644 eco_project/backend/static/chat.css create mode 100644 eco_project/backend/static/chat.html create mode 100644 eco_project/backend/static/chat.js create mode 100644 eco_project/backend/static/videos.css create mode 100644 eco_project/backend/static/videos.html create mode 100644 eco_project/backend/static/videos.js diff --git a/.gitignore b/.gitignore index 440cefd..d9590c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ __pycache__/ eco_project/backend/gcloud-credentials.json +server.log diff --git a/eco_project/backend/app.py b/eco_project/backend/app.py index e97fca4..04f6d17 100644 --- a/eco_project/backend/app.py +++ b/eco_project/backend/app.py @@ -1,4 +1,5 @@ from flask import Flask, jsonify, request, send_from_directory +from flask_socketio import SocketIO, emit import requests import os @@ -18,6 +19,7 @@ def log_struct(self, *args, **kwargs): logger = MockLogger() app = Flask(__name__, static_folder='static') +socketio = SocketIO(app) @app.route('/') def home(): @@ -213,56 +215,6 @@ def agricultural_land(): ) return jsonify({"error": str(e)}), 500 -@app.route('/api/chat', methods=['POST']) -def chat(): - data = request.get_json() - user_message = data.get('message') - - if not user_message: - return jsonify({"error": "No message provided."}), 400 - - # Get Ollama API URL from environment variable or use default - ollama_api_url = os.environ.get("OLLAMA_API_URL", "http://localhost:11434/api/generate") - - try: - # Prepare the data for the Ollama API - ollama_data = { - "model": "gemma:2b", - "prompt": user_message, - "stream": False - } - - # Send the request to the Ollama API - response = requests.post(ollama_api_url, json=ollama_data) - response.raise_for_status() # Raise an exception for bad status codes - - # Extract the response from Ollama - ai_response = response.json().get('response', "I'm sorry, I couldn't generate a response.") - - logger.log_struct( - { - "message": f"Chat message received: {user_message}", - "response": ai_response, - "component": "backend", - "endpoint": "/api/chat", - }, - severity="INFO", - ) - - return jsonify({"response": ai_response}) - - except requests.exceptions.RequestException as e: - logger.log_struct( - { - "message": f"Error communicating with Ollama API: {e}", - "component": "backend", - "endpoint": "/api/chat", - "url": ollama_api_url, - }, - severity="ERROR", - ) - return jsonify({"error": "Failed to communicate with the AI service."}), 500 - @app.route('/api/drinking_water') def drinking_water(): # World Bank API URL for access to safely managed drinking water @@ -513,6 +465,77 @@ def livestock(): ] return jsonify(mock_data) +@app.route('/api/videos') +def videos(): + mock_videos = [ + {"title": "The Problem with Traditional Agriculture", "url": "https://www.youtube.com/embed/Yp7XFAE8kr4"}, + {"title": "Agroecology for Sustainable Food Systems", "url": "https://www.youtube.com/embed/6OyGlwYUS5w"}, + {"title": "How does an organic farmer conserve water?", "url": "https://www.youtube.com/embed/32ZMYDbItQ8"} + ] + return jsonify(mock_videos) + +@app.route('/api/chat', methods=['POST']) +def chat(): + data = request.get_json() + user_message = data.get('message') + + if not user_message: + return jsonify({"error": "No message provided."}), 400 + + # Get Ollama API URL from environment variable or use default + ollama_api_url = os.environ.get("OLLAMA_API_URL", "http://localhost:11434/api/generate") + + try: + # Prepare the data for the Ollama API + ollama_data = { + "model": "gemma:2b", + "prompt": user_message, + "stream": False + } + + # Send the request to the Ollama API + response = requests.post(ollama_api_url, json=ollama_data) + response.raise_for_status() # Raise an exception for bad status codes + + # Extract the response from Ollama + ai_response = response.json().get('response', "I'm sorry, I couldn't generate a response.") + + logger.log_struct( + { + "message": f"Chat message received: {user_message}", + "response": ai_response, + "component": "backend", + "endpoint": "/api/chat", + }, + severity="INFO", + ) + + return jsonify({"response": ai_response}) + + except requests.exceptions.RequestException as e: + logger.log_struct( + { + "message": f"Error communicating with Ollama API: {e}", + "component": "backend", + "endpoint": "/api/chat", + "url": ollama_api_url, + }, + severity="ERROR", + ) + return jsonify({"error": "Failed to communicate with the AI service."}), 500 + +@socketio.on('connect') +def handle_connect(): + print('Client connected') + +@socketio.on('disconnect') +def handle_disconnect(): + print('Client disconnected') + +@socketio.on('chat_message') +def handle_chat_message(message): + emit('chat_message', message, broadcast=True) + if __name__ == '__main__': port = int(os.environ.get("PORT", 8080)) - app.run(host='0.0.0.0', port=port, debug=False) \ No newline at end of file + socketio.run(app, host='0.0.0.0', port=port, debug=False, allow_unsafe_werkzeug=True) diff --git a/eco_project/backend/requirements.txt b/eco_project/backend/requirements.txt index 1d4ca88..eaa9415 100644 --- a/eco_project/backend/requirements.txt +++ b/eco_project/backend/requirements.txt @@ -2,3 +2,4 @@ Flask requests gunicorn google-cloud-logging +Flask-SocketIO diff --git a/eco_project/backend/static/chat.css b/eco_project/backend/static/chat.css new file mode 100644 index 0000000..952cbe8 --- /dev/null +++ b/eco_project/backend/static/chat.css @@ -0,0 +1,23 @@ +#chat-container { + display: flex; + flex-direction: column; + height: 400px; + border: 1px solid #ccc; + padding: 10px; +} + +#chat-window { + flex-grow: 1; + overflow-y: auto; + border-bottom: 1px solid #ccc; + margin-bottom: 10px; +} + +#chat-input { + padding: 5px; +} + +#send-btn { + padding: 5px 10px; + cursor: pointer; +} \ No newline at end of file diff --git a/eco_project/backend/static/chat.html b/eco_project/backend/static/chat.html new file mode 100644 index 0000000..c029887 --- /dev/null +++ b/eco_project/backend/static/chat.html @@ -0,0 +1,32 @@ + + +
+ + +Explore data and insights on global health and education trends from leading international organizations. Learn more.
+Share your ideas and connect with others.
+Your personal guide to environmental protection.
diff --git a/eco_project/backend/static/videos.css b/eco_project/backend/static/videos.css new file mode 100644 index 0000000..1d9b7fc --- /dev/null +++ b/eco_project/backend/static/videos.css @@ -0,0 +1,23 @@ +.video-container { + display: flex; + flex-wrap: wrap; + justify-content: space-around; + padding: 20px; +} + +.video-item { + width: 300px; + margin: 15px; + border: 1px solid #ccc; + box-shadow: 0 0 5px rgba(0,0,0,0.1); +} + +.video-item iframe { + width: 100%; + height: 170px; +} + +.video-item-title { + padding: 10px; + font-weight: bold; +} \ No newline at end of file diff --git a/eco_project/backend/static/videos.html b/eco_project/backend/static/videos.html new file mode 100644 index 0000000..216a61a --- /dev/null +++ b/eco_project/backend/static/videos.html @@ -0,0 +1,30 @@ + + + + + +Error fetching videos: ${error.message}
`; + } + } + + function displayVideos(videos) { + let html = ''; + videos.forEach(video => { + html += ` +