#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import json import re import datetime from google_api_connector import fetch_and_update_raw_data as get_gsc_data import sys import argparse def run_pipeline(days=30): print(f"CRON JOB: Khởi chạy tiến trình ETL Bảng 04 TRỰC TIẾP TỪ GSC API THẬT cho {days} ngày...") print("CRON JOB: Khởi chạy tiến trình ETL Bảng 04 TRỰC TIẾP TỪ GSC API THẬT...") # 1. Đọc cấu hình quy tắc (table4_rules.json) rules_file = "/opt/ai-os/products/ceo/projects/corporate/GLV/seo-dashboard-app/cron_scripts/table4_rules.json" with open(rules_file, "r", encoding="utf-8") as rf: rules = json.load(rf) exclude_words = rules["filter_criteria"]["exclude_words"] scoring = rules["ai_opportunity_scoring"] # 2. Gọi Google Search Console API thật (Lấy dữ liệu 30 ngày gần nhất) data = get_gsc_data(date_range_days=days) raw_gsc_data = data.get("gsc_queries", []) pattern = r"(là gì|bao nhiêu|như thế nào|thế nào|tại sao|quy trình|ở đâu|có nên|làm sao|gần đây|thuê xe|kích thước|chiều dài|chiều rộng|giá|bảng giá|hợp đồng|dài hạn|theo tháng)" valid_queries = [] for row in raw_gsc_data: q = str(row["query"]).strip() words = q.split() # Tiêu chí: Độ dài >= 4 từ, khớp pattern nghi vấn/bối cảnh B2B và không thuộc từ chặn if len(words) >= 4 and re.search(pattern, q.lower()) and not any(rw in q.lower() for rw in exclude_words): pos = float(row["position"]) if pos <= scoring["very_high"]["max_position"]: opp = scoring["very_high"]["label"] elif pos <= scoring["high"]["max_position"]: opp = scoring["high"]["label"] else: opp = scoring["medium"]["label"] ctr_percent = str(row["ctr"]) if "%" not in ctr_percent: ctr_percent = f"{float(row['ctr']) * 100:.2f}%" valid_queries.append({ "query": q.capitalize(), "word_count": len(words), "impr": int(row["impressions"]), "clicks": int(row["clicks"]), "ctr": ctr_percent, "position": pos, "ai_opportunity": opp }) # Sắp xếp theo Impressions giảm dần và lấy Top 5 valid_queries = sorted(valid_queries, key=lambda x: x["impr"], reverse=True)[:5] # Nếu không đủ 5 từ GSC API, lấy theo thứ tự sẵn có if len(valid_queries) == 0: print("Cảnh báo: Không có query khớp bộ lọc, lấy top queries bất kỳ từ GSC.") for row in raw_gsc_data[:5]: q = str(row["query"]).strip() ctr_val = str(row["ctr"]) if "%" not in ctr_val: ctr_val = f"{float(row['ctr']) * 100:.2f}%" valid_queries.append({ "query": q.capitalize(), "word_count": len(q.split()), "impr": int(row["impressions"]), "clicks": int(row["clicks"]), "ctr": ctr_val, "position": float(row["position"]), "ai_opportunity": "Thường" }) current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # 3. Ghi kết quả vào file data JSON data_dir = "/opt/ai-os/products/ceo/projects/corporate/GLV/seo-dashboard-app/src/data" os.makedirs(data_dir, exist_ok=True) json_data = { "last_updated": current_time, "source": "Google Search Console API (Live)", "queries": valid_queries } with open(os.path.join(data_dir, "ai_queries.json"), "w", encoding="utf-8") as f: json.dump(json_data, f, ensure_ascii=False, indent=2) print(f"ETL GSC API THẬT hoàn tất! Đã lưu {len(valid_queries)} truy vấn tươi từ Google.") if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--days", type=int, default=30, help="Số ngày trích xuất dữ liệu GSC API") args = parser.parse_args() run_pipeline(days=args.days)