"""Content assembly: stable, site-scoped brand/category relationships. Only materializes associations supported by source data. Generated brand shells are clearly marked and contain no fabricated copy. """ from collections import defaultdict from . import db from .core import save_entry from .theme_pro import fields,slug KINDS=('product','vehicle') def preview(site_id): records=db.rows("SELECT * FROM entries WHERE site_id=? AND type IN ('product','vehicle','brand')",(site_id,)) brand_pages={r['title'].casefold():r for r in records if r['type']=='brand'} routes={r['route'] for r in db.rows('SELECT route FROM entries WHERE site_id=?',(site_id,))} brands=defaultdict(list);cats=defaultdict(list);issues=[] for row in records: if row['type'] not in KINDS:continue attrs=fields(row) brand=str(attrs.get('brand') or '').strip();category=str(attrs.get('category') or '').strip() if brand: brands[brand].append(row['route']) else:issues.append({'route':row['route'],'severity':'review','message':'未填写品牌'}) if category:cats[category].append(row['route']) else:issues.append({'route':row['route'],'severity':'review','message':'未填写分类'}) if not row['cover']:issues.append({'route':row['route'],'severity':'review','message':'缺少产品封面图'}) candidates=[] for name,products in brands.items(): if name.casefold() in brand_pages:continue url=f'/brands/{slug(name)}/' if url in routes: issues.append({'route':url,'severity':'block','message':'品牌自动生成路径与已有页面冲突'});continue candidates.append({'brand':name,'route':url,'products':len(products)}) return {'brands':[{ 'name':k,'items':len(v)} for k,v in brands.items()], 'categories':[{'name':k,'items':len(v)} for k,v in cats.items()], 'brand_pages_missing':candidates,'issues':issues, 'products':sum(len(x) for x in brands.values()), 'note':'仅根据已有产品字段建立关系;缺少真实品牌介绍/图片时不会自动编造。'} def commit(site_id): result=preview(site_id) if any(issue['severity']=='block' for issue in result['issues']): raise ValueError('存在路径冲突,请先处理后再装配') created=[] for brand in result['brand_pages_missing']: save_entry(site_id,{'type':'brand','title':brand['brand'],'route':brand['route'], 'summary':'','body':'','status':'published','meta':{'fields':{'source':'auto-assembled'},'source_auto_assembled':True}}, source='relations-assembly') created.append(brand['route']) return {'created_brand_pages':created,'count':len(created),'preview':result}