Spaces:
Runtime error
Runtime error
Update quality_audit_job.py
Browse files- quality_audit_job.py +37 -65
quality_audit_job.py
CHANGED
|
@@ -4,22 +4,23 @@ import time
|
|
| 4 |
import sys
|
| 5 |
import logging
|
| 6 |
from supabase import create_client
|
| 7 |
-
# from dotenv import load_dotenv
|
| 8 |
|
| 9 |
-
# 强制不缓存输出
|
| 10 |
-
logging.basicConfig(
|
| 11 |
-
level=logging.INFO,
|
| 12 |
-
format='%(message)s', # 简化格式让进度条更美观
|
| 13 |
-
stream=sys.stdout
|
| 14 |
-
)
|
| 15 |
logger = logging.getLogger(__name__)
|
| 16 |
|
| 17 |
-
#
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
-
|
|
|
|
|
|
|
| 20 |
|
| 21 |
-
|
| 22 |
-
|
|
|
|
| 23 |
fraction = current / total if total > 0 else 0
|
| 24 |
arrow = int(fraction * bar_length) * '█'
|
| 25 |
padding = (bar_length - len(arrow)) * '░'
|
|
@@ -30,81 +31,52 @@ def analyze_text(text):
|
|
| 30 |
is_empty = text_str.startswith("[Empty") or len(text_str) == 0
|
| 31 |
char_count = len(text_str)
|
| 32 |
has_garbage = bool(re.search(r'[ÂÃÅÐÑÒÓÔÕÖר]', text_str))
|
| 33 |
-
|
| 34 |
score = 100
|
| 35 |
-
|
| 36 |
-
if is_empty:
|
| 37 |
-
score = 0; tags.append("no_data")
|
| 38 |
else:
|
| 39 |
-
if char_count < 50: score -= 30
|
| 40 |
-
if has_garbage: score -= 20
|
| 41 |
-
|
| 42 |
-
return {
|
| 43 |
-
"is_filled": not is_empty,
|
| 44 |
-
"is_empty_placeholder": is_empty,
|
| 45 |
-
"is_null": text is None,
|
| 46 |
-
"char_count": char_count,
|
| 47 |
-
"word_count": len(text_str.split()),
|
| 48 |
-
"has_garbage_chars": has_garbage,
|
| 49 |
-
"quality_score": score,
|
| 50 |
-
"issue_tags": tags
|
| 51 |
-
}
|
| 52 |
|
| 53 |
def run_audit():
|
| 54 |
-
#
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
logger.info(f"🚀 启动审计引擎 | 目标数据量: {total_count} 条")
|
| 59 |
-
fields = ['edible_uses', 'medicinal_uses', 'cultivation_details']
|
| 60 |
|
| 61 |
while True:
|
| 62 |
try:
|
| 63 |
-
#
|
| 64 |
-
#
|
| 65 |
-
|
| 66 |
-
|
| 67 |
|
| 68 |
# 打印进度条
|
| 69 |
-
|
| 70 |
-
logger.info(f"📊 进度: {bar} ({processed_count}/{total_count})")
|
| 71 |
|
| 72 |
-
#
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
.order("updated_at", desc=True) \
|
| 76 |
-
.limit(1).execute()
|
| 77 |
-
|
| 78 |
-
last_time = last_audit_res.data[0]['updated_at'] if last_audit_res.data else "1970-01-01T00:00:00Z"
|
| 79 |
|
| 80 |
-
#
|
| 81 |
-
res = supabase.table("bs4_plants") \
|
| 82 |
-
.
|
| 83 |
-
.gt("updated_at", last_time) \
|
| 84 |
-
.order("updated_at", desc=False) \
|
| 85 |
-
.limit(50).execute()
|
| 86 |
|
| 87 |
if not res.data:
|
| 88 |
-
|
| 89 |
-
logger.info("✨ 100% 完成!正在监听增量更新...")
|
| 90 |
-
time.sleep(300)
|
| 91 |
-
else:
|
| 92 |
-
logger.info("⌛ 正在同步中,请稍候...")
|
| 93 |
-
time.sleep(30)
|
| 94 |
continue
|
| 95 |
|
| 96 |
for row in res.data:
|
| 97 |
-
for
|
| 98 |
-
analysis = analyze_text(row.get(
|
| 99 |
supabase.table("data_quality_audit").upsert({
|
| 100 |
-
"plant_id": row['plant_id'],
|
| 101 |
-
"field_name":
|
| 102 |
-
**analysis,
|
| 103 |
"updated_at": "now()"
|
| 104 |
}).execute()
|
| 105 |
|
| 106 |
except Exception as e:
|
| 107 |
-
|
| 108 |
time.sleep(10)
|
| 109 |
|
| 110 |
if __name__ == "__main__":
|
|
|
|
| 4 |
import sys
|
| 5 |
import logging
|
| 6 |
from supabase import create_client
|
|
|
|
| 7 |
|
| 8 |
+
# 强制不缓存输出
|
| 9 |
+
logging.basicConfig(level=logging.INFO, format='%(message)s', stream=sys.stdout)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
logger = logging.getLogger(__name__)
|
| 11 |
|
| 12 |
+
# --- 核心修正点:匹配你截图里的变量名 ---
|
| 13 |
+
url = os.environ.get("SUPABASE_URL")
|
| 14 |
+
# 尝试读取截图中的 SERVICE_ROLE_KEY
|
| 15 |
+
key = os.environ.get("SUPABASE_SERVICE_ROLE_KEY")
|
| 16 |
|
| 17 |
+
if not url or not key:
|
| 18 |
+
print(f"❌ 环境变量缺失! URL: {'OK' if url else 'MISSING'}, KEY: {'OK' if key else 'MISSING'}", flush=True)
|
| 19 |
+
sys.exit(1)
|
| 20 |
|
| 21 |
+
supabase = create_client(url, key)
|
| 22 |
+
|
| 23 |
+
def get_progress_bar(current, total, bar_length=30):
|
| 24 |
fraction = current / total if total > 0 else 0
|
| 25 |
arrow = int(fraction * bar_length) * '█'
|
| 26 |
padding = (bar_length - len(arrow)) * '░'
|
|
|
|
| 31 |
is_empty = text_str.startswith("[Empty") or len(text_str) == 0
|
| 32 |
char_count = len(text_str)
|
| 33 |
has_garbage = bool(re.search(r'[ÂÃÅÐÑÒÓÔÕÖר]', text_str))
|
|
|
|
| 34 |
score = 100
|
| 35 |
+
if is_empty: score = 0
|
|
|
|
|
|
|
| 36 |
else:
|
| 37 |
+
if char_count < 50: score -= 30
|
| 38 |
+
if has_garbage: score -= 20
|
| 39 |
+
return {"is_filled": not is_empty, "char_count": char_count, "has_garbage_chars": has_garbage, "quality_score": score}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
def run_audit():
|
| 42 |
+
# 你的数据湖大小
|
| 43 |
+
total_count = 7038
|
| 44 |
+
logger.info(f"🚀 审计引擎启动 | 目标量: {total_count}", flush=True)
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
while True:
|
| 47 |
try:
|
| 48 |
+
# --- 修正点:不使用 RPC,改用普通 COUNT ---
|
| 49 |
+
# 每个植物审计3个字段,所以 count / 3
|
| 50 |
+
count_res = supabase.table("data_quality_audit").select("id", count="exact").execute()
|
| 51 |
+
processed_plants = (count_res.count or 0) // 3
|
| 52 |
|
| 53 |
# 打印进度条
|
| 54 |
+
print(f"📊 进度: {get_progress_bar(processed_plants, total_count)} ({processed_plants}/{total_count})", flush=True)
|
|
|
|
| 55 |
|
| 56 |
+
# 水位线逻辑
|
| 57 |
+
last_res = supabase.table("data_quality_audit").select("updated_at").order("updated_at", desc=True).limit(1).execute()
|
| 58 |
+
last_time = last_res.data[0]['updated_at'] if last_res.data else "1970-01-01T00:00:00Z"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
+
# 抓取主表变动
|
| 61 |
+
res = supabase.table("bs4_plants").select("plant_id, edible_uses, medicinal_uses, cultivation_details, updated_at")\
|
| 62 |
+
.gt("updated_at", last_time).order("updated_at").limit(20).execute()
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
if not res.data:
|
| 65 |
+
time.sleep(30)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
continue
|
| 67 |
|
| 68 |
for row in res.data:
|
| 69 |
+
for f in ['edible_uses', 'medicinal_uses', 'cultivation_details']:
|
| 70 |
+
analysis = analyze_text(row.get(f))
|
| 71 |
supabase.table("data_quality_audit").upsert({
|
| 72 |
+
"plant_id": row['plant_id'],
|
| 73 |
+
"field_name": f,
|
| 74 |
+
**analysis,
|
| 75 |
"updated_at": "now()"
|
| 76 |
}).execute()
|
| 77 |
|
| 78 |
except Exception as e:
|
| 79 |
+
print(f"❌ 运行异常: {e}", flush=True)
|
| 80 |
time.sleep(10)
|
| 81 |
|
| 82 |
if __name__ == "__main__":
|