Spaces:
Running
Running
Restore auto_scheduler.py from commit 0280ca5 (v7: 3 topics, no AI Thế Giới)
Browse files- auto_scheduler.py +13 -9
auto_scheduler.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
-
"""VNEWS Auto Scheduler - tự động đăng
|
| 2 |
Vào các khung giờ: 7:00, 13:00, 19:00 (giờ Việt Nam)
|
| 3 |
Mỗi bài: Rewrite AI từ nguồn báo + short video tự động
|
| 4 |
-
FIX
|
| 5 |
"""
|
| 6 |
import os, re, json, time, threading, asyncio, logging, random, hashlib, html as html_lib
|
| 7 |
from datetime import datetime, timezone, timedelta, date
|
|
@@ -44,9 +44,10 @@ _STOP = set('và của các những một được trong với cho tại sau tr
|
|
| 44 |
|
| 45 |
def _clean(s):
|
| 46 |
s = html_lib.unescape(s or "")
|
|
|
|
| 47 |
s = s.replace('<a href=" src="', '').replace("<a href=' src='", '')
|
| 48 |
s = s.replace('<a href=" src=', '').replace("<a href=' src=", '')
|
| 49 |
-
s = re.sub(r'<[^>]+>', '', s)
|
| 50 |
return re.sub(r"\s+", " ", s).strip()
|
| 51 |
|
| 52 |
def _get_hot_topics():
|
|
@@ -91,7 +92,7 @@ def _get_hot_topics():
|
|
| 91 |
seen.add(key)
|
| 92 |
topics.append({'label': '#' + re.sub(r'\s+', '', kw.title()), 'topic': kw, 'count': count})
|
| 93 |
if len(topics) >= 20: break
|
| 94 |
-
for kw in ['World Cup 2026', 'Kinh tế Việt Nam', 'Bóng đá châu Âu', 'Công nghệ AI', '
|
| 95 |
if len(topics) >= 24: break
|
| 96 |
if not any(kw.lower() in s for s in seen):
|
| 97 |
topics.append({'label': '#' + re.sub(r'\s+', '', kw.title()), 'topic': kw, 'count': 0})
|
|
@@ -162,6 +163,7 @@ async def _create_ai_post(topic):
|
|
| 162 |
LOG.warning(f"No articles for topic: {topic}. Fallback.")
|
| 163 |
return await _create_fallback_post(topic, ai_ext, ai_patch)
|
| 164 |
posts = []
|
|
|
|
| 165 |
now = datetime.now(VN_TZ)
|
| 166 |
hour = now.hour
|
| 167 |
time_label = "7h sáng" if hour == 7 else ("13h trưa" if hour == 13 else "19h tối")
|
|
@@ -174,11 +176,13 @@ async def _create_ai_post(topic):
|
|
| 174 |
text = await ai_ext.qwen_generate(prompt, image_url=art.get('image'), max_tokens=1500)
|
| 175 |
text = ai_patch._postprocess_ai_text(text, max_units=20)
|
| 176 |
src = [art.get('source', {'title': art.get('title', topic), 'url': art.get('url', ''), 'via': art.get('via', '')})]
|
|
|
|
| 177 |
if text and not text.startswith(text_intro):
|
| 178 |
text = f"{text_intro}\n\n{text}"
|
| 179 |
if 'Nguồn tham khảo:' not in (text or ''):
|
| 180 |
text = (text or '') + "\n\n" + ai_patch._source_line(src)
|
| 181 |
img = art.get('image') or ai_ext.pollination_image_url(art.get('title', topic))
|
|
|
|
| 182 |
post = ai_ext.make_post(art.get('title', topic), text, img, art.get('url', ''), 'auto_scheduled', sources=src)
|
| 183 |
try:
|
| 184 |
page_data = ai_patch._scrape_article_images(art.get('url', ''))
|
|
@@ -206,6 +210,7 @@ async def _create_ai_post(topic):
|
|
| 206 |
async def _create_fallback_post(topic, ai_ext, ai_patch):
|
| 207 |
LOG.info(f"Fallback: {topic}")
|
| 208 |
try:
|
|
|
|
| 209 |
now = datetime.now(VN_TZ)
|
| 210 |
hour = now.hour
|
| 211 |
time_label = "7h sáng" if hour == 7 else ("13h trưa" if hour == 13 else "19h tối")
|
|
@@ -313,10 +318,9 @@ def _run_scheduled_posting():
|
|
| 313 |
label = t.get('label', '')
|
| 314 |
if label and label not in seen_labels:
|
| 315 |
seen_labels.add(label); selected.append(t['topic'])
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
selected = ['Thời sự Việt Nam', 'Kinh tế Việt Nam', 'Công nghệ AI', 'Thể thao', 'Thế giới']
|
| 320 |
LOG.info(f"Topics: {selected}")
|
| 321 |
async def _do_all():
|
| 322 |
results = []
|
|
@@ -389,4 +393,4 @@ def start_auto_scheduler():
|
|
| 389 |
t = threading.Thread(target=_scheduler_loop, daemon=True, name="auto-scheduler")
|
| 390 |
t.start()
|
| 391 |
LOG.info("Auto scheduler started")
|
| 392 |
-
return t
|
|
|
|
| 1 |
+
"""VNEWS Auto Scheduler - tự động đăng 3 bài rewrite AI + shorts từ 3 chủ đề HOT
|
| 2 |
Vào các khung giờ: 7:00, 13:00, 19:00 (giờ Việt Nam)
|
| 3 |
Mỗi bài: Rewrite AI từ nguồn báo + short video tự động
|
| 4 |
+
FIX v7: Giữ nguyên tiêu đề gốc từng bài viết + thêm "Tin tóm tắt VNEWS 7h sáng/13h trưa/19h tối" ở đầu text
|
| 5 |
"""
|
| 6 |
import os, re, json, time, threading, asyncio, logging, random, hashlib, html as html_lib
|
| 7 |
from datetime import datetime, timezone, timedelta, date
|
|
|
|
| 44 |
|
| 45 |
def _clean(s):
|
| 46 |
s = html_lib.unescape(s or "")
|
| 47 |
+
# FIX: Remove malformed HTML artifacts (truncated tags without closing >)
|
| 48 |
s = s.replace('<a href=" src="', '').replace("<a href=' src='", '')
|
| 49 |
s = s.replace('<a href=" src=', '').replace("<a href=' src=", '')
|
| 50 |
+
s = re.sub(r'<[^>]+>', '', s) # Remove all HTML tags
|
| 51 |
return re.sub(r"\s+", " ", s).strip()
|
| 52 |
|
| 53 |
def _get_hot_topics():
|
|
|
|
| 92 |
seen.add(key)
|
| 93 |
topics.append({'label': '#' + re.sub(r'\s+', '', kw.title()), 'topic': kw, 'count': count})
|
| 94 |
if len(topics) >= 20: break
|
| 95 |
+
for kw in ['World Cup 2026', 'Kinh tế Việt Nam', 'Bóng đá châu Âu', 'Công nghệ AI', 'Giá vàng', 'Thời tiết']:
|
| 96 |
if len(topics) >= 24: break
|
| 97 |
if not any(kw.lower() in s for s in seen):
|
| 98 |
topics.append({'label': '#' + re.sub(r'\s+', '', kw.title()), 'topic': kw, 'count': 0})
|
|
|
|
| 163 |
LOG.warning(f"No articles for topic: {topic}. Fallback.")
|
| 164 |
return await _create_fallback_post(topic, ai_ext, ai_patch)
|
| 165 |
posts = []
|
| 166 |
+
# Get schedule time label for text intro (7h sáng, 13h trưa, 19h tối)
|
| 167 |
now = datetime.now(VN_TZ)
|
| 168 |
hour = now.hour
|
| 169 |
time_label = "7h sáng" if hour == 7 else ("13h trưa" if hour == 13 else "19h tối")
|
|
|
|
| 176 |
text = await ai_ext.qwen_generate(prompt, image_url=art.get('image'), max_tokens=1500)
|
| 177 |
text = ai_patch._postprocess_ai_text(text, max_units=20)
|
| 178 |
src = [art.get('source', {'title': art.get('title', topic), 'url': art.get('url', ''), 'via': art.get('via', '')})]
|
| 179 |
+
# Prepend time label intro to text (giữ nguyên title là tiêu đề gốc của bài báo)
|
| 180 |
if text and not text.startswith(text_intro):
|
| 181 |
text = f"{text_intro}\n\n{text}"
|
| 182 |
if 'Nguồn tham khảo:' not in (text or ''):
|
| 183 |
text = (text or '') + "\n\n" + ai_patch._source_line(src)
|
| 184 |
img = art.get('image') or ai_ext.pollination_image_url(art.get('title', topic))
|
| 185 |
+
# Dùng art.get('title') GIỮ NGUYÊN tiêu đề gốc từ bài báo
|
| 186 |
post = ai_ext.make_post(art.get('title', topic), text, img, art.get('url', ''), 'auto_scheduled', sources=src)
|
| 187 |
try:
|
| 188 |
page_data = ai_patch._scrape_article_images(art.get('url', ''))
|
|
|
|
| 210 |
async def _create_fallback_post(topic, ai_ext, ai_patch):
|
| 211 |
LOG.info(f"Fallback: {topic}")
|
| 212 |
try:
|
| 213 |
+
# Still add time label to fallback posts
|
| 214 |
now = datetime.now(VN_TZ)
|
| 215 |
hour = now.hour
|
| 216 |
time_label = "7h sáng" if hour == 7 else ("13h trưa" if hour == 13 else "19h tối")
|
|
|
|
| 318 |
label = t.get('label', '')
|
| 319 |
if label and label not in seen_labels:
|
| 320 |
seen_labels.add(label); selected.append(t['topic'])
|
| 321 |
+
if len(selected) >= 3: break
|
| 322 |
+
if len(selected) < 3:
|
| 323 |
+
selected = ['Thời sự Việt Nam', 'Kinh tế Việt Nam', 'Thể thao']
|
|
|
|
| 324 |
LOG.info(f"Topics: {selected}")
|
| 325 |
async def _do_all():
|
| 326 |
results = []
|
|
|
|
| 393 |
t = threading.Thread(target=_scheduler_loop, daemon=True, name="auto-scheduler")
|
| 394 |
t.start()
|
| 395 |
LOG.info("Auto scheduler started")
|
| 396 |
+
return t
|