import gradio as gr import yfinance as yf import numpy as np import pandas as pd from keras.models import load_model import joblib import os # Load the saved components MODEL_PATH = 'stock_model.keras' SCALER_PATH = 'scaler.gz' if os.path.exists(MODEL_PATH) and os.path.exists(SCALER_PATH): model = load_model(MODEL_PATH) scaler = joblib.load(SCALER_PATH) else: model = None scaler = None def predict_next_day(ticker): if model is None or scaler is None: return "Error: Model or Scaler files not found." try: # 1. Fetch more data (120d) to accommodate MA50 and RSI calculations df = yf.download(ticker, period='120d', interval='1d', multi_level_index=False) if df.empty: return f"Error: No data for '{ticker}'." # 2. Re-create all 9 features from your notebook # Moving Averages df['MA7'] = df['Close'].rolling(window=7).mean() df['MA21'] = df['Close'].rolling(window=21).mean() df['MA50'] = df['Close'].rolling(window=50).mean() # Volatility & Returns df['Volatility'] = df['Close'].rolling(window=7).std() df['Daily_Return'] = df['Close'].pct_change() # Price Range & Volume Trend df['Price_Range'] = df['High'] - df['Low'] df['Volume_MA7'] = df['Volume'].rolling(window=7).mean() # RSI (Relative Strength Index) delta = df['Close'].diff() gain = (delta.where(delta > 0, 0)).rolling(window=14).mean() loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean() rs = gain / loss df['RSI'] = 100 - (100 / (1 + rs)) df.dropna(inplace=True) # 3. Check if we have enough data left if len(df) < 60: return "Error: Not enough data for a 60-day prediction window." # 4. Prepare features in the EXACT order used in training feature_cols = ['Close', 'MA7', 'MA21', 'MA50', 'RSI', 'Volatility', 'Price_Range', 'Daily_Return', 'Volume_MA7'] last_60_days = df[feature_cols].tail(60).values # 5. Scale and Predict scaled_data = scaler.transform(last_60_days) # Reshape to (1 sample, 60 time steps, 9 features) input_data = np.reshape(scaled_data, (1, 60, 9)) prediction_scaled = model.predict(input_data, verbose=0) # 6. Inverse Transform (using 9-column dummy) dummy = np.zeros((1, 9)) dummy[0, 0] = prediction_scaled.flatten()[0] prediction_final = scaler.inverse_transform(dummy)[0, 0] return f"Predicted Next Closing Price for {ticker}: ₹{prediction_final:.2f}" except Exception as e: return f"Technical Error: {str(e)}" # Interface interface = gr.Interface( fn=predict_next_day, inputs=gr.Textbox(label="Stock Ticker", placeholder="e.g., TCS.NS, RELIANCE.NS, AAPL"), outputs=gr.Textbox(label="Forecasted Price"), title="📈 StockPulse Predictor", description="LSTM model predicting stock price using 9 technical indicators.", theme="soft" ) if __name__ == "__main__": interface.launch()