Spaces:
Running
Running
Fix: ensure rewrite has image, updates wall, short works after rewrite"
Browse files- app_entry.py +20 -9
app_entry.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
"""Wrapper: extra fixes + auto title rewrite + topic source image."""
|
| 2 |
from ai_runtime_patch_fast import *
|
| 3 |
from ai_runtime_patch_fast import app, f5, f6, rt, PATCH_INJECT, _scrape, _domain, clean
|
| 4 |
from patch_extra import EXTRA_FIX
|
|
@@ -6,7 +6,9 @@ from fastapi.responses import HTMLResponse, JSONResponse
|
|
| 6 |
from fastapi import Request
|
| 7 |
import asyncio, re
|
| 8 |
|
| 9 |
-
|
|
|
|
|
|
|
| 10 |
app.router.routes=[r for r in app.router.routes if not (
|
| 11 |
(getattr(r,'path',None)=='/api/topic_post' and 'POST' in getattr(r,'methods',set())) or
|
| 12 |
(getattr(r,'path',None)=='/api/topic/rewrite' and 'POST' in getattr(r,'methods',set())) or
|
|
@@ -36,6 +38,11 @@ def _source_image(sources, details):
|
|
| 36 |
if img and 'pollinations' not in img and len(img)>20:return img
|
| 37 |
return ''
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
@app.post('/api/topic_post')
|
| 40 |
async def _tp(request:Request):
|
| 41 |
b=await request.json();topic=clean(b.get('topic',''))
|
|
@@ -43,8 +50,7 @@ async def _tp(request:Request):
|
|
| 43 |
research=f6._fast_context(topic) if hasattr(f6,'_fast_context') else f6._web_research_context(topic)
|
| 44 |
ctx=research.get('context','');src=research.get('sources',[]);det=f6._extract_source_details_from_context(ctx,src) if hasattr(f6,'_extract_source_details_from_context') else []
|
| 45 |
if not ctx or not src:return JSONResponse({'error':'Không tìm được nội dung.'},status_code=422)
|
| 46 |
-
|
| 47 |
-
img=_source_image(src,det) or f6._topic_image(topic)
|
| 48 |
sb='\n\n'.join([f"[{i+1}] {d.get('title','')} ({d.get('via','')})\n{d.get('content','')[:1400]}" for i,d in enumerate(det)]) if det else ctx[:18000]
|
| 49 |
text=None
|
| 50 |
try:text=await asyncio.wait_for(f5.base.qwen_generate(f'Viết bài tiếng Việt VỀ: "{topic}"\nNGUỒN:\n{sb[:18000]}\nCHỈ viết về "{topic}". 5-8 đoạn. Cuối có nguồn.',image_url=img,max_tokens=1700),timeout=35)
|
|
@@ -61,6 +67,7 @@ async def _rw(request:Request):
|
|
| 61 |
title,raw,img=_scrape(url,14000)
|
| 62 |
if len(raw)<50:raw=ctx[:14000]
|
| 63 |
if len(raw)<50:return JSONResponse({'error':'Không đọc được bài'},status_code=422)
|
|
|
|
| 64 |
prompt=f"""Tóm tắt bài viết đăng Tường AI. Dòng đầu tiên là TIÊU ĐỀ MỚI hấp dẫn phù hợp nội dung (không dùng tiêu đề gốc).
|
| 65 |
|
| 66 |
Tiêu đề gốc (tham khảo): {title}
|
|
@@ -71,7 +78,7 @@ Dòng 1: Tiêu đề mới hấp dẫn.
|
|
| 71 |
Tiếp theo: 4-6 ý chính tóm tắt.
|
| 72 |
Cuối: ghi nguồn."""
|
| 73 |
text=None
|
| 74 |
-
try:text=await asyncio.wait_for(f5.base.qwen_generate(prompt,image_url=img
|
| 75 |
except:pass
|
| 76 |
if not text or len(text)<80:text=f"{title}\n\n{raw[:1200]}\n\nNguồn: {_domain(url)}"
|
| 77 |
ai_title=_extract_title(text)
|
|
@@ -87,9 +94,13 @@ async def _tr(request:Request):
|
|
| 87 |
ps=f5.base._load_ai_wall();p=next((x for x in ps if str(x.get('id'))==pid),None)
|
| 88 |
if not p:return JSONResponse({'error':'Bài không tồn tại'},status_code=404)
|
| 89 |
urls=list(dict.fromkeys([s['url'] for s in (p.get('source_details') or []) if s.get('url')]+[s['url'] for s in (p.get('sources') or []) if s.get('url')]))[:5]
|
| 90 |
-
parts=[]
|
| 91 |
-
for u in urls:
|
|
|
|
|
|
|
|
|
|
| 92 |
ac='\n---\n'.join(parts) if parts else (p.get('text') or '')
|
|
|
|
| 93 |
prompt=f"""Viết lại thành bản tóm tắt mới. Dòng đầu tiên là TIÊU ĐỀ MỚI hấp dẫn phù hợp nội dung.
|
| 94 |
|
| 95 |
Chủ đề gốc: {p.get('title','')}
|
|
@@ -100,13 +111,13 @@ Dòng 1: Tiêu đề mới.
|
|
| 100 |
Tiếp: 4-6 ý chính.
|
| 101 |
Cuối: nguồn tham khảo."""
|
| 102 |
text=None
|
| 103 |
-
try:text=await asyncio.wait_for(f5.base.qwen_generate(prompt,image_url=
|
| 104 |
except:pass
|
| 105 |
if not text or len(text)<100:text=f"Tóm tắt: {p.get('title','')}\n\n{ac[:1500]}\n\nNguồn: VNEWS AI"
|
| 106 |
ai_title=_extract_title(text)
|
| 107 |
lines=text.strip().split('\n')
|
| 108 |
body_text='\n'.join(lines[1:]).strip() if lines and lines[0].strip()==ai_title else text
|
| 109 |
-
np=f5.base.make_post(ai_title,body_text,
|
| 110 |
all_p=f5.base._load_ai_wall();all_p.insert(0,np);f5.base._save_ai_wall(all_p);return JSONResponse({'post':np})
|
| 111 |
|
| 112 |
@app.get('/')
|
|
|
|
| 1 |
+
"""Wrapper: extra fixes + auto title rewrite + topic source image + guaranteed image."""
|
| 2 |
from ai_runtime_patch_fast import *
|
| 3 |
from ai_runtime_patch_fast import app, f5, f6, rt, PATCH_INJECT, _scrape, _domain, clean
|
| 4 |
from patch_extra import EXTRA_FIX
|
|
|
|
| 6 |
from fastapi import Request
|
| 7 |
import asyncio, re
|
| 8 |
|
| 9 |
+
DEFAULT_IMG="https://s1.vnecdn.net/vnexpress/restruct/i/v9505/logo_default.jpg"
|
| 10 |
+
|
| 11 |
+
# Override endpoints.
|
| 12 |
app.router.routes=[r for r in app.router.routes if not (
|
| 13 |
(getattr(r,'path',None)=='/api/topic_post' and 'POST' in getattr(r,'methods',set())) or
|
| 14 |
(getattr(r,'path',None)=='/api/topic/rewrite' and 'POST' in getattr(r,'methods',set())) or
|
|
|
|
| 38 |
if img and 'pollinations' not in img and len(img)>20:return img
|
| 39 |
return ''
|
| 40 |
|
| 41 |
+
def _ensure_img(img):
|
| 42 |
+
"""Always return a valid image URL."""
|
| 43 |
+
if img and len(img)>20 and img.startswith('http'):return img
|
| 44 |
+
return DEFAULT_IMG
|
| 45 |
+
|
| 46 |
@app.post('/api/topic_post')
|
| 47 |
async def _tp(request:Request):
|
| 48 |
b=await request.json();topic=clean(b.get('topic',''))
|
|
|
|
| 50 |
research=f6._fast_context(topic) if hasattr(f6,'_fast_context') else f6._web_research_context(topic)
|
| 51 |
ctx=research.get('context','');src=research.get('sources',[]);det=f6._extract_source_details_from_context(ctx,src) if hasattr(f6,'_extract_source_details_from_context') else []
|
| 52 |
if not ctx or not src:return JSONResponse({'error':'Không tìm được nội dung.'},status_code=422)
|
| 53 |
+
img=_ensure_img(_source_image(src,det) or f6._topic_image(topic))
|
|
|
|
| 54 |
sb='\n\n'.join([f"[{i+1}] {d.get('title','')} ({d.get('via','')})\n{d.get('content','')[:1400]}" for i,d in enumerate(det)]) if det else ctx[:18000]
|
| 55 |
text=None
|
| 56 |
try:text=await asyncio.wait_for(f5.base.qwen_generate(f'Viết bài tiếng Việt VỀ: "{topic}"\nNGUỒN:\n{sb[:18000]}\nCHỈ viết về "{topic}". 5-8 đoạn. Cuối có nguồn.',image_url=img,max_tokens=1700),timeout=35)
|
|
|
|
| 67 |
title,raw,img=_scrape(url,14000)
|
| 68 |
if len(raw)<50:raw=ctx[:14000]
|
| 69 |
if len(raw)<50:return JSONResponse({'error':'Không đọc được bài'},status_code=422)
|
| 70 |
+
img=_ensure_img(img)
|
| 71 |
prompt=f"""Tóm tắt bài viết đăng Tường AI. Dòng đầu tiên là TIÊU ĐỀ MỚI hấp dẫn phù hợp nội dung (không dùng tiêu đề gốc).
|
| 72 |
|
| 73 |
Tiêu đề gốc (tham khảo): {title}
|
|
|
|
| 78 |
Tiếp theo: 4-6 ý chính tóm tắt.
|
| 79 |
Cuối: ghi nguồn."""
|
| 80 |
text=None
|
| 81 |
+
try:text=await asyncio.wait_for(f5.base.qwen_generate(prompt,image_url=img,max_tokens=1000),timeout=30)
|
| 82 |
except:pass
|
| 83 |
if not text or len(text)<80:text=f"{title}\n\n{raw[:1200]}\n\nNguồn: {_domain(url)}"
|
| 84 |
ai_title=_extract_title(text)
|
|
|
|
| 94 |
ps=f5.base._load_ai_wall();p=next((x for x in ps if str(x.get('id'))==pid),None)
|
| 95 |
if not p:return JSONResponse({'error':'Bài không tồn tại'},status_code=404)
|
| 96 |
urls=list(dict.fromkeys([s['url'] for s in (p.get('source_details') or []) if s.get('url')]+[s['url'] for s in (p.get('sources') or []) if s.get('url')]))[:5]
|
| 97 |
+
parts=[];best_img=''
|
| 98 |
+
for u in urls:
|
| 99 |
+
t,r,uimg=_scrape(u,6000)
|
| 100 |
+
if r and len(r)>150:parts.append(f"[{_domain(u)}] {t}\n{r}")
|
| 101 |
+
if not best_img and uimg and len(uimg)>20:best_img=uimg
|
| 102 |
ac='\n---\n'.join(parts) if parts else (p.get('text') or '')
|
| 103 |
+
img=_ensure_img(best_img or p.get('img',''))
|
| 104 |
prompt=f"""Viết lại thành bản tóm tắt mới. Dòng đầu tiên là TIÊU ĐỀ MỚI hấp dẫn phù hợp nội dung.
|
| 105 |
|
| 106 |
Chủ đề gốc: {p.get('title','')}
|
|
|
|
| 111 |
Tiếp: 4-6 ý chính.
|
| 112 |
Cuối: nguồn tham khảo."""
|
| 113 |
text=None
|
| 114 |
+
try:text=await asyncio.wait_for(f5.base.qwen_generate(prompt,image_url=img,max_tokens=1200),timeout=35)
|
| 115 |
except:pass
|
| 116 |
if not text or len(text)<100:text=f"Tóm tắt: {p.get('title','')}\n\n{ac[:1500]}\n\nNguồn: VNEWS AI"
|
| 117 |
ai_title=_extract_title(text)
|
| 118 |
lines=text.strip().split('\n')
|
| 119 |
body_text='\n'.join(lines[1:]).strip() if lines and lines[0].strip()==ai_title else text
|
| 120 |
+
np=f5.base.make_post(ai_title,body_text,img,'','rewrite_topic',sources=p.get('sources',[]));np['images']=[img]
|
| 121 |
all_p=f5.base._load_ai_wall();all_p.insert(0,np);f5.base._save_ai_wall(all_p);return JSONResponse({'post':np})
|
| 122 |
|
| 123 |
@app.get('/')
|