Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import time | |
| import threading | |
| import logging | |
| from flask import Flask, request, jsonify, send_from_directory | |
| from flask_cors import CORS | |
| from huggingface_hub import HfApi, hf_hub_download | |
| from huggingface_hub.utils import RepositoryNotFoundError, EntryNotFoundError | |
| # --- تنظیمات --- | |
| DATASET_REPO = "ezmarynoori/Karbaran-rayegan-tedad" | |
| DATASET_FILENAME = "voice_conversion_usage_data.json" | |
| USAGE_LIMIT_PER_MODEL = 3 # محدودیت ۳ عدد برای هر مدل در هفته | |
| HF_TOKEN = os.environ.get("HF_TOKEN") | |
| # پوشه بیلد شده توسط Docker (dist) | |
| STATIC_FOLDER = 'dist' | |
| # --- راهاندازی برنامه --- | |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | |
| app = Flask(__name__, static_folder=STATIC_FOLDER, static_url_path='') | |
| CORS(app) | |
| # --- متغیرهای ذخیرهسازی داده --- | |
| usage_data_cache = [] | |
| cache_lock = threading.Lock() | |
| data_changed = threading.Event() | |
| api = None | |
| if not HF_TOKEN: | |
| logging.error("هشدار: توکن HF_TOKEN یافت نشد. دیتابیس کار نخواهد کرد.") | |
| else: | |
| api = HfApi(token=HF_TOKEN) | |
| # --- لود اولیه دادهها --- | |
| def load_initial_data(): | |
| global usage_data_cache | |
| with cache_lock: | |
| if not api: return | |
| try: | |
| 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() | |
| if content: | |
| usage_data_cache = json.loads(content) | |
| except (RepositoryNotFoundError, EntryNotFoundError): | |
| usage_data_cache = [] | |
| except Exception as e: | |
| logging.warning(f"Error loading data: {e}") | |
| usage_data_cache = [] | |
| # --- ذخیرهسازی در پسزمینه --- | |
| def persist_data_to_hub(): | |
| if not api: return | |
| data_snapshot = None | |
| with cache_lock: | |
| if data_changed.is_set(): | |
| data_snapshot = list(usage_data_cache) | |
| data_changed.clear() | |
| if data_snapshot is not None: | |
| temp_filepath = "/tmp/temp_voice_usage.json" | |
| try: | |
| with open(temp_filepath, 'w', encoding='utf-8') as f: | |
| json.dump(data_snapshot, 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 voice usage" | |
| ) | |
| logging.info("Data saved to HF Hub.") | |
| except Exception as e: | |
| logging.error(f"Failed to save data: {e}") | |
| data_changed.set() | |
| def background_persister(): | |
| while True: | |
| time.sleep(300) # هر 5 دقیقه ذخیره کن | |
| persist_data_to_hub() | |
| 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 | |
| # --- API Endpoints --- | |
| def index(): | |
| return send_from_directory(STATIC_FOLDER, 'index.html') | |
| def serve_static(path): | |
| if os.path.exists(os.path.join(STATIC_FOLDER, path)): | |
| return send_from_directory(STATIC_FOLDER, path) | |
| return send_from_directory(STATIC_FOLDER, 'index.html') | |
| def check_credit(): | |
| data = request.get_json() | |
| if not data: return jsonify({"error": "Invalid request"}), 400 | |
| user_id = get_user_identifier(data) | |
| model_id = data.get('model_id', 'custom') | |
| with cache_lock: | |
| now = time.time() | |
| one_week = 7 * 24 * 60 * 60 | |
| user_record = next((u for u in usage_data_cache if u.get('id') == user_id), None) | |
| credits_remaining = USAGE_LIMIT_PER_MODEL | |
| limit_reached = False | |
| reset_timestamp = 0 | |
| if user_record: | |
| # بررسی انقضای هفته برای کل کاربر (ریست همه مدلها) | |
| if user_record.get('week_start', 0) < (now - one_week): | |
| user_record['usage'] = {} | |
| user_record['week_start'] = now | |
| data_changed.set() | |
| usage_dict = user_record.get('usage', {}) | |
| current_model_usage = usage_dict.get(model_id, 0) | |
| credits_remaining = max(0, USAGE_LIMIT_PER_MODEL - current_model_usage) | |
| if credits_remaining == 0: | |
| limit_reached = True | |
| reset_timestamp = user_record.get('week_start', now) + one_week | |
| return jsonify({ | |
| "credits_remaining": credits_remaining, | |
| "limit_reached": limit_reached, | |
| "reset_timestamp": reset_timestamp, | |
| "model_id": model_id | |
| }) | |
| def use_credit(): | |
| data = request.get_json() | |
| if not data: return jsonify({"error": "Invalid request"}), 400 | |
| user_id = get_user_identifier(data) | |
| model_id = data.get('model_id', 'custom') | |
| with cache_lock: | |
| now = time.time() | |
| one_week = 7 * 24 * 60 * 60 | |
| user_record = next((u for u in usage_data_cache if u.get('id') == user_id), None) | |
| if user_record: | |
| # ریست هفتگی | |
| if user_record.get('week_start', 0) < (now - one_week): | |
| user_record['usage'] = {} | |
| user_record['week_start'] = now | |
| if 'usage' not in user_record: | |
| user_record['usage'] = {} | |
| current_model_usage = user_record['usage'].get(model_id, 0) | |
| if current_model_usage >= USAGE_LIMIT_PER_MODEL: | |
| reset_timestamp = user_record.get('week_start', now) + one_week | |
| return jsonify({ | |
| "status": "limit_reached", | |
| "credits_remaining": 0, | |
| "reset_timestamp": reset_timestamp | |
| }), 429 | |
| user_record['usage'][model_id] = current_model_usage + 1 | |
| else: | |
| # کاربر جدید | |
| user_record = { | |
| "id": user_id, | |
| "week_start": now, | |
| "usage": {model_id: 1} | |
| } | |
| usage_data_cache.append(user_record) | |
| credits_remaining = USAGE_LIMIT_PER_MODEL - user_record['usage'][model_id] | |
| data_changed.set() | |
| return jsonify({"status": "success", "credits_remaining": credits_remaining}) | |
| # --- Main --- | |
| if __name__ != '__main__': | |
| load_initial_data() | |
| t = threading.Thread(target=background_persister, daemon=True) | |
| t.start() | |
| if __name__ == '__main__': | |
| app.run(host='0.0.0.0', port=7860) | |