FOOTBALL_AI / app.py
choloka's picture
Upload 3 files
7c13c18 verified
Raw
History Blame Contribute Delete
7.59 kB
import pandas as pd
import numpy as np
from scipy.stats import poisson
import gradio as gr
import os
import matplotlib.pyplot as plt
import seaborn as sns
import requests
import json
# --- 1. แƒ™แƒแƒœแƒคแƒ˜แƒ’แƒฃแƒ แƒแƒชแƒ˜แƒ ---
GEMINI_API_KEY = "AIzaSyBe9TNXLWuZO995kKxbj4KvqjSLhZcJwvo"
# --- 2. แƒ›แƒแƒœแƒแƒชแƒ”แƒ›แƒ”แƒ‘แƒ˜แƒก แƒ›แƒแƒ›แƒ–แƒแƒ“แƒ”แƒ‘แƒ ---
file_path = 'top_50_european_teams_2026.csv'
if os.path.exists(file_path):
df = pd.read_csv(file_path, sep=None, engine='python')
df.columns = df.columns.str.strip()
else:
data = {
'team_nam': [
'Real Madrid', 'Manchester City', 'Bayern Munich',
'FC Barcelona', 'Arsenal', 'PSG', 'Inter Milan', 'Liverpool'
],
'fifa_elo': [1950, 1980, 1890, 1910, 1880, 1860, 1870, 1885],
'last_10_w': [8, 7, 6, 7, 8, 6, 7, 5],
'win_vs_high': [3, 4, 2, 3, 2, 1, 2, 1],
'injuries': [1, 0, 3, 1, 2, 4, 1, 2]
}
df = pd.DataFrame(data)
# --- 3. แƒจแƒ”แƒœแƒ˜ แƒ’แƒแƒแƒœแƒ’แƒแƒ แƒ˜แƒจแƒ”แƒ‘แƒ˜แƒก แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ”แƒ‘แƒ˜ (แƒฃแƒชแƒ•แƒšแƒ”แƒšแƒ˜) ---
def plot_score_heatmap(matrix, home_name, away_name):
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(
matrix,
annot=True,
fmt=".1%",
cmap="YlGnBu",
cbar_kws={'label': 'แƒแƒšแƒ‘แƒแƒ—แƒแƒ‘แƒ'},
ax=ax
)
ax.set_title(f"แƒ–แƒฃแƒกแƒขแƒ˜ แƒแƒœแƒ’แƒแƒ แƒ˜แƒจแƒ˜แƒก แƒแƒšแƒ‘แƒแƒ—แƒแƒ‘แƒ”แƒ‘แƒ˜: {home_name} vs {away_name}")
ax.set_xlabel(f"{away_name} (แƒกแƒขแƒฃแƒ›แƒแƒ แƒ˜) แƒ’แƒแƒšแƒ”แƒ‘แƒ˜")
ax.set_ylabel(f"{home_name} (แƒ›แƒแƒกแƒžแƒ˜แƒœแƒซแƒ”แƒšแƒ˜) แƒ’แƒแƒšแƒ”แƒ‘แƒ˜")
ax.set_xticks(np.arange(0.5, 8.5, 1))
ax.set_xticklabels(range(8))
ax.set_yticks(np.arange(0.5, 8.5, 1))
ax.set_yticklabels(range(8))
plt.tight_layout()
plot_path = "score_matrix_heatmap.png"
plt.savefig(plot_path, dpi=120)
plt.close(fig)
return plot_path
def calculate_balanced_odds_with_plot(home_team, away_team):
if home_team == away_team:
return "แƒแƒ˜แƒ แƒฉแƒ˜แƒ”แƒ— แƒ’แƒแƒœแƒกแƒฎแƒ•แƒแƒ•แƒ”แƒ‘แƒฃแƒšแƒ˜ แƒ’แƒฃแƒœแƒ“แƒ”แƒ‘แƒ˜", 0, 0, 0, None
try:
h = df[df['team_nam'] == home_team].iloc[0]
a = df[df['team_nam'] == away_team].iloc[0]
except IndexError:
return "แƒ’แƒฃแƒœแƒ“แƒ˜ แƒแƒ  แƒ›แƒแƒ˜แƒซแƒ”แƒ‘แƒœแƒ", 0, 0, 0, None
def get_conservative_power(row):
base_elo = row['fifa_elo'] / 400
form_bonus = np.log1p(row['last_10_w']) * 0.15
giant_killer = row['win_vs_high'] * 0.05
injury_penalty = row['injuries'] * 0.05
return base_elo + form_bonus + giant_killer - injury_penalty
h_power = get_conservative_power(h)
a_power = get_conservative_power(a)
diff = h_power - a_power
l1 = max(0.6, 1.35 + diff * 0.8 + 0.2)
l2 = max(0.6, 1.35 - diff * 0.8)
max_goals = 8
home_probs = poisson.pmf(range(max_goals), l1)
away_probs = poisson.pmf(range(max_goals), l2)
matrix = np.outer(home_probs, away_probs)
plot_file = plot_score_heatmap(matrix, home_team, away_team)
p_win = np.sum(np.tril(matrix, -1))
p_draw = np.sum(np.diag(matrix))
p_lose = np.sum(np.triu(matrix, 1))
total = p_win + p_draw + p_lose
if total == 0: total = 1
p_win, p_draw, p_lose = p_win / total, p_draw / total, p_lose / total
margin = 0.06
o1 = round(1 / (p_win + margin / 3), 2) if p_win > 0 else 10.0
ox = round(1 / (p_draw + margin / 3), 2) if p_draw > 0 else 10.0
o2 = round(1 / (p_lose + margin / 3), 2) if p_lose > 0 else 10.0
return f"xG {l1:.2f} - {l2:.2f}", max(o1, 1.15), max(ox, 1.15), max(o2, 1.15), plot_file
# --- 4. แƒฉแƒแƒขแƒ˜ (แƒจแƒ”แƒœแƒ˜ แƒ›แƒแƒ—แƒฎแƒแƒ•แƒœแƒ˜แƒšแƒ˜ แƒคแƒฃแƒœแƒฅแƒชแƒ˜แƒ) ---
def football_chat_bot(message, history):
api_key = GEMINI_API_KEY.strip()
list_url = f"https://generativelanguage.googleapis.com/v1/models?key={api_key}"
try:
models_res = requests.get(list_url).json()
working_models = [m['name'] for m in models_res.get('models', [])
if 'generateContent' in m.get('supportedGenerationMethods', [])]
if not working_models:
return "แƒจแƒ”แƒชแƒ“แƒแƒ›แƒ: แƒ—แƒฅแƒ•แƒ”แƒœแƒก API แƒ’แƒแƒกแƒแƒฆแƒ”แƒ‘แƒ–แƒ” แƒแƒ แƒชแƒ”แƒ แƒ—แƒ˜ แƒ›แƒแƒ“แƒ”แƒšแƒ˜ แƒแƒ  แƒแƒ แƒ˜แƒก แƒ’แƒแƒแƒฅแƒขแƒ˜แƒฃแƒ แƒ”แƒ‘แƒฃแƒšแƒ˜."
target_model = working_models[0]
except Exception as e:
return f"แƒ›แƒแƒ“แƒ”แƒšแƒ”แƒ‘แƒ˜แƒก แƒซแƒ˜แƒ”แƒ‘แƒ˜แƒก แƒจแƒ”แƒชแƒ“แƒแƒ›แƒ: {str(e)}"
chat_url = f"https://generativelanguage.googleapis.com/v1/{target_model}:generateContent?key={api_key}"
headers = {'Content-Type': 'application/json'}
data = {
"contents": [{"parts": [{"text": f"แƒจแƒ”แƒœ แƒฎแƒแƒ  แƒคแƒ”แƒฎแƒ‘แƒฃแƒ แƒ—แƒ˜แƒก แƒ”แƒฅแƒกแƒžแƒ”แƒ แƒขแƒ˜ 2026 แƒฌแƒ”แƒšแƒก. แƒฃแƒžแƒแƒกแƒฃแƒฎแƒ” แƒฅแƒแƒ แƒ—แƒฃแƒšแƒแƒ“: {message}"}]}]
}
try:
response = requests.post(chat_url, headers=headers, data=json.dumps(data))
res_json = response.json()
if response.status_code == 200:
return res_json['candidates'][0]['content']['parts'][0]['text']
else:
return f"API แƒฃแƒแƒ แƒ˜ ({target_model}): {res_json.get('error', {}).get('message', 'แƒฃแƒชแƒœแƒแƒ‘แƒ˜ แƒจแƒ”แƒชแƒ“แƒแƒ›แƒ')}"
except Exception as e:
return f"แƒ™แƒแƒ•แƒจแƒ˜แƒ แƒ˜แƒก แƒจแƒ”แƒชแƒ“แƒแƒ›แƒ: {str(e)}"
# --- 5. Gradio แƒ˜แƒœแƒขแƒ”แƒ แƒคแƒ”แƒ˜แƒกแƒ˜ ---
teams_list = sorted(df['team_nam'].unique())
start_home = 'Real Madrid' if 'Real Madrid' in teams_list else teams_list[0]
start_away = 'FC Barcelona' if 'FC Barcelona' in teams_list else teams_list[1]
with gr.Blocks(theme=gr.themes.Soft()) as demo:
with gr.Row():
gr.Image(
"https://images.eu.ctfassets.net/psnuheg7hu1m/2855AOJwV8YSxZmk2TfF5T/1d0af7cd5353cd782e217f91e3bfc77b/TBC-ge.png?fm=jpg&fl=progressive&q=90",
show_label=False, height=100, width=200)
gr.Markdown("# โšฝ Football AI Hub 2026")
with gr.Tabs():
with gr.TabItem("๐Ÿ“Š แƒžแƒ แƒแƒ’แƒœแƒแƒ–แƒ˜ แƒ“แƒ แƒ›แƒแƒขแƒ แƒ˜แƒชแƒ"):
gr.Markdown("แƒแƒ˜แƒ แƒฉแƒ˜แƒ”แƒ— แƒ’แƒฃแƒœแƒ“แƒ”แƒ‘แƒ˜ AI แƒ›แƒแƒ“แƒ”แƒšแƒ˜แƒก แƒแƒœแƒแƒšแƒ˜แƒ–แƒ˜แƒกแƒ—แƒ•แƒ˜แƒก")
with gr.Row():
with gr.Column(scale=1):
h_drop = gr.Dropdown(teams_list, label="แƒ›แƒแƒกแƒžแƒ˜แƒœแƒซแƒ”แƒšแƒ˜", value=start_home)
a_drop = gr.Dropdown(teams_list, label="แƒกแƒขแƒฃแƒ›แƒแƒ แƒ˜", value=start_away)
btn = gr.Button("๐Ÿ“Š แƒแƒœแƒแƒšแƒ˜แƒ–แƒ˜แƒก แƒ“แƒแƒฌแƒงแƒ”แƒ‘แƒ", variant="primary")
xg_val = gr.Textbox(label="แƒ›แƒแƒกแƒแƒšแƒแƒ“แƒœแƒ”แƒšแƒ˜ แƒ’แƒแƒšแƒ”แƒ‘แƒ˜ (xG)")
out_1 = gr.Number(label="1 (Home Win)")
out_x = gr.Number(label="X (Draw)")
out_2 = gr.Number(label="2 (Away Win)")
with gr.Column(scale=2):
matrix_plot = gr.Image(label="แƒ–แƒฃแƒกแƒขแƒ˜ แƒแƒœแƒ’แƒแƒ แƒ˜แƒจแƒ˜แƒก แƒ›แƒแƒขแƒ แƒ˜แƒชแƒ")
with gr.TabItem("๐Ÿ’ฌ แƒฉแƒแƒขแƒ˜ แƒ”แƒฅแƒกแƒžแƒ”แƒ แƒขแƒ—แƒแƒœ"):
gr.ChatInterface(fn=football_chat_bot)
btn.click(
calculate_balanced_odds_with_plot,
inputs=[h_drop, a_drop],
outputs=[xg_val, out_1, out_x, out_2, matrix_plot]
)
if __name__ == "__main__":
demo.launch()