Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- .github/workflows/sync_to_huggingface.yml +4 -0
- bot.py +30 -13
- src/files_data.ts +40 -4
.github/workflows/sync_to_huggingface.yml
CHANGED
|
@@ -5,6 +5,10 @@ on:
|
|
| 5 |
branches: [ "main", "master" ]
|
| 6 |
workflow_dispatch:
|
| 7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
jobs:
|
| 9 |
sync-to-hub:
|
| 10 |
runs-on: ubuntu-latest
|
|
|
|
| 5 |
branches: [ "main", "master" ]
|
| 6 |
workflow_dispatch:
|
| 7 |
|
| 8 |
+
concurrency:
|
| 9 |
+
group: ${{ github.workflow }}-${{ github.ref }}
|
| 10 |
+
cancel-in-progress: true
|
| 11 |
+
|
| 12 |
jobs:
|
| 13 |
sync-to-hub:
|
| 14 |
runs-on: ubuntu-latest
|
bot.py
CHANGED
|
@@ -2021,6 +2021,9 @@ async def handle_youtube(message: Message, url: str) -> None:
|
|
| 2021 |
|
| 2022 |
@dp.callback_query(F.data.startswith("yt:"))
|
| 2023 |
async def yt_callback(cb: CallbackQuery) -> None:
|
|
|
|
|
|
|
|
|
|
| 2024 |
parts = cb.data.split(":")
|
| 2025 |
if len(parts) != 3:
|
| 2026 |
await _safe_callback_answer(cb, "Некорректный формат сессии.")
|
|
@@ -2079,6 +2082,7 @@ async def yt_callback(cb: CallbackQuery) -> None:
|
|
| 2079 |
if not download_success:
|
| 2080 |
raise Exception("Не удалось загрузить медиа ни через Cobalt API, ни через резервный шлюз yt-dlp.")
|
| 2081 |
|
|
|
|
| 2082 |
if is_audio:
|
| 2083 |
dst_mp3 = os.path.join(tmp_dir, "output.mp3")
|
| 2084 |
if await _audio_from_file_ffmpeg(src_file, dst_mp3):
|
|
@@ -2090,7 +2094,7 @@ async def yt_callback(cb: CallbackQuery) -> None:
|
|
| 2090 |
with open(send_file_p, "rb") as f:
|
| 2091 |
await bot.send_audio(
|
| 2092 |
chat_id=cb.message.chat.id, audio=BufferedInputFile(f.read(), filename=f"{title[:60]}.mp3"),
|
| 2093 |
-
title=title, performer=uploader, reply_to_message_id=
|
| 2094 |
)
|
| 2095 |
else:
|
| 2096 |
dst_mp4 = os.path.join(tmp_dir, "output.mp4")
|
|
@@ -2103,7 +2107,7 @@ async def yt_callback(cb: CallbackQuery) -> None:
|
|
| 2103 |
await bot.send_video(
|
| 2104 |
chat_id=cb.message.chat.id, video=BufferedInputFile(f.read(), filename=f"{title[:60]}.mp4"),
|
| 2105 |
caption=f"<b>{_html_mod.escape(title)}</b>\nОтправитель: {_html_mod.escape(uploader)}",
|
| 2106 |
-
parse_mode=ParseMode.HTML, reply_to_message_id=
|
| 2107 |
)
|
| 2108 |
except Exception as exc:
|
| 2109 |
log.exception("YouTube downloader callback failed: ")
|
|
@@ -2181,6 +2185,9 @@ async def cmd_model(message: Message) -> None:
|
|
| 2181 |
|
| 2182 |
@dp.callback_query(F.data.startswith("model:"))
|
| 2183 |
async def cb_gemini_model(cb: CallbackQuery) -> None:
|
|
|
|
|
|
|
|
|
|
| 2184 |
mid = cb.data.split(":", 1)[1]
|
| 2185 |
if mid not in GEMINI_MODELS:
|
| 2186 |
await _safe_callback_answer(cb, "Выбранная модель не поддерживается.")
|
|
@@ -2458,6 +2465,9 @@ async def _show_or_menu(message: Message, category: str, cat_label: str) -> None
|
|
| 2458 |
|
| 2459 |
@dp.callback_query(F.data.startswith("or_model:"))
|
| 2460 |
async def cb_or_model(cb: CallbackQuery) -> None:
|
|
|
|
|
|
|
|
|
|
| 2461 |
try:
|
| 2462 |
parts = cb.data.split(":")
|
| 2463 |
if len(parts) == 3:
|
|
@@ -2599,6 +2609,7 @@ async def _process_media_group_buffers(mgid: str) -> None:
|
|
| 2599 |
await _handle_message_core(main_msg)
|
| 2600 |
|
| 2601 |
async def _handle_message_core(message: Message) -> None:
|
|
|
|
| 2602 |
t = message.text or message.caption or ""
|
| 2603 |
is_private = message.chat.type == ChatType.PRIVATE
|
| 2604 |
is_guest = is_guest_message(message)
|
|
@@ -2609,10 +2620,8 @@ async def _handle_message_core(message: Message) -> None:
|
|
| 2609 |
url = extract_url(t)
|
| 2610 |
if not url:
|
| 2611 |
if t.strip():
|
| 2612 |
-
state = get_state(message.chat.id)
|
| 2613 |
username = message.from_user.username or message.from_user.first_name or "User"
|
| 2614 |
state["ctx"].append(f"@{username}: {t.strip()}")
|
| 2615 |
-
state = get_state(message.chat.id)
|
| 2616 |
_save_media_to_history(_msg_media_source(message), state)
|
| 2617 |
save_state_to_disk()
|
| 2618 |
return
|
|
@@ -2750,6 +2759,11 @@ async def _handle_message_core(message: Message) -> None:
|
|
| 2750 |
with contextlib.suppress(Exception):
|
| 2751 |
os.unlink(med_path)
|
| 2752 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2753 |
@dp.message()
|
| 2754 |
async def handle_message(message: Message) -> None:
|
| 2755 |
if message.media_group_id:
|
|
@@ -2798,15 +2812,18 @@ async def _raw_get_updates(offset: int | None = None) -> list[dict]:
|
|
| 2798 |
async def _process_raw_update(raw_update: dict) -> None:
|
| 2799 |
if not isinstance(raw_update, dict):
|
| 2800 |
return
|
| 2801 |
-
|
| 2802 |
-
|
| 2803 |
-
|
| 2804 |
-
|
| 2805 |
-
|
| 2806 |
-
|
| 2807 |
-
|
| 2808 |
-
|
| 2809 |
-
|
|
|
|
|
|
|
|
|
|
| 2810 |
|
| 2811 |
async def _polling_loop() -> None:
|
| 2812 |
load_state_from_disk()
|
|
|
|
| 2021 |
|
| 2022 |
@dp.callback_query(F.data.startswith("yt:"))
|
| 2023 |
async def yt_callback(cb: CallbackQuery) -> None:
|
| 2024 |
+
if cb.message is None:
|
| 2025 |
+
await _safe_callback_answer(cb, "Ошибка: сообщение не найдено.", show_alert=True)
|
| 2026 |
+
return
|
| 2027 |
parts = cb.data.split(":")
|
| 2028 |
if len(parts) != 3:
|
| 2029 |
await _safe_callback_answer(cb, "Некорректный формат сессии.")
|
|
|
|
| 2082 |
if not download_success:
|
| 2083 |
raise Exception("Не удалось загрузить медиа ни через Cobalt API, ни через резервный шлюз yt-dlp.")
|
| 2084 |
|
| 2085 |
+
reply_id = cb.message.reply_to_message.message_id if cb.message.reply_to_message else None
|
| 2086 |
if is_audio:
|
| 2087 |
dst_mp3 = os.path.join(tmp_dir, "output.mp3")
|
| 2088 |
if await _audio_from_file_ffmpeg(src_file, dst_mp3):
|
|
|
|
| 2094 |
with open(send_file_p, "rb") as f:
|
| 2095 |
await bot.send_audio(
|
| 2096 |
chat_id=cb.message.chat.id, audio=BufferedInputFile(f.read(), filename=f"{title[:60]}.mp3"),
|
| 2097 |
+
title=title, performer=uploader, reply_to_message_id=reply_id
|
| 2098 |
)
|
| 2099 |
else:
|
| 2100 |
dst_mp4 = os.path.join(tmp_dir, "output.mp4")
|
|
|
|
| 2107 |
await bot.send_video(
|
| 2108 |
chat_id=cb.message.chat.id, video=BufferedInputFile(f.read(), filename=f"{title[:60]}.mp4"),
|
| 2109 |
caption=f"<b>{_html_mod.escape(title)}</b>\nОтправитель: {_html_mod.escape(uploader)}",
|
| 2110 |
+
parse_mode=ParseMode.HTML, reply_to_message_id=reply_id
|
| 2111 |
)
|
| 2112 |
except Exception as exc:
|
| 2113 |
log.exception("YouTube downloader callback failed: ")
|
|
|
|
| 2185 |
|
| 2186 |
@dp.callback_query(F.data.startswith("model:"))
|
| 2187 |
async def cb_gemini_model(cb: CallbackQuery) -> None:
|
| 2188 |
+
if cb.message is None:
|
| 2189 |
+
await _safe_callback_answer(cb, "Ошибка: сообщение не найдено.", show_alert=True)
|
| 2190 |
+
return
|
| 2191 |
mid = cb.data.split(":", 1)[1]
|
| 2192 |
if mid not in GEMINI_MODELS:
|
| 2193 |
await _safe_callback_answer(cb, "Выбранная модель не поддерживается.")
|
|
|
|
| 2465 |
|
| 2466 |
@dp.callback_query(F.data.startswith("or_model:"))
|
| 2467 |
async def cb_or_model(cb: CallbackQuery) -> None:
|
| 2468 |
+
if cb.message is None:
|
| 2469 |
+
await _safe_callback_answer(cb, "Ошибка: сообщение не найдено.", show_alert=True)
|
| 2470 |
+
return
|
| 2471 |
try:
|
| 2472 |
parts = cb.data.split(":")
|
| 2473 |
if len(parts) == 3:
|
|
|
|
| 2609 |
await _handle_message_core(main_msg)
|
| 2610 |
|
| 2611 |
async def _handle_message_core(message: Message) -> None:
|
| 2612 |
+
state = get_state(message.chat.id)
|
| 2613 |
t = message.text or message.caption or ""
|
| 2614 |
is_private = message.chat.type == ChatType.PRIVATE
|
| 2615 |
is_guest = is_guest_message(message)
|
|
|
|
| 2620 |
url = extract_url(t)
|
| 2621 |
if not url:
|
| 2622 |
if t.strip():
|
|
|
|
| 2623 |
username = message.from_user.username or message.from_user.first_name or "User"
|
| 2624 |
state["ctx"].append(f"@{username}: {t.strip()}")
|
|
|
|
| 2625 |
_save_media_to_history(_msg_media_source(message), state)
|
| 2626 |
save_state_to_disk()
|
| 2627 |
return
|
|
|
|
| 2759 |
with contextlib.suppress(Exception):
|
| 2760 |
os.unlink(med_path)
|
| 2761 |
|
| 2762 |
+
@dp.errors()
|
| 2763 |
+
async def global_error_handler(event: Any) -> bool:
|
| 2764 |
+
log.error("Global error handler caught exception: %s", event.exception, exc_info=event.exception)
|
| 2765 |
+
return True
|
| 2766 |
+
|
| 2767 |
@dp.message()
|
| 2768 |
async def handle_message(message: Message) -> None:
|
| 2769 |
if message.media_group_id:
|
|
|
|
| 2812 |
async def _process_raw_update(raw_update: dict) -> None:
|
| 2813 |
if not isinstance(raw_update, dict):
|
| 2814 |
return
|
| 2815 |
+
try:
|
| 2816 |
+
guest = raw_update.get("guest_message")
|
| 2817 |
+
if isinstance(guest, dict):
|
| 2818 |
+
try:
|
| 2819 |
+
await _handle_message_core(Message.model_validate(guest, context={"bot": bot}))
|
| 2820 |
+
except Exception as exc:
|
| 2821 |
+
log.warning("[guest] Guest processing failed: %s", exc)
|
| 2822 |
+
return
|
| 2823 |
+
upd = Update.model_validate(raw_update, context={"bot": bot})
|
| 2824 |
+
await dp.feed_update(bot, upd)
|
| 2825 |
+
except Exception as exc:
|
| 2826 |
+
log.warning("[update] Raw update processing failed: %s", exc)
|
| 2827 |
|
| 2828 |
async def _polling_loop() -> None:
|
| 2829 |
load_state_from_disk()
|
src/files_data.ts
CHANGED
|
@@ -171,6 +171,10 @@ on:
|
|
| 171 |
branches: [ "main", "master" ]
|
| 172 |
workflow_dispatch:
|
| 173 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
jobs:
|
| 175 |
sync-to-hub:
|
| 176 |
runs-on: ubuntu-latest
|
|
@@ -179,15 +183,47 @@ jobs:
|
|
| 179 |
uses: actions/checkout@v4
|
| 180 |
with:
|
| 181 |
fetch-depth: 0
|
| 182 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
|
| 184 |
- name: Push to Hugging Face Spaces
|
| 185 |
env:
|
| 186 |
HF_TOKEN: \${{ secrets.HF_TOKEN }}
|
| 187 |
run: |
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
`
|
| 192 |
}
|
| 193 |
];
|
|
|
|
| 171 |
branches: [ "main", "master" ]
|
| 172 |
workflow_dispatch:
|
| 173 |
|
| 174 |
+
concurrency:
|
| 175 |
+
group: \${{ github.workflow }}-\${{ github.ref }}
|
| 176 |
+
cancel-in-progress: true
|
| 177 |
+
|
| 178 |
jobs:
|
| 179 |
sync-to-hub:
|
| 180 |
runs-on: ubuntu-latest
|
|
|
|
| 183 |
uses: actions/checkout@v4
|
| 184 |
with:
|
| 185 |
fetch-depth: 0
|
| 186 |
+
|
| 187 |
+
- name: Set up Python
|
| 188 |
+
uses: actions/setup-python@v5
|
| 189 |
+
with:
|
| 190 |
+
python-version: '3.10'
|
| 191 |
|
| 192 |
- name: Push to Hugging Face Spaces
|
| 193 |
env:
|
| 194 |
HF_TOKEN: \${{ secrets.HF_TOKEN }}
|
| 195 |
run: |
|
| 196 |
+
if [ -z "$HF_TOKEN" ]; then
|
| 197 |
+
echo "=========================================================================="
|
| 198 |
+
echo "ERROR: HF_TOKEN is missing or empty!"
|
| 199 |
+
echo "Please add HF_TOKEN as repository secret under:"
|
| 200 |
+
echo "Settings -> Secrets and variables -> Actions"
|
| 201 |
+
echo "=========================================================================="
|
| 202 |
+
exit 1
|
| 203 |
+
fi
|
| 204 |
+
|
| 205 |
+
python -m pip install --upgrade pip
|
| 206 |
+
pip install huggingface_hub
|
| 207 |
+
|
| 208 |
+
cat << 'EOF' > sync.py
|
| 209 |
+
import os
|
| 210 |
+
from huggingface_hub import HfApi
|
| 211 |
+
|
| 212 |
+
token = os.environ.get("HF_TOKEN")
|
| 213 |
+
repo_id = "SilverElixir/SilverGemini"
|
| 214 |
+
|
| 215 |
+
print(f"Uploading all files to Hugging Face Space: {repo_id}...")
|
| 216 |
+
api = HfApi(token=token)
|
| 217 |
+
api.upload_folder(
|
| 218 |
+
folder_path=".",
|
| 219 |
+
repo_id=repo_id,
|
| 220 |
+
repo_type="space",
|
| 221 |
+
ignore_patterns=[".git", ".git/**", "sync.py", "__pycache__", "**/*.pyc"]
|
| 222 |
+
)
|
| 223 |
+
print("Upload completed successfully!")
|
| 224 |
+
EOF
|
| 225 |
+
|
| 226 |
+
python sync.py
|
| 227 |
`
|
| 228 |
}
|
| 229 |
];
|