File size: 6,949 Bytes
ab0a6c9
b2d5b74
 
 
 
 
985f897
ed8fc2e
985f897
4badfda
b2d5b74
 
 
8370475
c279867
 
 
eb2bf76
 
 
c279867
8cab4b7
c279867
 
 
 
 
 
 
 
 
eb2bf76
 
c279867
 
eb2bf76
c279867
eb2bf76
 
c279867
6d49e02
e68a6e8
 
01a0a48
e68a6e8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb2bf76
 
c279867
eb2bf76
 
 
 
c279867
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb2bf76
56da3ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb2bf76
 
 
c279867
eb2bf76
 
 
 
 
 
 
 
 
 
c279867
eb2bf76
 
5c2eabd
eb2bf76
 
56da3ec
 
 
 
 
3e9225c
e68a6e8
3e9225c
 
 
 
 
e68a6e8
 
 
 
 
 
 
3e9225c
 
56da3ec
e68a6e8
3e9225c
 
 
 
 
 
eb2bf76
 
 
 
 
 
 
 
 
4948018
eb2bf76
 
 
 
c279867
eb2bf76
 
 
c279867
 
 
 
 
eb2bf76
 
 
 
c279867
eb2bf76
 
6d49e02
8caee6c
 
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
import gradio as gr
from services.llm_client import llm_service
from core.analyzer import PortfolioAnalyzer
from core.comparer import PortfolioComparer
from core.chat import ChatAssistant
from core.metrics import show_metrics_table
from core.visualization import build_alpha_chart

MODEL_NAME = "meta-llama/Meta-Llama-3.1-8B-Instruct"

analyzer = PortfolioAnalyzer(llm_service, MODEL_NAME)
comparer = PortfolioComparer(llm_service, MODEL_NAME)
chatbot = ChatAssistant(llm_service, MODEL_NAME)

# === Bloomberg-style dark theme ===
dark_theme = gr.themes.Base(
    primary_hue="violet",
    secondary_hue="gray",
    neutral_hue="zinc",
).set(
    body_background_fill="#0d1117",          # main background (dark navy)
    body_text_color="#e6edf3",               # main text
    block_background_fill="#161b22",         # card background
    block_border_color="#30363d",            # subtle border
    button_primary_background_fill="#4f46e5",# indigo-violet accent
    button_primary_background_fill_hover="#6366f1",
    button_primary_text_color="#ffffff",
    input_background_fill="#0d1117",
    block_shadow="0 2px 6px rgba(0,0,0,0.3)",
    block_label_text_color="#9da5b4",
    block_label_text_size="sm",
)

with gr.Blocks(theme=dark_theme, css="""
/* === Bloomberg / Dark Finance Style === */
.gradio-container {
    max-width: 1000px !important;
    margin: auto !important;
    font-family: 'Inter', sans-serif;
    background-color: #0d1117 !important;
}
/* === LLM Commentary Styling === */
#llm_comment_box textarea {
    max-height: 420px !important;   /* ограничение высоты */
    overflow-y: auto !important;    /* вертикальный скроллинг */
    background-color: #161b22 !important;
    color: #f0f6fc !important;
    border: 1px solid #30363d !important;
    border-radius: 6px !important;
    font-family: 'JetBrains Mono', monospace !important;
    font-size: 14px !important;
    line-height: 1.5 !important;
    padding: 12px !important;
}
/* === Comparison Table === */
#comparison_table {
    margin-top: 8px !important;
}

h2, h3, .gr-markdown {
    font-weight: 600;
    color: #f0f6fc !important;
}
.gr-button {
    border-radius: 6px !important;
    font-weight: 600 !important;
    letter-spacing: 0.3px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.25);
}
.gr-textbox, .gr-dataframe {
    border-radius: 6px !important;
}
.gr-button.primary {
    background: linear-gradient(90deg, #6366f1, #4f46e5);
    border: none !important;
}
.gr-tab {
    background-color: #161b22 !important;
    color: #c9d1d9 !important;
}
.gr-tabs {
    border-bottom: 1px solid #30363d !important;
}
.gr-plot {
    background: #0d1117 !important;
}
/* Fix Gradio plot overlay */
#alpha_chart svg {
    display: none !important;
}
#alpha_chart .wrap {
    background: transparent !important;
    box-shadow: none !important;
}
/* === Styled comparison table === */
.gr-dataframe table {
    border-collapse: collapse !important;
    width: 100% !important;
    color: #c9d1d9 !important;
    background-color: #161b22 !important;
}
.gr-dataframe th {
    background-color: #21262d !important;
    color: #f0f6fc !important;
    font-weight: 600 !important;
    text-transform: uppercase;
    border-bottom: 1px solid #30363d !important;
}
.gr-dataframe td {
    border-top: 1px solid #30363d !important;
    padding: 8px !important;
}

""") as demo:
    gr.Markdown("## Investment Portfolio Analyzer")
    gr.Markdown(
        "A professional dashboard for analyzing and comparing investment portfolios using AI insights.",
        elem_classes="subtitle",
    )

    with gr.Tabs():
        # --- Analysis Tab ---
        with gr.TabItem("Analysis"):
            portfolio_input = gr.Textbox(
                label="Portfolio ID or Link",
                placeholder="Enter a portfolio ID (e.g. ea856c1b-...)",
                lines=1,
                value='b1ef37aa-5b9a-41b4-9394-8823f2de36bb',
            )
            analyze_button = gr.Button("Run Analysis", variant="primary")
            analyze_output = gr.Textbox(label="Analysis Result", lines=15)
            analyze_button.click(fn=analyzer.run, inputs=portfolio_input, outputs=analyze_output)

        # --- Comparison Table Tab ---
        with gr.TabItem("Comparison Table"):
            comp_input_1 = gr.Textbox(label="Portfolio A", value="3852a354-e66e-4bc5-97e9-55124e31e687")
            comp_input_2 = gr.Textbox(label="Portfolio B", value="b1ef37aa-5b9a-41b4-9394-8823f2de36bb")
            comp_button = gr.Button("Load Comparison", variant="primary")

            # комментарий теперь над таблицей
            comp_output_comment = gr.Textbox(
                label="AI Commentary",
                lines=8,
                interactive=False,
                show_copy_button=True,
                elem_id="llm_comment_box",
            )

            comp_output_table = gr.Dataframe(
                label="Comparative Metrics",
                wrap=True,
                elem_id="comparison_table",
            )

            from core.comparison_table import show_comparison_table

            comp_button.click(
                fn=show_comparison_table,
                inputs=[comp_input_1, comp_input_2],
                outputs=[comp_output_table, comp_output_comment],
            )

        # --- Chat Assistant Tab ---
        with gr.TabItem("Assistant"):
            chat_input = gr.Textbox(label="Ask about investments or analysis")
            chat_button = gr.Button("Send Question", variant="primary")
            chat_output = gr.Textbox(label="AI Response", lines=8)
            chat_button.click(fn=chatbot.run, inputs=chat_input, outputs=chat_output)

        # --- Metrics Table Tab ---
        with gr.TabItem("Metrics Table"):
            metrics_input = gr.Textbox(label="Portfolio ID", value='b1ef37aa-5b9a-41b4-9394-8823f2de36bb')
            metrics_button = gr.Button("Load Metrics", variant="primary")
            metrics_output = gr.Dataframe(label="Portfolio Metrics", wrap=True)
            metrics_button.click(fn=show_metrics_table, inputs=metrics_input, outputs=metrics_output)

        # --- AlphaBTC Chart Tab (fixed overlay) ---
        with gr.TabItem("AlphaBTC Chart"):
            chart_input = gr.Textbox(label="Portfolio ID", value="3852a354-e66e-4bc5-97e9-55124e31e687")
            chart_button = gr.Button("Generate Chart", variant="primary")
            chart_output = gr.Plot(
                label="Alpha vs BTC",
                show_label=False,
                elem_id="alpha_chart",
            )
            chart_button.click(fn=build_alpha_chart, inputs=chart_input, outputs=chart_output)

    gr.Markdown("---")
    gr.Markdown(
        "<center><small style='color:#6e7681;'>Developed with Featherless.ai • Powered by OpenAI-compatible API</small></center>",
        elem_classes="footer",
    )

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