The whole engine is ~250 lines of plain Python — no framework, no platform. run.py queries the engines and saves a dated snapshot; report.py turns snapshots into the weekly action report. Open any file raw below.
Links open the raw source in your browser. run.py is shown in full below.
#!/usr/bin/env python3
"""GIG AI-Visibility runner. Asks a prompt set across answer engines, detects whether
GIG Gulf (and competitors) get cited, scores by GEO phase, saves a dated snapshot.
Action-first weekly report is generated by report.py from the saved snapshots."""
import json, os, re, sys, time, datetime, urllib.request, concurrent.futures as cf
ROOT = os.path.dirname(os.path.abspath(__file__))
CRED = os.path.expanduser("~/ClaudeWork/Claude/credentials.md")
def key(section, pat):
f=False
for l in open(CRED, errors="ignore"):
if l.startswith("### "+section): f=True; continue
if f and re.search(pat, l):
m=re.search(pat, l); return m.group(0)
return None
ANTH = key("Anthropic API", r"sk-ant-[A-Za-z0-9_-]{20,}")
OAI = key("OpenAI", r"sk-[A-Za-z0-9_-]{20,}")
SERP = key("Serper", r"[a-f0-9]{40}")
# GIG Gulf is the rebrand of AXA Gulf (UAE, 2022). AXA legacy equity is OWNED demand --
# AXA queries deliver up to ~25% of GIG GWP, so an "AXA" mention counts as GIG-favourable.
GIG = [r"gig gulf", r"giggulf", r"gig insurance", r"gulf insurance group", r"gig-gulf", r"\baxa\b"]
COMP = {"Sukoon":[r"sukoon","oman insurance"],"Tawuniya":["tawuniya"],"Salama":["salama"],
"Orient":["orient insurance"],"Watania":["watania"],"Daman":["daman"],
"ADNIC":["adnic"],"RSA/Liva":["liva","rsa "],"Dubai Insurance":["dubai insurance"],
"Noor Takaful":["noor takaful"],"Yallacompare":["yallacompare","policybazaar"]}
def mentioned(text, pats):
t=text.lower()
return any(re.search(p, t) for p in pats)
def comp_hits(text):
return [c for c,pats in COMP.items() if mentioned(text,pats)]
def http(url, data, headers, timeout=30):
req=urllib.request.Request(url, data=json.dumps(data).encode(), headers=headers)
with urllib.request.urlopen(req, timeout=timeout) as r: return json.loads(r.read())
def ask_openai(q):
d=http("https://api.openai.com/v1/chat/completions",
{"model":"gpt-4o-mini","max_tokens":400,"messages":[
{"role":"system","content":"You are an insurance shopping assistant for the UAE. Name specific insurers and brands."},
{"role":"user","content":q}]},
{"Authorization":f"Bearer {OAI}","Content-Type":"application/json"})
return d["choices"][0]["message"]["content"]
def ask_claude(q):
d=http("https://api.anthropic.com/v1/messages",
{"model":"claude-haiku-4-5-20251001","max_tokens":400,"messages":[
{"role":"user","content":"You are an insurance shopping assistant for the UAE. Name specific insurers and brands.\n\n"+q}]},
{"x-api-key":ANTH,"anthropic-version":"2023-06-01","content-type":"application/json"})
return d["content"][0]["text"]
def ask_google(q):
d=http("https://google.serper.dev/search",{"q":q,"gl":"ae","num":10},
{"X-API-KEY":SERP,"Content-Type":"application/json"})
parts=[]
if "answerBox" in d: parts.append(json.dumps(d["answerBox"]))
for o in d.get("organic",[])[:10]:
parts.append(o.get("title","")+" "+o.get("link","")+" "+o.get("snippet",""))
return "\n".join(parts)
ENGINES={"ChatGPT":ask_openai,"Claude":ask_claude,"Google":ask_google}
def run_one(p, eng):
try:
txt=ENGINES[eng](p["q"])
return {"id":p["id"],"phase":p["phase"],"lob":p["lob"],"q":p["q"],"engine":eng,
"gig":mentioned(txt,GIG),"competitors":comp_hits(txt),"ok":True,"text":txt[:1200]}
except Exception as e:
return {"id":p["id"],"phase":p["phase"],"lob":p["lob"],"q":p["q"],"engine":eng,
"gig":None,"competitors":[],"ok":False,"err":str(e)[:200]}
def main():
prompts=json.load(open(os.path.join(ROOT,"prompts.json")))
jobs=[(p,e) for p in prompts for e in ENGINES]
rows=[]
with cf.ThreadPoolExecutor(max_workers=12) as ex:
futs=[ex.submit(run_one,p,e) for p,e in jobs]
for f in cf.as_completed(futs): rows.append(f.result())
date=datetime.date.today().isoformat()
os.makedirs(os.path.join(ROOT,"snapshots"),exist_ok=True)
out=os.path.join(ROOT,"snapshots",date+".json")
json.dump({"date":date,"rows":rows},open(out,"w"),indent=1)
ok=[r for r in rows if r["ok"]]
gig=sum(1 for r in ok if r["gig"]); n=len(ok)
print("saved",out,"|",n,"ok |","GIG",gig,"/",n)
if __name__=="__main__": main()
cd ~/ClaudeWork/Clients/GIG/AIVisibility python3 run.py # probes the engines, writes snapshots/YYYY-MM-DD.json python3 report.py # builds weekly-report.html from the snapshots
Roadmap (the ladder, R1→R2): add Perplexity + Gemini callers next to the three above, wrap each prompt in n≥3 sampling, capture the cited URLs, and ingest GIG CDN logs. Same shape, ~80 more lines.