Spaces:
Sleeping
Sleeping
| import pandas as pd | |
| import random | |
| import os | |
| import asyncio | |
| from googleapiclient.discovery import build | |
| from config import LOCAL_EXCEL_PATH, DRIVE_EXCEL_FILE_ID, TEMP_VIDEO_DIR | |
| import google_utils | |
| import facebook_utils | |
| # Lock để tránh 2 page cùng ghi file Excel 1 lúc | |
| excel_lock = asyncio.Lock() | |
| async def process_single_page(page_config, drive_credentials): | |
| sheet_name = page_config['sheet_name'] | |
| print(f"🚀 [Processor] Bắt đầu xử lý cho Sheet: {sheet_name}") | |
| drive_service = build('drive', 'v3', credentials=drive_credentials) | |
| async with excel_lock: | |
| # 1. Tải file Excel mới nhất về | |
| await google_utils.download_file_from_drive(drive_service, DRIVE_EXCEL_FILE_ID, LOCAL_EXCEL_PATH) | |
| # 2. Đọc dữ liệu | |
| try: | |
| df = pd.read_excel(LOCAL_EXCEL_PATH, sheet_name=sheet_name) | |
| except ValueError: | |
| print(f"❌ Không tìm thấy sheet {sheet_name}") | |
| return | |
| # 3. Lọc các dòng NYS (Giả sử cột Status là cột E - index 4) | |
| # Cấu trúc: A:STT, B:Desc, C:Shopee, D:DriveID, E:Status | |
| # Pandas index cột: 0, 1, 2, 3, 4 | |
| # Chuẩn hóa tên cột để dễ gọi | |
| df.columns = ['STT', 'Desc', 'ShopeeLink', 'DriveVideoID', 'Status', 'NewContent'] # Thêm cột NewContent nếu cần | |
| nys_rows = df[df['Status'] == 'NYS'] | |
| if nys_rows.empty: | |
| print(f"⚠️ Sheet {sheet_name} đã hết bài (không còn NYS).") | |
| return | |
| # 4. Chọn ngẫu nhiên | |
| selected_row_index = random.choice(nys_rows.index) | |
| row_data = df.loc[selected_row_index] | |
| print(f"--- Đã chọn dòng {selected_row_index + 2} ---") | |
| # (Nhả lock Excel ra để xử lý nặng) | |
| try: | |
| # 5. Gemini viết lại nội dung | |
| original_desc = str(row_data['Desc']) | |
| new_content = await google_utils.generate_content_with_gemini(original_desc) | |
| # 6. Tải video | |
| video_drive_id = str(row_data['DriveVideoID']) | |
| if not os.path.exists(TEMP_VIDEO_DIR): os.makedirs(TEMP_VIDEO_DIR) | |
| local_video_path = os.path.join(TEMP_VIDEO_DIR, f"{sheet_name}_{video_drive_id}.mp4") | |
| await google_utils.download_video_by_id(drive_service, video_drive_id, local_video_path) | |
| # 7. Upload Facebook | |
| video_id = await facebook_utils.upload_reel( | |
| page_config['page_id'], | |
| page_config['access_token'], | |
| local_video_path, | |
| new_content | |
| ) | |
| print(f"✅ Upload thành công. ID: {video_id}") | |
| # 8. Comment | |
| cta = "🔥 Săn ngay tại đây cả nhà ơi: " | |
| comment_msg = f"{cta} {row_data['ShopeeLink']}" | |
| await facebook_utils.comment_on_video(video_id, page_config['access_token'], comment_msg) | |
| # 9. Cập nhật Excel (Cần Lock lại) | |
| async with excel_lock: | |
| # Đọc lại file để đảm bảo không đè dữ liệu của luồng khác | |
| # (Trong thực tế nên dùng Google Sheets API update cell trực tiếp sẽ tốt hơn download/upload) | |
| # Nhưng ở đây ta làm theo logic file Excel local | |
| df_update = pd.read_excel(LOCAL_EXCEL_PATH, sheet_name=None) # Đọc tất cả sheet | |
| # Cập nhật sheet hiện tại | |
| sheet_df = df_update[sheet_name] | |
| sheet_df.at[selected_row_index, 'Status'] = 'Uploaded' | |
| # Giả sử cột F là nội dung mới | |
| if len(sheet_df.columns) > 5: | |
| sheet_df.iloc[selected_row_index, 5] = new_content | |
| # Lưu và Upload | |
| with pd.ExcelWriter(LOCAL_EXCEL_PATH, engine='openpyxl') as writer: | |
| for s_name, s_df in df_update.items(): | |
| s_df.to_excel(writer, sheet_name=s_name, index=False) | |
| await google_utils.upload_file_to_drive(drive_service, LOCAL_EXCEL_PATH, DRIVE_EXCEL_FILE_ID) | |
| print(f"✅ Đã cập nhật Excel lên Drive.") | |
| # Dọn dẹp | |
| if os.path.exists(local_video_path): os.remove(local_video_path) | |
| except Exception as e: | |
| print(f"❌ Lỗi xử lý Page {sheet_name}: {e}") |