| |
| import os |
| import json |
| import time |
| from flask import Flask, request, jsonify, render_template |
| from flask_cors import CORS |
| import logging |
| import threading |
| from huggingface_hub import HfApi, hf_hub_download |
| from huggingface_hub.utils import RepositoryNotFoundError, EntryNotFoundError |
|
|
| |
| |
| DATASET_REPO = "Ezmary/Karbaran-rayegan-tedad" |
| DATASET_FILENAME = "video_usage_data.json" |
| USAGE_LIMIT = 5 |
| HF_TOKEN = os.environ.get("HF_TOKEN") |
|
|
| |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
| app = Flask(__name__) |
| CORS(app) |
|
|
| |
| usage_data_cache = [] |
| cache_lock = threading.Lock() |
| data_changed = threading.Event() |
| api = None |
|
|
| if not HF_TOKEN: |
| logging.error("CRITICAL: Secret 'HF_TOKEN' not found. Cannot access the private dataset.") |
| else: |
| api = HfApi(token=HF_TOKEN) |
| logging.info("HfApi initialized successfully.") |
|
|
| def load_initial_data(): |
| global usage_data_cache |
| with cache_lock: |
| if not api: return |
| try: |
| logging.info(f"Attempting to load data from '{DATASET_REPO}'...") |
| local_path = hf_hub_download( |
| repo_id=DATASET_REPO, |
| filename=DATASET_FILENAME, |
| repo_type="dataset", |
| token=HF_TOKEN, |
| force_download=True |
| ) |
| with open(local_path, 'r', encoding='utf-8') as f: |
| content = f.read() |
| usage_data_cache = json.loads(content) if content else [] |
| logging.info(f"Loaded {len(usage_data_cache)} records.") |
| except (RepositoryNotFoundError, EntryNotFoundError): |
| logging.warning("Dataset file not found. A new one will be created.") |
| usage_data_cache = [] |
| except Exception as e: |
| logging.error(f"Failed to load initial data: {e}") |
|
|
| def persist_data_to_hub(): |
| with cache_lock: |
| if not data_changed.is_set() or not api: |
| return |
| |
| logging.info("Change detected, preparing to write to Hub...") |
| try: |
| |
| data_to_write = list(usage_data_cache) |
| temp_filepath = "temp_usage_data.json" |
| with open(temp_filepath, 'w', encoding='utf-8') as f: |
| json.dump(data_to_write, f, ensure_ascii=False, indent=2) |
| |
| api.upload_file( |
| path_or_fileobj=temp_filepath, |
| path_in_repo=DATASET_FILENAME, |
| repo_id=DATASET_REPO, |
| repo_type="dataset", |
| commit_message="Update video usage data" |
| ) |
| os.remove(temp_filepath) |
| data_changed.clear() |
| logging.info(f"Successfully persisted {len(data_to_write)} records to Hub.") |
| except Exception as e: |
| logging.error(f"CRITICAL: Failed to persist data to Hub: {e}") |
|
|
| def background_persister(): |
| while True: |
| time.sleep(30) |
| persist_data_to_hub() |
|
|
| |
| @app.route('/') |
| def index(): |
| return render_template('index.html') |
|
|
| def get_user_identifier(data): |
| |
| fingerprint = data.get('fingerprint') |
| if fingerprint: |
| return str(fingerprint) |
| |
| if request.headers.getlist("X-Forwarded-For"): |
| return request.headers.getlist("X-Forwarded-For")[0].split(',')[0].strip() |
| return request.remote_addr |
|
|
| @app.route('/api/check-credit', methods=['POST']) |
| def check_credit(): |
| data = request.get_json() |
| if not data: return jsonify({"error": "Invalid request"}), 400 |
| |
| user_id = get_user_identifier(data) |
| if not user_id: return jsonify({"error": "User identifier is required."}), 400 |
|
|
| with cache_lock: |
| now = time.time() |
| one_week_seconds = 7 * 24 * 60 * 60 |
| |
| user_record = next((user for user in usage_data_cache if user.get('id') == user_id), None) |
| |
| credits_remaining = USAGE_LIMIT |
| limit_reached = False |
| reset_timestamp = 0 |
|
|
| if user_record: |
| if user_record.get('week_start', 0) < (now - one_week_seconds): |
| user_record['count'] = 0 |
| user_record['week_start'] = now |
| data_changed.set() |
| |
| credits_remaining = max(0, USAGE_LIMIT - user_record.get('count', 0)) |
| if credits_remaining == 0: |
| limit_reached = True |
| reset_timestamp = user_record.get('week_start', now) + one_week_seconds |
| |
| return jsonify({ |
| "credits_remaining": credits_remaining, |
| "limit_reached": limit_reached, |
| "reset_timestamp": reset_timestamp |
| }) |
|
|
| @app.route('/api/use-credit', methods=['POST']) |
| def use_credit(): |
| data = request.get_json() |
| if not data: return jsonify({"error": "Invalid request"}), 400 |
| |
| user_id = get_user_identifier(data) |
| if not user_id: return jsonify({"error": "User identifier is required."}), 400 |
| |
| with cache_lock: |
| now = time.time() |
| one_week_seconds = 7 * 24 * 60 * 60 |
| |
| user_record = next((user for user in usage_data_cache if user.get('id') == user_id), None) |
| |
| if user_record: |
| if user_record.get('week_start', 0) < (now - one_week_seconds): |
| user_record['count'] = 0 |
| user_record['week_start'] = now |
| |
| if user_record.get('count', 0) >= USAGE_LIMIT: |
| reset_timestamp = user_record.get('week_start', now) + one_week_seconds |
| return jsonify({ |
| "status": "limit_reached", |
| "credits_remaining": 0, |
| "reset_timestamp": reset_timestamp |
| }), 429 |
| |
| user_record['count'] += 1 |
| else: |
| user_record = {"id": user_id, "count": 1, "week_start": now} |
| usage_data_cache.append(user_record) |
| |
| credits_remaining = USAGE_LIMIT - user_record['count'] |
| data_changed.set() |
| |
| return jsonify({"status": "success", "credits_remaining": credits_remaining}) |
|
|
| |
| if __name__ != '__main__': |
| load_initial_data() |
| persister_thread = threading.Thread(target=background_persister, daemon=True) |
| persister_thread.start() |
|
|
| if __name__ == '__main__': |
| port = int(os.environ.get('PORT', 7860)) |
| app.run(host='0.0.0.0', port=port) |