开发者生态
morning
2026 世界杯:一个通过与 CoCo 对话构建的实时应用 | 技术实践
2026-08-19
1 阅读
约10分钟阅读
Dash Desai
字号:
2026 年,智能体将在企业级应用中取得哪些实质性突破? 点击下载 "《2026 年 AI 与数据发展预测》白皮书,获悉专家一手前瞻,抢先拥抱新的工作方式! 我构建了一个 FIFA World Cup 2026 应用,它包含实时比分、淘汰赛对阵生成器、交锋统计、场馆地图、比赛预测等功能,而且整个过程几乎完全是通过与 Cortex Code Desktop(CoCo)的一系列自然语言对话完成的。 之所以花了几周时间,是因为一开始我完全没有任何样板代码;同时随着赛事推进,我也不断想把新的想法、更好的交互和更多实时统计数据迭代进来。 首页就是一个典型例子:它最初只是一个静态倒计时卡片,后来通过纯对话式开发,逐渐长成一个实时 dashboard。 一开始它只有四个指标卡片(距离开赛天数、剩余比赛场次、48 支球队、16 个场馆)和一个赛程 dataframe;后来又加上了实时比赛卡片,以及带动画的统计 pills(控球率、射门、角球)和进球/黄牌/红牌事件标记;接着加入了下一场比赛的 JS 倒计时,以及当多场比赛同时开踢时的多卡片堆叠显示;然后加入了纵向淘汰赛 bracket,并叠加了以金色 badge 呈现的 AI 预测;再后来加入了比赛进行中的实时胜率条,以及带赛事统计摘要的球队卡片;最后,又加上了冠军庆祝卡片和 confetti 动效,用在 World Cup 2026 决赛结束之后。 其他页面也经历了类似过程,只是迭代次数可能略少,例如: Head-to-Head " Venue Map " Knockout Bracket " Quiz " 技术栈 GitHub → Streamlit Community Cloud (auto-deploy on push) ├── Snowflake │ ├── TEAMS (48 teams, flags, FIFA rankings) │ ├── VENUES (16 stadiums, lat/lng, capacity) │ └── MATCHES (72 group stage fixtures) ├── ESPN Free API (live scores, no auth) └── Snowflake Cortex AI_COMPLETE (match predictions) 这个应用运行在 Streamlit Community Cloud 上,静态赛事数据存储在 Snowflake 中,实时比分和比赛统计来自 ESPN 的公开但未文档化的 API,而 AI 驱动的比赛预测则通过 Snowflake Cortex AI Functions 生成。 开发过程:AI 辅助迭代 从最初脚手架到最后的冠军庆祝卡片,每一个功能几乎都是通过和 CoCo 对话构建出来的。我只需要描述想要什么,然后在生成结果基础上继续迭代。 一个很典型的例子是 predictions.py 模块。这个模块有 200 多行代码,里面包含统计聚合、综合评分计算,以及对 Cortex AI Functions 的集成,而这些内容几乎是在一次对话中完成的。 ESPN 未文档化 API:踩过的一些坑 在使用这个 API 的过程中,我们遇到了几个很典型的问题。 100 条赛事截断 问题:当你查询 ?dates=20260611–20260719 这种覆盖整个赛事周期的时间范围时,ESPN 会悄悄把结果截断在大约 100 场比赛左右。我们是在赛事进行到中段时才发现这个问题,因为半决赛结果竟然“消失”了。 解决办法:把查询拆成两个日期区间。 @st.cache_data(ttl=60) def get_all_results(): results = [] # Split to avoid ESPN's ~100 event cap for date_range in ["20260611–20260627", "20260628-" + _today_str()]: resp = requests.get(ESPN_API, params={"dates": date_range}, timeout=10) # … normalize and collect return results 跨午夜边界丢比赛 问题:如果不传 dates 参数,ESPN 默认只返回当前美东时间自然日的数据。这意味着,一场在美东时间晚上 11:55 开始、并在午夜后仍处于补时阶段的比赛,会在跨天后直接从结果里消失。 解决办法:始终查询一个 3 天窗口。 et = pytz.timezone("US/Eastern") now_et = datetime.now(et) yesterday = (now_et - timedelta(days=1)).strftime("%Y%m%d") tomorrow = (now_et + timedelta(days=1)).strftime("%Y%m%d") 状态识别 ESPN 使用 6 种不同的进行中状态:STATUS_FIRST_HALF、STATUS_SECOND_HALF、STATUS_HALFTIME、STATUS_EXTRA_TIME、STATUS_PENALTY_SHOOTOUT、STATUS_IN_PROGRESS;还使用 3 种结束状态:STATUS_FULL_TIME、STATUS_FINAL_PEN、STATUS_FINAL_AET。 只要漏掉其中任何一个,淘汰赛 bracket 就会出错。 不用 WebSockets 也能做到实时更新 我们使用了 Streamlit 的 @st.fragment(run_every=N) 装饰器,它可以按固定间隔只重跑被装饰的函数,而无需整页刷新。 @st.fragment(run_every=10) def _live_section(): live = get_live_matches() if live: for i, match in enumerate(live): _render_live_match(match, i) 再结合 API 调用上的 @st.cache_data(ttl=15),就能以极低的 ESPN API 负载实现接近实时的更新。实时比赛区域每 10 秒刷新一次,赛程/结果区域每 60 秒刷新一次,页面顶部 banner 也是每 60 秒刷新一次。 为了防止页面闪烁,我们还处理了一个额外问题:ESPN 偶尔会因为 CDN 抖动返回空结果。为了解决这个问题,我们把最近一次可用状态缓存在 st.session_state 里: if live: st.session_state["_last_live"] = live elif "_last_live" in st.session_state: live = st.session_state["_last_live"] 使用 Snowflake Cortex AI 做比赛预测 预测系统分成两层。 第一层:统计评分 基于真实赛事表现数据计算加权综合评分: rating = ( win_rate * 35 + # Points
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱