Spaces:
Sleeping
Sleeping
| import os | |
| import pickle | |
| import base64 | |
| from google.auth.transport.requests import Request | |
| from googleapiclient.discovery import build | |
| from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload | |
| import io | |
| import pandas as pd | |
| import google.generativeai as genai | |
| # --- CẤU HÌNH --- | |
| SCOPES = ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/spreadsheets'] | |
| async def get_drive_credentials_no_chat_id(): | |
| """ | |
| Lấy credentials từ biến môi trường PICKLE_TOKEN_B64 (đã mã hóa Base64). | |
| Không cần file vật lý, không cần chat_id để báo lỗi. | |
| """ | |
| creds = None | |
| # 1. Lấy chuỗi Base64 từ Secret | |
| base64_pickle = os.getenv("PICKLE_TOKEN_B64") | |
| if base64_pickle: | |
| try: | |
| # 2. Giải mã Base64 -> Binary -> Object | |
| pickle_data = base64.b64decode(base64_pickle) | |
| creds = pickle.loads(pickle_data) | |
| print("✅ Đã load Credentials từ Secret thành công.") | |
| except Exception as e: | |
| print(f"❌ Lỗi giải mã Pickle: {e}") | |
| return None | |
| else: | |
| print("❌ Lỗi: Chưa cấu hình Secret 'PICKLE_TOKEN_B64' trên Hugging Face.") | |
| return None | |
| # 3. Kiểm tra và Refresh Token nếu hết hạn (Quan trọng) | |
| if creds and creds.expired and creds.refresh_token: | |
| try: | |
| print("🔄 Token hết hạn, đang refresh...") | |
| creds.refresh(Request()) | |
| # Lưu ý: Trên môi trường Docker stateless, ta refresh để dùng tạm, | |
| # không cần lưu lại file vì lần sau khởi động lại nó sẽ load từ Secret gốc. | |
| except Exception as e: | |
| print(f"❌ Không thể refresh token: {e}") | |
| return None | |
| return creds | |
| # --- CÁC HÀM XỬ LÝ DRIVE & GEMINI (GIỮ NGUYÊN LOGIC) --- | |
| async def download_file_from_drive(drive_service, file_id, save_path): | |
| try: | |
| if os.path.exists(save_path): | |
| os.remove(save_path) | |
| request = drive_service.files().get_media(fileId=file_id) | |
| fh = io.BytesIO() | |
| downloader = MediaIoBaseDownload(fh, request) | |
| done = False | |
| while not done: | |
| status, done = downloader.next_chunk() | |
| with open(save_path, 'wb') as f: | |
| f.write(fh.getvalue()) | |
| print(f"📥 Đã tải file {file_id} về {save_path}") | |
| except Exception as e: | |
| print(f"❌ Lỗi tải file Drive: {e}") | |
| async def upload_file_to_drive(drive_service, local_path, file_id): | |
| try: | |
| media = MediaFileUpload(local_path, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') | |
| drive_service.files().update(fileId=file_id, media_body=media).execute() | |
| print(f"📤 Đã update file lên Drive ID: {file_id}") | |
| except Exception as e: | |
| print(f"❌ Lỗi upload file Drive: {e}") | |
| # Load key Gemini từ file Excel (sau khi đã tải về) | |
| async def load_gemini_keys(excel_path): | |
| global GEMINI_KEYS | |
| try: | |
| # Đọc sheet APIKey | |
| df = pd.read_excel(excel_path, sheet_name='APIKey', header=None) | |
| # Giả sử key nằm ở cột A, bỏ dòng tiêu đề | |
| GEMINI_KEYS = df.iloc[1:, 0].dropna().astype(str).tolist() | |
| print(f"🔑 Đã load {len(GEMINI_KEYS)} Gemini Keys.") | |
| except Exception as e: | |
| print(f"❌ Lỗi đọc Gemini Keys từ Excel: {e}") | |
| GEMINI_KEYS = [] | |
| async def generate_content_with_gemini(product_desc): | |
| # (Giữ nguyên phần import và check key) | |
| import random | |
| if not GEMINI_KEYS: return product_desc | |
| prompt = f"Viết caption Facebook Reels hấp dẫn cho: {product_desc}" | |
| for _ in range(3): | |
| key = random.choice(GEMINI_KEYS) | |
| genai.configure(api_key=key) | |
| try: | |
| # SỬA LẠI TÊN MODEL CHO ĐÚNG VỚI APP.PY CỦA BẠN | |
| model = genai.GenerativeModel('models/gemini-2.5-flash') | |
| response = await model.generate_content_async(prompt) | |
| return response.text.strip() | |
| except Exception as e: | |
| print(f"Lỗi Gemini (Key ...{key[-4:]}): {e}") | |
| continue | |
| return product_desc | |
| async def download_video_by_id(drive_service, file_id, save_path): | |
| # Tái sử dụng hàm download | |
| await download_file_from_drive(drive_service, file_id, save_path) |