forked from retoor/devplacepy
feat: add news module with admin panel, pagination, and service toggle via env flag
This commit is contained in:
+59
-50
@@ -77,80 +77,85 @@ class NewsService(BaseService):
|
||||
articles = data.get("articles", [])
|
||||
self.log(f"Received {len(articles)} articles")
|
||||
|
||||
sync_table = get_table("news_sync")
|
||||
news_table = get_table("news")
|
||||
images_table = get_table("news_images")
|
||||
|
||||
synced = 0
|
||||
skipped = 0
|
||||
below = 0
|
||||
failed = 0
|
||||
new_count = 0
|
||||
updated_count = 0
|
||||
draft_count = 0
|
||||
failed_count = 0
|
||||
|
||||
for article in articles:
|
||||
external_id = article.get("guid", "")
|
||||
if not external_id:
|
||||
continue
|
||||
|
||||
existing = sync_table.find_one(external_id=external_id)
|
||||
if existing is not None:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
grade = await self._grade_article(article, ai_url, ai_model)
|
||||
now = datetime.utcnow().isoformat()
|
||||
|
||||
if grade is None:
|
||||
failed += 1
|
||||
sync_table.insert({
|
||||
grade_val = 0
|
||||
auto_published = False
|
||||
failed_count += 1
|
||||
elif grade < threshold:
|
||||
grade_val = grade
|
||||
auto_published = False
|
||||
draft_count += 1
|
||||
else:
|
||||
grade_val = grade
|
||||
auto_published = True
|
||||
|
||||
is_published = "published" if auto_published else "draft"
|
||||
existing = news_table.find_one(external_id=external_id)
|
||||
|
||||
if existing:
|
||||
news_table.update({
|
||||
"id": existing["id"],
|
||||
"grade": grade_val,
|
||||
"status": is_published,
|
||||
"title": article.get("title", ""),
|
||||
"description": (article.get("description", "") or "")[:5000],
|
||||
"url": article.get("link", ""),
|
||||
"source_name": article.get("feed_name", ""),
|
||||
"content": (article.get("content", "") or "")[:10000],
|
||||
"author": article.get("author", ""),
|
||||
"article_published": article.get("published", ""),
|
||||
"synced_at": now,
|
||||
}, ["id"])
|
||||
updated_count += 1
|
||||
images_table.delete(news_uid=existing["uid"])
|
||||
article_uid = existing["uid"]
|
||||
else:
|
||||
article_uid = generate_uid()
|
||||
news_table.insert({
|
||||
"uid": article_uid,
|
||||
"external_id": external_id,
|
||||
"grade": 0,
|
||||
"status": "grading_failed",
|
||||
"title": article.get("title", ""),
|
||||
"description": (article.get("description", "") or "")[:5000],
|
||||
"url": article.get("link", ""),
|
||||
"image_url": "",
|
||||
"source_name": article.get("feed_name", ""),
|
||||
"grade": grade_val,
|
||||
"status": is_published,
|
||||
"content": (article.get("content", "") or "")[:10000],
|
||||
"author": article.get("author", ""),
|
||||
"article_published": article.get("published", ""),
|
||||
"synced_at": now,
|
||||
})
|
||||
continue
|
||||
|
||||
sync_table.insert({
|
||||
"external_id": external_id,
|
||||
"grade": grade,
|
||||
"status": "below_threshold" if grade < threshold else "synced",
|
||||
"synced_at": now,
|
||||
})
|
||||
|
||||
if grade < threshold:
|
||||
below += 1
|
||||
continue
|
||||
|
||||
news_uid = generate_uid()
|
||||
|
||||
news_table.insert({
|
||||
"uid": news_uid,
|
||||
"external_id": external_id,
|
||||
"title": article.get("title", ""),
|
||||
"description": (article.get("description", "") or "")[:5000],
|
||||
"url": article.get("link", ""),
|
||||
"image_url": "",
|
||||
"source_name": article.get("feed_name", ""),
|
||||
"grade": grade,
|
||||
"content": (article.get("content", "") or "")[:10000],
|
||||
"author": article.get("author", ""),
|
||||
"published": article.get("published", ""),
|
||||
"synced_at": now,
|
||||
})
|
||||
new_count += 1
|
||||
|
||||
link = article.get("link", "")
|
||||
if link:
|
||||
images = await _get_article_images(link)
|
||||
for img in images:
|
||||
fresh_images = await _get_article_images(link)
|
||||
for img in fresh_images:
|
||||
images_table.insert({
|
||||
"uid": generate_uid(),
|
||||
"news_uid": news_uid,
|
||||
"news_uid": article_uid,
|
||||
"url": img["url"],
|
||||
"alt_text": img.get("alt_text", ""),
|
||||
})
|
||||
|
||||
synced += 1
|
||||
|
||||
self.log(f"Synced {synced}, skipped {skipped}, below {below}, grading failed {failed}")
|
||||
self.log(f"New {new_count}, updated {updated_count}, draft {draft_count}, grading failed {failed_count}")
|
||||
|
||||
async def _grade_article(self, article: dict, ai_url: str, ai_model: str) -> int | None:
|
||||
title = (article.get("title", "") or "")[:500]
|
||||
@@ -172,9 +177,13 @@ class NewsService(BaseService):
|
||||
"temperature": 0.0,
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=15.0) as client:
|
||||
resp = await client.post(ai_url, json=payload)
|
||||
resp = await client.post(ai_url, json=payload, headers=headers)
|
||||
resp.raise_for_status()
|
||||
result = resp.json()
|
||||
text = result.get("choices", [{}])[0].get("message", {}).get("content", "")
|
||||
|
||||
Reference in New Issue
Block a user