# -*- coding: utf-8 -*-
"""原创离线合成样例；不连接模型、不读取账户。输出位于脚本旁。
已有输入保留，修改输入后可以重跑。失败边界由 --negative 单独演示。
"""
from pathlib import Path
import sys, json, csv, math, io, hashlib, html, base64, re
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
BASE = Path(__file__).resolve().parent
NEG = '--negative' in sys.argv
def write(name, value):
    p=BASE/name; p.parent.mkdir(parents=True,exist_ok=True)
    if isinstance(value,bytes): p.write_bytes(value)
    else: p.write_text(value,encoding='utf-8',newline='')
def seed(name,value):
    if not (BASE/name).exists(): write(name,value)
def jwrite(name,value): write(name,json.dumps(value,ensure_ascii=False,indent=2))
def jseed(name,value):
    if not (BASE/name).exists(): jwrite(name,value)
def load(name): return json.loads((BASE/name).read_text(encoding='utf-8'))
def table(name,heads,rows):
    f=io.StringIO(newline='');w=csv.writer(f);w.writerow(heads);w.writerows(rows);write(name,f.getvalue())
def page(name,title,body):
    write(name,'<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>'+html.escape(title)+'</title><style>body{max-width:1000px;margin:2rem auto;padding:0 1rem;font:17px/1.7 system-ui}table{border-collapse:collapse}td,th{border:1px solid #aaa;padding:.5rem}pre{white-space:pre-wrap;overflow-wrap:anywhere}img,svg{max-width:100%;height:auto}a{color:#125caa}</style><h1>'+html.escape(title)+'</h1>'+body+'</html>')
def emit(data): print(json.dumps(data,ensure_ascii=False))

urls=['https://ai.google.dev/gemini-api/docs/url-context','https://ai.google.dev/gemini-api/docs/files','https://ai.google.dev/gemini-api/docs/video-understanding']
jseed('url-context-fixture.json',{'fixture_only':True,'requested_urls':urls,'steps':[{'type':'url_context_result','url':urls[0],'status':'success'},{'type':'url_context_result','url':urls[1],'status':'unsafe'},{'type':'model_output','content':[{'type':'text','text':'合成摘要只演示有来源与缺材料的区别。','annotations':[{'type':'url_citation','url':urls[0],'title':'URL context 官方说明'}]}]}]});d=load('url-context-fixture.json')
if NEG:d['steps']=[s for s in d['steps'] if s['type']!='url_context_result']
attempts={s['url']:s['status'] for s in d['steps'] if s['type']=='url_context_result'};citations={a['url'] for s in d['steps'] for c in s.get('content',[]) for a in c.get('annotations',[]) if a['type']=='url_citation'};rows=[[u,attempts.get(u,'not_attempted'),u in citations,'材料仍需人工核对' if attempts.get(u)=='success' else '缺材料，不能比较'] for u in d['requested_urls']]
table('source-coverage.csv',['url','retrieval_status','cited','comparison_limit'],rows);page('source-coverage.html','输入来源覆盖表','<p>所有状态为原创合成夹具；没有实际联网读取。检索成功不保证全文都读到。</p><table><tr><th>输入URL</th><th>状态</th><th>引用</th><th>结论边界</th></tr>'+''.join('<tr>'+''.join('<td>'+html.escape(str(x))+'</td>' for x in r)+'</tr>' for r in rows)+'</table>');emit({'coverage':rows,'missing_materials':sum(r[1]!='success' for r in rows)})
