bep40 commited on
Commit
0d607ac
·
verified ·
1 Parent(s): 589a639

Restore b9b6ba4 with safe runtime patch for topic cleanup and fast shorts

Browse files
Files changed (1) hide show
  1. restore_b9b6ba4_runner.py +169 -8
restore_b9b6ba4_runner.py CHANGED
@@ -1,6 +1,5 @@
1
  import os
2
  import sys
3
- import shutil
4
  from huggingface_hub import snapshot_download
5
 
6
  REVISION = "b9b6ba4"
@@ -14,18 +13,180 @@ snapshot_dir = snapshot_download(
14
  local_dir_use_symlinks=False,
15
  )
16
 
17
- # Copy patch from current repo into the restored snapshot.
18
- patch_src = "/app/patch_b9b6ba4.py"
19
- patch_dst = os.path.join(snapshot_dir, "patch_b9b6ba4.py")
20
- if os.path.exists(patch_src):
21
- shutil.copyfile(patch_src, patch_dst)
22
-
23
  os.chdir(snapshot_dir)
24
  sys.path.insert(0, snapshot_dir)
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  cmd = [
27
  "uvicorn",
28
- "patch_b9b6ba4:app",
29
  "--host",
30
  "0.0.0.0",
31
  "--port",
 
1
  import os
2
  import sys
 
3
  from huggingface_hub import snapshot_download
4
 
5
  REVISION = "b9b6ba4"
 
13
  local_dir_use_symlinks=False,
14
  )
15
 
 
 
 
 
 
 
16
  os.chdir(snapshot_dir)
17
  sys.path.insert(0, snapshot_dir)
18
 
19
+ # Runtime patch is written into the restored snapshot so the restored UI is used
20
+ # (no placeholder index.html), while only the requested fixes are applied.
21
+ patch_code = r'''
22
+ import re, time, json, asyncio
23
+ from fastapi import Request, Query
24
+ from fastapi.responses import JSONResponse, HTMLResponse
25
+ import ai_runtime_final6 as m
26
+
27
+ app = m.app
28
+ _SHORTS_CACHE = {"t": 0, "d": []}
29
+ BAD_LINES = [
30
+ 'Chỉ xuất bản bài viết cuối cùng',
31
+ 'không nhắc lại yêu cầu',
32
+ 'không liệt kê chỉ dẫn',
33
+ 'Không sao chép nguyên văn',
34
+ 'Bài có tiêu đề, sapo',
35
+ 'Nhiệm vụ: viết một bài báo tiếng Việt hoàn chỉnh',
36
+ ]
37
+
38
+ def _clean_topic_text(txt):
39
+ txt = str(txt or '')
40
+ out = []
41
+ for line in txt.splitlines():
42
+ s = line.strip()
43
+ if not s:
44
+ out.append(line); continue
45
+ low = s.lower()
46
+ if any(x.lower() in low for x in BAD_LINES):
47
+ continue
48
+ if re.match(r'^nhiệm vụ\s*:', low):
49
+ continue
50
+ # Drop prompt-like bullet instructions that accidentally leak into output.
51
+ if re.match(r'^[•\-*]\s*(chỉ xuất bản|không sao chép|bài có tiêu đề|nhiệm vụ)', low):
52
+ continue
53
+ out.append(line)
54
+ txt = '\n'.join(out)
55
+ txt = re.sub(r'\n{3,}', '\n\n', txt).strip()
56
+ return txt
57
+
58
+ def _fallback_shorts():
59
+ out=[];seen=set()
60
+ try:
61
+ for v in getattr(m.f5.rt if hasattr(m,'f5') else m, 'SHORTS_FALLBACK', []) or []:
62
+ vid=v.get('id')
63
+ if vid and vid not in seen:
64
+ seen.add(vid);out.append(v)
65
+ except Exception:
66
+ pass
67
+ hard=[
68
+ ('Lu_iCQ5YwNM','Công an lập hồ sơ xử lý người phụ nữ chửi bới, tát tài xế ô tô | Dân trí','baodantri7941'),
69
+ ('CwWvijF8BOA','Chú rể bật khóc nhận món quà bí mật người cha quá cố gửi 26 năm trước | Dân trí','baodantri7941'),
70
+ ('tvPewsc2ph4','Tính năng ẩn trên iPhone giúp giảm mỏi mắt | Dân trí','baodantri7941'),
71
+ ('7Pd6vZ2Lz1M','Hành động ấm lòng trong tìm kiếm học sinh tử vong ở sông Lô | SKĐS','baosuckhoedoisongboyte'),
72
+ ('SlHLt_ZyPiE','Xử phạt người đàn ông xóa số điện thoại cứu hộ trên cao tốc Bắc - Nam | SKĐS','baosuckhoedoisongboyte'),
73
+ ('IUOprcJyYr4','Phụ nữ táo bón có phải do lười ăn rau? | SKĐS','baosuckhoedoisongboyte')
74
+ ]
75
+ for vid,title,ch in hard:
76
+ if vid not in seen:
77
+ seen.add(vid);out.append({'id':vid,'title':title,'channel':ch,'link':'https://www.youtube.com/watch?v='+vid,'img':'https://i.ytimg.com/vi/'+vid+'/hqdefault.jpg','source':'yt'})
78
+ return out
79
+
80
+ def _fresh_shorts_fast():
81
+ seen=set();out=[]
82
+ handles=getattr(m, 'YOUTUBE_HANDLES', ['baodantri7941','baosuckhoedoisongboyte'])
83
+ for h in handles:
84
+ got=[]
85
+ try: got = m._yt_html(h, 24) or []
86
+ except Exception: got=[]
87
+ # yt-dlp can be slower; only use if html returns too few.
88
+ if len(got)<4:
89
+ try: got = (m._yt_ytdlp(h, 24) or []) + got
90
+ except Exception: pass
91
+ for v in got:
92
+ vid=v.get('id') or ''
93
+ if vid and vid not in seen:
94
+ seen.add(vid);out.append(v)
95
+ for v in _fallback_shorts():
96
+ vid=v.get('id') or ''
97
+ if vid and vid not in seen:
98
+ seen.add(vid);out.append(v)
99
+ return out[:50]
100
+
101
+ # Remove only routes we override.
102
+ _PATCH={('/api/topic_post','POST'),('/api/shorts','GET'),('/','GET')}
103
+ app.router.routes=[r for r in app.router.routes if not any(getattr(r,'path',None)==p and method in getattr(r,'methods',set()) for p,method in _PATCH)]
104
+
105
+ @app.get('/api/shorts')
106
+ def api_shorts_patch(refresh:int=Query(default=0)):
107
+ now=time.time()
108
+ if not refresh and _SHORTS_CACHE['d'] and now-_SHORTS_CACHE['t']<600:
109
+ return JSONResponse(_SHORTS_CACHE['d'])
110
+ data=_fresh_shorts_fast()
111
+ _SHORTS_CACHE.update({'t':now,'d':data})
112
+ return JSONResponse(data)
113
+
114
+ @app.post('/api/topic_post')
115
+ async def topic_post_patch(request:Request):
116
+ body=await request.json(); topic=m.clean(body.get('topic',''))
117
+ if not topic: return JSONResponse({'error':'missing topic'},status_code=400)
118
+ img=m._topic_image(topic)
119
+ # Use fast context if available; fall back safely.
120
+ try:
121
+ research=m._fast_context(topic)
122
+ except Exception:
123
+ research=m._web_research_context(topic)
124
+ context=research.get('context',''); sources=research.get('sources',[])
125
+ source_brief=context[:18000]
126
+ prompt=f'''Bạn là biên tập viên VNEWS. Hãy viết một bài báo tiếng Việt hoàn chỉnh về chủ đề: "{topic}" dựa trên dữ liệu nguồn bên dưới.
127
+
128
+ DỮ LIỆU NGUỒN:
129
+ {source_brief}
130
+
131
+ YÊU CẦU NỘI DUNG:
132
+ - Viết trực tiếp bài cuối cùng, không nhắc lại yêu cầu hay chỉ dẫn.
133
+ - Tổng hợp và diễn đạt lại bằng ngôn ngữ báo chí tự nhiên.
134
+ - Có tiêu đề mới, sapo ngắn, các đoạn bối cảnh/phân tích/tác động.
135
+ - Không sao chép nguyên văn nguồn.
136
+ - Cuối bài có mục Nguồn tham khảo ngắn.
137
+ '''
138
+ try:
139
+ text=await asyncio.wait_for(m.f5.base.qwen_generate(prompt,image_url=img,max_tokens=1700),timeout=35)
140
+ except Exception:
141
+ text=None
142
+ if not text or len(str(text))<300:
143
+ vias=', '.join(sorted({s.get('via','') for s in sources if s.get('via')}))
144
+ titles='\n'.join('• '+s.get('title','') for s in sources[:6])
145
+ text=f'{topic}: những điểm đáng chú ý\n\n{topic} đang thu hút sự quan tâm qua nhiều nguồn tin. Tổng hợp nhanh cho thấy chủ đề này cần được nhìn từ bối cảnh, tác động và những diễn biến liên quan.\n\n{titles}\n\nNguồn tham khảo: {vias}'
146
+ text=_clean_topic_text(text)
147
+ src=[s for s in sources if s.get('url')]
148
+ post=m.f5.base.make_post(topic,text,img,'','topic_cleaned_b9b6ba4',sources=src)
149
+ post['images']=[img]
150
+ posts=m.f5.base._load_ai_wall(); posts.insert(0,post); m.f5.base._save_ai_wall(posts)
151
+ return JSONResponse({'post':post})
152
+
153
+ EXTRA_JS = r'''
154
+ <style>
155
+ .topic-extra-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}.topic-extra-actions button{background:#2d8659;border:0;color:#fff;border-radius:12px;padding:8px 12px;font-size:12px}.topic-extra-actions button.secondary{background:#222;border:1px solid #444}.topic-source-links{margin-top:10px;background:#151515;border:1px solid #2b2b2b;border-radius:10px;padding:10px}.topic-source-links a{display:block;color:#5cb87a;font-size:12px;margin:5px 0;text-decoration:none}.shorts-b9-wrap{margin:6px 4px;background:#1a1a1a;border:1px solid #2a2a2a;border-radius:8px;overflow:hidden}
156
+ </style>
157
+ <script>
158
+ (function(){
159
+ function esc(s){return String(s||'').replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]));}
160
+ async function ensureFastShorts(){let home=document.getElementById('view-home');if(!home||document.getElementById('shorts-b9-fast'))return;let data=await fetch('/api/shorts').then(r=>r.json()).catch(()=>[]);if(!data.length)return;let wrap=document.createElement('div');wrap.id='shorts-b9-fast';wrap.className='shorts-b9-wrap';let h='<div class="slider-header"><span class="slider-label">📱 Shorts Dân trí & SKĐS</span><span class="slider-note">Tải nhanh</span></div><div class="slider-track">';data.slice(0,24).forEach((a,i)=>{h+=`<div class="slider-item shorts-item" onclick="openTikTok('shorts',${i})"><div class="slider-thumb shorts-thumb">${a.img?`<img src="${esc(a.img)}">`:''}<div class="card-play">▶</div></div><div class="slider-title">${esc(a.title)}</div></div>`});h+='</div>';wrap.innerHTML=h;let comp=document.querySelector('.ai-compose')||home.firstChild;if(comp)comp.after(wrap);else home.prepend(wrap);}
161
+ function addTopicActions(){let art=document.querySelector('#view-article.active .article-view');if(!art||document.getElementById('topic-extra-actions'))return;let text=art.innerText||'';if(!/Nguồn tham khảo|Qwen|Tường AI|AI/i.test(text))return;let box=document.createElement('div');box.id='topic-extra-actions';box.className='topic-extra-actions';box.innerHTML='<button onclick="rewriteTopicArticleB9()">🤖 Rewrite AI & đăng tường</button><button class="secondary" onclick="openFirstTopicSourceB9()">🔗 Mở nguồn đầu tiên</button><div id="topic-source-links" class="topic-source-links" style="display:none"></div>';art.appendChild(box);}
162
+ window.rewriteTopicArticleB9=function(){let title=document.querySelector('.article-title')?.innerText||'Bài chủ đề';let content=document.querySelector('.article-view')?.innerText||'';let payload={topic:title+'\n'+content.slice(0,2500)};fetch('/api/topic_post',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(r=>r.json()).then(j=>{if(j.post)alert('Đã rewrite AI và đăng lại lên Tường AI');else alert(j.error||'Lỗi rewrite')}).catch(e=>alert(e.message));};
163
+ window.openFirstTopicSourceB9=function(){let a=document.querySelector('.article-summary a,.source-detail-box a,.topic-source-links a');if(a)a.click();else alert('Bài này chưa có link nguồn hiển thị.');};
164
+ setInterval(()=>{ensureFastShorts();addTopicActions();},1500);setTimeout(()=>{ensureFastShorts();addTopicActions();},800);
165
+ })();
166
+ </script>
167
+ '''
168
+
169
+ @app.get('/')
170
+ async def index_patch():
171
+ # Call restored final6 root if available to keep 100% restored UI and avoid placeholder.
172
+ try:
173
+ resp=await m.index_final6_fast_home()
174
+ except Exception:
175
+ try: resp=await m.index_final6()
176
+ except Exception:
177
+ html=m.f5.f4.f3.f2.f1._load_index_html()
178
+ return HTMLResponse(html.replace('</body>',EXTRA_JS+'</body>') if '</body>' in html else html+EXTRA_JS)
179
+ html=resp.body.decode('utf-8') if hasattr(resp,'body') else str(resp)
180
+ return HTMLResponse(html.replace('</body>',EXTRA_JS+'\n</body>') if '</body>' in html else html+EXTRA_JS)
181
+ '''
182
+
183
+ patch_path=os.path.join(snapshot_dir,'b9b6ba4_safe_patch.py')
184
+ with open(patch_path,'w',encoding='utf-8') as f:
185
+ f.write(patch_code)
186
+
187
  cmd = [
188
  "uvicorn",
189
+ "b9b6ba4_safe_patch:app",
190
  "--host",
191
  "0.0.0.0",
192
  "--port",