Mayur-cinderace commited on
Commit
f396c16
·
1 Parent(s): 5e45743

Remove local models, load from HF Model Hub

Browse files
Files changed (3) hide show
  1. Dockerfile +0 -1
  2. requirements.txt +1 -0
  3. src/api.py +59 -37
Dockerfile CHANGED
@@ -6,7 +6,6 @@ COPY requirements_api.txt .
6
  RUN pip install --no-cache-dir -r requirements_api.txt
7
 
8
  COPY src src
9
- COPY models models
10
  COPY data data
11
 
12
  EXPOSE 7860
 
6
  RUN pip install --no-cache-dir -r requirements_api.txt
7
 
8
  COPY src src
 
9
  COPY data data
10
 
11
  EXPOSE 7860
requirements.txt CHANGED
@@ -6,3 +6,4 @@ scikit-learn
6
  joblib
7
  nltk
8
  prometheus-client
 
 
6
  joblib
7
  nltk
8
  prometheus-client
9
+ huggingface-hub
src/api.py CHANGED
@@ -1,9 +1,10 @@
1
- from fastapi import FastAPI, Request
2
  from pydantic import BaseModel
3
- import joblib
4
  import numpy as np
5
  import pandas as pd
6
  import time
 
 
7
 
8
  from prometheus_client import (
9
  Counter,
@@ -13,14 +14,14 @@ from prometheus_client import (
13
  )
14
  from fastapi.responses import Response
15
 
16
- # -----------------------------
17
  # App
18
- # -----------------------------
19
  app = FastAPI(title="Investor Sentiment Inference API")
20
 
21
- # -----------------------------
22
- # Prometheus metrics
23
- # -----------------------------
24
  REQUEST_COUNT = Counter(
25
  "prediction_requests_total",
26
  "Total number of prediction requests"
@@ -37,18 +38,39 @@ SENTIMENT_DISTRIBUTION = Histogram(
37
  buckets=(-1, -0.5, 0, 0.5, 1)
38
  )
39
 
40
- # -----------------------------
41
- # Load model + scaler
42
- # -----------------------------
43
- MODEL_PATH = "models/AAPL"
44
- model = joblib.load(f"{MODEL_PATH}/rf.joblib")
45
- scaler_x = joblib.load(f"{MODEL_PATH}/scaler_x.joblib")
46
-
47
- # -----------------------------
48
- # Sentiment logic
49
- # -----------------------------
50
- POS_WORDS = {"good", "buy", "up", "rise", "gain", "bull", "profit", "growth", "bullish"}
51
- NEG_WORDS = {"bad", "sell", "down", "fall", "loss", "bear", "risk", "crash", "bearish"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
  def simple_sentiment(text: str) -> float:
54
  words = text.lower().split()
@@ -56,23 +78,23 @@ def simple_sentiment(text: str) -> float:
56
  neg = sum(w in NEG_WORDS for w in words)
57
  return (pos - neg) / (pos + neg) if (pos + neg) > 0 else 0.0
58
 
59
- # -----------------------------
60
- # Input schema
61
- # -----------------------------
62
  class InputText(BaseModel):
63
  sentence: str
64
 
65
- # -----------------------------
66
- # Market context
67
- # -----------------------------
68
  def get_latest_market_context():
69
  df = pd.read_csv("data/processed/merged_features.csv")
70
- last = df[df["Ticker"] == "AAPL"].iloc[-1]
71
  return last["return_lag1"], last["volume_lag1"]
72
 
73
- # -----------------------------
74
- # Prediction endpoint
75
- # -----------------------------
76
  @app.post("/predict")
77
  def predict(data: InputText):
78
  start_time = time.time()
@@ -85,26 +107,26 @@ def predict(data: InputText):
85
 
86
  X = np.array([[return_lag1, volume_lag1, sentiment]])
87
  Xs = scaler_x.transform(X)
88
- pred = model.predict(Xs)[0]
89
 
90
  REQUEST_LATENCY.observe(time.time() - start_time)
91
 
92
  return {
93
  "sentence": data.sentence,
94
  "sentiment_score": sentiment,
95
- "predicted_return": float(pred)
96
  }
97
 
98
- # -----------------------------
99
- # Prometheus scrape endpoint
100
- # -----------------------------
101
  @app.get("/metrics")
102
  def metrics():
103
  return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)
104
 
105
- # -----------------------------
106
- # Health check (very important)
107
- # -----------------------------
108
  @app.get("/health")
109
  def health():
110
  return {"status": "ok"}
 
1
+ from fastapi import FastAPI
2
  from pydantic import BaseModel
 
3
  import numpy as np
4
  import pandas as pd
5
  import time
6
+ import joblib
7
+ from huggingface_hub import hf_hub_download
8
 
9
  from prometheus_client import (
10
  Counter,
 
14
  )
15
  from fastapi.responses import Response
16
 
17
+ # =====================================================
18
  # App
19
+ # =====================================================
20
  app = FastAPI(title="Investor Sentiment Inference API")
21
 
22
+ # =====================================================
23
+ # Prometheus Metrics
24
+ # =====================================================
25
  REQUEST_COUNT = Counter(
26
  "prediction_requests_total",
27
  "Total number of prediction requests"
 
38
  buckets=(-1, -0.5, 0, 0.5, 1)
39
  )
40
 
41
+ # =====================================================
42
+ # Load model dynamically from Hugging Face Hub
43
+ # =====================================================
44
+ HF_MODEL_REPO = "Mayur-cinderace/investormlops-models"
45
+ TICKER = "AAPL"
46
+
47
+ def load_model():
48
+ model_path = hf_hub_download(
49
+ repo_id=HF_MODEL_REPO,
50
+ filename=f"{TICKER}/rf.joblib"
51
+ )
52
+ scaler_path = hf_hub_download(
53
+ repo_id=HF_MODEL_REPO,
54
+ filename=f"{TICKER}/scaler_x.joblib"
55
+ )
56
+
57
+ model = joblib.load(model_path)
58
+ scaler = joblib.load(scaler_path)
59
+ return model, scaler
60
+
61
+ model, scaler_x = load_model()
62
+
63
+ # =====================================================
64
+ # Sentiment Logic
65
+ # =====================================================
66
+ POS_WORDS = {
67
+ "good", "buy", "up", "rise", "gain", "bull",
68
+ "profit", "growth", "bullish", "strong"
69
+ }
70
+ NEG_WORDS = {
71
+ "bad", "sell", "down", "fall", "loss",
72
+ "bear", "risk", "crash", "bearish", "weak"
73
+ }
74
 
75
  def simple_sentiment(text: str) -> float:
76
  words = text.lower().split()
 
78
  neg = sum(w in NEG_WORDS for w in words)
79
  return (pos - neg) / (pos + neg) if (pos + neg) > 0 else 0.0
80
 
81
+ # =====================================================
82
+ # Input Schema
83
+ # =====================================================
84
  class InputText(BaseModel):
85
  sentence: str
86
 
87
+ # =====================================================
88
+ # Market Context (latest available features)
89
+ # =====================================================
90
  def get_latest_market_context():
91
  df = pd.read_csv("data/processed/merged_features.csv")
92
+ last = df[df["Ticker"] == TICKER].iloc[-1]
93
  return last["return_lag1"], last["volume_lag1"]
94
 
95
+ # =====================================================
96
+ # Prediction Endpoint
97
+ # =====================================================
98
  @app.post("/predict")
99
  def predict(data: InputText):
100
  start_time = time.time()
 
107
 
108
  X = np.array([[return_lag1, volume_lag1, sentiment]])
109
  Xs = scaler_x.transform(X)
110
+ prediction = model.predict(Xs)[0]
111
 
112
  REQUEST_LATENCY.observe(time.time() - start_time)
113
 
114
  return {
115
  "sentence": data.sentence,
116
  "sentiment_score": sentiment,
117
+ "predicted_return": float(prediction)
118
  }
119
 
120
+ # =====================================================
121
+ # Prometheus Metrics Endpoint
122
+ # =====================================================
123
  @app.get("/metrics")
124
  def metrics():
125
  return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)
126
 
127
+ # =====================================================
128
+ # Health Check
129
+ # =====================================================
130
  @app.get("/health")
131
  def health():
132
  return {"status": "ok"}