File size: 11,770 Bytes
e9131f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
import gradio as ui
import yfinance as yf
import pandas as pd
from prophet import Prophet
import plotly.graph_objects as go
from huggingface_hub import InferenceClient

# 🌍 מאגר המדדים והנכסים
MARKET_ASSETS = {
    "✡️ מדד תל אביב 125 (ישראל)": "^TA125.TA",
    "S&P 500": "^GSPC",
    "Nasdaq 100 (טכנולוגיה)": "^NDX",
    "Dow Jones 30": "^DJI",
    "VIX (מדד הפחד והחרדה)": "^VIX",
    "DAX 40 (גרמניה)": "^GDAXI",
    "FTSE 100 (בריטניה)": "^FTSE",
    "Nikkei 225 (יפן)": "^N225",
    "זהב (Gold)": "GC=F",
    "נפט גולמי (Crude Oil)": "CL=F",
    "ביטקוין (Bitcoin USD)": "BTC-USD"
}

client = InferenceClient("meta-llama/Meta-Llama-3-8B-Instruct")
PRECOMPUTED_CACHE = {}

def get_llm_analysis(asset_symbol, asset_name, summary_stats, character):
    """מנוע ה-LLM המתוקן - משתמש ב-chat_completion יציב ומהיר יותר"""
    
    # 1. מגדירים את ה-System Prompt (האופי של הדמות)
    if character == "סבתא פולנייה (ציפי)":
        system_instruction = "אתה סבתא פולנייה פולשנית, פסימיסטית ומודאגת מאוד בשם ציפי. את חושבת שלשים כסף בבורסה זה הימור מסוכן שיגמור את החסכונות של הנכדים, ומזכירה שצריך לאכול משהו חם. דברי בסגנון פולני קלאסי ומשעשע."
    elif character == "הרבי מהאינסטגרם (רב ברוך)":
        system_instruction = "אתה 'הרבי מהאינסטגרם' בשם הרב ברוך. אתה מוצא השגחה פרטית ופסוקים בכל גרף. אם המניה עולה - זה חסדי שמיים, אם היא יורדת - זה ניסיון מלמעלה. שלב ביטויים כמו 'ברוך השם', 'בעזרת השם', ו'לתת מעשר'."
    else:
        system_instruction = "אתה מוישי, ברוקר חרדי מבוול סטריט (ניו יורק). אתה מדבר בקצב מהיר, משלב המון מילים באנגלית (Yiddish-English כמו Listen, My friend, Oh my god, Buy the dip, Gvalt). אתה לחוץ על כסף, מקצוען אבל עם אופי חסידי-אמריקאי תזזיתי."

    # 2. הבקשה הספציפית (User Prompt)
    user_prompt = f"""
    נתח בקצרה (עד 4 שורות) ובעברית את הנכס/מניה הבאה: {asset_name} (סימול: {asset_symbol}).
    נתונים פיננסיים אחרונים מהשוק:
    {summary_stats}
    
    התשובה חייבת להיות נאמנה לחלוטין לדמות שלך, ולשלב את הנתונים הפיננסיים בצורה הומוריסטית ובשפה עשירה.
    """
    
    try:
        # שימוש במודל Llama 3.2 יציב ומהיר דרך chat_completion
        response = client.chat_completion(
            model="meta-llama/Llama-3.2-3B-Instruct",
            messages=[
                {"role": "system", "content": system_instruction},
                {"role": "user", "content": user_prompt}
            ],
            max_tokens=250,
            temperature=0.8
        )
        return response.choices[0].message.content.strip()
    except Exception as e:
        # אם יש שגיאה, נדפיס אותה ללוגים של Hugging Face כדי שנוכל לראות אותה, ונחזיר הודעה משעשעת
        print(f"LLM Error: {e}")
        return f"אוי גוואלד! השרת אומר: '{str(e)[:50]}...'. כנראה עין הרע, תנסה ללחוץ שוב!"
def run_calculation(ticker_symbol, asset_name, history_period="2y", forecast_days=60):
    """פונקציית ליבה שמבצעת את הורדת הנתונים וחישוב ה-Prophet"""
    ticker = yf.Ticker(ticker_symbol)
    df = ticker.history(period=history_period)
    if df.empty or len(df) < 15:
        return None, None
    
    # חיזוי Prophet
    df_prophet = df.reset_index()[['Date', 'Close']]
    df_prophet['Date'] = df_prophet['Date'].dt.tz_localize(None)
    df_prophet.columns = ['ds', 'y']
    
    model = Prophet(daily_seasonality=False, weekly_seasonality=True, yearly_seasonality=True)
    model.fit(df_prophet)
    future = model.make_future_dataframe(periods=int(forecast_days))
    forecast = model.predict(future)
    
    # בניית גרף Plotly בצבעי כחול-לבן-תכלת
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=df_prophet['ds'], y=df_prophet['y'], name='מה שקרה בפועל', line=dict(color='#0d47a1', width=3)))
    
    df_future = forecast.iloc[-int(forecast_days):]
    fig.add_trace(go.Scatter(
        x=pd.concat([df_future['ds'], df_future['ds'].iloc[::-1]]),
        y=pd.concat([df_future['yhat_upper'], df_future['yhat_lower'].iloc[::-1]]),
        fill='toself', fillcolor='rgba(100, 181, 246, 0.2)', line=dict(color='rgba(255,255,255,0)'), hoverinfo="skip", name='טווח הסטייה המשוער'
    ))
    fig.add_trace(go.Scatter(x=df_future['ds'], y=df_future['yhat'], name='התחזית של JEWMINI', line=dict(color='#1e88e5', width=3, dash='dash')))
    
    fig.update_layout(
        title=f"📊 מגמות ונבואות עבור {asset_name}", xaxis_title="תאריך", yaxis_title="מחיר שוק",
        hovermode="x unified", template="plotly_white", margin=dict(l=20, r=20, t=60, b=20),
        plot_bgcolor='white', paper_bgcolor='white'
    )
    
    # סטטיסטיקות
    last_price = df_prophet['y'].iloc[-1]
    start_price = df_prophet['y'].iloc[0]
    total_change = ((last_price - start_price) / start_price) * 100
    future_price = df_future['yhat'].iloc[-1]
    predicted_change = ((future_price - last_price) / last_price) * 100
    
    summary_stats = (
        f"מחיר נוכחי בשוק: {last_price:,.2f}\n"
        f"תשואה היסטורית בתקופה: {total_change:+.2f}%\n"
        f"מחיר חזוי לעוד {forecast_days} ימים: {future_price:,.2f} ({predicted_change:+.2f}%)"
    )
    
    return summary_stats, fig

def precompute_all_assets():
    """פונקציה שרצה בטעינת האפליקציה וממלאת את הזיכרון מראש"""
    for name, symbol in MARKET_ASSETS.items():
        if name.startswith("--"): 
            continue
        try:
            summary, fig = run_calculation(symbol, name)
            if summary and fig:
                PRECOMPUTED_CACHE[name] = {"summary": summary, "fig": fig, "symbol": symbol}
        except Exception as e:
            pass

# הרצת הטעינה מראש
precompute_all_assets()

def analyze_and_forecast(selected_asset, custom_ticker, history_period, forecast_days, character):
    if custom_ticker and custom_ticker.strip():
        ticker_symbol = custom_ticker.strip().upper()
        asset_name = f"מניית {ticker_symbol}"
        summary_stats, fig = run_calculation(ticker_symbol, asset_name, history_period, forecast_days)
        if not summary_stats:
            return f"שגיאה: לא נמצאו נתונים עבור הסימול '{ticker_symbol}'.", None, "שגיאה"
    else:
        if selected_asset.startswith("--"):
            return "נו באמת, תבחר נכס אמיתי כמו בנאדם.", None, "אויש נו."
        
        if history_period == "2y" and forecast_days == 60 and selected_asset in PRECOMPUTED_CACHE:
            summary_stats = PRECOMPUTED_CACHE[selected_asset]["summary"]
            fig = PRECOMPUTED_CACHE[selected_asset]["fig"]
            ticker_symbol = PRECOMPUTED_CACHE[selected_asset]["symbol"]
            asset_name = selected_asset
        else:
            ticker_symbol = MARKET_ASSETS[selected_asset]
            asset_name = selected_asset
            summary_stats, fig = run_calculation(ticker_symbol, asset_name, history_period, forecast_days)

    llm_insights = get_llm_analysis(ticker_symbol, asset_name, summary_stats, character)
    return summary_stats, fig, llm_insights


# --- 🔵 עיצוב כחול-לבן מותאם אישית (Custom Theme & CSS) ⚪ ---
blue_white_theme = ui.themes.Default(
    primary_hue="blue",
    secondary_hue="sky",
    neutral_hue="slate"
).set(
    body_background_fill="white",
    body_text_color="#0d47a1",
    block_background_fill="#f1f8ff",
    block_border_width="2px",
    block_border_color="#90caf9",
    button_primary_background_fill="#0d47a1",
    button_primary_background_fill_hover="#1565c0",
    button_primary_text_color="white"
)

custom_css = """
body { direction: rtl !important; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
.markdown-text h1 { color: #0d47a1 !important; border-bottom: 3px solid #0d47a1; padding-bottom: 10px; }
.markdown-text h3 { color: #1565c0 !important; }
"""

with ui.Blocks(theme=blue_white_theme, css=custom_css, title="JEWMINI AI") as demo:
    
    # כותרת האתר
    ui.Markdown("""
    # ✡️ JEWMINI AI - חמ״ל פיננסי כחול-לבן
    דשבורד פיננסי חכם למדדים ומניות מהארץ ומהעולם. המערכת משתמשת במודל החיזוי **Prophet** ובבינה מלאכותית מבוססת דמויות לניתוח השוק.
    """)
    
    with ui.Row():
        # עמודת שליטה בצד (כחלחל בהיר)
        with ui.Column(scale=1):
            ui.Markdown("### 🕵️‍♂️ 1. האנליסט שלך")
            character_dropdown = ui.Dropdown(
                choices=["סבתא פולנייה (ציפי)", "הרבי מהאינסטגרם (רב ברוך)", "מוישי הברוקר מוול סטריט"],
                value="סבתא פולנייה (ציפי)",
                label="בחר דמות לניתוח השוק"
            )
            
            ui.Markdown("### 🔍 2. נכס או מניה")
            selected_asset = ui.Dropdown(
                choices=list(MARKET_ASSETS.keys()), 
                value="✡️ מדד תל אביב 125 (ישראל)", 
                label="בחר נכס מהרשימה"
            )
            
            custom_ticker = ui.Textbox(
                label="או הקלד סימול חופשי (למשל: AAPL, NVDA, TSLA)",
                placeholder="הקלד באנגלית..."
            )
            
            ui.Markdown("### ⚙️ הגדרות המודל")
            history_radio = ui.Radio(
                choices=["1y", "2y", "5y"], value="2y", label="טווח היסטוריית למידה"
            )
            forecast_slider = ui.Slider(
                minimum=7, maximum=180, value=60, step=1, label="טווח החיזוי העתידי (בימים)"
            )
            
            # כפתור כחול כהה בולט
            btn = ui.Button("🚀 הפעל ניתוח ונבואה", variant="primary")
            
        # עמודת תוצאות במרכז (לבן נקי עם אלמנטים כחולים)
        with ui.Column(scale=2):
            with ui.Group():
                ui.Markdown("### 💬 ניתוח אנליטי (JEWMINI Insights)")
                llm_output = ui.Textbox(show_label=False, interactive=False, lines=5)
                
            output_text = ui.Textbox(label="📊 נתונים מספריים ותחזית", interactive=False, lines=3)
            output_chart = ui.Plot(label="📈 גרף הנביא (כחול-לבן)")

    # חיבור פונקציות לאירועים
    inputs = [selected_asset, custom_ticker, history_radio, forecast_slider, character_dropdown]
    outputs = [output_text, output_chart, llm_output]
    
    btn.click(fn=analyze_and_forecast, inputs=inputs, outputs=outputs)
    demo.load(fn=analyze_and_forecast, inputs=inputs, outputs=outputs)

if __name__ == "__main__":
    demo.launch()