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)