Asrasahar commited on
Commit
e6dff50
·
verified ·
1 Parent(s): 785879a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +9 -155
app.py CHANGED
@@ -3,16 +3,11 @@ import uuid
3
  import requests
4
  import io
5
  import logging
6
- import threading # برای اجرای همزمان ربات و وب اپلیکیشن
7
  from flask import Flask, request, jsonify, send_from_directory
8
  from huggingface_hub import HfApi
9
  import mimetypes
10
 
11
- # کتابخانه های جدید برای ربات تلگرام
12
- from telegram import Update, File as TelegramFile
13
- from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext
14
-
15
- # 1. تنظیمات لاگینگ برای نمایش پیام ها در کنسول اسپیس
16
  logging.basicConfig(
17
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
18
  level=logging.INFO
@@ -23,26 +18,20 @@ app = Flask(__name__, static_folder='static', static_url_path='/static')
23
 
24
  # 2. خواندن متغیرهای محیطی
25
  HF_TOKEN = os.getenv("HF_TOKEN")
26
- TELEGRAM_TOKEN = os.getenv("TELEGRAM_TOKEN") # <-- توکن ربات تلگرام
27
- HF_REPO_ID = "Asrasahar/Ezmary-uploads" # <-- آدرس دیتاسنت شما
28
 
29
- # 3. بررسی وجود توکن ها
30
  if not HF_TOKEN:
31
  logger.error("FATAL ERROR: HF_TOKEN environment variable not set!")
32
  exit()
33
- if not TELEGRAM_TOKEN:
34
- logger.error("FATAL ERROR: TELEGRAM_TOKEN environment variable not set! Please set it in your Space's 'Repository secrets'.")
35
- exit()
36
 
37
  # 4. ایجاد یک نمونه از HfApi
38
  hf_api = HfApi(token=HF_TOKEN)
39
- logger.info(f"Flask app initialized. Target dataset repository: {HF_REPO_ID}")
40
 
41
  # --- توابع کمکی (بدون تغییر) ---
42
  def get_folder_by_mimetype(mimetype):
43
- """بر اساس نوع MIME، نام پوشه مقصد را برمی‌گرداند."""
44
- if not mimetype:
45
- return "others"
46
  main_type = mimetype.split('/')[0]
47
  if main_type == "image": return "images"
48
  elif main_type == "video": return "videos"
@@ -54,37 +43,20 @@ def get_folder_by_mimetype(mimetype):
54
  elif main_type == "text": return "documents/texts"
55
  else: return "others"
56
 
57
- # --- تابع اصلی آپلود (بازنویسی شده برای استفاده مشترک) ---
58
  def process_and_upload(file_content: bytes, original_filename: str, mimetype: str) -> str:
59
- """
60
- محتوای فایل را گرفته، پردازش کرده و به Hugging Face آپلود می‌کند.
61
- لینک مستقیم فایل آپلود شده را برمی‌گرداند.
62
- """
63
- # ایجاد نام فایل منحصر به فرد
64
  file_extension = os.path.splitext(original_filename)[1] or mimetypes.guess_extension(mimetype) or ""
65
  filename = f"{uuid.uuid4().hex}{file_extension}"
66
-
67
- # تعیین پوشه مقصد
68
  target_folder = get_folder_by_mimetype(mimetype)
69
  path_in_repo = f"{target_folder}/{filename}"
70
 
71
- # آپلود به Hugging Face Hub
72
  file_stream = io.BytesIO(file_content)
73
  logger.info(f"Uploading to Hugging Face: {path_in_repo}")
74
- hf_api.upload_file(
75
- path_or_fileobj=file_stream,
76
- path_in_repo=path_in_repo,
77
- repo_id=HF_REPO_ID,
78
- repo_type="dataset",
79
- )
80
-
81
  direct_url = f"https://huggingface.co/datasets/{HF_REPO_ID}/resolve/main/{path_in_repo}"
82
  logger.info(f"File uploaded successfully! URL: {direct_url}")
83
-
84
  return direct_url
85
 
86
- # --- بخش Flask (برای وب سایت) ---
87
-
88
  @app.route('/')
89
  def serve_html():
90
  return send_from_directory(app.static_folder, 'index.html')
@@ -92,138 +64,20 @@ def serve_html():
92
  @app.route('/upload', methods=['POST'])
93
  def upload_file_endpoint():
94
  try:
95
- # حالت اول: آپلود از کامپیوتر
96
  if 'file' in request.files:
97
  uploaded_file = request.files['file']
98
  if uploaded_file.filename == '':
99
  return jsonify({"error": "No selected file"}), 400
100
-
101
  file_content = uploaded_file.read()
102
  direct_url = process_and_upload(file_content, uploaded_file.filename, uploaded_file.mimetype)
103
  return jsonify({"message": "File uploaded successfully!", "hf_url": direct_url}), 200
104
-
105
- # حالت دوم: آپلود از طریق لینک
106
- elif request.is_json and 'url' in request.json:
107
- file_url = request.json['url']
108
- if not file_url:
109
- return jsonify({"error": "No URL provided"}), 400
110
-
111
- logger.info(f"Downloading file from URL: {file_url}")
112
- response = requests.get(file_url, stream=True, timeout=30)
113
- response.raise_for_status()
114
-
115
- file_content = response.content
116
- mimetype = response.headers.get('Content-Type')
117
- original_filename = file_url.split('/')[-1].split('?')[0]
118
-
119
- direct_url = process_and_upload(file_content, original_filename, mimetype)
120
- return jsonify({"message": "File uploaded successfully!", "hf_url": direct_url}), 200
121
-
122
  else:
123
- return jsonify({"error": "Invalid request"}), 400
124
-
125
- except requests.exceptions.RequestException as e:
126
- logger.error(f"Failed to download from URL: {e}", exc_info=True)
127
- return jsonify({"error": f"Failed to download from URL: {str(e)}"}), 400
128
  except Exception as e:
129
  logger.error(f"An internal server error occurred: {e}", exc_info=True)
130
  return jsonify({"error": f"An internal server error occurred: {str(e)}"}), 500
131
 
132
- # --- بخش ربات تلگرام ---
133
-
134
- def start(update: Update, context: CallbackContext) -> None:
135
- """پاسخ به دستور /start"""
136
- welcome_message = "سلام! من ربات آپلودر فایل هستم.\n\n" \
137
- "فایل (عکس، ویدیو، داکیومنت و...) یا لینک مستقیم آن را برای من بفرستید تا آن را برای شما به یک لینک مستقیم دائمی تبدیل کنم."
138
- update.message.reply_text(welcome_message)
139
-
140
- def handle_file(update: Update, context: CallbackContext) -> None:
141
- """پردازش فایل های ارسالی (داکیومنت، ویدیو، عکس و...)"""
142
- message = update.message
143
- file_to_process = message.document or message.video or message.audio or (message.photo[-1] if message.photo else None)
144
-
145
- if not file_to_process:
146
- message.reply_text("نوع فایل ارسالی پشتیبانی نمی‌شود.")
147
- return
148
-
149
- # ارسال پیام "در حال پردازش" به کاربر
150
- status_message = message.reply_text("فایل دریافت شد، در حال پردازش و آپلود...")
151
-
152
- try:
153
- tg_file: TelegramFile = file_to_process.get_file()
154
- file_content = tg_file.download_as_bytearray()
155
-
156
- # نام فایل و نوع آن را از تلگرام می گیریم
157
- original_filename = file_to_process.file_name if hasattr(file_to_process, 'file_name') else tg_file.file_path.split('/')[-1]
158
- mimetype = file_to_process.mime_type or mimetypes.guess_type(original_filename)[0]
159
-
160
- logger.info(f"Received file from Telegram: {original_filename} (MIME: {mimetype})")
161
-
162
- # آپلود فایل با استفاده از تابع مشترک
163
- direct_url = process_and_upload(bytes(file_content), original_filename, mimetype)
164
-
165
- # ویرایش پیام "در حال پردازش" و ارسال لینک نهایی
166
- status_message.edit_text(f"✅ آپلود با موفقیت انجام شد!\n\nلینک مستقیم شما:\n{direct_url}")
167
-
168
- except Exception as e:
169
- logger.error(f"Error processing Telegram file: {e}", exc_info=True)
170
- status_message.edit_text(f"❌ خطا در پردازش فایل: {e}")
171
-
172
- def handle_text(update: Update, context: CallbackContext) -> None:
173
- """پردازش پیام های متنی (برای لینک ها)"""
174
- message = update.message
175
- url = message.text.strip()
176
-
177
- # بررسی اینکه آیا متن یک لینک معتبر است یا نه
178
- if url.startswith(('http://', 'https://')):
179
- status_message = message.reply_text("لینک دریافت شد، در حال دانلود و آپلود...")
180
- try:
181
- logger.info(f"Downloading file from URL via Telegram: {url}")
182
- response = requests.get(url, stream=True, timeout=30)
183
- response.raise_for_status()
184
-
185
- file_content = response.content
186
- mimetype = response.headers.get('Content-Type')
187
- original_filename = url.split('/')[-1].split('?')[0]
188
-
189
- # آپلود فایل با استفاده از تابع مشترک
190
- direct_url = process_and_upload(file_content, original_filename, mimetype)
191
- status_message.edit_text(f"✅ آپلود از لینک با موفقیت انجام شد!\n\nلینک مستقیم شما:\n{direct_url}")
192
-
193
- except requests.exceptions.RequestException as e:
194
- logger.error(f"Failed to download from URL (Telegram): {e}", exc_info=True)
195
- status_message.edit_text(f"❌ خطا در دانلود از لینک: {e}")
196
- except Exception as e:
197
- logger.error(f"An internal error occurred (Telegram URL): {e}", exc_info=True)
198
- status_message.edit_text(f"❌ خطا در پردازش لینک: {e}")
199
- else:
200
- message.reply_text("لطفا یک فایل یا یک لینک معتبر ارسال کنید.")
201
-
202
-
203
- def run_bot():
204
- """تابع اصلی برای راه اندازی و اجرای ربات تلگرام"""
205
- updater = Updater(TELEGRAM_TOKEN)
206
- dispatcher = updater.dispatcher
207
-
208
- # تعریف دستورات و پاسخ ها
209
- dispatcher.add_handler(CommandHandler("start", start))
210
- dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, handle_text))
211
- dispatcher.add_handler(MessageHandler(Filters.document | Filters.video | Filters.photo | Filters.audio, handle_file))
212
-
213
- # راه اندازی ربات
214
- updater.start_polling()
215
- logger.info("Telegram bot started polling...")
216
- # updater.idle() # این خط لازم نیست چون وب سرور برنامه را فعال نگه می دارد
217
-
218
- # --- راه اندازی برنامه ---
219
-
220
- # اجرای ربات در یک ترد (نخ) جداگانه تا با وب سرور تداخل نداشته باشد
221
- bot_thread = threading.Thread(target=run_bot)
222
- bot_thread.daemon = True # با بستن برنامه اصلی، این ترد هم بسته می شود
223
- bot_thread.start()
224
-
225
- # این بخش فقط برای اجرای محلی (local) است
226
- # در Hugging Face Spaces، از gunicorn برای اجرای برنامه استفاده می شود
227
  if __name__ == '__main__':
228
  port = int(os.environ.get('PORT', 7860))
229
  app.run(host='0.0.0.0', port=port, debug=False)
 
3
  import requests
4
  import io
5
  import logging
 
6
  from flask import Flask, request, jsonify, send_from_directory
7
  from huggingface_hub import HfApi
8
  import mimetypes
9
 
10
+ # 1. تنظیمات لاگینگ
 
 
 
 
11
  logging.basicConfig(
12
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
13
  level=logging.INFO
 
18
 
19
  # 2. خواندن متغیرهای محیطی
20
  HF_TOKEN = os.getenv("HF_TOKEN")
21
+ HF_REPO_ID = "Asrasahar/Ezmary-uploads"
 
22
 
23
+ # 3. بررسی وجود توکن
24
  if not HF_TOKEN:
25
  logger.error("FATAL ERROR: HF_TOKEN environment variable not set!")
26
  exit()
 
 
 
27
 
28
  # 4. ایجاد یک نمونه از HfApi
29
  hf_api = HfApi(token=HF_TOKEN)
30
+ logger.info(f"Public File Upload API Initialized. Target repo: {HF_REPO_ID}")
31
 
32
  # --- توابع کمکی (بدون تغییر) ---
33
  def get_folder_by_mimetype(mimetype):
34
+ if not mimetype: return "others"
 
 
35
  main_type = mimetype.split('/')[0]
36
  if main_type == "image": return "images"
37
  elif main_type == "video": return "videos"
 
43
  elif main_type == "text": return "documents/texts"
44
  else: return "others"
45
 
 
46
  def process_and_upload(file_content: bytes, original_filename: str, mimetype: str) -> str:
 
 
 
 
 
47
  file_extension = os.path.splitext(original_filename)[1] or mimetypes.guess_extension(mimetype) or ""
48
  filename = f"{uuid.uuid4().hex}{file_extension}"
 
 
49
  target_folder = get_folder_by_mimetype(mimetype)
50
  path_in_repo = f"{target_folder}/{filename}"
51
 
 
52
  file_stream = io.BytesIO(file_content)
53
  logger.info(f"Uploading to Hugging Face: {path_in_repo}")
54
+ hf_api.upload_file(path_or_fileobj=file_stream, path_in_repo=path_in_repo, repo_id=HF_REPO_ID, repo_type="dataset")
 
 
 
 
 
 
55
  direct_url = f"https://huggingface.co/datasets/{HF_REPO_ID}/resolve/main/{path_in_repo}"
56
  logger.info(f"File uploaded successfully! URL: {direct_url}")
 
57
  return direct_url
58
 
59
+ # --- بخش API ---
 
60
  @app.route('/')
61
  def serve_html():
62
  return send_from_directory(app.static_folder, 'index.html')
 
64
  @app.route('/upload', methods=['POST'])
65
  def upload_file_endpoint():
66
  try:
67
+ # آپلود از کامپیوتر یا ربات (حالت FormData)
68
  if 'file' in request.files:
69
  uploaded_file = request.files['file']
70
  if uploaded_file.filename == '':
71
  return jsonify({"error": "No selected file"}), 400
 
72
  file_content = uploaded_file.read()
73
  direct_url = process_and_upload(file_content, uploaded_file.filename, uploaded_file.mimetype)
74
  return jsonify({"message": "File uploaded successfully!", "hf_url": direct_url}), 200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  else:
76
+ return jsonify({"error": "Invalid request. 'file' part is missing."}), 400
 
 
 
 
77
  except Exception as e:
78
  logger.error(f"An internal server error occurred: {e}", exc_info=True)
79
  return jsonify({"error": f"An internal server error occurred: {str(e)}"}), 500
80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  if __name__ == '__main__':
82
  port = int(os.environ.get('PORT', 7860))
83
  app.run(host='0.0.0.0', port=port, debug=False)