from fastapi import FastAPI, Request, Response, Form, Header, HTTPException, BackgroundTasks from fastapi.responses import JSONResponse from fastapi.middleware.cors import CORSMiddleware # 匯入 FastAPI 的 CORS 中介軟體 from fastapi.staticfiles import StaticFiles from typing import Annotated # 推薦用於 Pydantic v2+ import pandas as pd import os import json import io import os from datetime import datetime import uvicorn from dotenv import load_dotenv # 匯入 dotenv 以載入 .env 環境變數檔案 STATIC_DIR = "static" os.environ["TORCH_HOME"] = "./.cache" os.environ["HF_HOME"] = "./.cache" os.environ["TRANSFORMERS_CACHE"] = "./.cache" os.makedirs("./.cache", exist_ok=True) os.makedirs(STATIC_DIR, exist_ok=True) load_dotenv() # ===================== # 初始化 FastAPI # ===================== app = FastAPI(title="Crypt Price") app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static") # 設定 CORS (跨來源資源共用) app.add_middleware( CORSMiddleware, allow_origins=["*"], # 允許所有來源 allow_credentials=True, # 允許憑證 allow_methods=["*"], # 允許所有 HTTP 方法 allow_headers=["*"], # 允許所有 HTTP 標頭 ) # ===================== # API 路由 # ===================== @app.get("/") def root(): return {"message": "Crypt Price API ready!"} @app.get("/history") async def cryptohistory(): try: print("### start /cryptohistory !!") file_path = os.path.join("static", "eth_history.csv") # 讀取 CSV df = pd.read_csv(file_path) # 標準化欄位名稱 df.columns = df.columns.str.lower() # 轉換日期格式 #df["date"] = pd.to_datetime(df["date"]).dt.strftime("%Y-%m-%d") df["date"] = df["date"].astype(str) # 建立回傳資料 # date,open,high,low,close,volume results = [] for idx, row in df.iterrows(): results.append({ "id": idx + 1, "date": row["date"], "open": float(row["open"]), "high": float(row["high"]), "low": float(row["low"]), "close": float(row["close"]), "volume": float(row["volume"]) }) return { "status": "success", "data": results } except Exception as e: return JSONResponse( status_code=500, content={ "status": "error", "message": str(e) } ) if __name__ == "__main__": uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=False)