Spaces:
Paused
Paused
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +34 -47
src/streamlit_app.py
CHANGED
|
@@ -139,45 +139,36 @@ def generate_llm_report(investor_style, ticker):
|
|
| 139 |
{news_text}
|
| 140 |
"""
|
| 141 |
system_prompt = """You are an expert financial analyst. Your mission is to write a concise, objective investment report for a client based on their specific risk profile.
|
| 142 |
-
|
| 143 |
ANALYSIS INSTRUCTIONS:
|
| 144 |
- Use BOTH the provided financial metrics ("Facts") and recent news headlines ("News").
|
| 145 |
- Always include the metrics listed under `core_metrics` in Facts. These are the most important indicators for the company/sector.
|
| 146 |
- Each Key Highlight should integrate at least one financial fact and one news item together (not listed separately).
|
| 147 |
- Do not hallucinate numbers that are not in Facts.
|
| 148 |
- Adjust the focus and tone strictly based on the investor's style:
|
| 149 |
-
|
| 150 |
If the style is SAFE (Conservative):
|
| 151 |
* Focus: Capital preservation and stable income.
|
| 152 |
* Highlight: Balance sheet strength, liquidity, predictable returns.
|
| 153 |
* Mention risks (regulatory, legal, earnings decline) first, then cautiously note positives.
|
| 154 |
* Downplay speculative or uncertain news.
|
| 155 |
-
|
| 156 |
If the style is NEUTRAL (Moderate):
|
| 157 |
* Focus: A balance between growth and safety.
|
| 158 |
* Highlight: Strategic trade-offs. Analyze how growth initiatives (from news) interact with financial stability (from facts).
|
| 159 |
* Present risks and opportunities in equal measure.
|
| 160 |
-
|
| 161 |
If the style is RISKY (Aggressive):
|
| 162 |
* Focus: High growth potential and maximum returns.
|
| 163 |
* Highlight: Exciting, forward-looking growth story. Emphasize innovation, expansion, competitive advantages.
|
| 164 |
* Frame risks as natural volatility on the path to high rewards.
|
| 165 |
* Place financial facts in the context of supporting aggressive growth.
|
| 166 |
-
|
| 167 |
OUTPUT REPORT TEMPLATE
|
| 168 |
Report for: A (investor_style) Investor
|
| 169 |
Company: (company_name)
|
| 170 |
-
|
| 171 |
1. Executive Summary:
|
| 172 |
(Provide a brief, one-paragraph summary that aligns with the investor's style, integrating at least one key metric and one recent news item.)
|
| 173 |
-
|
| 174 |
2. Key Analysis & Highlights:
|
| 175 |
(5–7 bullet points. Each bullet must combine a financial metric with a relevant news event, written from the perspective of the given investor style.)
|
| 176 |
-
|
| 177 |
3. Concluding Remark:
|
| 178 |
(One or two sentences, neutrally summarizing the company’s current standing for this type of investor.
|
| 179 |
Do NOT provide direct financial advice or buy/sell recommendations.)
|
| 180 |
-
|
| 181 |
IMPORTANT:
|
| 182 |
- Keep the tone professional and concise.
|
| 183 |
- Reports must be grounded in Facts and News only.
|
|
@@ -200,9 +191,6 @@ def generate_llm_report(investor_style, ticker):
|
|
| 200 |
|
| 201 |
return result
|
| 202 |
|
| 203 |
-
def reset_search_input():
|
| 204 |
-
if "stock_search_input" in st.session_state:
|
| 205 |
-
st.session_state.stock_search_input = None
|
| 206 |
|
| 207 |
# 1. 세션 상태(Session State) 초기화
|
| 208 |
# st.session_state : 스트림릿이 재실행되어도 값을 유지하는 변수
|
|
@@ -233,41 +221,40 @@ full_market_df = load_full_df() # (Srisk 모듈용 데이터)
|
|
| 233 |
# 3. 입력 섹션 (종목 추가)
|
| 234 |
st.subheader("1. 보유 종목 추가하기")
|
| 235 |
|
| 236 |
-
|
| 237 |
-
col1, col2 = st.columns([2, 1])
|
| 238 |
-
|
| 239 |
-
with col1:
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
quantity = st.number_input("보유 수량 (주)", min_value=0.01, step=0.1, format="%.2f")
|
| 250 |
-
|
| 251 |
-
# '종목 추가' 버튼
|
| 252 |
-
if st.button("➕ 포트폴리오에 추가", use_container_width=True, on_click=reset_search_input):
|
| 253 |
-
selected_ticker = None
|
| 254 |
-
if selected_display:
|
| 255 |
-
selected_ticker = DISPLAY_TO_TICKER_MAP.get(selected_display)
|
| 256 |
-
current_price = TICKER_TO_PRICE_MAP.get(selected_ticker)
|
| 257 |
-
|
| 258 |
-
if selected_ticker:
|
| 259 |
-
st.session_state.portfolio.append({
|
| 260 |
-
"ticker": selected_ticker,
|
| 261 |
-
"quantity": quantity,
|
| 262 |
-
"price": current_price,
|
| 263 |
-
"total_value": quantity * current_price
|
| 264 |
-
})
|
| 265 |
-
st.success(f"{selected_ticker} {quantity}주 (현재가 ${current_price:,.2f})를 포트폴리오에 추가했습니다.")
|
| 266 |
-
|
| 267 |
-
st.rerun()
|
| 268 |
|
| 269 |
-
|
| 270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
|
| 272 |
# 4. 포트폴리오 요약 및 보고서 생성 (스케치 레이아웃)
|
| 273 |
st.subheader("2. 포트폴리오 요약 및 보고서 생성")
|
|
@@ -373,7 +360,7 @@ with col_controls:
|
|
| 373 |
)
|
| 374 |
|
| 375 |
with col_regen:
|
| 376 |
-
if st.button(f"'{new_style}' 스타일로 재생성", use_container_width=True,
|
| 377 |
with st.spinner(f"'{new_style}' 스타일로 보고서를 다시 작성 중입니다..."):
|
| 378 |
regenerated_reports = generate_llm_reports(
|
| 379 |
st.session_state.portfolio,
|
|
|
|
| 139 |
{news_text}
|
| 140 |
"""
|
| 141 |
system_prompt = """You are an expert financial analyst. Your mission is to write a concise, objective investment report for a client based on their specific risk profile.
|
|
|
|
| 142 |
ANALYSIS INSTRUCTIONS:
|
| 143 |
- Use BOTH the provided financial metrics ("Facts") and recent news headlines ("News").
|
| 144 |
- Always include the metrics listed under `core_metrics` in Facts. These are the most important indicators for the company/sector.
|
| 145 |
- Each Key Highlight should integrate at least one financial fact and one news item together (not listed separately).
|
| 146 |
- Do not hallucinate numbers that are not in Facts.
|
| 147 |
- Adjust the focus and tone strictly based on the investor's style:
|
|
|
|
| 148 |
If the style is SAFE (Conservative):
|
| 149 |
* Focus: Capital preservation and stable income.
|
| 150 |
* Highlight: Balance sheet strength, liquidity, predictable returns.
|
| 151 |
* Mention risks (regulatory, legal, earnings decline) first, then cautiously note positives.
|
| 152 |
* Downplay speculative or uncertain news.
|
|
|
|
| 153 |
If the style is NEUTRAL (Moderate):
|
| 154 |
* Focus: A balance between growth and safety.
|
| 155 |
* Highlight: Strategic trade-offs. Analyze how growth initiatives (from news) interact with financial stability (from facts).
|
| 156 |
* Present risks and opportunities in equal measure.
|
|
|
|
| 157 |
If the style is RISKY (Aggressive):
|
| 158 |
* Focus: High growth potential and maximum returns.
|
| 159 |
* Highlight: Exciting, forward-looking growth story. Emphasize innovation, expansion, competitive advantages.
|
| 160 |
* Frame risks as natural volatility on the path to high rewards.
|
| 161 |
* Place financial facts in the context of supporting aggressive growth.
|
|
|
|
| 162 |
OUTPUT REPORT TEMPLATE
|
| 163 |
Report for: A (investor_style) Investor
|
| 164 |
Company: (company_name)
|
|
|
|
| 165 |
1. Executive Summary:
|
| 166 |
(Provide a brief, one-paragraph summary that aligns with the investor's style, integrating at least one key metric and one recent news item.)
|
|
|
|
| 167 |
2. Key Analysis & Highlights:
|
| 168 |
(5–7 bullet points. Each bullet must combine a financial metric with a relevant news event, written from the perspective of the given investor style.)
|
|
|
|
| 169 |
3. Concluding Remark:
|
| 170 |
(One or two sentences, neutrally summarizing the company’s current standing for this type of investor.
|
| 171 |
Do NOT provide direct financial advice or buy/sell recommendations.)
|
|
|
|
| 172 |
IMPORTANT:
|
| 173 |
- Keep the tone professional and concise.
|
| 174 |
- Reports must be grounded in Facts and News only.
|
|
|
|
| 191 |
|
| 192 |
return result
|
| 193 |
|
|
|
|
|
|
|
|
|
|
| 194 |
|
| 195 |
# 1. 세션 상태(Session State) 초기화
|
| 196 |
# st.session_state : 스트림릿이 재실행되어도 값을 유지하는 변수
|
|
|
|
| 221 |
# 3. 입력 섹션 (종목 추가)
|
| 222 |
st.subheader("1. 보유 종목 추가하기")
|
| 223 |
|
| 224 |
+
with st.form(key='portfolio_add_form', clear_on_submit=True):
|
| 225 |
+
col1, col2 = st.columns([2, 1])
|
| 226 |
+
|
| 227 |
+
with col1:
|
| 228 |
+
# `selectbox`를 검색 가능한 입력창으로 사용
|
| 229 |
+
selected_display = st.selectbox(
|
| 230 |
+
"종목 검색 (NASDAQ100 or S&P500 티커 또는 기업명)",
|
| 231 |
+
options=TICKER_OPTIONS_LIST,
|
| 232 |
+
index=None,
|
| 233 |
+
placeholder="티커를 검색하거나 선택하세요 (예: AAPL 또는 Apple)"
|
| 234 |
+
)
|
| 235 |
+
with col2:
|
| 236 |
+
quantity = st.number_input("보유 수량 (주)", min_value=0.01, step=0.1, format="%.2f")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
+
submitted = st.form_submit_button("➕ 포트폴리오에 추가", use_container_width=True, type="primary")
|
| 239 |
+
|
| 240 |
+
# '종목 추가' 버튼
|
| 241 |
+
if submitted:
|
| 242 |
+
selected_ticker = None
|
| 243 |
+
if selected_display:
|
| 244 |
+
selected_ticker = DISPLAY_TO_TICKER_MAP.get(selected_display)
|
| 245 |
+
current_price = TICKER_TO_PRICE_MAP.get(selected_ticker)
|
| 246 |
+
|
| 247 |
+
if selected_ticker:
|
| 248 |
+
st.session_state.portfolio.append({
|
| 249 |
+
"ticker": selected_ticker,
|
| 250 |
+
"quantity": quantity,
|
| 251 |
+
"price": current_price,
|
| 252 |
+
"total_value": quantity * current_price
|
| 253 |
+
})
|
| 254 |
+
st.success(f"{selected_ticker} {quantity}주 (현재가 ${current_price:,.2f})를 포트폴리오에 추가했습니다.")
|
| 255 |
+
st.rerun()
|
| 256 |
+
else:
|
| 257 |
+
st.warning("종목, 수량을 모두 올바르게 입력하세요.")
|
| 258 |
|
| 259 |
# 4. 포트폴리오 요약 및 보고서 생성 (스케치 레이아웃)
|
| 260 |
st.subheader("2. 포트폴리오 요약 및 보고서 생성")
|
|
|
|
| 360 |
)
|
| 361 |
|
| 362 |
with col_regen:
|
| 363 |
+
if st.button(f"'{new_style}' 스타일로 재생성", use_container_width=True, "my_regen_button"):
|
| 364 |
with st.spinner(f"'{new_style}' 스타일로 보고서를 다시 작성 중입니다..."):
|
| 365 |
regenerated_reports = generate_llm_reports(
|
| 366 |
st.session_state.portfolio,
|