[Python] Unable to type texts to chatbot user input

Discussão em 'Python' iniciado por Stack, Junho 22, 2025.

  1. Stack

    Stack Membro Participativo

    Description


    I am trying to add a chatbot for the backtesting platform built with Flask and there is a button on the right side that toggles the sidebar. If the user clicks the button, it shows the sidebar with a chatbot.

    Expected Behavior


    The user should be able to type texts into the chatbot user input field.

    Current Behavior


    Currently unable to type texts into the chatbot user input field.

    HTML, CSS, JS



    const promptInput = document.getElementById("userInput");
    const chatContainer = document.getElementById("chatContainer");
    const typingIndicator = document.getElementById("typingIndicator");
    const sidebar = document.getElementById("sidebar");
    const sidebarContent = document.getElementById("sidebarContent");

    async function sendMessage() {
    const prompt = promptInput.value.trim();
    if (!prompt) {
    alert("Please enter a message.");
    return;
    }

    addMessage(prompt, 'user');
    promptInput.value = "";

    showTypingIndicator();

    const generatedText = await generateText(prompt);
    addMessage(generatedText, 'bot');

    hideTypingIndicator();
    }

    async function generateText(prompt) {
    try {
    const response = await fetch("http://127.0.0.1:5000/generate_text_stream", {
    method: "POST",
    headers: {
    "Content-Type": "application/json",
    },
    body: JSON.stringify({ prompt }),
    });

    if (!response.ok) {
    console.error("Error:", response.statusText);
    return "Error occurred while generating response.";
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let isFinished = false;
    let generatedTextContent = "";

    while (!isFinished) {
    const { done, value } = await reader.read();
    if (done) {
    isFinished = true;
    break;
    }
    generatedTextContent += decoder.decode(value, {stream: true});
    }

    return generatedTextContent;
    } catch (error) {
    console.error("Error:", error);
    return "An error occurred.";
    }
    }

    function addMessage(text, type) {
    const messageDiv = document.createElement("div");
    messageDiv.className = `message ${type}`;
    messageDiv.innerHTML = `<div class="message-bubble fadeIn">${text}</div>`;
    chatContainer.appendChild(messageDiv);

    chatContainer.scrollTop = chatContainer.scrollHeight;

    hideTypingIndicator();
    }

    let typingTimeout;

    function showTypingIndicator() {
    clearTimeout(typingTimeout);
    typingIndicator.style.display = "inline-block";
    }

    function hideTypingIndicator() {
    typingTimeout = setTimeout(() => {
    typingIndicator.style.display = "none";
    }, 1000);
    }

    function handleKeyPress(event) {
    if (event.key === "Enter") {
    sendMessage();
    }
    }

    function toggleSidebar() {
    if (sidebar.style.width === "500px") {
    sidebar.style.width = "0";
    sidebarContent.style.display = "none";
    } else {
    sidebar.style.width = "500px";
    sidebarContent.style.display = "block";
    }
    }

    window.onload = () => addMessage("Hello! How can I assist you today?", 'bot');

    body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    text-align: center;
    background-color: #f4f4f4;
    }



    .container {
    margin-top: 0;
    width: 90%;
    max-width: 450px;
    margin: 10px auto 0;
    background-color: #fff;
    border-radius: 12px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.1);
    padding: 20px;
    transition: all 0.3s;
    }

    .chat {
    overflow-y: auto;
    height: 400px;
    margin-bottom: 20px;
    border-bottom: 2px solid #e2e2e2;
    }

    .message {
    display: flex;
    margin-bottom: 12px;
    }

    .message.user {
    justify-content: flex-end;
    }

    .message-bubble {
    padding: 12px 18px;
    max-width: 70%;
    border-radius: 20px;
    line-height: 1.6;
    font-size: 0.95rem;
    }

    .message.user .message-bubble {
    background-color: #3182ce;
    color: white;
    }

    .message.bot .message-bubble {
    background-color: #e2e2e2;
    color: #333;
    }

    input[type="text"] {
    width: calc(100% - 110px);
    padding: 12px 18px;
    border: 2px solid #e2e2e2;
    border-radius: 8px 0 0 8px;
    font-size: 1rem;
    outline: none;
    z-index: 2; /* Ensure it's above other elements */
    }

    .send-button {
    width: 110px;
    background-color: #3182ce;
    color: white;
    padding: 12px 18px;
    border: none;
    border-radius: 0 8px 8px 0;
    cursor: pointer;
    transition: background-color 0.3s;
    }

    .send-button:hover {
    background-color: #2c5282;
    }

    .footer {
    text-align: center;
    padding: 15px 0;
    font-size: 0.9rem;
    color: #666;
    position: static;
    border-top: 1px solid #e2e2e2;
    background-color: #fff;
    position: fixed;
    bottom: 0;
    width: 100%;
    }

    @keyframes fadeIn {
    from {
    opacity: 0;
    }

    to {
    opacity: 1;
    }
    }

    .fadeIn {
    animation: fadeIn 1s;
    }

    @media (max-width: 600px) {
    .container {
    width: 95%;
    margin: 10px auto 0;
    }

    .chat {
    height: 300px;
    }

    input[type="text"],
    .send-button {
    padding: 10px 14px;
    font-size: 0.9rem;
    }

    .footer {
    font-size: 0.8rem;
    margin-top: 30px;
    }
    }

    .typing-indicator {
    display: none;
    align-items: center;
    justify-content: flex-end;
    margin-top: 8px;
    width: 10px;
    height: 10px;
    background-color: #333;
    border-radius: 50%;
    margin-left: 4px;
    animation: typing 1s infinite;
    }

    @keyframes typing {
    0%,
    100% {
    transform: scale(1);
    opacity: 1;
    }

    50% {
    transform: scale(1.2);
    opacity: 0.7;
    }
    }

    /* Sidebar Styles */
    .sidebar {
    position: fixed;
    right: 0;
    top: 0;
    height: 100%;
    width: 100%;
    max-width: 500px;
    background-color: #f4f4f4;
    overflow-x: hidden;
    transition: 0.5s;
    padding-top: 60px;
    color: white;
    }

    .sidebar-content {
    display: none;
    }

    .sidebar-content h2 {
    text-align: center;
    }

    .sidebar-content p {
    padding: 10px;
    }

    .toggle-button {
    position: fixed;
    right: 0;
    top: 0;
    padding: 15px;
    background-color: #3182ce;
    color: white;
    border: none;
    cursor: pointer;
    }

    .toggle-button:hover {
    background-color: #2c5282;
    }





    h1 {
    color: rgb(0, 0, 0);
    padding: 20px 0;
    margin: 0 0 20px 0;
    }

    form {
    display: inline-block;
    background-color: #fff;
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    }

    label {
    display: block;
    margin-bottom: 10px;
    font-weight: bold;
    }

    select {
    width: 100%;
    padding: 10px;
    margin-bottom: 20px;
    border-radius: 5px;
    border: 1px solid #ccc;
    }

    button {
    padding: 10px 20px;
    border: none;
    border-radius: 5px;
    background-color: #4CAF50;
    color: white;
    font-size: 16px;
    cursor: pointer;
    }

    button:hover {
    background-color: #45a049;
    }

    img {
    max-width: 90%;
    margin: 20px 0;
    border: 1px solid #ddd;
    border-radius: 10px;
    }

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Backtesting Engine</title>
    <link
    href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"
    rel="stylesheet"
    />
    <link
    rel="stylesheet"
    href="{{ url_for('static', filename='css/style.css') }}"
    />
    </head>
    <body>
    <h1 class="text-6xl font-bold mb-4 text-center">Backtesting Engine</h1>

    <div class="sidebar" id="sidebar">
    <button class="toggle-button" onclick="toggleSidebar()">☰</button>
    <div class="sidebar-content" id="sidebarContent">
    <div class="container bg-white rounded-lg shadow-md">
    <h1 class="text-3xl font-bold mb-4 text-center">ChatBot</h1>
    <div class="chat" id="chatContainer"></div>
    <div class="flex">
    <input
    type="text"
    id="userInput"
    placeholder="Type your message here..."
    class="outline-none"
    onkeyup="handleKeyPress(event)"
    />
    <button class="send-button" onclick="sendMessage()">Send</button>
    </div>
    <div class="typing-indicator" id="typingIndicator"></div>
    </div>
    </div>
    </div>

    <form method="post">
    <label for="cs_model">Cross-Sectional Model:</label>
    <select name="cs_model" id="cs_model">
    <option value="EW">EW</option>
    <option value="MSR">MSR</option>
    <option value="GMV">GMV</option>
    <option value="MDP">MDP</option>
    <option value="EMV">EMV</option>
    <option value="RP">RP</option></select
    ><br /><br />
    <label for="ts_model">Time-Series Model:</label>
    <select name="ts_model" id="ts_model">
    <option value="VT">VT</option>
    <option value="CVT">CVT</option>
    <option value="KL">KL</option>
    <option value="CPPI">CPPI</option>
    <option value="">None</option></select
    ><br /><br />
    <button type="submit">Run Backtest</button>
    </form>
    {% if plot_url1 and plot_url2 and plot_url3 %}
    <h2>Backtesting Results</h2>
    <img src="data:image/png;base64,{{ plot_url1 }}" alt="Portfolio Weights" />
    <img
    src="data:image/png;base64,{{ plot_url2 }}"
    alt="Underlying Asset Performance"
    />
    <img
    src="data:image/png;base64,{{ plot_url3 }}"
    alt="Portfolio Performance"
    />
    {% endif %}

    <script src="{{ url_for('static', filename='js/script.js') }}"></script>
    </body>
    </html>

    app.py


    from flask import Flask, render_template, request
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import yfinance as yf
    import quantstats as qs
    from scipy.optimize import minimize
    from scipy.stats import norm
    from io import BytesIO
    import base64

    app = Flask(__name__)

    # Function to get ETF price data
    def get_etf_price_data():
    tickers = ['AAPL', 'MSFT', 'NVDA', 'GOOG', 'XLK']
    etf = yf.Tickers(tickers)
    data = etf.history(start='2010-01-01', actions=False)
    data.drop(['Open', 'High', 'Low', 'Volume'], inplace=True, axis=1)
    data = data.droplevel(0, axis=1)
    data.ffill(inplace=True)
    df = data.resample('W').last()
    return df

    df = get_etf_price_data()

    # Portfolio Backtesting Engine Class
    class GEMTU772:
    # Initialization Function
    def __init__(self, price, param=52):

    # Annualization Parameter
    self.param = param

    # Intraday Return Rate
    self.rets = price.pct_change().dropna()

    # Expected Rate of Return
    self.er = np.array(self.rets * self.param)

    # Volatility
    self.vol = np.array(self.rets.rolling(self.param).std() * np.sqrt(self.param))

    # Covariance Matrix
    cov = self.rets.rolling(self.param).cov().dropna() * self.param

    # Transaction Cost per Unit
    self.cov = cov.values.reshape(int(cov.shape[0]/cov.shape[1]), cov.shape[1], cov.shape[1])

    self.cost = 0.0005

    # Cross-Sectional Risk Models Class
    class CrossSectional:
    #EW
    def ew(self, er):
    noa = er.shape[0]
    weights = np.ones_like(er) * (1/noa)
    return weights

    def msr(self, er, cov):
    noa = er.shape[0]
    init_guess = np.repeat(1/noa, noa)
    bounds = ((0.0, 1.0), ) * noa
    weights_sum_to_1 = {'type': 'eq', 'fun': lambda weights: np.sum(weights) - 1}


    def neg_sharpe(weights, er, cov):
    r = weights.T @ er # @ means multiplication
    vol = np.sqrt(weights.T @ cov @ weights)
    return - r / vol

    weights = minimize(neg_sharpe, init_guess, args=(er, cov), method='SLSQP', constraints=(weights_sum_to_1,), bounds=bounds)
    return weights.x

    #GMV
    def gmv(self, cov):
    noa = cov.shape[0]
    init_guess = np.repeat(1/noa, noa)
    bounds = ((0.0, 1.0), ) * noa
    weights_sum_to_1 = {'type': 'eq', 'fun': lambda weights: np.sum(weights) - 1}

    def port_vol(weights, cov):
    vol = np.sqrt(weights.T @ cov @ weights)
    return vol

    weights = minimize(port_vol, init_guess, args=(cov,), method='SLSQP', constraints=(weights_sum_to_1,), bounds=bounds)
    return weights.x
    #MDP
    def mdp(self, vol, cov):
    noa = vol.shape[0]
    init_guess = np.repeat(1/noa, noa)
    bounds = ((0.0, 1.0), ) * noa
    weights_sum_to_1 = {'type': 'eq', 'fun': lambda weights: np.sum(weights) - 1}

    def neg_div_ratio(weights, vol, cov):
    weighted_vol = weights.T @ vol
    port_vol = np.sqrt(weights.T @ cov @ weights)
    return - weighted_vol / port_vol

    weights = minimize(neg_div_ratio, init_guess, args=(vol, cov), method='SLSQP', constraints=(weights_sum_to_1,), bounds=bounds)
    return weights.x
    #RP
    def rp(self, cov):
    noa = cov.shape[0]
    init_guess = np.repeat(1/noa, noa)
    bounds = ((0.0, 1.0), ) * noa
    target_risk = np.repeat(1/noa, noa)
    weights_sum_to_1 = {'type': 'eq', 'fun': lambda weights: np.sum(weights) - 1}

    def msd_risk(weights, target_risk, cov):
    port_var = weights.T @ cov @ weights
    marginal_contribs = cov @ weights
    risk_contribs = np.multiply(marginal_contribs, weights.T) / port_var
    w_contribs = risk_contribs
    return ((w_contribs - target_risk)**2).sum()

    weights = minimize(msd_risk, init_guess, args=(target_risk, cov), method='SLSQP', constraints=(weights_sum_to_1,), bounds=bounds)
    return weights.x
    #EMV
    def emv(self, vol):
    inv_vol = 1 / vol
    weights = inv_vol / inv_vol.sum()
    return weights

    # Time-Series Risk Models Class
    class TimeSeries:
    #VT
    def vt(self, port_rets, param, vol_target=0.1):
    vol = port_rets.rolling(param).std().fillna(0) * np.sqrt(param)
    weights = (vol_target / vol).replace([np.inf, -np.inf], 0).shift(1).fillna(0)
    weights[weights > 1] = 1
    return weights
    #CVT
    def cvt(self, port_rets, param, delta=0.01, cvar_target=0.05):
    def calculate_CVaR(rets, delta=0.01):
    VaR = rets.quantile(delta)
    return rets[rets <= VaR].mean()

    rolling_CVaR = -port_rets.rolling(param).apply(calculate_CVaR, args=(delta,)).fillna(0)
    weights = (cvar_target / rolling_CVaR).replace([np.inf, -np.inf], 0).shift(1).fillna(0)
    weights[weights > 1] = 1
    return weights
    #KL
    def kl(self, port_rets, param):
    sharpe_ratio = (port_rets.rolling(param).mean() * np.sqrt(param) / port_rets.rolling(param).std())
    weights = pd.Series(2 * norm.cdf(sharpe_ratio) - 1, index=port_rets.index).fillna(0)
    weights[weights < 0] = 0
    weights = weights.shift(1).fillna(0)
    return weights
    #CPPI
    def cppi(self, port_rets, m=3, floor=0.7, init_val=1):
    n_steps = len(port_rets)
    port_value = init_val
    floor_value = init_val * floor
    peak = init_val

    port_history = pd.Series(dtype=np.float64).reindex_like(port_rets)
    weight_history = pd.Series(dtype=np.float64).reindex_like(port_rets)
    floor_history = pd.Series(dtype=np.float64).reindex_like(port_rets)

    for step in range(n_steps):
    peak = np.maximum(peak, port_value)
    floor_value = peak * floor

    cushion = (port_value - floor_value) / port_value
    weight = m * cushion

    risky_alloc = port_value * weight
    safe_alloc = port_value * (1 - weight)
    port_value = risky_alloc * (1 + port_rets.iloc[step]) + safe_alloc

    port_history.iloc[step] = port_value
    weight_history.iloc[step] = weight
    floor_history.iloc[step] = floor_value

    return weight_history.shift(1).fillna(0)

    # Transaction Cost Function (Compound rate of return method assuming reinvestment)
    def transaction_cost(self, weights_df, rets_df, cost=0.0005):
    prev_weights_df = (weights_df.shift(1).fillna(0) * (1 + rets_df.iloc[self.param-1:,:])) \
    .div((weights_df.shift(1).fillna(0) * (1 + rets_df.iloc[self.param-1:,:])).sum(axis=1), axis=0)

    # Investment Weight of Previous Period (The backslash ('\') in Python is used as a line continuation character.)
    cost_df = abs(weights_df - prev_weights_df) * cost
    cost_df.fillna(0, inplace=True)
    return cost_df

    # Backtesting Execution Function
    def run(self, cs_model, ts_model, cost):

    # Empty Dictionary
    backtest_dict = {}

    # Intraday Return Rate DataFrame
    rets = self.rets

    # Select and Run Cross-Sectional Risk Models
    for i, index in enumerate(rets.index[self.param-1:]):
    if cs_model == 'EW':
    backtest_dict[index] = self.CrossSectional().ew(self.er)
    elif cs_model == 'MSR':
    backtest_dict[index] = self.CrossSectional().msr(self.er, self.cov)
    elif cs_model == 'GMV':
    backtest_dict[index] = self.CrossSectional().gmv(self.cov)
    elif cs_model == 'MDP':
    backtest_dict[index] = self.CrossSectional().mdp(self.vol, self.cov)
    elif cs_model == 'EMV':
    backtest_dict[index] = self.CrossSectional().emv(self.vol)
    elif cs_model == 'RP':
    backtest_dict[index] = self.CrossSectional().rp(self.cov)

    # Cross-Sectional Weights DataFrame
    cs_weights = pd.DataFrame(list(backtest_dict.values()), index=backtest_dict.keys(), columns=rets.columns)
    cs_weights.fillna(0, inplace=True)

    # Cross-Sectional Risk Models Return on Assets
    cs_rets = cs_weights.shift(1) * rets.iloc[self.param-1:,:]

    # Cross-Sectional Risk Models Portfolio Return
    cs_port_rets = cs_rets.sum(axis=1)

    # Select and Run Time-Series Risk Models
    if ts_model == 'VT':
    ts_weights = self.TimeSeries().vt(cs_port_rets, self.param)
    elif ts_model == 'CVT':
    ts_weights = self.TimeSeries().cvt(cs_port_rets, self.param)
    elif ts_model == 'KL':
    ts_weights = self.TimeSeries().kl(cs_port_rets, self.param)
    elif ts_model == 'CPPI':
    ts_weights = self.TimeSeries().cppi(cs_port_rets)
    elif ts_model == None:
    ts_weights = 1

    # Final Portfolio Investment Weights
    port_weights = cs_weights.multiply(ts_weights, axis=0)

    # Transaction Cost DataFrame
    cost = self.transaction_cost(port_weights, rets)

    # Final Portfolio Return by Assets
    port_asset_rets = port_weights.shift() * rets - cost

    # Final Portfolio Return
    port_rets = port_asset_rets.sum(axis=1)
    port_rets.index = pd.to_datetime(port_rets.index).strftime("%Y-%m-%d")

    return port_weights, port_asset_rets, port_rets

    def performance_analytics(self, port_weights, port_asset_rets, port_rets):
    img = BytesIO()

    plt.figure(figsize=(12, 7))
    port_weights['Cash'] = 1 - port_weights.sum(axis=1)
    plt.stackplot(port_weights.index, port_weights.T, labels=port_weights.columns)
    plt.title('Portfolio Weights')
    plt.xlabel('Date')
    plt.ylabel('Weights')
    plt.legend(loc='upper left')
    plt.savefig(img, format='png')
    plt.close()
    img.seek(0)
    plot_url1 = base64.b64encode(img.getvalue()).decode('utf8')

    img = BytesIO()
    plt.figure(figsize=(12, 7))
    plt.plot((1 + port_asset_rets).cumprod() - 1)
    plt.title('Underlying Asset Performance')
    plt.xlabel('Date')
    plt.ylabel('Returns')
    plt.legend(port_asset_rets.columns, loc='upper left')
    plt.savefig(img, format='png')
    plt.close()
    img.seek(0)
    plot_url2 = base64.b64encode(img.getvalue()).decode('utf8')

    img = BytesIO()
    plt.figure(figsize=(12, 7))
    plt.plot((1 + port_rets).cumprod() - 1)
    plt.title('Portfolio Performance')
    plt.xlabel('Date')
    plt.ylabel('Returns')
    plt.savefig(img, format='png')
    plt.close()
    img.seek(0)
    plot_url3 = base64.b64encode(img.getvalue()).decode('utf8')

    return plot_url1, plot_url2, plot_url3

    #Route function
    @app.route('/', methods=['GET', 'POST'])
    def index():
    if request.method == 'POST':
    cs_model = request.form.get('cs_model') # cs model selection
    ts_model = request.form.get('ts_model') # ts model selection
    engine = GEMTU772(df) # Run backtesting
    res = engine.run(cs_model=cs_model, ts_model=ts_model, cost=0.0005) # Run method
    port_weights = res[0]
    port_asset_rets = res[1]
    port_rets = res[2]
    plot_url1, plot_url2, plot_url3 = engine.performance_analytics(port_weights, port_asset_rets, port_rets)
    return render_template('index.html', plot_url1=plot_url1, plot_url2=plot_url2, plot_url3=plot_url3) # Rendering
    return render_template('index.html')



    if __name__ == '__main__':
    app.run(debug=True)

    Continue reading...

Compartilhe esta Página