# 热点统计:全维度 from datetime import datetime, timedelta from sqlor.dbpools import DBPools async def main(request): db = DBPools() now = datetime.now() day_ago = (now - timedelta(hours=24)).strftime('%Y-%m-%d %H:%M:%S') async with db.sqlorContext('sage') as sor: items = await sor.R('hotspot_item', {'order': 'heat_score desc'}) sources = await sor.R('hotspot_source', {}) logs = await sor.sqlExe( "select * from hotspot_fetch_log where start_time >= ${t}$", {'t': day_ago} ) status_count = {'emerging': 0, 'rising': 0, 'hot': 0, 'cooling': 0, 'expired': 0} for item in items: s = item.get('status', 'emerging') status_count[s] = status_count.get(s, 0) + 1 sources_active = sum(1 for s in sources if s.get('enabled') == '1') failures = sum(1 for log in logs if log.get('status') == 'failed') # Top sources by item count src_count = {} for item in items: sid = item.get('source_id', '') src_count[sid] = src_count.get(sid, 0) + 1 top_src = sorted(src_count.items(), key=lambda x: x[1], reverse=True)[:5] src_names = {s['id']: s.get('name', s['id']) for s in sources} # Avg heat by category cat_heat = {} for item in items: cat = item.get('category', '未分类') or '未分类' h = float(item.get('heat_score', 0)) if cat not in cat_heat: cat_heat[cat] = {'sum': 0, 'cnt': 0} cat_heat[cat]['sum'] += h cat_heat[cat]['cnt'] += 1 top_categories = sorted( [{'name': k, 'avg': round(v['sum']/v['cnt'], 1), 'cnt': v['cnt']} for k, v in cat_heat.items()], key=lambda x: x['cnt'], reverse=True )[:10] return { 'total': len(items), 'emerging': status_count['emerging'], 'rising': status_count['rising'], 'hot': status_count['hot'], 'cooling': status_count['cooling'], 'expired': status_count['expired'], 'sources': sources_active, 'failures': failures, 'top_sources': [{'name': src_names.get(k, k), 'count': v} for k, v in top_src], 'top_categories': top_categories, 'log_count_24h': len(logs), }