|
@@ -72,10 +72,12 @@ def _compress(mp4: Path) -> Path:
|
|
|
|
|
|
|
|
|
|
|
|
|
def classify_imgtext(p: dict, extractor: GeminiExtractor) -> tuple:
|
|
def classify_imgtext(p: dict, extractor: GeminiExtractor) -> tuple:
|
|
|
- ec = extractor.extract(_imgtext_post(p)) # 完整 extract.txt → is_empty
|
|
|
|
|
|
|
+ ec = extractor.extract(_imgtext_post(p)) # 完整 extract.txt → is_empty + 提取的知识
|
|
|
if ec.is_empty:
|
|
if ec.is_empty:
|
|
|
- return 0, "判为非创作:无可迁移的创作方法"
|
|
|
|
|
- return 1, (ec.text or "")[:60]
|
|
|
|
|
|
|
+ return 0, "判为非创作:无可迁移的创作方法", "", ""
|
|
|
|
|
+ points = json.dumps([{"index": c.index, "content": c.content} for c in (ec.cards or [])],
|
|
|
|
|
+ ensure_ascii=False)
|
|
|
|
|
+ return 1, (ec.text or "")[:60], (ec.text or ""), points # reason 取开头,knowledge 存全文
|
|
|
|
|
|
|
|
|
|
|
|
|
def classify_video(p: dict, settings: Settings) -> tuple:
|
|
def classify_video(p: dict, settings: Settings) -> tuple:
|
|
@@ -84,7 +86,7 @@ def classify_video(p: dict, settings: Settings) -> tuple:
|
|
|
rel = p.get("video") or ""
|
|
rel = p.get("video") or ""
|
|
|
mp4 = ROOT / rel.lstrip("/")
|
|
mp4 = ROOT / rel.lstrip("/")
|
|
|
if not rel or not mp4.exists():
|
|
if not rel or not mp4.exists():
|
|
|
- return None, "无本地视频"
|
|
|
|
|
|
|
+ return None, "无本地视频", "", ""
|
|
|
use = _compress(mp4) if mp4.stat().st_size > COMPRESS_OVER_MB * 1048576 else mp4
|
|
use = _compress(mp4) if mp4.stat().st_size > COMPRESS_OVER_MB * 1048576 else mp4
|
|
|
try:
|
|
try:
|
|
|
media = "data:video/mp4;base64," + base64.b64encode(use.read_bytes()).decode()
|
|
media = "data:video/mp4;base64," + base64.b64encode(use.read_bytes()).decode()
|
|
@@ -108,19 +110,22 @@ def classify_video(p: dict, settings: Settings) -> tuple:
|
|
|
if resp.status_code == 200:
|
|
if resp.status_code == 200:
|
|
|
d = json.loads(resp.json()["choices"][0]["message"]["content"])
|
|
d = json.loads(resp.json()["choices"][0]["message"]["content"])
|
|
|
is_empty = bool(d.get("is_empty"))
|
|
is_empty = bool(d.get("is_empty"))
|
|
|
- return (0 if is_empty else 1), str(d.get("reason", ""))[:60]
|
|
|
|
|
|
|
+ if is_empty:
|
|
|
|
|
+ return 0, str(d.get("reason", ""))[:60], "", ""
|
|
|
|
|
+ kn = str(d.get("knowledge", "") or "")
|
|
|
|
|
+ return 1, str(d.get("reason", ""))[:60], kn, ""
|
|
|
last = f"http {resp.status_code}"
|
|
last = f"http {resp.status_code}"
|
|
|
except Exception as exc:
|
|
except Exception as exc:
|
|
|
last = str(exc)[:50]
|
|
last = str(exc)[:50]
|
|
|
time.sleep(2 * (attempt + 1))
|
|
time.sleep(2 * (attempt + 1))
|
|
|
- return None, f"判定失败: {last}"
|
|
|
|
|
|
|
+ return None, f"判定失败: {last}", "", ""
|
|
|
|
|
|
|
|
|
|
|
|
|
def _safe(fn, *a) -> tuple:
|
|
def _safe(fn, *a) -> tuple:
|
|
|
try:
|
|
try:
|
|
|
return fn(*a)
|
|
return fn(*a)
|
|
|
except Exception as exc:
|
|
except Exception as exc:
|
|
|
- return None, f"判定失败: {str(exc)[:60]}"
|
|
|
|
|
|
|
+ return None, f"判定失败: {str(exc)[:60]}", "", ""
|
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> None:
|
|
def main() -> None:
|
|
@@ -137,11 +142,11 @@ def main() -> None:
|
|
|
done = {"n": 0, "fail": 0}
|
|
done = {"n": 0, "fail": 0}
|
|
|
|
|
|
|
|
def _write(p, res):
|
|
def _write(p, res):
|
|
|
- ic, reason = res
|
|
|
|
|
|
|
+ ic, reason, knowledge, points = res
|
|
|
if ic is None:
|
|
if ic is None:
|
|
|
done["fail"] += 1
|
|
done["fail"] += 1
|
|
|
else:
|
|
else:
|
|
|
- store.upsert_class(conn, p["url"], ic, reason, ts)
|
|
|
|
|
|
|
+ store.upsert_class(conn, p["url"], ic, reason, ts, knowledge, points)
|
|
|
done["n"] += 1
|
|
done["n"] += 1
|
|
|
if done["n"] % 20 == 0:
|
|
if done["n"] % 20 == 0:
|
|
|
print(f" {done['n']}/{total}(失败 {done['fail']})")
|
|
print(f" {done['n']}/{total}(失败 {done['fail']})")
|