QAway-to commited on
Commit
3e9225c
·
1 Parent(s): 56da3ec

New style APP (Tab Changes v1.8)

Browse files
Files changed (2) hide show
  1. app.py +16 -2
  2. core/comparison_table.py +31 -13
app.py CHANGED
@@ -118,9 +118,23 @@ h2, h3, .gr-markdown {
118
  comp_input_1 = gr.Textbox(label="Portfolio A", value="3852a354-e66e-4bc5-97e9-55124e31e687")
119
  comp_input_2 = gr.Textbox(label="Portfolio B", value="b1ef37aa-5b9a-41b4-9394-8823f2de36bb")
120
  comp_button = gr.Button("Load Comparison", variant="primary")
121
- comp_output = gr.Dataframe(label="Comparative Metrics", wrap=True)
 
 
 
 
 
 
 
 
 
122
  from core.comparison_table import show_comparison_table
123
- comp_button.click(fn=show_comparison_table, inputs=[comp_input_1, comp_input_2], outputs=comp_output)
 
 
 
 
 
124
 
125
 
126
  # --- Chat Assistant Tab ---
 
118
  comp_input_1 = gr.Textbox(label="Portfolio A", value="3852a354-e66e-4bc5-97e9-55124e31e687")
119
  comp_input_2 = gr.Textbox(label="Portfolio B", value="b1ef37aa-5b9a-41b4-9394-8823f2de36bb")
120
  comp_button = gr.Button("Load Comparison", variant="primary")
121
+
122
+ # Таблица и комментарий — два разных вывода
123
+ comp_output_table = gr.Dataframe(label="Comparative Metrics", wrap=True)
124
+ comp_output_comment = gr.Textbox(
125
+ label="AI Commentary",
126
+ lines=8,
127
+ interactive=False,
128
+ show_copy_button=True,
129
+ )
130
+
131
  from core.comparison_table import show_comparison_table
132
+ comp_button.click(
133
+ fn=show_comparison_table,
134
+ inputs=[comp_input_1, comp_input_2],
135
+ outputs=[comp_output_table, comp_output_comment],
136
+ )
137
+
138
 
139
 
140
  # --- Chat Assistant Tab ---
core/comparison_table.py CHANGED
@@ -1,39 +1,39 @@
1
  """
2
  🇬🇧 Module: comparison_table.py
3
- Purpose: Generates comparative DataFrame for two portfolios with styled metric differences.
4
 
5
  🇷🇺 Модуль: comparison_table.py
6
- Назначение: создаёт сравнительную таблицу метрик двух портфелей в формате DataFrame
7
- с визуальными индикаторами различий и форматированными значениями.
8
  """
9
 
10
  import pandas as pd
11
  import asyncio
12
  from services.output_api import fetch_metrics_async, extract_portfolio_id
 
 
13
 
14
 
15
  def show_comparison_table(portfolio_a: str, portfolio_b: str):
16
- """Public function for Gradio: build a styled comparison DataFrame."""
17
  pid_a = extract_portfolio_id(portfolio_a)
18
  pid_b = extract_portfolio_id(portfolio_b)
19
  if not pid_a or not pid_b:
20
- return "❌ Invalid portfolio IDs."
21
 
22
  try:
23
- df = asyncio.run(_build_comparison_df(pid_a, pid_b))
24
- return df
25
  except Exception as e:
26
- return f"❌ Error building comparison table: {e}"
27
 
28
 
29
- async def _build_comparison_df(p1: str, p2: str) -> pd.DataFrame:
30
- """Async helper to build portfolio comparison DataFrame."""
31
  m1 = await fetch_metrics_async(p1)
32
  m2 = await fetch_metrics_async(p2)
33
  if not m1 or not m2:
34
  raise ValueError("Metrics unavailable for one or both portfolios.")
35
 
36
- # Union of all metrics
37
  all_keys = sorted(set(m1.keys()) | set(m2.keys()))
38
  rows = []
39
  for k in all_keys:
@@ -47,6 +47,24 @@ async def _build_comparison_df(p1: str, p2: str) -> pd.DataFrame:
47
  "Portfolio B": round(v2, 3),
48
  "Δ Difference": f"{symbol} {diff:+.3f}"
49
  })
50
-
51
  df = pd.DataFrame(rows, columns=["Metric", "Portfolio A", "Portfolio B", "Δ Difference"])
52
- return df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  """
2
  🇬🇧 Module: comparison_table.py
3
+ Purpose: Generates comparative DataFrame for two portfolios and an LLM commentary.
4
 
5
  🇷🇺 Модуль: comparison_table.py
6
+ Назначение: создаёт сравнительную таблицу метрик двух портфелей и комментарий LLM.
 
7
  """
8
 
9
  import pandas as pd
10
  import asyncio
11
  from services.output_api import fetch_metrics_async, extract_portfolio_id
12
+ from services.llm_client import llm_service
13
+ from prompts.system_prompts import COMPARISON_SYSTEM_PROMPT
14
 
15
 
16
  def show_comparison_table(portfolio_a: str, portfolio_b: str):
17
+ """Public Gradio entry: returns both a DataFrame and LLM commentary."""
18
  pid_a = extract_portfolio_id(portfolio_a)
19
  pid_b = extract_portfolio_id(portfolio_b)
20
  if not pid_a or not pid_b:
21
+ return "❌ Invalid portfolio IDs.", "No commentary available."
22
 
23
  try:
24
+ df, commentary = asyncio.run(_build_comparison_with_comment(pid_a, pid_b))
25
+ return df, commentary
26
  except Exception as e:
27
+ return f"❌ Error building comparison table: {e}", "❌ LLM analysis failed."
28
 
29
 
30
+ async def _build_comparison_with_comment(p1: str, p2: str):
31
+ """Async helper: builds table and gets commentary."""
32
  m1 = await fetch_metrics_async(p1)
33
  m2 = await fetch_metrics_async(p2)
34
  if not m1 or not m2:
35
  raise ValueError("Metrics unavailable for one or both portfolios.")
36
 
 
37
  all_keys = sorted(set(m1.keys()) | set(m2.keys()))
38
  rows = []
39
  for k in all_keys:
 
47
  "Portfolio B": round(v2, 3),
48
  "Δ Difference": f"{symbol} {diff:+.3f}"
49
  })
 
50
  df = pd.DataFrame(rows, columns=["Metric", "Portfolio A", "Portfolio B", "Δ Difference"])
51
+
52
+ # Generate LLM commentary
53
+ summary = "\n".join(f"{r['Metric']}: {r['Δ Difference']}" for r in rows)
54
+ prompt = (
55
+ f"{COMPARISON_SYSTEM_PROMPT}\n"
56
+ f"Compare and explain the differences between Portfolio A and B:\n{summary}\n"
57
+ f"Write your insights as a concise professional commentary."
58
+ )
59
+
60
+ commentary = ""
61
+ for delta in llm_service.stream_chat(
62
+ messages=[
63
+ {"role": "system", "content": "You are an investment portfolio analyst."},
64
+ {"role": "user", "content": prompt},
65
+ ],
66
+ model="meta-llama/Meta-Llama-3.1-8B-Instruct",
67
+ ):
68
+ commentary += delta
69
+
70
+ return df, commentary