Poowanath commited on
Commit
59a4043
·
verified ·
1 Parent(s): 60ccee3

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +194 -0
app.py ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Hugging Face Space - BTC Prediction API"""
2
+ from fastapi import FastAPI, HTTPException
3
+ from pydantic import BaseModel
4
+ import pandas as pd
5
+ import yfinance as yf
6
+ import torch
7
+ import numpy as np
8
+ import random
9
+ from chronos import ChronosPipeline
10
+ from datetime import date, timedelta
11
+ from typing import Optional
12
+
13
+ # ตั้ง seed
14
+ SEED = 42
15
+ random.seed(SEED)
16
+ np.random.seed(SEED)
17
+ torch.manual_seed(SEED)
18
+
19
+ app = FastAPI(title="BTC Prediction API", version="1.0.0")
20
+
21
+ # โหลด model ตอน startup
22
+ model_pipeline = None
23
+
24
+ @app.on_event("startup")
25
+ async def load_model():
26
+ global model_pipeline
27
+ print("🤖 Loading Chronos model...")
28
+ model_pipeline = ChronosPipeline.from_pretrained(
29
+ "amazon/chronos-t5-tiny",
30
+ device_map="cpu",
31
+ torch_dtype=torch.float32
32
+ )
33
+ print("✅ Model loaded successfully")
34
+
35
+
36
+ class PredictionRequest(BaseModel):
37
+ start_date: str = "2020-01-01"
38
+ window_size: int = 256
39
+
40
+
41
+ class BatchPredictionRequest(BaseModel):
42
+ """สำหรับทำนายหลายวัน (ใช้ใน strategy filter)"""
43
+ prices: list[float] # ราคาที่ต้องการทำนาย
44
+ window_size: int = 256
45
+
46
+
47
+ def get_btc_data(start: str) -> pd.DataFrame:
48
+ """ดึงข้อมูล BTC"""
49
+ end = (date.today() + timedelta(days=1)).strftime("%Y-%m-%d")
50
+ btc = yf.download("BTC-USD", start=start, end=end, progress=False)
51
+
52
+ if isinstance(btc.columns, pd.MultiIndex):
53
+ btc.columns = btc.columns.get_level_values(0)
54
+
55
+ df = btc[["Close"]].copy()
56
+ df = df.ffill().dropna()
57
+ return df
58
+
59
+
60
+ def predict_price(data: pd.DataFrame, window_size: int = 256) -> Optional[float]:
61
+ """ทำนายราคา"""
62
+ if model_pipeline is None:
63
+ raise RuntimeError("Model not loaded")
64
+
65
+ if len(data) < window_size:
66
+ context = data['Close'].values.tolist()
67
+ else:
68
+ context = data['Close'].values[-window_size:].tolist()
69
+
70
+ context_tensor = torch.tensor([context])
71
+
72
+ torch.manual_seed(SEED)
73
+
74
+ with torch.no_grad():
75
+ forecast = model_pipeline.predict(
76
+ context_tensor,
77
+ prediction_length=1,
78
+ num_samples=1
79
+ )
80
+
81
+ predicted_price = forecast[0, 0, 0].item()
82
+ return float(predicted_price)
83
+
84
+
85
+ @app.get("/")
86
+ def root():
87
+ return {
88
+ "service": "BTC Prediction API",
89
+ "model": "amazon/chronos-t5-tiny",
90
+ "status": "ready" if model_pipeline else "loading"
91
+ }
92
+
93
+
94
+ @app.get("/health")
95
+ def health():
96
+ return {
97
+ "status": "ok",
98
+ "model_loaded": model_pipeline is not None
99
+ }
100
+
101
+
102
+ @app.head("/health")
103
+ def health_head():
104
+ """HEAD endpoint for uptime monitoring."""
105
+ return
106
+
107
+
108
+ @app.post("/predict")
109
+ def predict(req: PredictionRequest):
110
+ """ทำนายราคา BTC วันถัดไป"""
111
+ try:
112
+ if model_pipeline is None:
113
+ raise HTTPException(status_code=503, detail="Model is still loading")
114
+
115
+ # ดึงข้อมูล
116
+ data = get_btc_data(req.start_date)
117
+
118
+ if len(data) < 30:
119
+ raise HTTPException(status_code=400, detail="Not enough data")
120
+
121
+ # ทำนาย
122
+ predicted_price = predict_price(data, req.window_size)
123
+
124
+ if predicted_price is None:
125
+ raise HTTPException(status_code=500, detail="Prediction failed")
126
+
127
+ # คำนวณผลลัพธ์
128
+ last_close = float(data["Close"].iloc[-1])
129
+ last_date = data.index[-1]
130
+ next_date = last_date + pd.Timedelta(days=1)
131
+ change_pct = ((predicted_price / last_close) - 1) * 100
132
+
133
+ return {
134
+ "symbol": "BTC-USD",
135
+ "last_date": str(last_date.date()),
136
+ "next_date": str(next_date.date()),
137
+ "last_close": last_close,
138
+ "predicted_close": predicted_price,
139
+ "predicted_change_pct": float(change_pct),
140
+ "model": "amazon/chronos-t5-tiny",
141
+ "window_size": req.window_size
142
+ }
143
+
144
+ except HTTPException:
145
+ raise
146
+ except Exception as e:
147
+ raise HTTPException(status_code=500, detail=str(e))
148
+
149
+
150
+ @app.post("/predict_from_data")
151
+ def predict_from_data(req: BatchPredictionRequest):
152
+ """ทำนายราคาจากข้อมูลที่ส่งมา (สำหรับ strategy filter)"""
153
+ try:
154
+ if model_pipeline is None:
155
+ raise HTTPException(status_code=503, detail="Model is still loading")
156
+
157
+ # ลดข้อกำหนดจาก 30 เป็น 10 วัน
158
+ if len(req.prices) < 10:
159
+ raise HTTPException(status_code=400, detail="Not enough data (need at least 10 prices)")
160
+
161
+ # ใช้���าคาที่ส่งมา
162
+ if len(req.prices) < req.window_size:
163
+ context = req.prices
164
+ else:
165
+ context = req.prices[-req.window_size:]
166
+
167
+ context_tensor = torch.tensor([context])
168
+
169
+ torch.manual_seed(SEED)
170
+
171
+ with torch.no_grad():
172
+ forecast = model_pipeline.predict(
173
+ context_tensor,
174
+ prediction_length=1,
175
+ num_samples=1
176
+ )
177
+
178
+ predicted_price = forecast[0, 0, 0].item()
179
+
180
+ return {
181
+ "predicted_price": float(predicted_price),
182
+ "input_length": len(req.prices),
183
+ "window_size": req.window_size
184
+ }
185
+
186
+ except HTTPException:
187
+ raise
188
+ except Exception as e:
189
+ raise HTTPException(status_code=500, detail=str(e))
190
+
191
+
192
+ if __name__ == "__main__":
193
+ import uvicorn
194
+ uvicorn.run(app, host="0.0.0.0", port=7860)