"""A1 · muestra del cotejo manual (30 contratos válidos): orden md5('cotejo-a1'||source||'|'||id_canonical); 15 de vía L (si hay menos, todas) y el resto de vía R; como mucho 2 por órgano. Escribe priv/35_cotejo_muestra.txt (con objeto y fragmento del texto: 700) para que el coordinador compruebe a mano cantidad, unidad, producto (y periodo y tipo de importe en L).""" import duckdb, hashlib, csv, collections, re, os con = duckdb.connect() k = con.execute("""SELECT c.source, c.id_canonical, c.organo_clave, c.via, c.producto, c.cantidad_total, c.imp, c.razon, a.objeto, a.cant_v2, a.literal_v2, a.duracion_meses FROM read_csv_auto('/p/priv/30_contratos_calculo.csv') c JOIN read_parquet('/p/priv/a1_base.parquet') a USING (source, id_canonical) WHERE c.valido AND a.mercado='carburantes'""").fetchall() h = lambda r: hashlib.md5(f'cotejo-a1{r[0]}|{r[1]}'.encode()).hexdigest() k.sort(key=h); sel = []; por = collections.Counter() for via, cupo in (('L', 15), ('R', 30)): for r in k: if len(sel) >= 30 or (via == 'L' and sum(x[3] == 'L' for x in sel) >= cupo): break if r[3] == via and por[r[2]] < 2: sel.append(r); por[r[2]] += 1 lec = {(r['source'], r['id_canonical']): r for r in csv.DictReader(open('/p/priv/lectura_final.csv'))} if os.path.exists('/p/priv/lectura_final.csv') else {} with open('/p/priv/35_cotejo_muestra.txt', 'w') as f: for i, r in enumerate(sel, 1): f.write(f"\n##### {i} · vía {r[3]} · {r[4]} · cantidad_total {r[5]} · razón {r[7]:.3f} · dur {r[11]}\nOBJETO: {r[8]}\n") if r[3] == 'R': f.write(f'LITERAL REGLA: {r[9]} ← «{r[10]}»\n') else: l = lec[(r[0], r[1])]; f.write(f"LECTURA: {dict((x, l[x]) for x in ('caso','lote','producto','cantidad','unidad','periodo','importe_tipo','via'))}\n") t = open(f"/p/lectura/textos/{l['caso']}.txt", encoding='utf-8').read() cant = float(l['cantidad']); pats = {f'{int(cant):,}'.replace(',', '.'), str(int(cant)), f'{int(cant):,}'} for p in pats: for m in list(re.finditer(re.escape(p), t))[:2]: f.write('…' + t[max(0, m.start() - 400):m.end() + 300].replace('\n', ' ') + '…\n') print('cotejo', len(sel), collections.Counter(x[3] for x in sel))