2 Commits

Author SHA1 Message Date
fahricansecer 15c6313246 Merge branch 'main' of https://gitea.bilgich.com/fahricansecer/iddaai-be
Deploy Iddaai Backend / build-and-deploy (push) Successful in 54s
2026-05-24 02:44:52 +03:00
fahricansecer 1b420a425e Update .gitignore 2026-05-24 02:43:10 +03:00
6 changed files with 937 additions and 1 deletions
+4 -1
View File
@@ -21,7 +21,10 @@ venv/
env/ env/
# Database / Docker Volumes # Database / Docker Volumes
data/ /data/
ai-engine/data/**/*.csv
ai-engine/data/v26_shadow/
ai-engine/data/__pycache__/
postgres-data/ postgres-data/
redis-data/ redis-data/
+1
View File
@@ -0,0 +1 @@
# data package
+97
View File
@@ -0,0 +1,97 @@
"""
Async Database Module — V2 Betting Engine
==========================================
Provides async SQLAlchemy sessions via asyncpg for the V2 router.
Usage:
async with get_session() as session:
result = await session.execute(text("SELECT ..."))
"""
from __future__ import annotations
import os
from contextlib import asynccontextmanager
from typing import AsyncGenerator
from dotenv import load_dotenv
from sqlalchemy.ext.asyncio import (
AsyncEngine,
AsyncSession,
async_sessionmaker,
create_async_engine,
)
load_dotenv()
_engine: AsyncEngine | None = None
_session_maker: async_sessionmaker[AsyncSession] | None = None
def _get_async_dsn() -> str:
"""
Convert DATABASE_URL to asyncpg-compatible format.
Handles:
1. Prisma's ``?schema=public`` suffix → stripped
2. ``postgresql://`` driver prefix → ``postgresql+asyncpg://``
"""
dsn = os.getenv(
"DATABASE_URL",
"postgresql://suggestbet:SuGGesT2026SecuRe@localhost:15432/boilerplate_db",
)
# Strip Prisma's ?schema= parameter
if "?" in dsn:
base, query = dsn.split("?", 1)
kept_parts = [
part for part in query.split("&") if part and not part.startswith("schema=")
]
dsn = base if not kept_parts else f"{base}?{'&'.join(kept_parts)}"
# Convert driver prefix for asyncpg
if dsn.startswith("postgresql://"):
dsn = dsn.replace("postgresql://", "postgresql+asyncpg://", 1)
elif dsn.startswith("postgres://"):
dsn = dsn.replace("postgres://", "postgresql+asyncpg://", 1)
return dsn
def _ensure_engine() -> AsyncEngine:
global _engine, _session_maker
if _engine is None:
_engine = create_async_engine(
_get_async_dsn(),
pool_size=5,
max_overflow=5,
pool_timeout=10,
pool_pre_ping=True,
echo=False,
)
_session_maker = async_sessionmaker(
bind=_engine,
class_=AsyncSession,
expire_on_commit=False,
)
print("✅ Async database engine created (asyncpg)")
return _engine
@asynccontextmanager
async def get_session() -> AsyncGenerator[AsyncSession, None]:
"""Provide an async session context manager."""
_ensure_engine()
assert _session_maker is not None
async with _session_maker() as session:
yield session
async def dispose_engine() -> None:
"""Shut down the async engine cleanly."""
global _engine, _session_maker
if _engine is not None:
await _engine.dispose()
_engine = None
_session_maker = None
print("️ Async database engine disposed")
+92
View File
@@ -0,0 +1,92 @@
"""
Synchronous psycopg2 database helper for the AI Engine.
Uses a thread-safe connection pool for legacy V20+ endpoints.
"""
from __future__ import annotations
import os
from contextlib import contextmanager
from typing import Generator
import psycopg2
from psycopg2 import pool
from psycopg2.extensions import connection as PgConnection
from dotenv import load_dotenv
load_dotenv()
# Safe default with no credentials — will fail fast if not configured.
_DEFAULT_DSN = "postgresql://postgres:postgres@localhost:15432/boilerplate_db"
def get_clean_dsn() -> str:
"""
Return a psycopg2-compatible DSN from DATABASE_URL.
Handles DSN cleanup issues that break raw usage:
1. Prisma appends '?schema=public' which psycopg2 cannot parse.
"""
dsn: str = os.getenv("DATABASE_URL", _DEFAULT_DSN)
connect_timeout: str = os.getenv("PGCONNECT_TIMEOUT", "5").strip() or "5"
# Strip Prisma's ?schema= query parameter while preserving any other query args.
if "?" in dsn:
base, query = dsn.split("?", 1)
kept_parts: list[str] = [
part for part in query.split("&") if part and not part.startswith("schema=")
]
dsn = base if not kept_parts else f"{base}?{'&'.join(kept_parts)}"
# Force bounded DB connect attempts so API calls do not hang indefinitely.
if "connect_timeout=" not in dsn:
separator = "&" if "?" in dsn else "?"
dsn = f"{dsn}{separator}connect_timeout={connect_timeout}"
return dsn
class Database:
_pool: pool.ThreadedConnectionPool | None = None
@classmethod
def initialize(cls) -> None:
if cls._pool is None:
dsn: str = get_clean_dsn()
try:
cls._pool = pool.ThreadedConnectionPool(
minconn=1,
maxconn=10,
dsn=dsn,
)
print("✅ Database connection pool created")
except Exception as e:
print(f"❌ Failed to create DB pool: {e}")
raise
@classmethod
def get_conn(cls) -> PgConnection:
if cls._pool is None:
cls.initialize()
assert cls._pool is not None # guaranteed by initialize()
return cls._pool.getconn()
@classmethod
def return_conn(cls, conn: PgConnection) -> None:
if cls._pool:
cls._pool.putconn(conn)
@classmethod
@contextmanager
def connection(cls) -> Generator[PgConnection, None, None]:
"""Context manager for safe connection handling."""
conn: PgConnection = cls.get_conn()
try:
yield conn
finally:
cls.return_conn(conn)
@classmethod
def close_all(cls) -> None:
if cls._pool:
cls._pool.closeall()
print("️ Database connection pool closed")
+726
View File
@@ -0,0 +1,726 @@
{
"version": "v1",
"description": "Per-league odds reliability scores computed from Brier Score analysis",
"min_matches_threshold": 50,
"total_leagues": 265,
"default_reliability": 0.35,
"lookup": {
"bx57cmq1edfq53ckfk791supi": 0.9476,
"55hcphd1ccc6eai1ms77460on": 0.9445,
"d9eaigzyfnfiraqc3ius757tl": 0.9402,
"1gxlzw2ezkyeykhcaa5x8ozkk": 0.9259,
"5jd0k2txwnq69frs79eulba8j": 0.9233,
"6694fff47wqxl10lrd9tb91f8": 0.9193,
"4jg7he1n3rb5dniq6hf49xorq": 0.9061,
"59tpnfrwnvhnhzmnvfyug68hj": 0.8988,
"ac42gi3penartj88fe9l6plpk": 0.8937,
"3j81qr7yc4gdnakfwnxf95ovh": 0.8771,
"9z5643nd06afqu01ea2wt8y4g": 0.8734,
"482ofyysbdbeoxauk19yg7tdt": 0.8722,
"ahl3vljaignq9ebaos4uqkrvo": 0.8696,
"8x3sbh85gc8qir50utw39jl04": 0.865,
"agpweohvn9tugnyl6ry4rhivp": 0.8428,
"4c1nfi2j1m731hcay25fcgndq": 0.8425,
"1j4ehtrbry9depwt6oghaq3lu": 0.8299,
"40yjcbx2sq6oq736iqqqczwt1": 0.8237,
"145hkd59i6foieuwr4mwi6wlq": 0.823,
"34pl8szyvrbwcmfkuocjm3r6t": 0.8227,
"cse5oqqt2pzfcy8uz6yz3tkbj": 0.8212,
"zs18qaehvhg3w1208874zvfa": 0.8176,
"57nu0wygurzkp6fuy5hhrtaa2": 0.8099,
"1eruend45vd20g9hbrpiggs5u": 0.8083,
"595nsvo7ykvoe690b1e4u5n56": 0.7987,
"6vq8j5p3av14nr3iuyi4okhjt": 0.793,
"486rhdgz7yc0sygziht7hje65": 0.7901,
"9hh6n2f84k31zmlcxyvmc1w2y": 0.789,
"3n5046abeu3x482ds3jwda238": 0.7863,
"8yi6ejjd1zudcqtbn07haahg6": 0.7752,
"byhmntnl1b4lxw0zz21im3zkd": 0.7719,
"2bmwykmdlcc2u1c40ytoc39vy": 0.7668,
"82jkgccg7phfjpd0mltdl3pat": 0.7643,
"2nttcoriwf5co73vmz1vr8frm": 0.7641,
"dr2xk7muj8aqcjdz2b3li1c0k": 0.759,
"4yngyfinzd6bb1k7anqtqs0wt": 0.7586,
"eog6knrkfei68si736fpquyzc": 0.756,
"eg6s9f1jj7jr6stmbosn0g6c8": 0.7538,
"ae1wva3zrzcp2zd15gpvsntg6": 0.7517,
"cesdwwnxbc5fmajgroc0hqzy2": 0.7466,
"8k1xcsyvxapl4jlsluh3eomre": 0.7463,
"bdtat25m14jy85y484z3e6lf": 0.7437,
"iu1vi94p4p28oozl1h9bvplr": 0.7411,
"1r097lpxe0xn03ihb7wi98kao": 0.7391,
"2kwbbcootiqqgmrzs6o5inle5": 0.7386,
"9fuwphq8kvugrlc3ckm7k8wes": 0.7358,
"civf31q1inxohs4a03y8reetf": 0.735,
"ili150pwfuf39f7yfdch9lhw": 0.7286,
"abs7n2ae3oydilk0tgmpnsj89": 0.7277,
"9nbpdi9q3ywcm4q0j5u0ekwcq": 0.7254,
"6by3h89i2eykc341oz7lv1ddd": 0.7252,
"4qehj8hfxmy6o2ohp4fxinnzo": 0.7244,
"9u4pm8x0lfmfq3r0pypmrls71": 0.7244,
"c7b8o53flg36wbuevfzy3lb10": 0.7144,
"89ovpy1rarewwzqvi30bfdr8b": 0.7068,
"4d5d3sf6805n5u6jdoa0hdlog": 0.7052,
"eqz64pn0qsp2y7aq4m9id3fn6": 0.7031,
"8q60vlvn3krynkob6igrncdjq": 0.703,
"6ihotpaocgiovlxw18e9r9prx": 0.7019,
"c0r21rtokgnbtc0o2rldjmkxu": 0.7013,
"1mpjd0vbxbtu9zw89yj09xk3z": 0.6996,
"4zwgbb66rif2spcoeeol2motx": 0.6995,
"bu1l7ckihyr0errxw61p0m05": 0.6995,
"cv3tuitw3ho3v0opjjxpn83b9": 0.6974,
"8r98daokeuzsamu5fmjtblqx5": 0.6922,
"dvstmwnvw0mt5p38twn9yttyb": 0.688,
"8y29fg2s85ppcb8uugm5ee8s4": 0.6866,
"19q13y6ruzo0o84ipblcuouzs": 0.6858,
"f4jc2cc5nq7flaoptpi5ua4k4": 0.6852,
"4oogyu6o156iphvdvphwpck10": 0.684,
"3e40pestup9xzagsu2o6c0i8u": 0.6824,
"4rls982p5uzil6x30mhyhv9f3": 0.6812,
"e21cf135btr8t3upw0vl6n6x0": 0.6771,
"65q4uwm6ol1rkf5dp89m8omny": 0.6754,
"46b141eaqq9q7o4gz5gtdpikk": 0.6752,
"75i269i1ak43magshljadydrh": 0.6741,
"3ab1uwtoyjopdj1y1fynyy9jg": 0.6737,
"4mbfidy8zum5u0aqjqo0vuqs2": 0.673,
"7wssxdqi4xihseeam8grqa2b8": 0.666,
"61fzfjogstjuukzcehighq7mu": 0.6641,
"6g8hw3acenrw828la7gwx4mvs": 0.663,
"e1kxdivp5g4cpldgpwvnzl1vv": 0.6626,
"9ikchyu9fb8bvx0s673jofj6s": 0.6622,
"a9vrdkelbgif0gtu3wxsr75xo": 0.6618,
"6sxm2iln2w45ux498pty9miw8": 0.6615,
"ea0h6cf3bhl698hkxhpulh2zz": 0.661,
"apdwh753fupxheygs8seahh7x": 0.6604,
"er5745q30wnr8jv9nr863omzg": 0.659,
"2z7257m7hj58zuxcjrsg4erzc": 0.6551,
"2o9svokc5s7diish3ycrzk7jm": 0.655,
"8usjlmziv3p2re0r2wwzezki9": 0.6549,
"c0yqkbilbbg70ij2473xymmqv": 0.6506,
"du6jsenbjql5e8f3yk880ox4g": 0.6494,
"cbdbziaqczfuyuwqsylqi26zd": 0.6478,
"725gd73msyt08xm76v7gkxj7u": 0.6445,
"enzlj1as2raqm4ids1zyb07y1": 0.6442,
"scf9p4y91yjvqvg5jndxzhxj": 0.6414,
"5z8v4mj6cjs9ex6hdrpourjzh": 0.6389,
"4zwjlzdszduqmxzusysvzymms": 0.6387,
"7nmz249q89qg5ezcvzlheljji": 0.6381,
"2mdmx668tyhy4u4z9zszwjv5v": 0.6345,
"4a7o9rf7ytl8g3ejwpblc6p5n": 0.6306,
"2ty8ihceabty8yddmu31iuuej": 0.6283,
"dy8zaksw5e9nwrs1p5ss4o1nu": 0.628,
"1b70m6qtxrp75b4vtk8hxh8c3": 0.6261,
"ajxs0e0g6ryg5ol8qvw3evrcz": 0.6249,
"a4fgj2rfbpf4ejo1qi624fefo": 0.6184,
"akmkihra9ruad09ljapsm84b3": 0.6182,
"907l7wtxdvugdo9i2249wcmr0": 0.6171,
"6lwpjhktjhl9g7x2w7njmzva6": 0.6164,
"ax1yf4nlzqpcji4j8epdgx3zl": 0.6163,
"6ybvtzejh91761lqe7y1csrqo": 0.6158,
"3btdfgw79qiz3jmyfudovtbu2": 0.6122,
"5cwsxtx37les6m10xj71htkgf": 0.6101,
"9p3nnxhdjahfn8qswpzy8oyc3": 0.61,
"2xg0qvif1rh7du6wmk2eleku3": 0.6091,
"1wwro3z1eb3fl601dju6inlc6": 0.6084,
"gfskxsdituog2kqp9yiu7bzi": 0.6076,
"zilopfej2h0n3vpan5tcynpo": 0.6051,
"2hsidwomhjsaaytdy9u5niyi4": 0.6012,
"1klyfth8tl6lu6ra7k8zmy2n2": 0.5996,
"cegl2ivkc25blcatxp4jmk1ec": 0.5993,
"7qf0jaayyxy3ruamsexv5p1kl": 0.5988,
"erpufio3qaujd9gkszcqvb0bf": 0.5972,
"cfesxhzb83yl8b779uv3revz1": 0.597,
"3ww12jab49q8q8mk9avdwjqgk": 0.5961,
"8t2o4huu2e48ij23dxnl9w5qx": 0.5928,
"5vq1bl8h8dxdr34w0jaanokto": 0.5919,
"ac112osli9fvox1epcg4ld3t6": 0.59,
"3frp1zxrqulrlrnk503n6l4l": 0.5808,
"c76z5d6j7dpi1e79tm8fpm39z": 0.5807,
"6ifaeunfdelecgticvxanikzu": 0.5796,
"81txfenlgw75nq3u2nfdkj92o": 0.5789,
"yv73ms6v1995b5wny16jcfi3": 0.5787,
"b3ufcd24wfnnd5j98ped6irfu": 0.5752,
"29actv1ohj8r10kd9hu0jnb0n": 0.5737,
"bfqezwfhot1l3p1cpk4oonh25": 0.5705,
"5taraea6mqjjldg9zxswo825y": 0.5696,
"7qdv1xae7ikfe8dft3oj29yqc": 0.5692,
"dm5ka0os1e3dxcp3vh05kmp33": 0.5678,
"ay4u6j7lfkcg7x21mx5q121j": 0.5676,
"7af85xa75vozt2l4hzi6ryts7": 0.5663,
"5k620c7y6dlbmcm88dt3eb7t": 0.5644,
"ejunkmfhjz9weugd2bqrkgobb": 0.564,
"3428tckxcirwwh3o3jgc1m8ji": 0.5597,
"d6zovb8puwgcmsg91iya6rbtm": 0.5593,
"2wolc27r8z03itcvwp43e38c5": 0.5592,
"alpfd99yd3lfv7bhjo0biuq7b": 0.5582,
"beqqnubkv05mamuwvimeum015": 0.5577,
"4w7x0s5gfs5abasphlha5de8k": 0.5558,
"9ynnnx1qmkizq1o3qr3v0nsuk": 0.554,
"722fdbecxzcq9788l6jqclzlw": 0.5539,
"287tckirbfj9nb8ar2k9r60vn": 0.5529,
"esrunz7rjb0td98mx9e5cedoy": 0.5516,
"32n2r9bl6x90psj0wa7bfs6vq": 0.5487,
"50ap4sua1xyut3mpu7ehesp63": 0.5483,
"5c96g1zm7vo5ons9c42uy2w3r": 0.5469,
"3p81ltz6845appgkbgkzxueii": 0.5454,
"3n9mk5b2mxmq831wfmv6pu86i": 0.5437,
"5zr0b05eyx25km7z1k03ca9jx": 0.5424,
"1owhvvge4wlx7e0e431b4vhqx": 0.5423,
"3iwftmprsznl6yribr11a8l9m": 0.5393,
"7r1f93t6ddrsa5n8v1nq6qlzm": 0.5393,
"1gwajyt0pk2jm5fx5mu36v114": 0.5389,
"581t4mywybx21wcpmpykhyzr3": 0.5388,
"6wubmo7di3kdpflluf6s8c7vs": 0.5375,
"bq89wbdvedtov6auzuh6rsv7s": 0.5363,
"byu00jvt1j6csyv4y1lkt2fm2": 0.5359,
"af79lqrc0ntom74zq13ccjslo": 0.5357,
"3ri6juw2w6ma0jezszdlv1uqm": 0.5356,
"3l29w00m506ex93t5bbh9cg2a": 0.5355,
"1zp1du9n4rj36p1ss9zbxtqfb": 0.5353,
"9chuiarcjofld1dkj9kysehmb": 0.5346,
"5aw6uyw4pz2bpj24t5z8aacim": 0.5333,
"by5nibd18nkt40t0j8a0j5yzx": 0.5332,
"4yzidekywejmxxp77gqmdgopg": 0.5323,
"7ntvbsyq31jnzoqoa8850b9b8": 0.5305,
"a7247po5qs29o3zsfmt222ydu": 0.5299,
"117yqo02rs8dykkxpm274w3bd": 0.5298,
"193wqkyb0v5jnsblhvd2ocmyo": 0.5296,
"8jh0jejuxfhrpawnoztz2jlv4": 0.5295,
"5y0z0l2epprzbscvzsgldw8vu": 0.5288,
"47s2kt0e8m444ftqvsrqa3bvq": 0.5268,
"2hj3286pqov1g1g59k2t2qcgm": 0.5245,
"7swf4kpu3v38i2it4h94c5s9k": 0.5227,
"78wml3z5wrfxe5iky50tiotgu": 0.5196,
"f39uq10c8xhg5e6rwwcf6lhgc": 0.5186,
"bbajzna018c79opa1kl5kmkqo": 0.5172,
"4davonpqws4a4ejl1awu98zdg": 0.5168,
"1fedahp0rws09tj451onten8r": 0.5163,
"aho73e5udydy96iun3tkzdzsi": 0.5149,
"3aa4mumjl6zyetg6o9hwd5hhx": 0.5125,
"7cwemnr3vi40znjq451zxkus6": 0.5115,
"ajm86skyzse4ym8g6fpgzncxa": 0.5112,
"bgen5kjer2ytfp7lo9949t72g": 0.5102,
"8ey0ww2zsosdmwr8ehsorh6t7": 0.51,
"8najqkluatpaxvqws78b9s17c": 0.5082,
"8v97rcbthsxmzqk4ufxws9mug": 0.506,
"degxm4y6gmvp011ccyrev6z5p": 0.5049,
"3oa9e03e7w9nr8kqwqc3tlqz9": 0.5049,
"5dycj9wdhxh3n33qubw18ohlk": 0.5036,
"3is4bkgf3loxv9qfg3hm8zfqb": 0.5033,
"f47f3717z2vtpxfxrpdd4jl1x": 0.498,
"8ivsfwex4dfx1tvgsiq8askcx": 0.4972,
"8vbck9a4mxjms783lf72779uu": 0.4946,
"aql5z4osw5wmun0emnakfpwji": 0.4946,
"e6vzdkz6l236s9p288mharefy": 0.4925,
"4nidzmunvpvxk1ir9b6m8mpay": 0.4874,
"ein4fkggto3pdh5msp8huafiq": 0.4856,
"1q4ab2bpg5e8jl1g2udnakrju": 0.4852,
"8ztsv3pzrsyq5w1r3a0nfk1y5": 0.4842,
"1qd0wvt30rlswa4g6nu4na660": 0.4826,
"jznihqxle06xych9ygwiwnsa": 0.4796,
"2y8bntiif3a9y6gtmauv30gt": 0.4782,
"477yyajzheg2z8u7uick0e13e": 0.4706,
"bockl24qpr7ryjl8b6obukga": 0.4671,
"7mxwwunvot2pi69pj1yr1kh8i": 0.466,
"3w1hkk9k9gr8fwssyn4icvdfo": 0.4657,
"1txej2dzohnydl21zc9pgx6hy": 0.464,
"b8rae0ib0frjmwlca429bq19q": 0.4624,
"b5udgm9vakjqz8dcmy5b2g0xt": 0.4582,
"eitf7hulqfv1clb7toewkil24": 0.458,
"7hl0svs2hg225i2zud0g3xzp2": 0.4559,
"2aso72utuctat2ecs6nahjss6": 0.4521,
"3ymqchdzk8tt6lfphf26xfvh0": 0.4519,
"2yyjcbbryf1r10apyzl7c7jvp": 0.4507,
"bly7ema5au6j40i0grhl0pnub": 0.4476,
"b1rveez5u792gess9w3e7v5le": 0.4444,
"8sdpk4aerruf515yh76ezo7vi": 0.4434,
"32vph7vcjqgo1ksj1548di90n": 0.44,
"65ggsqdi6drpa4m8y3gkll25k": 0.4394,
"xaouuwuk8qyhv1libkeexwjh": 0.4347,
"6qitd9h242qkvjenaytfdnsf2": 0.4312,
"duuc1qczfnawwncru1ly6o66": 0.4213,
"b60nisd3qn427jm0hrg9kvmab": 0.4203,
"xwnjb1az11zffwty3m6vn8y6": 0.4197,
"dkarmrybx9vx10rg7cywumth0": 0.4158,
"75434tz9rc14xkkvudex742ui": 0.4137,
"c1d9p6b2e9zr5tqlzx3ktjplg": 0.4129,
"b73zounsynk9d3u1p9nvpu7i2": 0.4049,
"913mb508il6jzwtlj28fl892h": 0.4044,
"e0lck99w8meo9qoalfrxgo33o": 0.401,
"8dn0w8zh7nbn2i904603eigwf": 0.3984,
"ddyrh5latwfhesgfh4w401n92": 0.3973,
"avs3xposm3t9x1x2vzsoxzcbu": 0.3957,
"eu2g5j36zzxiazpd729osx0wm": 0.3924,
"67uya58idol2eq18ljecsru5o": 0.3912,
"23e698ls3x6vi9x8wl0mz7bsa": 0.3838,
"6321dlqv4ziuwqte4xpohijtw": 0.382,
"8o5tv5viv4hy1qg9jp94k7ayb": 0.381,
"53tknno09wqihmwxrqcuwq9sa": 0.3782,
"82wo38rqeizxlfjjhfjy4rx7u": 0.3781,
"dvtl8sf1262pd2aqgu641qa7u": 0.3767,
"663a54fmymndjeev47qm7d3nf": 0.3522,
"macko16888165594668885588": 0.3309,
"macko16698982162572521585": 0.3262,
"6lkj3o21cr4g7bql6tb3fk222": 0.3261,
"cu0rmpyff5692eo06ltddjo8a": 0.3161,
"1cnx2c8g3hhp8ssxnwwli0mjb": 0.3121,
"4vt0ldrcl6thpxpcs8zmpdq1g": 0.2926,
"etta63x1t7tnkn4jheisjwk4p": 0.2907,
"1n9l0ex47bu0762qg574hzjtd": 0.2626,
"6jgwiu2gq3dllmrwt45pfdn2z": 0.2416,
"392slbmf1kdqlr6sd1ckt71rs": 0.24,
"8z3180hhw2pj1i65uftlk54uz": 0.2096
},
"details": [
{
"league_id": "bx57cmq1edfq53ckfk791supi",
"league_name": "CAF Konfederasyon Kupası",
"match_count": 98,
"brier_score": 0.3046,
"heavy_fav_win_pct": 84.1,
"fav_win_pct": 63.3,
"odds_reliability": 0.9476
},
{
"league_id": "55hcphd1ccc6eai1ms77460on",
"league_name": "Şampiyonlar Ligi Kadınlar",
"match_count": 89,
"brier_score": 0.3258,
"heavy_fav_win_pct": 83.3,
"fav_win_pct": 74.2,
"odds_reliability": 0.9445
},
{
"league_id": "d9eaigzyfnfiraqc3ius757tl",
"league_name": "Kupa",
"match_count": 78,
"brier_score": 0.3141,
"heavy_fav_win_pct": 81.2,
"fav_win_pct": 73.1,
"odds_reliability": 0.9402
},
{
"league_id": "1gxlzw2ezkyeykhcaa5x8ozkk",
"league_name": "Concacaf Orta Amerika Kupası",
"match_count": 88,
"brier_score": 0.3338,
"heavy_fav_win_pct": 79.4,
"fav_win_pct": 61.4,
"odds_reliability": 0.9259
},
{
"league_id": "5jd0k2txwnq69frs79eulba8j",
"league_name": "Kupa",
"match_count": 69,
"brier_score": 0.3223,
"heavy_fav_win_pct": 78.4,
"fav_win_pct": 66.7,
"odds_reliability": 0.9233
},
{
"league_id": "6694fff47wqxl10lrd9tb91f8",
"league_name": "Kupa",
"match_count": 55,
"brier_score": 0.3099,
"heavy_fav_win_pct": 78.8,
"fav_win_pct": 67.3,
"odds_reliability": 0.9193
},
{
"league_id": "4jg7he1n3rb5dniq6hf49xorq",
"league_name": "Premier Lig",
"match_count": 79,
"brier_score": 0.3333,
"heavy_fav_win_pct": 77.1,
"fav_win_pct": 64.6,
"odds_reliability": 0.9061
},
{
"league_id": "59tpnfrwnvhnhzmnvfyug68hj",
"league_name": "Libertadores Kupası",
"match_count": 180,
"brier_score": 0.3408,
"heavy_fav_win_pct": 76.2,
"fav_win_pct": 61.7,
"odds_reliability": 0.8988
},
{
"league_id": "ac42gi3penartj88fe9l6plpk",
"league_name": "Premier Lig",
"match_count": 185,
"brier_score": 0.3148,
"heavy_fav_win_pct": 70.7,
"fav_win_pct": 68.1,
"odds_reliability": 0.8937
},
{
"league_id": "3j81qr7yc4gdnakfwnxf95ovh",
"league_name": "Premier Lig",
"match_count": 106,
"brier_score": 0.333,
"heavy_fav_win_pct": 72.2,
"fav_win_pct": 60.4,
"odds_reliability": 0.8771
},
{
"league_id": "9z5643nd06afqu01ea2wt8y4g",
"league_name": "Kuu Bara Ligi",
"match_count": 110,
"brier_score": 0.3294,
"heavy_fav_win_pct": 70.3,
"fav_win_pct": 53.6,
"odds_reliability": 0.8734
},
{
"league_id": "482ofyysbdbeoxauk19yg7tdt",
"league_name": "Trendyol Süper Lig",
"match_count": 342,
"brier_score": 0.3627,
"heavy_fav_win_pct": 80.7,
"fav_win_pct": 59.6,
"odds_reliability": 0.8722
},
{
"league_id": "ahl3vljaignq9ebaos4uqkrvo",
"league_name": "Kupa",
"match_count": 105,
"brier_score": 0.331,
"heavy_fav_win_pct": 70.4,
"fav_win_pct": 63.8,
"odds_reliability": 0.8696
},
{
"league_id": "8x3sbh85gc8qir50utw39jl04",
"league_name": "UEFA Kadınlar Euro 2025 Elemeleri",
"match_count": 88,
"brier_score": 0.3421,
"heavy_fav_win_pct": 75.5,
"fav_win_pct": 61.4,
"odds_reliability": 0.865
},
{
"league_id": "agpweohvn9tugnyl6ry4rhivp",
"league_name": "Eredivisie Kadınlar",
"match_count": 51,
"brier_score": 0.3356,
"heavy_fav_win_pct": 72.0,
"fav_win_pct": 56.9,
"odds_reliability": 0.8428
},
{
"league_id": "4c1nfi2j1m731hcay25fcgndq",
"league_name": "Avrupa Ligi",
"match_count": 242,
"brier_score": 0.3625,
"heavy_fav_win_pct": 77.6,
"fav_win_pct": 61.6,
"odds_reliability": 0.8425
},
{
"league_id": "1j4ehtrbry9depwt6oghaq3lu",
"league_name": "Süper Lig",
"match_count": 84,
"brier_score": 0.3201,
"heavy_fav_win_pct": 65.9,
"fav_win_pct": 60.7,
"odds_reliability": 0.8299
},
{
"league_id": "40yjcbx2sq6oq736iqqqczwt1",
"league_name": "DK Elemeler",
"match_count": 88,
"brier_score": 0.3383,
"heavy_fav_win_pct": 68.6,
"fav_win_pct": 55.7,
"odds_reliability": 0.8237
},
{
"league_id": "145hkd59i6foieuwr4mwi6wlq",
"league_name": "Pro Lig",
"match_count": 143,
"brier_score": 0.3546,
"heavy_fav_win_pct": 73.8,
"fav_win_pct": 60.1,
"odds_reliability": 0.823
},
{
"league_id": "34pl8szyvrbwcmfkuocjm3r6t",
"league_name": "LaLiga",
"match_count": 364,
"brier_score": 0.3773,
"heavy_fav_win_pct": 80.2,
"fav_win_pct": 56.6,
"odds_reliability": 0.8227
},
{
"league_id": "cse5oqqt2pzfcy8uz6yz3tkbj",
"league_name": "CAF Şampiyonlar Ligi",
"match_count": 91,
"brier_score": 0.3513,
"heavy_fav_win_pct": 73.9,
"fav_win_pct": 57.1,
"odds_reliability": 0.8212
},
{
"league_id": "zs18qaehvhg3w1208874zvfa",
"league_name": "1. Lig",
"match_count": 225,
"brier_score": 0.3744,
"heavy_fav_win_pct": 82.1,
"fav_win_pct": 59.6,
"odds_reliability": 0.8176
},
{
"league_id": "57nu0wygurzkp6fuy5hhrtaa2",
"league_name": "1. Lig",
"match_count": 286,
"brier_score": 0.3626,
"heavy_fav_win_pct": 72.9,
"fav_win_pct": 59.1,
"odds_reliability": 0.8099
},
{
"league_id": "1eruend45vd20g9hbrpiggs5u",
"league_name": "Botola Pro",
"match_count": 265,
"brier_score": 0.3625,
"heavy_fav_win_pct": 72.9,
"fav_win_pct": 50.2,
"odds_reliability": 0.8083
},
{
"league_id": "595nsvo7ykvoe690b1e4u5n56",
"league_name": "UEFA Uluslar Ligi",
"match_count": 67,
"brier_score": 0.3687,
"heavy_fav_win_pct": 83.3,
"fav_win_pct": 50.7,
"odds_reliability": 0.7987
},
{
"league_id": "6vq8j5p3av14nr3iuyi4okhjt",
"league_name": "Süper Lig Kadınlar",
"match_count": 70,
"brier_score": 0.356,
"heavy_fav_win_pct": 73.5,
"fav_win_pct": 58.6,
"odds_reliability": 0.793
},
{
"league_id": "486rhdgz7yc0sygziht7hje65",
"league_name": "Kupa",
"match_count": 62,
"brier_score": 0.3704,
"heavy_fav_win_pct": 81.1,
"fav_win_pct": 66.1,
"odds_reliability": 0.7901
},
{
"league_id": "9hh6n2f84k31zmlcxyvmc1w2y",
"league_name": "2. Lig",
"match_count": 204,
"brier_score": 0.357,
"heavy_fav_win_pct": 69.2,
"fav_win_pct": 62.3,
"odds_reliability": 0.789
},
{
"league_id": "3n5046abeu3x482ds3jwda238",
"league_name": "WE Lig Kadınlar",
"match_count": 102,
"brier_score": 0.3761,
"heavy_fav_win_pct": 85.4,
"fav_win_pct": 58.8,
"odds_reliability": 0.7863
},
{
"league_id": "8yi6ejjd1zudcqtbn07haahg6",
"league_name": "Premier Lig",
"match_count": 302,
"brier_score": 0.3712,
"heavy_fav_win_pct": 72.1,
"fav_win_pct": 56.3,
"odds_reliability": 0.7752
},
{
"league_id": "byhmntnl1b4lxw0zz21im3zkd",
"league_name": "Kupa",
"match_count": 96,
"brier_score": 0.3528,
"heavy_fav_win_pct": 68.2,
"fav_win_pct": 58.3,
"odds_reliability": 0.7719
},
{
"league_id": "2bmwykmdlcc2u1c40ytoc39vy",
"league_name": "Açık Kupası",
"match_count": 93,
"brier_score": 0.3807,
"heavy_fav_win_pct": 84.6,
"fav_win_pct": 66.7,
"odds_reliability": 0.7668
},
{
"league_id": "82jkgccg7phfjpd0mltdl3pat",
"league_name": "Süper Lig",
"match_count": 289,
"brier_score": 0.3782,
"heavy_fav_win_pct": 74.0,
"fav_win_pct": 57.4,
"odds_reliability": 0.7643
},
{
"league_id": "2nttcoriwf5co73vmz1vr8frm",
"league_name": "Nesine 2. Lig",
"match_count": 525,
"brier_score": 0.3782,
"heavy_fav_win_pct": 71.8,
"fav_win_pct": 55.2,
"odds_reliability": 0.7641
},
{
"league_id": "dr2xk7muj8aqcjdz2b3li1c0k",
"league_name": "Meistaradeildin",
"match_count": 129,
"brier_score": 0.3714,
"heavy_fav_win_pct": 73.6,
"fav_win_pct": 61.2,
"odds_reliability": 0.759
},
{
"league_id": "4yngyfinzd6bb1k7anqtqs0wt",
"league_name": "Premier Lig",
"match_count": 195,
"brier_score": 0.3772,
"heavy_fav_win_pct": 74.4,
"fav_win_pct": 57.4,
"odds_reliability": 0.7586
},
{
"league_id": "eog6knrkfei68si736fpquyzc",
"league_name": "Lig Kupası",
"match_count": 120,
"brier_score": 0.3632,
"heavy_fav_win_pct": 69.9,
"fav_win_pct": 66.7,
"odds_reliability": 0.756
},
{
"league_id": "eg6s9f1jj7jr6stmbosn0g6c8",
"league_name": "Süper Lig",
"match_count": 108,
"brier_score": 0.3657,
"heavy_fav_win_pct": 71.2,
"fav_win_pct": 55.6,
"odds_reliability": 0.7538
},
{
"league_id": "ae1wva3zrzcp2zd15gpvsntg6",
"league_name": "Ulusal Lig",
"match_count": 278,
"brier_score": 0.3783,
"heavy_fav_win_pct": 72.7,
"fav_win_pct": 55.0,
"odds_reliability": 0.7517
},
{
"league_id": "cesdwwnxbc5fmajgroc0hqzy2",
"league_name": "Hazırlık Maçları Ülkeler",
"match_count": 235,
"brier_score": 0.3669,
"heavy_fav_win_pct": 67.6,
"fav_win_pct": 56.2,
"odds_reliability": 0.7466
},
{
"league_id": "8k1xcsyvxapl4jlsluh3eomre",
"league_name": "Premier Lig",
"match_count": 328,
"brier_score": 0.385,
"heavy_fav_win_pct": 74.2,
"fav_win_pct": 45.7,
"odds_reliability": 0.7463
},
{
"league_id": "bdtat25m14jy85y484z3e6lf",
"league_name": "Kupa",
"match_count": 90,
"brier_score": 0.3772,
"heavy_fav_win_pct": 75.7,
"fav_win_pct": 55.6,
"odds_reliability": 0.7437
},
{
"league_id": "iu1vi94p4p28oozl1h9bvplr",
"league_name": "1. Lig",
"match_count": 158,
"brier_score": 0.3729,
"heavy_fav_win_pct": 71.2,
"fav_win_pct": 50.0,
"odds_reliability": 0.7411
},
{
"league_id": "1r097lpxe0xn03ihb7wi98kao",
"league_name": "Serie A",
"match_count": 359,
"brier_score": 0.3732,
"heavy_fav_win_pct": 67.8,
"fav_win_pct": 56.5,
"odds_reliability": 0.7391
},
{
"league_id": "2kwbbcootiqqgmrzs6o5inle5",
"league_name": "Premier Lig",
"match_count": 369,
"brier_score": 0.3791,
"heavy_fav_win_pct": 70.2,
"fav_win_pct": 54.2,
"odds_reliability": 0.7386
},
{
"league_id": "9fuwphq8kvugrlc3ckm7k8wes",
"league_name": "Ligler Kupası",
"match_count": 143,
"brier_score": 0.3934,
"heavy_fav_win_pct": 81.6,
"fav_win_pct": 50.3,
"odds_reliability": 0.7358
},
{
"league_id": "civf31q1inxohs4a03y8reetf",
"league_name": "Premier Lig",
"match_count": 320,
"brier_score": 0.3721,
"heavy_fav_win_pct": 67.2,
"fav_win_pct": 57.8,
"odds_reliability": 0.735
},
{
"league_id": "ili150pwfuf39f7yfdch9lhw",
"league_name": "UEFA U21 Şampiyonası Elemeler",
"match_count": 112,
"brier_score": 0.3715,
"heavy_fav_win_pct": 70.4,
"fav_win_pct": 67.9,
"odds_reliability": 0.7286
},
{
"league_id": "abs7n2ae3oydilk0tgmpnsj89",
"league_name": "Azadegan Ligi",
"match_count": 217,
"brier_score": 0.3801,
"heavy_fav_win_pct": 71.4,
"fav_win_pct": 45.2,
"odds_reliability": 0.7277
},
{
"league_id": "9nbpdi9q3ywcm4q0j5u0ekwcq",
"league_name": "Serie D",
"match_count": 232,
"brier_score": 0.3718,
"heavy_fav_win_pct": 67.2,
"fav_win_pct": 54.7,
"odds_reliability": 0.7254
}
]
}
+17
View File
@@ -0,0 +1,17 @@
import json
targets = [
"bet_recommender.py", "score_calculator.py", "db.py", "upset_engine_v2.py",
"v20_ensemble.py", "v27_predictor.py", "betting_brain.py",
"single_match_orchestrator.py", "v26_shadow_engine.py"
]
d = json.load(open("pyright_main_errors.json", encoding="utf-16"))
for diag in d["generalDiagnostics"]:
if diag["severity"] == "error":
fname = diag["file"]
if any(t in fname for t in targets):
# Print safely encoding to ascii to avoid charmap errors
safe_fname = fname.split('ai-engine')[1].encode('ascii', 'ignore').decode()
safe_msg = diag["message"].encode('ascii', 'ignore').decode()
print(f"{safe_fname} L{diag['range']['start']['line']+1}: {safe_msg}")