11
This commit is contained in:
parent
9b79a433a4
commit
e37803de09
Binary file not shown.
Binary file not shown.
@ -29,41 +29,66 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def intraday_market_temperature(prev_temp: MarketTemperature) -> MarketTemperature:
|
||||
"""盘中市场温度:在前一日基线上叠加实时指数涨跌"""
|
||||
"""盘中市场温度:用腾讯实时行情计算真实涨跌数据"""
|
||||
index_data = await tencent_client.get_index_realtime()
|
||||
sh_index = index_data.get("000001.SH")
|
||||
|
||||
if not sh_index:
|
||||
return prev_temp
|
||||
|
||||
# 盘中温度调整:基于上证实时涨跌幅微调
|
||||
pct = sh_index.get("pct_chg", 0)
|
||||
adjustment = 0
|
||||
if pct > 1.5:
|
||||
adjustment = 10
|
||||
elif pct > 0.5:
|
||||
adjustment = 5
|
||||
elif pct > 0:
|
||||
adjustment = 2
|
||||
elif pct > -0.5:
|
||||
adjustment = -2
|
||||
elif pct > -1.5:
|
||||
adjustment = -5
|
||||
else:
|
||||
adjustment = -10
|
||||
# ── 用腾讯实时行情计算真实涨跌数量 ──
|
||||
up_count = prev_temp.up_count
|
||||
down_count = prev_temp.down_count
|
||||
limit_up_count = prev_temp.limit_up_count
|
||||
limit_down_count = prev_temp.limit_down_count
|
||||
|
||||
new_temp = min(max(prev_temp.temperature + adjustment, 0), 100)
|
||||
try:
|
||||
stock_basic = tushare_client.get_stock_basic()
|
||||
if not stock_basic.empty:
|
||||
# 过滤 ST 股票
|
||||
all_codes = stock_basic[~stock_basic["name"].str.contains("ST", na=False)]["ts_code"].tolist()
|
||||
|
||||
if all_codes:
|
||||
quotes = await tencent_client.get_realtime_quotes_batch(all_codes)
|
||||
up_count = sum(1 for q in quotes.values() if q.pct_chg > 0)
|
||||
down_count = sum(1 for q in quotes.values() if q.pct_chg < 0)
|
||||
limit_up_count = sum(
|
||||
1 for q in quotes.values()
|
||||
if q.limit_up and q.price >= q.limit_up * 0.995
|
||||
)
|
||||
limit_down_count = sum(
|
||||
1 for q in quotes.values()
|
||||
if q.limit_down and q.price <= q.limit_down * 1.005
|
||||
)
|
||||
logger.info(
|
||||
f"盘中实时涨跌统计: 上涨={up_count} 下跌={down_count} "
|
||||
f"涨停={limit_up_count} 跌停={limit_down_count} (共{len(quotes)}只)"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"获取盘中实时涨跌统计失败,使用上一日数据: {e}")
|
||||
|
||||
# ── 温度分数:基于实时涨跌比重新计算 ──
|
||||
ratio = up_count / max(down_count, 1)
|
||||
temp_from_ratio = min(ratio / 3.0 * 25, 25) # 涨跌比维度 (0-25)
|
||||
temp_from_limit_up = min(limit_up_count / 2, 25) # 涨停数维度 (0-25)
|
||||
|
||||
# 指数方向调整 (0-25)
|
||||
pct = sh_index.get("pct_chg", 0)
|
||||
temp_from_index = min(max(pct * 8 + 12.5, 0), 25)
|
||||
|
||||
new_temp = round(temp_from_ratio + temp_from_limit_up + temp_from_index + 25, 1)
|
||||
new_temp = min(max(new_temp, 0), 100)
|
||||
|
||||
return MarketTemperature(
|
||||
trade_date=datetime.now().strftime("%Y%m%d"),
|
||||
up_count=prev_temp.up_count,
|
||||
down_count=prev_temp.down_count,
|
||||
limit_up_count=prev_temp.limit_up_count,
|
||||
limit_down_count=prev_temp.limit_down_count,
|
||||
up_count=up_count,
|
||||
down_count=down_count,
|
||||
limit_up_count=limit_up_count,
|
||||
limit_down_count=limit_down_count,
|
||||
max_streak=prev_temp.max_streak,
|
||||
broken_rate=prev_temp.broken_rate,
|
||||
index_above_ma20=prev_temp.index_above_ma20,
|
||||
temperature=round(new_temp, 1),
|
||||
index_above_ma20=pct > 0 if sh_index else prev_temp.index_above_ma20,
|
||||
temperature=new_temp,
|
||||
)
|
||||
|
||||
|
||||
|
||||
416
backend/app/analysis/potential_scanner.py
Normal file
416
backend/app/analysis/potential_scanner.py
Normal file
@ -0,0 +1,416 @@
|
||||
"""潜在启动股扫描器(Channel B)
|
||||
|
||||
从全市场中寻找底部蓄势、即将启动的股票。
|
||||
不依赖板块热度,独立于 Channel A(强中选强)。
|
||||
|
||||
筛选逻辑:
|
||||
1. 基本面预筛:PE/PB 合理、市值适中、非 ST 非次新
|
||||
2. 底部形态:股价在 60 日低点附近,近期不再创新低
|
||||
3. 缩量蓄势:成交量萎缩至地量水平
|
||||
4. 技术早期信号:MACD 底部金叉、RSI 从超卖回升等
|
||||
"""
|
||||
|
||||
import logging
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from app.data.tushare_client import tushare_client
|
||||
from app.analysis.technical import add_all_indicators
|
||||
from app.analysis.capital_flow import _score_valuation
|
||||
from app.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def scan_potential_breakout(
|
||||
trade_date: str = None,
|
||||
exclude_codes: set[str] = None,
|
||||
) -> list[dict]:
|
||||
"""扫描全市场潜在启动股票
|
||||
|
||||
Args:
|
||||
trade_date: 交易日期,默认最新
|
||||
exclude_codes: 需要排除的股票代码集合(Channel A 已推荐的)
|
||||
|
||||
Returns:
|
||||
list[dict]: [{ts_code, name, sector, capital_score, ...}]
|
||||
"""
|
||||
if not trade_date:
|
||||
trade_date = tushare_client.get_latest_trade_date()
|
||||
|
||||
exclude_codes = exclude_codes or set()
|
||||
|
||||
# ── 第一步:基本面预筛 ──
|
||||
basic_df = tushare_client.get_daily_basic(trade_date)
|
||||
if basic_df.empty:
|
||||
logger.warning("Channel B: daily_basic 数据为空")
|
||||
return []
|
||||
|
||||
stock_basic = tushare_client.get_stock_basic()
|
||||
|
||||
# 过滤 ST
|
||||
st_codes = set()
|
||||
if not stock_basic.empty:
|
||||
st_codes = set(stock_basic[stock_basic["name"].str.contains("ST", na=False)]["ts_code"])
|
||||
|
||||
# 过滤次新(上市不足 min_list_days 天)
|
||||
new_codes = set()
|
||||
if not stock_basic.empty:
|
||||
cutoff = (datetime.now() - timedelta(days=settings.min_list_days)).strftime("%Y%m%d")
|
||||
new_codes = set(stock_basic[stock_basic["list_date"] > cutoff]["ts_code"])
|
||||
|
||||
# 基本面硬性条件:仅沪深主板(00/60) + 创业板(30)
|
||||
# 自动排除:北证(xxxxx.BJ)、科创板(68xxxx.SH)、ST、次新
|
||||
eligible = basic_df[
|
||||
(basic_df["ts_code"].str.startswith(("00", "30", "60"))) &
|
||||
(~basic_df["ts_code"].isin(st_codes)) &
|
||||
(~basic_df["ts_code"].isin(new_codes)) &
|
||||
(~basic_df["ts_code"].isin(exclude_codes))
|
||||
].copy()
|
||||
|
||||
# PE 筛选:0-60(排除亏损和泡沫)
|
||||
if "pe_ttm" in eligible.columns:
|
||||
eligible = eligible[
|
||||
eligible["pe_ttm"].notna() &
|
||||
(eligible["pe_ttm"] > 0) &
|
||||
(eligible["pe_ttm"] <= 60)
|
||||
]
|
||||
|
||||
# PB 筛选:0-8
|
||||
if "pb" in eligible.columns:
|
||||
eligible = eligible[
|
||||
eligible["pb"].notna() &
|
||||
(eligible["pb"] > 0) &
|
||||
(eligible["pb"] <= 8)
|
||||
]
|
||||
|
||||
# 流通市值:30-500 亿
|
||||
if "circ_mv" in eligible.columns:
|
||||
eligible["circ_mv_yi"] = eligible["circ_mv"] / 10000 # 万 → 亿
|
||||
eligible = eligible[
|
||||
(eligible["circ_mv_yi"] >= 30) &
|
||||
(eligible["circ_mv_yi"] <= 500)
|
||||
]
|
||||
|
||||
# 换手率 > 1%(有一定活跃度)
|
||||
if "turnover_rate" in eligible.columns:
|
||||
eligible = eligible[eligible["turnover_rate"].notna() & (eligible["turnover_rate"] > 1)]
|
||||
|
||||
# 当日跌幅或微涨(底部区域:涨幅 < 3%,排除已启动的)
|
||||
if "pct_chg" in eligible.columns:
|
||||
eligible = eligible[
|
||||
eligible["pct_chg"].notna() &
|
||||
(eligible["pct_chg"] < 3)
|
||||
]
|
||||
|
||||
if eligible.empty:
|
||||
logger.warning("Channel B: 基本面预筛后无股票")
|
||||
return []
|
||||
|
||||
# 按换手率排序取 Top N(活跃度高的优先,避免扫描过多)
|
||||
if "turnover_rate" in eligible.columns:
|
||||
eligible = eligible.sort_values("turnover_rate", ascending=False)
|
||||
|
||||
max_candidates = 300 # 最多扫描 300 只,控制 K 线请求量
|
||||
candidate_codes = eligible["ts_code"].head(max_candidates).tolist()
|
||||
logger.info(f"Channel B: 基本面预筛后 {len(eligible)} 只,取 Top {len(candidate_codes)} 只进行技术扫描")
|
||||
|
||||
# ── 第二步:技术面扫描 ──
|
||||
results = []
|
||||
processed = 0
|
||||
|
||||
for ts_code in candidate_codes:
|
||||
try:
|
||||
df = tushare_client.get_stock_daily(ts_code, days=120)
|
||||
if df.empty or len(df) < 30:
|
||||
continue
|
||||
|
||||
df = df.sort_values("trade_date").reset_index(drop=True)
|
||||
df = add_all_indicators(df)
|
||||
|
||||
# 底部形态检测
|
||||
if not _check_bottom_reversal(df):
|
||||
continue
|
||||
|
||||
# 缩量蓄势检测
|
||||
volume_shrink = _check_volume_shrink(df)
|
||||
|
||||
# 技术早期信号(至少满足一个)
|
||||
early_signal = _check_technical_early_signal(df)
|
||||
if not early_signal:
|
||||
continue
|
||||
|
||||
# 计算评分
|
||||
score = _score_potential(df, volume_shrink)
|
||||
|
||||
# 估值评分
|
||||
row_data = eligible[eligible["ts_code"] == ts_code]
|
||||
pe = None
|
||||
pb = None
|
||||
circ_mv = None
|
||||
turnover_rate = 0
|
||||
if not row_data.empty:
|
||||
r = row_data.iloc[0]
|
||||
pe = float(r["pe_ttm"]) if pd.notna(r.get("pe_ttm")) else None
|
||||
pb = float(r["pb"]) if pd.notna(r.get("pb")) else None
|
||||
circ_mv = float(r.get("circ_mv_yi", 0)) or None
|
||||
turnover_rate = float(r.get("turnover_rate", 0) or 0)
|
||||
|
||||
valuation_score = _score_valuation(pe, pb)
|
||||
|
||||
# 股票名称
|
||||
name = ts_code
|
||||
if not stock_basic.empty:
|
||||
name_row = stock_basic[stock_basic["ts_code"] == ts_code]
|
||||
if not name_row.empty:
|
||||
name = name_row.iloc[0]["name"]
|
||||
|
||||
# 行业作为 sector
|
||||
sector = ""
|
||||
if not stock_basic.empty:
|
||||
ind_row = stock_basic[stock_basic["ts_code"] == ts_code]
|
||||
if not ind_row.empty:
|
||||
sector = str(ind_row.iloc[0].get("industry", ""))
|
||||
|
||||
results.append({
|
||||
"ts_code": ts_code,
|
||||
"name": name,
|
||||
"sector": sector,
|
||||
"sectors": [sector] if sector else [],
|
||||
"capital_score": round(score, 1),
|
||||
"valuation_score": round(valuation_score, 1),
|
||||
"main_net_inflow": 0,
|
||||
"inflow_ratio": 0,
|
||||
"turnover_rate": round(turnover_rate, 2),
|
||||
"volume_ratio": None,
|
||||
"circ_mv": circ_mv,
|
||||
"pe": round(pe, 2) if pe else None,
|
||||
"pb": round(pb, 2) if pb else None,
|
||||
})
|
||||
|
||||
processed += 1
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Channel B 扫描 {ts_code} 异常: {e}")
|
||||
continue
|
||||
|
||||
# 按评分排序
|
||||
results.sort(key=lambda x: x["capital_score"], reverse=True)
|
||||
top = results[:settings.top_stock_count]
|
||||
|
||||
logger.info(f"Channel B: 扫描完成,{len(results)} 只底部股票,取 Top {len(top)}")
|
||||
for r in top:
|
||||
logger.info(
|
||||
f"Channel B: {r['name']}({r['ts_code']}) "
|
||||
f"评分={r['capital_score']} 估值={r['valuation_score']}"
|
||||
)
|
||||
|
||||
return top
|
||||
|
||||
|
||||
def _check_bottom_reversal(df: pd.DataFrame) -> bool:
|
||||
"""底部反转形态检测
|
||||
|
||||
条件(满足任一即可):
|
||||
1. 股价距 60 日低点 < 10%(深度底部)
|
||||
2. 股价距 60 日低点 < 20% 且近 5 日止跌企稳
|
||||
"""
|
||||
if len(df) < 20:
|
||||
return False
|
||||
|
||||
lookback = min(60, len(df))
|
||||
recent = df.tail(lookback)
|
||||
last = df.iloc[-1]
|
||||
|
||||
low_60d = recent["low"].min()
|
||||
dist_from_low = (last["close"] - low_60d) / low_60d * 100
|
||||
|
||||
# 深度底部:距低点 < 10%,直接通过
|
||||
if dist_from_low < 10:
|
||||
return True
|
||||
|
||||
# 一般底部:距低点 < 20% 且近期止跌
|
||||
if dist_from_low > 20:
|
||||
return False
|
||||
|
||||
# 止跌检测:近 5 日最低价 vs 之前 5 日最低价
|
||||
last_5 = df.tail(5)
|
||||
if len(df) >= 10:
|
||||
prev_5 = df.iloc[-10:-5]
|
||||
recent_min = last_5["low"].min()
|
||||
prev_min = prev_5["low"].min()
|
||||
return recent_min >= prev_min * 0.97 # 允许 3% 误差
|
||||
return False
|
||||
|
||||
|
||||
def _check_volume_shrink(df: pd.DataFrame) -> bool:
|
||||
"""缩量蓄势检测
|
||||
|
||||
条件:近 3 日均量 < vol_ma20 * 0.7
|
||||
"""
|
||||
if len(df) < 20:
|
||||
return False
|
||||
|
||||
last = df.iloc[-1]
|
||||
vol_ma20 = last.get("vol_ma10", last["vol"]) # 用 vol_ma10 近似
|
||||
|
||||
recent_3_vol = df["vol"].tail(3).mean()
|
||||
return recent_3_vol < vol_ma20 * 0.7
|
||||
|
||||
|
||||
def _check_technical_early_signal(df: pd.DataFrame) -> bool:
|
||||
"""技术早期信号检测(满足任一即可)
|
||||
|
||||
1. MACD 底部金叉(DIF 从负区上穿 DEA)
|
||||
2. MACD 柱状线由负转正或缩短(底部动能转换)
|
||||
3. RSI 从超卖区回升(5 日前 RSI < 40,当前 > 40)
|
||||
4. 底部放量长阳(近 10 日内有涨幅 >3% 且量 > vol_ma5*1.3)
|
||||
5. MA5 开始向上拐头(短期趋势转变)
|
||||
6. 布林带下轨支撑(触及下轨后反弹)
|
||||
"""
|
||||
if len(df) < 10:
|
||||
return False
|
||||
|
||||
last = df.iloc[-1]
|
||||
prev = df.iloc[-2]
|
||||
|
||||
# 信号 1:MACD 底部金叉
|
||||
if (prev["dif"] <= prev["dea"] and last["dif"] > last["dea"]
|
||||
and last["dif"] < 0):
|
||||
return True
|
||||
|
||||
# 信号 2:MACD 柱状线缩短(绿柱变短,动能衰减)
|
||||
if len(df) >= 3:
|
||||
hist_1 = last["macd_hist"]
|
||||
hist_2 = prev["macd_hist"]
|
||||
hist_3 = df.iloc[-3]["macd_hist"]
|
||||
if hist_1 < 0 and hist_2 < 0 and hist_1 > hist_2 and hist_2 > hist_3:
|
||||
return True # 绿柱连续缩短
|
||||
|
||||
# 信号 3:RSI 从超卖区回升
|
||||
if len(df) >= 6:
|
||||
rsi_5d_ago = df.iloc[-6].get("rsi14", 50)
|
||||
rsi_now = last.get("rsi14", 50)
|
||||
if rsi_5d_ago < 40 and rsi_now > 40:
|
||||
return True
|
||||
|
||||
# 信号 4:底部放量长阳
|
||||
recent_10 = df.tail(10)
|
||||
for _, row in recent_10.iterrows():
|
||||
pct = row.get("pct_chg", 0) or 0
|
||||
vol = row["vol"]
|
||||
vol_ma = row.get("vol_ma5", vol)
|
||||
if pct > 3 and vol > vol_ma * 1.3:
|
||||
return True
|
||||
|
||||
# 信号 5:MA5 向上拐头(3 日前下降,现在上升)
|
||||
if len(df) >= 4:
|
||||
ma5_now = last["ma5"]
|
||||
ma5_1d = prev["ma5"]
|
||||
ma5_3d = df.iloc[-4]["ma5"]
|
||||
if ma5_1d < ma5_3d and ma5_now > ma5_1d: # 先降后升,拐头
|
||||
return True
|
||||
|
||||
# 信号 6:布林带下轨支撑后反弹
|
||||
if "boll_lower" in df.columns:
|
||||
recent_5 = df.tail(5)
|
||||
touched = any(row["low"] <= row["boll_lower"] * 1.01 for _, row in recent_5.iterrows())
|
||||
if touched and last["close"] > last["boll_lower"]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _score_potential(df: pd.DataFrame, volume_shrink: bool) -> float:
|
||||
"""潜在启动股评分(0-100)
|
||||
|
||||
评分维度:
|
||||
- 底部位置得分 (35%): 距 60 日低点越近越好
|
||||
- 技术信号强度 (30%): MACD/RSI/量价共振
|
||||
- 缩量蓄势 (20%): 成交量萎缩程度
|
||||
- 均线形态 (15%): 均线收敛或即将突破
|
||||
"""
|
||||
score = 0.0
|
||||
last = df.iloc[-1]
|
||||
|
||||
lookback = min(60, len(df))
|
||||
low_60d = df["low"].tail(lookback).min()
|
||||
dist_from_low = (last["close"] - low_60d) / low_60d * 100
|
||||
|
||||
# 1) 底部位置得分 (35 分)
|
||||
if dist_from_low < 5:
|
||||
score += 35 # 几乎在最低点
|
||||
elif dist_from_low < 8:
|
||||
score += 28
|
||||
elif dist_from_low < 12:
|
||||
score += 20
|
||||
elif dist_from_low <= 15:
|
||||
score += 12
|
||||
elif dist_from_low <= 20:
|
||||
score += 6 # 距低点较远但仍属底部区域
|
||||
|
||||
# 2) 技术信号强度 (30 分)
|
||||
signal_count = 0
|
||||
prev = df.iloc[-2] if len(df) >= 2 else last
|
||||
|
||||
# MACD 金叉
|
||||
if prev["dif"] <= prev["dea"] and last["dif"] > last["dea"] and last["dif"] < 0:
|
||||
signal_count += 1
|
||||
|
||||
# RSI 回升
|
||||
if len(df) >= 6:
|
||||
rsi_5d_ago = df.iloc[-6].get("rsi14", 50)
|
||||
rsi_now = last.get("rsi14", 50)
|
||||
if rsi_5d_ago < 35 and rsi_now > 40:
|
||||
signal_count += 1
|
||||
|
||||
# 放量长阳
|
||||
recent_10 = df.tail(10)
|
||||
for _, row in recent_10.iterrows():
|
||||
pct = row.get("pct_chg", 0) or 0
|
||||
vol = row["vol"]
|
||||
vol_ma = row.get("vol_ma5", vol)
|
||||
if pct > 3 and vol > vol_ma * 1.5:
|
||||
signal_count += 1
|
||||
break
|
||||
|
||||
if signal_count >= 3:
|
||||
score += 30
|
||||
elif signal_count == 2:
|
||||
score += 22
|
||||
elif signal_count == 1:
|
||||
score += 14
|
||||
|
||||
# 3) 缩量蓄势 (20 分)
|
||||
if volume_shrink:
|
||||
recent_3_vol = df["vol"].tail(3).mean()
|
||||
vol_ma10 = last.get("vol_ma10", df["vol"].mean())
|
||||
shrink_ratio = recent_3_vol / vol_ma10 if vol_ma10 > 0 else 1
|
||||
if shrink_ratio < 0.4:
|
||||
score += 20 # 极度缩量
|
||||
elif shrink_ratio < 0.55:
|
||||
score += 15
|
||||
elif shrink_ratio < 0.7:
|
||||
score += 10
|
||||
else:
|
||||
score += 3
|
||||
|
||||
# 4) 均线形态 (15 分): 短期均线开始上翘
|
||||
if len(df) >= 20:
|
||||
ma5_now = last["ma5"]
|
||||
ma5_3d = df.iloc[-3]["ma5"] if len(df) >= 3 else ma5_now
|
||||
ma10_now = last["ma10"]
|
||||
ma20_now = last["ma20"]
|
||||
|
||||
# MA5 上穿 MA10
|
||||
if ma5_now > ma10_now and df.iloc[-2]["ma5"] <= df.iloc[-2]["ma10"]:
|
||||
score += 15 # 金叉
|
||||
# MA5 向上
|
||||
elif ma5_now > ma5_3d:
|
||||
score += 10
|
||||
# 均线收敛(MA5 接近 MA20)
|
||||
elif abs(ma5_now - ma20_now) / ma20_now < 0.02:
|
||||
score += 8
|
||||
|
||||
return score
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -5,7 +5,7 @@ from fastapi import APIRouter
|
||||
from app.data.tushare_client import tushare_client
|
||||
from app.data import tencent_client
|
||||
from app.engine.recommender import get_latest_recommendations
|
||||
from app.config import is_trading_hours
|
||||
from app.config import is_trading_hours, is_market_session
|
||||
|
||||
router = APIRouter(prefix="/api/market", tags=["market"])
|
||||
|
||||
@ -48,7 +48,7 @@ async def get_overview():
|
||||
|
||||
盘中用腾讯实时行情,盘后用 Tushare 日线(有缓存)。
|
||||
"""
|
||||
if is_trading_hours():
|
||||
if is_market_session():
|
||||
return await _overview_realtime()
|
||||
return _overview_daily()
|
||||
|
||||
|
||||
@ -50,6 +50,8 @@ async def get_latest():
|
||||
"reasons": r.reasons,
|
||||
"risk_note": r.risk_note,
|
||||
"llm_analysis": r.llm_analysis,
|
||||
"llm_score": r.llm_score,
|
||||
"strategy": r.strategy,
|
||||
"scan_session": r.scan_session,
|
||||
"created_at": r.created_at.isoformat() if r.created_at else None,
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import logging
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.config import is_trading_hours
|
||||
from app.config import is_market_session
|
||||
from app.data.tushare_client import tushare_client
|
||||
from app.data.tencent_client import get_realtime_quotes_batch
|
||||
from app.engine.recommender import get_latest_sectors
|
||||
@ -15,7 +15,7 @@ router = APIRouter(prefix="/api/sectors", tags=["sectors"])
|
||||
|
||||
async def _enrich_sectors_realtime(sectors_data: list[dict]) -> list[dict]:
|
||||
"""盘中时,用腾讯实时行情补充板块涨幅和涨停数"""
|
||||
if not is_trading_hours():
|
||||
if not is_market_session():
|
||||
for s in sectors_data:
|
||||
s["realtime_pct_change"] = None
|
||||
s["realtime_limit_up_count"] = None
|
||||
@ -72,6 +72,9 @@ async def _enrich_sectors_realtime(sectors_data: list[dict]) -> list[dict]:
|
||||
|
||||
s["is_realtime"] = True
|
||||
|
||||
# 盘中按实时涨幅重新排序(涨幅高的排前面)
|
||||
sectors_data.sort(key=lambda s: s.get("realtime_pct_change") or 0, reverse=True)
|
||||
|
||||
return sectors_data
|
||||
|
||||
|
||||
|
||||
@ -79,6 +79,21 @@ def is_trading_hours() -> bool:
|
||||
return (930 <= t <= 1130) or (1300 <= t <= 1500)
|
||||
|
||||
|
||||
def is_market_session() -> bool:
|
||||
"""判断当前是否在 A 股交易日内(含午休 11:30-13:00)
|
||||
|
||||
午休期间腾讯实时行情仍返回上午收盘价,可用于展示。
|
||||
与 is_trading_hours() 的区别:午休时返回 True。
|
||||
"""
|
||||
from zoneinfo import ZoneInfo
|
||||
now = datetime.now(ZoneInfo("Asia/Shanghai"))
|
||||
weekday = now.weekday()
|
||||
if weekday >= 5:
|
||||
return False
|
||||
t = now.hour * 100 + now.minute
|
||||
return 930 <= t <= 1500
|
||||
|
||||
|
||||
def is_pre_close() -> bool:
|
||||
"""判断是否在收盘后、数据更新前(15:00-15:30 数据尚未完全更新)"""
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
Binary file not shown.
@ -119,6 +119,8 @@ class Recommendation(BaseModel):
|
||||
reasons: list[str] = []
|
||||
risk_note: str = ""
|
||||
level: str = "" # 强烈推荐/推荐/观望/回避
|
||||
strategy: str = "momentum" # momentum(强中选强) / potential(潜在启动)
|
||||
llm_analysis: str = "" # LLM 深度分析
|
||||
llm_score: float | None = None # AI 评分 1-10
|
||||
scan_session: str = ""
|
||||
created_at: datetime | None = None
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -29,6 +29,8 @@ async def init_db():
|
||||
"ALTER TABLE recommendations ADD COLUMN position_score REAL",
|
||||
"ALTER TABLE recommendations ADD COLUMN valuation_score REAL",
|
||||
"ALTER TABLE recommendations ADD COLUMN llm_analysis TEXT DEFAULT ''",
|
||||
"ALTER TABLE recommendations ADD COLUMN strategy TEXT DEFAULT 'momentum'",
|
||||
"ALTER TABLE recommendations ADD COLUMN llm_score REAL",
|
||||
"ALTER TABLE market_temperature ADD COLUMN max_streak INTEGER",
|
||||
"ALTER TABLE market_temperature ADD COLUMN broken_rate REAL",
|
||||
]:
|
||||
|
||||
@ -26,6 +26,8 @@ recommendations_table = Table(
|
||||
Column("stop_loss", Float),
|
||||
Column("reasons", Text),
|
||||
Column("llm_analysis", Text, default=""),
|
||||
Column("strategy", Text, default="momentum"),
|
||||
Column("llm_score", Float, default=None),
|
||||
Column("scan_session", Text),
|
||||
Column("created_at", DateTime, server_default=func.now()),
|
||||
)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -34,11 +34,11 @@ async def refresh_recommendations(trade_date: str = None, scan_session: str = "m
|
||||
# 持久化到数据库
|
||||
await _save_to_db(result)
|
||||
|
||||
# 异步 LLM 增强(不阻塞返回)
|
||||
# 异步 AI 深度分析(不阻塞返回)
|
||||
if settings.deepseek_api_key:
|
||||
import asyncio
|
||||
from app.llm.enhancer import enhance_recommendations
|
||||
asyncio.create_task(enhance_recommendations(result))
|
||||
from app.llm.analysis_agent import analyze_recommendations
|
||||
asyncio.create_task(analyze_recommendations(result))
|
||||
|
||||
return result
|
||||
|
||||
@ -138,6 +138,8 @@ async def _save_to_db(result: dict):
|
||||
stop_loss=rec.stop_loss,
|
||||
reasons=json.dumps(rec.reasons, ensure_ascii=False),
|
||||
llm_analysis=rec.llm_analysis,
|
||||
strategy=rec.strategy,
|
||||
llm_score=rec.llm_score,
|
||||
scan_session=rec.scan_session,
|
||||
)
|
||||
await db.execute(stmt)
|
||||
@ -201,6 +203,8 @@ async def _load_today_from_db() -> dict:
|
||||
stop_loss=r["stop_loss"],
|
||||
reasons=json.loads(r["reasons"]) if r["reasons"] else [],
|
||||
llm_analysis=r.get("llm_analysis") or "",
|
||||
strategy=r.get("strategy") or "momentum",
|
||||
llm_score=r.get("llm_score"),
|
||||
scan_session=r["scan_session"] or "",
|
||||
))
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"""四层漏斗筛选器
|
||||
"""双通道漏斗筛选器
|
||||
|
||||
串联市场温度 → 板块热度 → 资金筛选 → 技术信号,
|
||||
输出最终推荐列表。
|
||||
Channel A(强中选强):市场温度 → 板块热度 → 资金筛选 → 技术信号
|
||||
Channel B(潜在启动):全市场技术扫描 → 底部形态 → 估值筛选
|
||||
|
||||
自动检测是否在交易时段:
|
||||
- 盘中模式:用前一日 Tushare 数据 + 腾讯实时行情混合筛选
|
||||
@ -13,6 +13,7 @@ import logging
|
||||
from app.analysis.market_temp import calculate_market_temperature
|
||||
from app.analysis.sector_scanner import scan_hot_sectors
|
||||
from app.analysis.capital_flow import filter_stocks_by_capital
|
||||
from app.analysis.potential_scanner import scan_potential_breakout
|
||||
from app.analysis.signals import generate_signals
|
||||
from app.analysis.intraday import intraday_market_temperature, intraday_filter_stocks
|
||||
from app.data.models import MarketTemperature, SectorInfo, TechnicalSignal, Recommendation
|
||||
@ -22,7 +23,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def run_screening(trade_date: str = None) -> dict:
|
||||
"""执行完整的四层漏斗筛选流程
|
||||
"""执行双通道筛选流程
|
||||
|
||||
自动检测交易时段:
|
||||
- 盘中 → 用前一日板块+实时行情筛选
|
||||
@ -31,7 +32,6 @@ async def run_screening(trade_date: str = None) -> dict:
|
||||
返回: {
|
||||
"market_temp": MarketTemperature,
|
||||
"hot_sectors": [SectorInfo],
|
||||
"capital_filtered": [dict],
|
||||
"recommendations": [Recommendation],
|
||||
"scan_mode": "intraday" | "post_market",
|
||||
}
|
||||
@ -40,13 +40,11 @@ async def run_screening(trade_date: str = None) -> dict:
|
||||
scan_mode = "intraday" if intraday else "post_market"
|
||||
logger.info(f"=== 筛选模式: {'盘中实时' if intraday else '盘后'} ===")
|
||||
|
||||
# ── 第一层:市场温度 ──
|
||||
# 盘中和盘后都先计算基线温度(盘中用前一日数据)
|
||||
logger.info("=== 第一层:市场温度计 ===")
|
||||
# ── 市场温度(共享) ──
|
||||
logger.info("=== 市场温度计 ===")
|
||||
market_temp = calculate_market_temperature(trade_date)
|
||||
|
||||
if intraday:
|
||||
# 盘中叠加实时指数涨跌调整温度
|
||||
market_temp = await intraday_market_temperature(market_temp)
|
||||
logger.info(f"盘中市场温度(实时调整): {market_temp.temperature}")
|
||||
else:
|
||||
@ -54,54 +52,94 @@ async def run_screening(trade_date: str = None) -> dict:
|
||||
|
||||
market_temp_score = market_temp.temperature
|
||||
|
||||
# ── 第二层:板块热度 ──
|
||||
# 盘中用前一日的板块热度作为基线(哪些板块近期是热点)
|
||||
logger.info("=== 第二层:板块热度扫描 ===")
|
||||
# ── 板块热度(Channel A 需要) ──
|
||||
logger.info("=== 板块热度扫描 ===")
|
||||
all_sectors = scan_hot_sectors(trade_date)
|
||||
hot_sectors = all_sectors[:settings.top_sector_count]
|
||||
|
||||
if not hot_sectors:
|
||||
logger.warning("未找到热门板块")
|
||||
return {
|
||||
"market_temp": market_temp,
|
||||
"hot_sectors": [],
|
||||
"capital_filtered": [],
|
||||
"recommendations": [],
|
||||
"scan_mode": scan_mode,
|
||||
}
|
||||
# ── Channel A:强中选强 ──
|
||||
recommendations_a = []
|
||||
capital_filtered = []
|
||||
|
||||
# ── 第三层:资金/实时筛选 ──
|
||||
if intraday:
|
||||
logger.info("=== 第三层:盘中实时个股筛选 ===")
|
||||
capital_filtered = await intraday_filter_stocks(hot_sectors)
|
||||
else:
|
||||
logger.info("=== 第三层:个股资金筛选 ===")
|
||||
capital_filtered = await filter_stocks_by_capital(hot_sectors, trade_date)
|
||||
if hot_sectors:
|
||||
if intraday:
|
||||
logger.info("=== Channel A:盘中实时个股筛选 ===")
|
||||
capital_filtered = await intraday_filter_stocks(hot_sectors)
|
||||
else:
|
||||
logger.info("=== Channel A:个股资金筛选 ===")
|
||||
capital_filtered = await filter_stocks_by_capital(hot_sectors, trade_date)
|
||||
|
||||
if not capital_filtered:
|
||||
logger.warning("筛选后无符合条件的个股")
|
||||
return {
|
||||
"market_temp": market_temp,
|
||||
"hot_sectors": hot_sectors,
|
||||
"capital_filtered": [],
|
||||
"recommendations": [],
|
||||
"scan_mode": scan_mode,
|
||||
}
|
||||
if capital_filtered:
|
||||
recommendations_a = _build_recommendations(
|
||||
capital_filtered, market_temp, hot_sectors,
|
||||
market_temp_score=market_temp_score,
|
||||
strategy="momentum", intraday=intraday,
|
||||
)
|
||||
|
||||
# ── 第四层:技术面信号 ──
|
||||
logger.info("=== 第四层:技术面买卖信号 ===")
|
||||
logger.info(f"Channel A(强中选强): {len(recommendations_a)} 只")
|
||||
|
||||
# ── Channel B:潜在启动 ──
|
||||
logger.info("=== Channel B:潜在启动扫描 ===")
|
||||
exclude_codes = {r.ts_code for r in recommendations_a}
|
||||
potential_filtered = scan_potential_breakout(trade_date, exclude_codes)
|
||||
|
||||
recommendations_b = []
|
||||
if potential_filtered:
|
||||
recommendations_b = _build_recommendations(
|
||||
potential_filtered, market_temp, hot_sectors,
|
||||
market_temp_score=market_temp_score,
|
||||
strategy="potential", intraday=intraday,
|
||||
)
|
||||
|
||||
logger.info(f"Channel B(潜在启动): {len(recommendations_b)} 只")
|
||||
|
||||
# 合并,按评分排序
|
||||
all_recommendations = recommendations_a + recommendations_b
|
||||
all_recommendations.sort(key=lambda x: x.score, reverse=True)
|
||||
|
||||
# 过滤掉低质量推荐
|
||||
all_recommendations = [r for r in all_recommendations if r.score >= 40]
|
||||
|
||||
logger.info(f"=== 筛选完成: {len(all_recommendations)} 只股票 ({scan_mode}) ===")
|
||||
for r in all_recommendations[:5]:
|
||||
strategy_label = "强中选强" if r.strategy == "momentum" else "潜在启动"
|
||||
logger.info(f" [{strategy_label}] {r.name}({r.ts_code}) {r.level} 评分={r.score} 信号={r.signal}")
|
||||
|
||||
return {
|
||||
"market_temp": market_temp,
|
||||
"hot_sectors": hot_sectors,
|
||||
"capital_filtered": capital_filtered,
|
||||
"recommendations": all_recommendations,
|
||||
"scan_mode": scan_mode,
|
||||
}
|
||||
|
||||
|
||||
def _build_recommendations(
|
||||
stocks: list[dict],
|
||||
market_temp: MarketTemperature,
|
||||
hot_sectors: list[SectorInfo],
|
||||
market_temp_score: float = 0,
|
||||
strategy: str = "momentum",
|
||||
intraday: bool = False,
|
||||
) -> list[Recommendation]:
|
||||
"""从筛选结果构建推荐列表(Channel A/B 共用)"""
|
||||
recommendations = []
|
||||
|
||||
for stock in capital_filtered:
|
||||
for stock in stocks:
|
||||
ts_code = stock["ts_code"]
|
||||
name = stock["name"]
|
||||
sector = stock["sector"]
|
||||
|
||||
tech_signal = generate_signals(ts_code, name)
|
||||
|
||||
# 板块得分(含阶段调整)
|
||||
sector_score = _get_sector_score(stock["sector"], hot_sectors)
|
||||
sector_stage = _get_sector_stage(stock["sector"], hot_sectors)
|
||||
# 板块得分
|
||||
if strategy == "momentum":
|
||||
sector_score = _get_sector_score(sector, hot_sectors)
|
||||
sector_stage = _get_sector_stage(sector, hot_sectors)
|
||||
else:
|
||||
# Channel B:不在热门板块中,给基础分
|
||||
sector_score = 30.0
|
||||
sector_stage = "mid"
|
||||
|
||||
# 估值安全得分
|
||||
valuation_score = stock.get("valuation_score", 50)
|
||||
@ -109,37 +147,56 @@ async def run_screening(trade_date: str = None) -> dict:
|
||||
# 位置安全得分
|
||||
position_score = tech_signal.position_score
|
||||
|
||||
# 六维综合评分(降低动量权重,增加安全维度)
|
||||
# 市场10% + 板块20% + 资金20% + 技术20% + 位置安全15% + 估值安全15%
|
||||
final_score = (
|
||||
market_temp_score * 0.10 +
|
||||
sector_score * 0.20 +
|
||||
stock["capital_score"] * 0.20 +
|
||||
tech_signal.score * 0.20 +
|
||||
position_score * 0.15 +
|
||||
valuation_score * 0.15
|
||||
)
|
||||
# 综合评分(根据策略调整权重)
|
||||
if strategy == "momentum":
|
||||
# 强中选强:板块和资金权重高
|
||||
# 市场10% + 板块20% + 资金20% + 技术15% + 位置安全15% + 估值安全20%
|
||||
final_score = (
|
||||
market_temp_score * 0.10 +
|
||||
sector_score * 0.20 +
|
||||
stock["capital_score"] * 0.20 +
|
||||
tech_signal.score * 0.15 +
|
||||
position_score * 0.15 +
|
||||
valuation_score * 0.20
|
||||
)
|
||||
else:
|
||||
# 潜在启动:技术面和估值权重高
|
||||
# 市场10% + 技术25% + 资金(potential_score)15% + 位置安全25% + 估值安全25%
|
||||
final_score = (
|
||||
market_temp_score * 0.10 +
|
||||
tech_signal.score * 0.25 +
|
||||
stock["capital_score"] * 0.15 +
|
||||
position_score * 0.25 +
|
||||
valuation_score * 0.25
|
||||
)
|
||||
|
||||
# 板块尾声阶段额外惩罚(防止追板块尾部)
|
||||
if sector_stage == "end":
|
||||
final_score *= 0.85
|
||||
elif sector_stage == "late":
|
||||
final_score *= 0.92
|
||||
# 板块尾声阶段额外惩罚(仅 Channel A)
|
||||
if strategy == "momentum":
|
||||
if sector_stage == "end":
|
||||
final_score *= 0.85
|
||||
elif sector_stage == "late":
|
||||
final_score *= 0.92
|
||||
|
||||
# 确定信号和等级
|
||||
signal = "HOLD"
|
||||
if (tech_signal.score >= settings.buy_score_threshold
|
||||
and tech_signal.signal_count >= settings.buy_min_signals
|
||||
and position_score >= 30): # 位置太危险不给买入信号
|
||||
signal = "BUY"
|
||||
if strategy == "momentum":
|
||||
if (tech_signal.score >= settings.buy_score_threshold
|
||||
and tech_signal.signal_count >= settings.buy_min_signals
|
||||
and position_score >= 30):
|
||||
signal = "BUY"
|
||||
else:
|
||||
# Channel B:技术面要求稍低,但位置安全要求更高
|
||||
if (tech_signal.score >= settings.buy_score_threshold * 0.7
|
||||
and position_score >= 40):
|
||||
signal = "BUY"
|
||||
|
||||
level = _score_to_level(final_score)
|
||||
|
||||
# 生成推荐理由
|
||||
reasons = _generate_reasons(stock, tech_signal, market_temp, intraday)
|
||||
reasons = _generate_reasons(stock, tech_signal, market_temp, intraday, strategy)
|
||||
|
||||
# 风险提示
|
||||
risk_note = _generate_risk_note(market_temp, tech_signal, intraday)
|
||||
risk_note = _generate_risk_note(market_temp, tech_signal, intraday, strategy)
|
||||
|
||||
rec = Recommendation(
|
||||
ts_code=ts_code,
|
||||
@ -159,26 +216,11 @@ async def run_screening(trade_date: str = None) -> dict:
|
||||
reasons=reasons,
|
||||
risk_note=risk_note,
|
||||
level=level,
|
||||
strategy=strategy,
|
||||
)
|
||||
recommendations.append(rec)
|
||||
|
||||
# 按综合评分排序
|
||||
recommendations.sort(key=lambda x: x.score, reverse=True)
|
||||
|
||||
# 过滤掉低质量推荐(综合分 < 40 为"回避"级别,不展示)
|
||||
recommendations = [r for r in recommendations if r.score >= 40]
|
||||
|
||||
logger.info(f"=== 筛选完成: {len(recommendations)} 只股票 ({scan_mode}) ===")
|
||||
for r in recommendations[:5]:
|
||||
logger.info(f" {r.name}({r.ts_code}) {r.level} 评分={r.score} 信号={r.signal}")
|
||||
|
||||
return {
|
||||
"market_temp": market_temp,
|
||||
"hot_sectors": hot_sectors,
|
||||
"capital_filtered": capital_filtered,
|
||||
"recommendations": recommendations,
|
||||
"scan_mode": scan_mode,
|
||||
}
|
||||
return recommendations
|
||||
|
||||
|
||||
def _get_sector_score(sector_name: str, hot_sectors: list[SectorInfo]) -> float:
|
||||
@ -186,7 +228,7 @@ def _get_sector_score(sector_name: str, hot_sectors: list[SectorInfo]) -> float:
|
||||
for s in hot_sectors:
|
||||
if s.sector_name == sector_name:
|
||||
return s.heat_score
|
||||
return 30.0 # 不在热门板块中,给一个基础分
|
||||
return 30.0
|
||||
|
||||
|
||||
def _get_sector_stage(sector_name: str, hot_sectors: list[SectorInfo]) -> str:
|
||||
@ -210,12 +252,26 @@ def _score_to_level(score: float) -> str:
|
||||
|
||||
def _generate_reasons(
|
||||
stock: dict, tech: TechnicalSignal, market: MarketTemperature,
|
||||
intraday: bool = False,
|
||||
intraday: bool = False, strategy: str = "momentum",
|
||||
) -> list[str]:
|
||||
reasons = []
|
||||
|
||||
if intraday:
|
||||
# 盘中理由:侧重实时行情指标
|
||||
if strategy == "potential":
|
||||
# Channel B 理由:侧重底部形态和估值
|
||||
if tech.position_score >= 70:
|
||||
reasons.append("位置处于低位,距高点回调充分")
|
||||
if tech.macd_golden:
|
||||
reasons.append("MACD底部金叉,反转信号初现")
|
||||
if tech.pullback_support:
|
||||
reasons.append("缩量回踩支撑位,蓄势充分")
|
||||
if tech.big_yang:
|
||||
reasons.append("底部出现放量长阳,资金介入")
|
||||
if stock.get("valuation_score", 0) >= 60:
|
||||
reasons.append("估值安全,下行空间有限")
|
||||
if not reasons:
|
||||
reasons.append("技术面底部信号显现,关注启动时机")
|
||||
elif intraday:
|
||||
# Channel A 盘中理由
|
||||
pct = stock.get("pct_chg", 0)
|
||||
vr = stock.get("volume_ratio")
|
||||
if vr and vr > 2:
|
||||
@ -224,31 +280,41 @@ def _generate_reasons(
|
||||
reasons.append(f"盘中涨幅{pct:.1f}%,走势强劲")
|
||||
elif pct > 0:
|
||||
reasons.append(f"盘中涨幅{pct:.1f}%,温和上攻")
|
||||
|
||||
reasons.append(f"所属板块【{stock['sector']}】为当前热门概念")
|
||||
|
||||
tech_reasons = []
|
||||
if tech.ma_bullish:
|
||||
tech_reasons.append("均线多头排列")
|
||||
if tech.volume_breakout:
|
||||
tech_reasons.append("放量突破")
|
||||
if tech.macd_golden:
|
||||
tech_reasons.append("MACD金叉")
|
||||
if tech_reasons:
|
||||
reasons.append("技术面: " + "、".join(tech_reasons))
|
||||
else:
|
||||
# 盘后理由:侧重资金流向
|
||||
# Channel A 盘后理由
|
||||
inflow = stock.get("main_net_inflow", 0)
|
||||
if inflow > 5000:
|
||||
reasons.append(f"主力资金大幅流入{inflow:.0f}万元")
|
||||
elif inflow > 1000:
|
||||
reasons.append(f"主力资金持续流入{inflow:.0f}万元")
|
||||
|
||||
# 板块
|
||||
reasons.append(f"所属板块【{stock['sector']}】为当前热门概念")
|
||||
reasons.append(f"所属板块【{stock['sector']}】为当前热门概念")
|
||||
|
||||
# 技术面
|
||||
tech_reasons = []
|
||||
if tech.ma_bullish:
|
||||
tech_reasons.append("均线多头排列")
|
||||
if tech.volume_breakout:
|
||||
tech_reasons.append("放量突破")
|
||||
if tech.macd_golden:
|
||||
tech_reasons.append("MACD金叉")
|
||||
if tech.pullback_support:
|
||||
tech_reasons.append("缩量回踩支撑")
|
||||
if tech.big_yang:
|
||||
tech_reasons.append("底部放量长阳")
|
||||
if tech_reasons:
|
||||
reasons.append("技术面: " + "、".join(tech_reasons))
|
||||
tech_reasons = []
|
||||
if tech.ma_bullish:
|
||||
tech_reasons.append("均线多头排列")
|
||||
if tech.volume_breakout:
|
||||
tech_reasons.append("放量突破")
|
||||
if tech.macd_golden:
|
||||
tech_reasons.append("MACD金叉")
|
||||
if tech.pullback_support:
|
||||
tech_reasons.append("缩量回踩支撑")
|
||||
if tech.big_yang:
|
||||
tech_reasons.append("底部放量长阳")
|
||||
if tech_reasons:
|
||||
reasons.append("技术面: " + "、".join(tech_reasons))
|
||||
|
||||
# 位置安全
|
||||
if tech.position_score >= 70:
|
||||
@ -256,16 +322,18 @@ def _generate_reasons(
|
||||
elif tech.position_score < 30:
|
||||
reasons.append("注意:短期涨幅较大,追高风险")
|
||||
|
||||
return reasons[:3] # 最多3条
|
||||
return reasons[:3]
|
||||
|
||||
|
||||
def _generate_risk_note(
|
||||
market: MarketTemperature, tech: TechnicalSignal,
|
||||
intraday: bool = False,
|
||||
intraday: bool = False, strategy: str = "momentum",
|
||||
) -> str:
|
||||
notes = []
|
||||
if intraday:
|
||||
notes.append("盘中数据参考,需结合尾盘确认")
|
||||
if strategy == "potential":
|
||||
notes.append("底部股票可能继续盘整,注意时间成本")
|
||||
if market.temperature < 30:
|
||||
notes.append("市场情绪偏冷,系统性风险较高")
|
||||
elif market.temperature < 50:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
249
backend/app/llm/analysis_agent.py
Normal file
249
backend/app/llm/analysis_agent.py
Normal file
@ -0,0 +1,249 @@
|
||||
"""AI 深度分析
|
||||
|
||||
预先获取 K 线、资金流、技术信号等数据,一次性传入 LLM 生成结构化分析报告。
|
||||
不依赖 tool calling,避免 DeepSeek DSML 标签问题。
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
|
||||
from app.llm.client import chat_completion
|
||||
from app.llm.prompts import (
|
||||
MOMENTUM_ANALYSIS_PROMPT,
|
||||
POTENTIAL_ANALYSIS_PROMPT,
|
||||
)
|
||||
from app.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def analyze_recommendations(result: dict) -> None:
|
||||
"""对所有推荐股票执行 AI 深度分析"""
|
||||
recommendations = result.get("recommendations", [])
|
||||
if not recommendations or not settings.deepseek_api_key:
|
||||
return
|
||||
|
||||
try:
|
||||
await _do_analyze(result, recommendations)
|
||||
except Exception as e:
|
||||
logger.error(f"AI 分析任务异常: {e}")
|
||||
for rec in recommendations:
|
||||
if not rec.llm_analysis:
|
||||
rec.llm_analysis = "AI 分析暂时不可用"
|
||||
await _broadcast_llm_ready(recommendations)
|
||||
|
||||
|
||||
async def _do_analyze(result: dict, recommendations: list) -> None:
|
||||
"""分析核心逻辑"""
|
||||
market_temp = result.get("market_temp")
|
||||
hot_sectors = result.get("hot_sectors", [])
|
||||
|
||||
# 构建板块文本
|
||||
sectors_text = "\n".join(
|
||||
f"- {s.sector_name}: 涨幅{s.pct_change}%, 资金流入{s.capital_inflow}万, "
|
||||
f"涨停{s.limit_up_count}家, 热度{s.heat_score}分, 阶段={s.stage}"
|
||||
for s in hot_sectors[:5]
|
||||
) if hot_sectors else "暂无板块数据"
|
||||
|
||||
# 温度等级
|
||||
temp_val = market_temp.temperature if market_temp else 0
|
||||
if temp_val >= 60:
|
||||
temp_level = "积极"
|
||||
elif temp_val >= 30:
|
||||
temp_level = "谨慎"
|
||||
else:
|
||||
temp_level = "低迷"
|
||||
|
||||
enhanced_count = 0
|
||||
for rec in recommendations:
|
||||
try:
|
||||
# 预先获取该股票的详细数据
|
||||
stock_data = await _fetch_stock_data(rec.ts_code, rec.sector)
|
||||
|
||||
strategy_label = "强中选强" if rec.strategy == "momentum" else "潜在启动"
|
||||
system_prompt = (
|
||||
MOMENTUM_ANALYSIS_PROMPT
|
||||
if rec.strategy == "momentum"
|
||||
else POTENTIAL_ANALYSIS_PROMPT
|
||||
)
|
||||
|
||||
user_msg = _build_user_message(
|
||||
rec=rec,
|
||||
strategy_label=strategy_label,
|
||||
market_temp=market_temp,
|
||||
temp_level=temp_level,
|
||||
sectors_text=sectors_text,
|
||||
stock_data=stock_data,
|
||||
)
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_msg},
|
||||
]
|
||||
|
||||
resp = await chat_completion(messages)
|
||||
if resp and resp.content:
|
||||
analysis = resp.content.strip()
|
||||
rec.llm_analysis = analysis
|
||||
rec.llm_score = _extract_score(analysis)
|
||||
enhanced_count += 1
|
||||
else:
|
||||
rec.llm_analysis = "AI 分析暂时不可用"
|
||||
|
||||
except asyncio.CancelledError:
|
||||
logger.warning(f"AI 分析 {rec.ts_code} 被取消")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"AI 分析 {rec.ts_code} 失败: {e}")
|
||||
rec.llm_analysis = "AI 分析暂时不可用"
|
||||
|
||||
# 无论成功失败都保存并广播
|
||||
await _save_llm_analysis_to_db(recommendations)
|
||||
await _broadcast_llm_ready(recommendations)
|
||||
|
||||
logger.info(f"AI 深度分析完成: {enhanced_count}/{len(recommendations)} 条")
|
||||
|
||||
|
||||
async def _fetch_stock_data(ts_code: str, sector: str) -> str:
|
||||
"""预先获取个股详细数据,拼接为文本供 LLM 分析"""
|
||||
from app.llm.tool_executor import (
|
||||
_get_stock_kline,
|
||||
_get_stock_capital_flow,
|
||||
_get_stock_technical_signal,
|
||||
_get_sector_performance,
|
||||
)
|
||||
|
||||
parts = []
|
||||
|
||||
# K 线(最近 30 天摘要)
|
||||
try:
|
||||
kline_text = await _get_stock_kline(ts_code, 60)
|
||||
kline_data = json.loads(kline_text)
|
||||
if isinstance(kline_data, list) and kline_data:
|
||||
# 只取最近 10 条以控制 token
|
||||
recent = kline_data[-10:]
|
||||
kline_summary = "\n".join(
|
||||
f" {d.get('trade_date', '')}: 收{d.get('close', '')} "
|
||||
f"涨跌{d.get('pct_chg', '')}% 量{d.get('vol', '')} "
|
||||
f"MA5={d.get('ma5', '')} MA10={d.get('ma10', '')} MA20={d.get('ma20', '')} "
|
||||
f"DIF={d.get('dif', '')} DEA={d.get('dea', '')} RSI={d.get('rsi14', '')}"
|
||||
for d in recent
|
||||
)
|
||||
parts.append(f"## K线数据(近10日)\n{kline_summary}")
|
||||
except Exception as e:
|
||||
logger.debug(f"获取K线数据失败 {ts_code}: {e}")
|
||||
|
||||
# 资金流向
|
||||
try:
|
||||
flow_text = await _get_stock_capital_flow(ts_code, 5)
|
||||
flow_data = json.loads(flow_text)
|
||||
if isinstance(flow_data, list) and flow_data:
|
||||
flow_summary = "\n".join(
|
||||
f" {d.get('trade_date', '')}: 主力净流入{d.get('main_net_inflow', 0)}万"
|
||||
for d in flow_data[-5:]
|
||||
)
|
||||
parts.append(f"## 资金流向(近5日)\n{flow_summary}")
|
||||
except Exception as e:
|
||||
logger.debug(f"获取资金流向失败 {ts_code}: {e}")
|
||||
|
||||
# 技术信号
|
||||
try:
|
||||
signal_text = await _get_stock_technical_signal(ts_code)
|
||||
parts.append(f"## 技术信号\n{signal_text}")
|
||||
except Exception as e:
|
||||
logger.debug(f"获取技术信号失败 {ts_code}: {e}")
|
||||
|
||||
# 板块表现
|
||||
if sector:
|
||||
try:
|
||||
sector_text = await _get_sector_performance(sector)
|
||||
parts.append(f"## 板块数据\n{sector_text}")
|
||||
except Exception as e:
|
||||
logger.debug(f"获取板块数据失败 {sector}: {e}")
|
||||
|
||||
return "\n\n".join(parts) if parts else "暂无额外数据"
|
||||
|
||||
|
||||
def _build_user_message(
|
||||
rec,
|
||||
strategy_label: str,
|
||||
market_temp,
|
||||
temp_level: str,
|
||||
sectors_text: str,
|
||||
stock_data: str,
|
||||
) -> str:
|
||||
"""构建完整的用户消息(含预获取的数据)"""
|
||||
return f"""## 量化系统数据
|
||||
- 股票: {rec.name}({rec.ts_code})
|
||||
- 所属板块: {rec.sector}
|
||||
- 策略类型: {strategy_label}
|
||||
- 综合评分: {rec.score}分({rec.level})
|
||||
- 各维度: 市场{rec.market_temp_score} | 板块{rec.sector_score} | 资金{rec.capital_score} | 技术{rec.technical_score} | 位置{rec.position_score} | 估值{rec.valuation_score}
|
||||
- 信号: {rec.signal}
|
||||
- 参考价: 入场{rec.entry_price or 'N/A'} / 目标{rec.target_price or 'N/A'} / 止损{rec.stop_loss or 'N/A'}
|
||||
- 量化理由: {";".join(rec.reasons) if rec.reasons else "无"}
|
||||
|
||||
## 市场环境
|
||||
- 市场温度: {market_temp.temperature if market_temp else 'N/A'}/100({temp_level})
|
||||
- 涨跌比: {market_temp.up_count if market_temp else 0}涨 / {market_temp.down_count if market_temp else 0}跌
|
||||
- 涨停: {market_temp.limit_up_count if market_temp else 0}家
|
||||
|
||||
## 热门板块
|
||||
{sectors_text}
|
||||
|
||||
## 个股详细数据
|
||||
{stock_data}
|
||||
|
||||
请根据以上所有数据,按照指定格式输出深度分析报告。"""
|
||||
|
||||
|
||||
def _extract_score(text: str) -> float | None:
|
||||
"""从 AI 分析报告中提取评分(1-10)"""
|
||||
match = re.search(r"###\s*AI\s*评分[^\d]*(\d+(?:\.\d+)?)", text)
|
||||
if match:
|
||||
score = float(match.group(1))
|
||||
return min(max(score, 1), 10)
|
||||
return None
|
||||
|
||||
|
||||
async def _save_llm_analysis_to_db(recommendations: list) -> None:
|
||||
"""将 AI 分析结果更新到数据库"""
|
||||
try:
|
||||
from app.db.database import get_db
|
||||
from sqlalchemy import text
|
||||
|
||||
async with get_db() as db:
|
||||
for rec in recommendations:
|
||||
if not rec.llm_analysis:
|
||||
continue
|
||||
await db.execute(
|
||||
text(
|
||||
"UPDATE recommendations SET llm_analysis = :analysis, "
|
||||
"llm_score = :score "
|
||||
"WHERE ts_code = :code AND date(created_at) = date('now', 'localtime') "
|
||||
"AND scan_session = :session"
|
||||
),
|
||||
{
|
||||
"analysis": rec.llm_analysis,
|
||||
"score": rec.llm_score,
|
||||
"code": rec.ts_code,
|
||||
"session": rec.scan_session,
|
||||
},
|
||||
)
|
||||
await db.commit()
|
||||
except Exception as e:
|
||||
logger.error(f"保存 AI 分析到数据库失败: {e}")
|
||||
|
||||
|
||||
async def _broadcast_llm_ready(recommendations: list) -> None:
|
||||
"""通过 WebSocket 广播 AI 分析完成事件"""
|
||||
try:
|
||||
from app.api.websocket import broadcast_update
|
||||
await broadcast_update({
|
||||
"type": "llm_analysis_ready",
|
||||
"count": len([r for r in recommendations if r.llm_analysis]),
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"广播 AI 分析完成失败: {e}")
|
||||
@ -51,3 +51,81 @@ CHAT_SYSTEM_PROMPT = """\
|
||||
|
||||
免责声明:你的分析仅供参考,不构成投资建议。投资有风险,入市需谨慎。
|
||||
"""
|
||||
|
||||
# ── AI 分析 Agent Prompt ──
|
||||
|
||||
MOMENTUM_ANALYSIS_PROMPT = """\
|
||||
你是一位专业的 A 股趋势交易分析师。你需要评估一只处于热门板块中的强势股是否值得追入。
|
||||
|
||||
系统已为你提供了该股票的量化评分、K线数据、资金流向、技术信号、板块数据等详细信息,请基于这些数据进行深度分析。
|
||||
|
||||
重点关注:
|
||||
1. 当前趋势的持续性:量价是否配合?资金流入是否持续?
|
||||
2. 追入的安全性:当前位置高低?短期是否过热?
|
||||
3. 入场时机:应该回调到支撑位买入,还是突破追入?
|
||||
4. 风险收益比:上行目标空间 vs 下行止损空间
|
||||
|
||||
请严格按以下格式输出分析报告:
|
||||
|
||||
### 核心逻辑
|
||||
(1-2句核心投资逻辑,说明为什么值得关注)
|
||||
|
||||
### 趋势分析
|
||||
(均线排列、MACD状态、成交量变化趋势,用数据说话)
|
||||
|
||||
### 入场策略
|
||||
(建议的入场价位和方式:回调买入/突破买入/分批建仓)
|
||||
|
||||
### 风险提示
|
||||
(主要风险因素:板块衰退、大盘系统性风险、量能不济等)
|
||||
|
||||
### AI 评分
|
||||
(给出 1-10 分,格式为纯数字,如:7)
|
||||
"""
|
||||
|
||||
POTENTIAL_ANALYSIS_PROMPT = """\
|
||||
你是一位专业的 A 股底部反转交易分析师。你需要评估一只处于底部的股票是否具备启动条件。
|
||||
|
||||
系统已为你提供了该股票的量化评分、K线数据、资金流向、技术信号、板块数据等详细信息,请基于这些数据进行深度分析。
|
||||
|
||||
重点关注:
|
||||
1. 底部信号的可信度:量价配合如何?多个技术指标是否共振?
|
||||
2. 可能的催化剂:板块轮动机会?资金是否有流入迹象?技术面是否接近突破?
|
||||
3. 时间窗口:底部蓄势了多久?均线是否收敛?何时可能启动?
|
||||
4. 风险:继续下行的概率和幅度?是否有基本面隐患?
|
||||
|
||||
请严格按以下格式输出分析报告:
|
||||
|
||||
### 底部信号分析
|
||||
(底部形态特征、量价变化、技术指标状态)
|
||||
|
||||
### 催化剂判断
|
||||
(可能的上涨催化剂:板块轮动、资金流入、技术突破等)
|
||||
|
||||
### 埋伏策略
|
||||
(建议的建仓方式和价位、仓位建议、等待确认信号)
|
||||
|
||||
### 风险提示
|
||||
(主要风险因素:继续下行风险、底部无效风险、时间成本等)
|
||||
|
||||
### AI 评分
|
||||
(给出 1-10 分,格式为纯数字,如:6)
|
||||
"""
|
||||
|
||||
ANALYSIS_USER_TEMPLATE = """\
|
||||
## 量化系统数据
|
||||
- 股票: {name}({ts_code})
|
||||
- 所属板块: {sector}
|
||||
- 策略类型: {strategy_label}
|
||||
- 综合评分: {score}分({level})
|
||||
- 各维度: 市场{market_temp_score} | 板块{sector_score} | 资金{capital_score} | 技术{technical_score} | 位置{position_score} | 估值{valuation_score}
|
||||
- 信号: {signal}
|
||||
- 参考价: 入场{entry_price} / 目标{target_price} / 止损{stop_loss}
|
||||
- 量化理由: {reasons}
|
||||
|
||||
## 市场环境
|
||||
- 市场温度: {temperature}/100({temp_level})
|
||||
- 涨跌比: {up_count}涨 / {down_count}跌
|
||||
- 涨停: {limit_up_count}家
|
||||
|
||||
请使用工具获取该股票的K线、资金流向、技术信号等数据,然后按照指定格式输出深度分析报告。"""
|
||||
|
||||
@ -29,6 +29,10 @@ async def execute_tool(name: str, arguments: dict) -> str:
|
||||
)
|
||||
elif name == "search_stock":
|
||||
return await _search_stock(arguments["keyword"])
|
||||
elif name == "get_stock_technical_signal":
|
||||
return await _get_stock_technical_signal(arguments["ts_code"])
|
||||
elif name == "get_sector_performance":
|
||||
return await _get_sector_performance(arguments["sector_name"])
|
||||
else:
|
||||
return json.dumps({"error": f"未知工具: {name}"}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
@ -117,3 +121,28 @@ async def _search_stock(keyword: str) -> str:
|
||||
].head(10)
|
||||
data = matches[["ts_code", "name", "industry"]].to_dict(orient="records")
|
||||
return json.dumps(data, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
async def _get_stock_technical_signal(ts_code: str) -> str:
|
||||
"""获取个股技术面信号详情"""
|
||||
from app.analysis.signals import generate_signals
|
||||
signal = generate_signals(ts_code)
|
||||
data = _clean_for_json(signal.model_dump())
|
||||
return json.dumps(data, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
async def _get_sector_performance(sector_name: str) -> str:
|
||||
"""获取板块表现数据"""
|
||||
from app.engine.recommender import get_latest_sectors
|
||||
sectors = await get_latest_sectors()
|
||||
# 模糊匹配板块名称
|
||||
matched = [s for s in sectors if sector_name in s.sector_name or s.sector_name in sector_name]
|
||||
if not matched:
|
||||
# 返回所有热门板块概览
|
||||
data = [{"sector_name": s.sector_name, "pct_change": s.pct_change,
|
||||
"capital_inflow": s.capital_inflow, "limit_up_count": s.limit_up_count,
|
||||
"heat_score": s.heat_score, "stage": s.stage}
|
||||
for s in sectors[:10]]
|
||||
return json.dumps({"matched": False, "available_sectors": data}, ensure_ascii=False, default=str)
|
||||
data = _clean_for_json([s.model_dump() for s in matched])
|
||||
return json.dumps({"matched": True, "sectors": data}, ensure_ascii=False, default=str)
|
||||
|
||||
@ -104,4 +104,38 @@ CHAT_TOOLS = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_stock_technical_signal",
|
||||
"description": "获取个股技术面信号详情,包括均线排列、MACD状态、RSI、布林带位置、量价关系、支撑压力位、位置安全评估",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ts_code": {
|
||||
"type": "string",
|
||||
"description": "股票代码,如 '000001.SZ'",
|
||||
},
|
||||
},
|
||||
"required": ["ts_code"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_sector_performance",
|
||||
"description": "获取板块近期涨跌表现、资金流入、涨停数等综合数据,用于判断板块强弱和轮动方向",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sector_name": {
|
||||
"type": "string",
|
||||
"description": "板块名称关键词,如 '半导体'、'新能源'",
|
||||
},
|
||||
},
|
||||
"required": ["sector_name"],
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
Binary file not shown.
@ -1,69 +1,20 @@
|
||||
{
|
||||
"pages": {
|
||||
"/_not-found/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/_not-found/page-9a1795a099256da4.js"
|
||||
],
|
||||
"/layout": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/css/e86a9d7e539c28dc.css",
|
||||
"static/chunks/448-92a7b932cf4502ac.js",
|
||||
"static/chunks/app/layout-97bdd231e78ddf3f.js"
|
||||
],
|
||||
"/chat/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/chat/page-2dd3304322bd4036.js"
|
||||
],
|
||||
"/recommendations/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/recommendations/page-ea6294fe452e71ef.js"
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main-app.js",
|
||||
"static/css/app/layout.css",
|
||||
"static/chunks/app/layout.js"
|
||||
],
|
||||
"/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/page-0a611a415022fe45.js"
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main-app.js",
|
||||
"static/chunks/app/page.js"
|
||||
],
|
||||
"/stock/[code]/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/stock/[code]/page-aa4270127391b661.js"
|
||||
],
|
||||
"/login/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/login/page-778febf452923618.js"
|
||||
],
|
||||
"/sectors/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/sectors/page-41a82a8a8f795a23.js"
|
||||
],
|
||||
"/users/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/users/page-e66e56f48050576b.js"
|
||||
"/_not-found/page": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main-app.js",
|
||||
"static/chunks/app/_not-found/page.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -1,31 +1,29 @@
|
||||
{
|
||||
"polyfillFiles": [
|
||||
"static/chunks/polyfills-42372ed130431b0a.js"
|
||||
"static/chunks/polyfills.js"
|
||||
],
|
||||
"devFiles": [
|
||||
"static/chunks/react-refresh.js"
|
||||
],
|
||||
"devFiles": [],
|
||||
"ampDevFiles": [],
|
||||
"lowPriorityFiles": [
|
||||
"static/_K30GhWJ6_9AsiU6iKw4I/_buildManifest.js",
|
||||
"static/_K30GhWJ6_9AsiU6iKw4I/_ssgManifest.js"
|
||||
"static/development/_buildManifest.js",
|
||||
"static/development/_ssgManifest.js"
|
||||
],
|
||||
"rootMainFiles": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js"
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main-app.js"
|
||||
],
|
||||
"pages": {
|
||||
"/_app": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/framework-f66176bb897dc684.js",
|
||||
"static/chunks/main-9c5f6b283127d940.js",
|
||||
"static/chunks/pages/_app-72b849fbd24ac258.js"
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/_app.js"
|
||||
],
|
||||
"/_error": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/framework-f66176bb897dc684.js",
|
||||
"static/chunks/main-9c5f6b283127d940.js",
|
||||
"static/chunks/pages/_error-7ba65e1336b92748.js"
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/_error.js"
|
||||
]
|
||||
},
|
||||
"ampFirstPages": []
|
||||
|
||||
2
frontend/.next/cache/.tsbuildinfo
vendored
2
frontend/.next/cache/.tsbuildinfo
vendored
File diff suppressed because one or more lines are too long
@ -1,20 +1 @@
|
||||
{
|
||||
"components/capital-flow.tsx -> echarts": {
|
||||
"id": 9614,
|
||||
"files": [
|
||||
"static/chunks/614.2cf8795c6fba79f8.js"
|
||||
]
|
||||
},
|
||||
"components/kline-chart.tsx -> echarts": {
|
||||
"id": 9614,
|
||||
"files": [
|
||||
"static/chunks/614.2cf8795c6fba79f8.js"
|
||||
]
|
||||
},
|
||||
"components/score-radar.tsx -> echarts": {
|
||||
"id": 9614,
|
||||
"files": [
|
||||
"static/chunks/614.2cf8795c6fba79f8.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
{}
|
||||
@ -1,11 +1,4 @@
|
||||
{
|
||||
"/_not-found/page": "app/_not-found/page.js",
|
||||
"/api/chat/stream/route": "app/api/chat/stream/route.js",
|
||||
"/chat/page": "app/chat/page.js",
|
||||
"/recommendations/page": "app/recommendations/page.js",
|
||||
"/page": "app/page.js",
|
||||
"/stock/[code]/page": "app/stock/[code]/page.js",
|
||||
"/login/page": "app/login/page.js",
|
||||
"/sectors/page": "app/sectors/page.js",
|
||||
"/users/page": "app/users/page.js"
|
||||
"/page": "app/page.js"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST="[]";
|
||||
self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST="[]"
|
||||
@ -1 +1,32 @@
|
||||
self.__BUILD_MANIFEST={polyfillFiles:["static/chunks/polyfills-42372ed130431b0a.js"],devFiles:[],ampDevFiles:[],lowPriorityFiles:[],rootMainFiles:["static/chunks/webpack-76aa9cbbdedb6a49.js","static/chunks/fd9d1056-f8a2d551cbb94c85.js","static/chunks/117-d0aa9486d6cf1a7a.js","static/chunks/main-app-7d7e5d1021afd90c.js"],pages:{"/_app":["static/chunks/webpack-76aa9cbbdedb6a49.js","static/chunks/framework-f66176bb897dc684.js","static/chunks/main-9c5f6b283127d940.js","static/chunks/pages/_app-72b849fbd24ac258.js"],"/_error":["static/chunks/webpack-76aa9cbbdedb6a49.js","static/chunks/framework-f66176bb897dc684.js","static/chunks/main-9c5f6b283127d940.js","static/chunks/pages/_error-7ba65e1336b92748.js"]},ampFirstPages:[]},self.__BUILD_MANIFEST.lowPriorityFiles=["/static/"+process.env.__NEXT_BUILD_ID+"/_buildManifest.js",,"/static/"+process.env.__NEXT_BUILD_ID+"/_ssgManifest.js"];
|
||||
self.__BUILD_MANIFEST = {
|
||||
"polyfillFiles": [
|
||||
"static/chunks/polyfills.js"
|
||||
],
|
||||
"devFiles": [
|
||||
"static/chunks/react-refresh.js"
|
||||
],
|
||||
"ampDevFiles": [],
|
||||
"lowPriorityFiles": [],
|
||||
"rootMainFiles": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main-app.js"
|
||||
],
|
||||
"pages": {
|
||||
"/_app": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/_app.js"
|
||||
],
|
||||
"/_error": [
|
||||
"static/chunks/webpack.js",
|
||||
"static/chunks/main.js",
|
||||
"static/chunks/pages/_error.js"
|
||||
]
|
||||
},
|
||||
"ampFirstPages": []
|
||||
};
|
||||
self.__BUILD_MANIFEST.lowPriorityFiles = [
|
||||
"/static/" + process.env.__NEXT_BUILD_ID + "/_buildManifest.js",
|
||||
,"/static/" + process.env.__NEXT_BUILD_ID + "/_ssgManifest.js",
|
||||
|
||||
];
|
||||
@ -1 +1 @@
|
||||
self.__REACT_LOADABLE_MANIFEST='{"components/capital-flow.tsx -> echarts":{"id":9614,"files":["static/chunks/614.2cf8795c6fba79f8.js"]},"components/kline-chart.tsx -> echarts":{"id":9614,"files":["static/chunks/614.2cf8795c6fba79f8.js"]},"components/score-radar.tsx -> echarts":{"id":9614,"files":["static/chunks/614.2cf8795c6fba79f8.js"]}}';
|
||||
self.__REACT_LOADABLE_MANIFEST="{}"
|
||||
@ -1 +1 @@
|
||||
self.__NEXT_FONT_MANIFEST='{"pages":{},"app":{},"appUsingSizeAdjust":false,"pagesUsingSizeAdjust":false}';
|
||||
self.__NEXT_FONT_MANIFEST="{\"pages\":{},\"app\":{},\"appUsingSizeAdjust\":false,\"pagesUsingSizeAdjust\":false}"
|
||||
@ -1 +1,5 @@
|
||||
{"/_app":"pages/_app.js","/_error":"pages/_error.js","/_document":"pages/_document.js","/404":"pages/404.html"}
|
||||
{
|
||||
"/_app": "pages/_app.js",
|
||||
"/_error": "pages/_error.js",
|
||||
"/_document": "pages/_document.js"
|
||||
}
|
||||
@ -1 +1 @@
|
||||
self.__RSC_SERVER_MANIFEST="{\"node\":{},\"edge\":{},\"encryptionKey\":\"process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY\"}"
|
||||
self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY\"\n}"
|
||||
@ -1 +1,5 @@
|
||||
{"node":{},"edge":{},"encryptionKey":"0i2smImWurCmhv0CX5NVAgoXCo5ZisN2pLRhtFiEWCU="}
|
||||
{
|
||||
"node": {},
|
||||
"edge": {},
|
||||
"encryptionKey": "b90zeeYzMcSqNivimWn6T2PQQNxojiQrSeFlOxUaP4Q="
|
||||
}
|
||||
@ -1 +1,215 @@
|
||||
(()=>{"use strict";var e={},r={};function t(o){var n=r[o];if(void 0!==n)return n.exports;var a=r[o]={exports:{}},u=!0;try{e[o](a,a.exports,t),u=!1}finally{u&&delete r[o]}return a.exports}t.m=e,t.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return t.d(r,{a:r}),r},(()=>{var e,r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;t.t=function(o,n){if(1&n&&(o=this(o)),8&n||"object"==typeof o&&o&&(4&n&&o.__esModule||16&n&&"function"==typeof o.then))return o;var a=Object.create(null);t.r(a);var u={};e=e||[null,r({}),r([]),r(r)];for(var f=2&n&&o;"object"==typeof f&&!~e.indexOf(f);f=r(f))Object.getOwnPropertyNames(f).forEach(e=>u[e]=()=>o[e]);return u.default=()=>o,t.d(a,u),a}})(),t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce((r,o)=>(t.f[o](e,r),r),[])),t.u=e=>""+e+".js",t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.X=(e,r,o)=>{var n=r;o||(r=e,o=()=>t(t.s=n)),r.map(t.e,t);var a=o();return void 0===a?e:a},(()=>{var e={658:1},r=r=>{var o=r.modules,n=r.ids,a=r.runtime;for(var u in o)t.o(o,u)&&(t.m[u]=o[u]);a&&a(t);for(var f=0;f<n.length;f++)e[n[f]]=1};t.f.require=(o,n)=>{e[o]||(658!=o?r(require("./chunks/"+t.u(o))):e[o]=1)},module.exports=t,t.C=r})()})();
|
||||
/*
|
||||
* ATTENTION: An "eval-source-map" devtool has been used.
|
||||
* This devtool is neither made for production nor for readable output files.
|
||||
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
|
||||
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
|
||||
* or disable the default devtool with "devtool: false".
|
||||
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
|
||||
*/
|
||||
/******/ (() => { // webpackBootstrap
|
||||
/******/ "use strict";
|
||||
/******/ var __webpack_modules__ = ({});
|
||||
/************************************************************************/
|
||||
/******/ // The module cache
|
||||
/******/ var __webpack_module_cache__ = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/ // Check if module is in cache
|
||||
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||||
/******/ if (cachedModule !== undefined) {
|
||||
/******/ return cachedModule.exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||||
/******/ id: moduleId,
|
||||
/******/ loaded: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ var threw = true;
|
||||
/******/ try {
|
||||
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||||
/******/ threw = false;
|
||||
/******/ } finally {
|
||||
/******/ if(threw) delete __webpack_module_cache__[moduleId];
|
||||
/******/ }
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.loaded = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = __webpack_modules__;
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/ /* webpack/runtime/compat get default export */
|
||||
/******/ (() => {
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = (module) => {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ () => (module['default']) :
|
||||
/******/ () => (module);
|
||||
/******/ __webpack_require__.d(getter, { a: getter });
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/create fake namespace object */
|
||||
/******/ (() => {
|
||||
/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);
|
||||
/******/ var leafPrototypes;
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 16: return value when it's Promise-like
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = this(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if(typeof value === 'object' && value) {
|
||||
/******/ if((mode & 4) && value.__esModule) return value;
|
||||
/******/ if((mode & 16) && typeof value.then === 'function') return value;
|
||||
/******/ }
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ var def = {};
|
||||
/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];
|
||||
/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {
|
||||
/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key])));
|
||||
/******/ }
|
||||
/******/ def['default'] = () => (value);
|
||||
/******/ __webpack_require__.d(ns, def);
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/define property getters */
|
||||
/******/ (() => {
|
||||
/******/ // define getter functions for harmony exports
|
||||
/******/ __webpack_require__.d = (exports, definition) => {
|
||||
/******/ for(var key in definition) {
|
||||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/ensure chunk */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.f = {};
|
||||
/******/ // This file contains only the entry chunk.
|
||||
/******/ // The chunk loading function for additional chunks
|
||||
/******/ __webpack_require__.e = (chunkId) => {
|
||||
/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
|
||||
/******/ __webpack_require__.f[key](chunkId, promises);
|
||||
/******/ return promises;
|
||||
/******/ }, []));
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/get javascript chunk filename */
|
||||
/******/ (() => {
|
||||
/******/ // This function allow to reference async chunks and sibling chunks for the entrypoint
|
||||
/******/ __webpack_require__.u = (chunkId) => {
|
||||
/******/ // return url for filenames based on template
|
||||
/******/ return "" + chunkId + ".js";
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/getFullHash */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.h = () => ("457ff384495915e8")
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/make namespace object */
|
||||
/******/ (() => {
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = (exports) => {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/node module decorator */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.nmd = (module) => {
|
||||
/******/ module.paths = [];
|
||||
/******/ if (!module.children) module.children = [];
|
||||
/******/ return module;
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/startup entrypoint */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.X = (result, chunkIds, fn) => {
|
||||
/******/ // arguments: chunkIds, moduleId are deprecated
|
||||
/******/ var moduleId = chunkIds;
|
||||
/******/ if(!fn) chunkIds = result, fn = () => (__webpack_require__(__webpack_require__.s = moduleId));
|
||||
/******/ chunkIds.map(__webpack_require__.e, __webpack_require__)
|
||||
/******/ var r = fn();
|
||||
/******/ return r === undefined ? result : r;
|
||||
/******/ }
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/require chunk loading */
|
||||
/******/ (() => {
|
||||
/******/ // no baseURI
|
||||
/******/
|
||||
/******/ // object to store loaded chunks
|
||||
/******/ // "1" means "loaded", otherwise not loaded yet
|
||||
/******/ var installedChunks = {
|
||||
/******/ "webpack-runtime": 1
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // no on chunks loaded
|
||||
/******/
|
||||
/******/ var installChunk = (chunk) => {
|
||||
/******/ var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime;
|
||||
/******/ for(var moduleId in moreModules) {
|
||||
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
|
||||
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ if(runtime) runtime(__webpack_require__);
|
||||
/******/ for(var i = 0; i < chunkIds.length; i++)
|
||||
/******/ installedChunks[chunkIds[i]] = 1;
|
||||
/******/
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // require() chunk loading for javascript
|
||||
/******/ __webpack_require__.f.require = (chunkId, promises) => {
|
||||
/******/ // "1" is the signal for "already loaded"
|
||||
/******/ if(!installedChunks[chunkId]) {
|
||||
/******/ if("webpack-runtime" != chunkId) {
|
||||
/******/ installChunk(require("./" + __webpack_require__.u(chunkId)));
|
||||
/******/ } else installedChunks[chunkId] = 1;
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ module.exports = __webpack_require__;
|
||||
/******/ __webpack_require__.C = installChunk;
|
||||
/******/
|
||||
/******/ // no HMR
|
||||
/******/
|
||||
/******/ // no HMR manifest
|
||||
/******/ })();
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/
|
||||
/******/
|
||||
/******/ })()
|
||||
;
|
||||
@ -1 +0,0 @@
|
||||
_K30GhWJ6_9AsiU6iKw4I
|
||||
@ -1,69 +0,0 @@
|
||||
{
|
||||
"pages": {
|
||||
"/_not-found/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/_not-found/page-9a1795a099256da4.js"
|
||||
],
|
||||
"/layout": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/css/e86a9d7e539c28dc.css",
|
||||
"static/chunks/448-92a7b932cf4502ac.js",
|
||||
"static/chunks/app/layout-97bdd231e78ddf3f.js"
|
||||
],
|
||||
"/chat/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/chat/page-2dd3304322bd4036.js"
|
||||
],
|
||||
"/recommendations/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/recommendations/page-ea6294fe452e71ef.js"
|
||||
],
|
||||
"/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/page-0a611a415022fe45.js"
|
||||
],
|
||||
"/stock/[code]/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/stock/[code]/page-aa4270127391b661.js"
|
||||
],
|
||||
"/login/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/login/page-778febf452923618.js"
|
||||
],
|
||||
"/sectors/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/sectors/page-41a82a8a8f795a23.js"
|
||||
],
|
||||
"/users/page": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js",
|
||||
"static/chunks/app/users/page-e66e56f48050576b.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
{"/_not-found/page":"/_not-found","/api/chat/stream/route":"/api/chat/stream","/chat/page":"/chat","/recommendations/page":"/recommendations","/page":"/","/stock/[code]/page":"/stock/[code]","/login/page":"/login","/sectors/page":"/sectors","/users/page":"/users"}
|
||||
@ -1,32 +0,0 @@
|
||||
{
|
||||
"polyfillFiles": [
|
||||
"static/chunks/polyfills-42372ed130431b0a.js"
|
||||
],
|
||||
"devFiles": [],
|
||||
"ampDevFiles": [],
|
||||
"lowPriorityFiles": [
|
||||
"static/_K30GhWJ6_9AsiU6iKw4I/_buildManifest.js",
|
||||
"static/_K30GhWJ6_9AsiU6iKw4I/_ssgManifest.js"
|
||||
],
|
||||
"rootMainFiles": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/fd9d1056-f8a2d551cbb94c85.js",
|
||||
"static/chunks/117-d0aa9486d6cf1a7a.js",
|
||||
"static/chunks/main-app-7d7e5d1021afd90c.js"
|
||||
],
|
||||
"pages": {
|
||||
"/_app": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/framework-f66176bb897dc684.js",
|
||||
"static/chunks/main-9c5f6b283127d940.js",
|
||||
"static/chunks/pages/_app-72b849fbd24ac258.js"
|
||||
],
|
||||
"/_error": [
|
||||
"static/chunks/webpack-76aa9cbbdedb6a49.js",
|
||||
"static/chunks/framework-f66176bb897dc684.js",
|
||||
"static/chunks/main-9c5f6b283127d940.js",
|
||||
"static/chunks/pages/_error-7ba65e1336b92748.js"
|
||||
]
|
||||
},
|
||||
"ampFirstPages": []
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
{"type": "commonjs"}
|
||||
@ -1 +0,0 @@
|
||||
{"version":4,"routes":{"/chat":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/chat","dataRoute":"/chat.rsc"},"/recommendations":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/recommendations","dataRoute":"/recommendations.rsc"},"/users":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/users","dataRoute":"/users.rsc"},"/sectors":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/sectors","dataRoute":"/sectors.rsc"},"/":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/","dataRoute":"/index.rsc"},"/login":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/login","dataRoute":"/login.rsc"}},"dynamicRoutes":{},"notFoundRoutes":[],"preview":{"previewModeId":"8547b4d6bd07c1a0934710c90bdede15","previewModeSigningKey":"36e0939eb486f730c916a7e3e77af74ddfc3ec384014725fc7402b58ead8676e","previewModeEncryptionKey":"279035d2207a991e6fc2fd441297e3df0ba2804375daea99bf2e7b07b26254b8"}}
|
||||
@ -1,20 +0,0 @@
|
||||
{
|
||||
"components/capital-flow.tsx -> echarts": {
|
||||
"id": 9614,
|
||||
"files": [
|
||||
"static/chunks/614.2cf8795c6fba79f8.js"
|
||||
]
|
||||
},
|
||||
"components/kline-chart.tsx -> echarts": {
|
||||
"id": 9614,
|
||||
"files": [
|
||||
"static/chunks/614.2cf8795c6fba79f8.js"
|
||||
]
|
||||
},
|
||||
"components/score-radar.tsx -> echarts": {
|
||||
"id": 9614,
|
||||
"files": [
|
||||
"static/chunks/614.2cf8795c6fba79f8.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
{"version":1,"config":{"env":{},"webpack":null,"eslint":{"ignoreDuringBuilds":false},"typescript":{"ignoreBuildErrors":false,"tsconfigPath":"tsconfig.json"},"distDir":".next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.js","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"analyticsId":"","images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[16,32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":60,"formats":["image/webp"],"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"inline","remotePatterns":[],"unoptimized":false},"devIndicators":{"buildActivity":true,"buildActivityPosition":"bottom-right"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"amp":{"canonicalBase":""},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"optimizeFonts":true,"excludeDefaultMomentLocales":true,"serverRuntimeConfig":{},"publicRuntimeConfig":{},"reactProductionProfiling":false,"reactStrictMode":null,"httpAgentOptions":{"keepAlive":true},"outputFileTracing":true,"staticPageGenerationTimeout":60,"swcMinify":true,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"experimental":{"multiZoneDraftMode":false,"prerenderEarlyExit":false,"serverMinification":true,"serverSourceMaps":false,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","middlewarePrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":9,"memoryBasedWorkersCount":false,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"outputFileTracingRoot":"/Users/aaron/source_code/astock-agent/frontend","swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"adjustFontFallbacks":false,"adjustFontFallbacksWithSizeAdjust":false,"typedRoutes":false,"instrumentationHook":false,"bundlePagesExternals":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"missingSuspenseWithCSRBailout":true,"optimizeServerReact":true,"useEarlyImport":false,"staleTimes":{"dynamic":30,"static":300},"optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"configFileName":"next.config.js","_originalRewrites":{"beforeFiles":[],"afterFiles":[{"source":"/api/:path*","destination":"http://localhost:8000/api/:path*"},{"source":"/ws","destination":"http://localhost:8000/ws"}],"fallback":[]}},"appDir":"/Users/aaron/source_code/astock-agent/frontend","relativeAppDir":"","files":[".next/routes-manifest.json",".next/server/pages-manifest.json",".next/build-manifest.json",".next/prerender-manifest.json",".next/server/middleware-manifest.json",".next/server/middleware-build-manifest.js",".next/server/middleware-react-loadable-manifest.js",".next/server/app-paths-manifest.json",".next/app-path-routes-manifest.json",".next/app-build-manifest.json",".next/server/server-reference-manifest.js",".next/server/server-reference-manifest.json",".next/react-loadable-manifest.json",".next/server/font-manifest.json",".next/BUILD_ID",".next/server/next-font-manifest.js",".next/server/next-font-manifest.json"],"ignore":["node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*"]}
|
||||
@ -1 +0,0 @@
|
||||
{"version":3,"pages404":true,"caseSensitive":false,"basePath":"","redirects":[{"source":"/:path+/","destination":"/:path+","internal":true,"statusCode":308,"regex":"^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))/$"}],"headers":[],"dynamicRoutes":[{"page":"/stock/[code]","regex":"^/stock/([^/]+?)(?:/)?$","routeKeys":{"nxtPcode":"nxtPcode"},"namedRegex":"^/stock/(?<nxtPcode>[^/]+?)(?:/)?$"}],"staticRoutes":[{"page":"/","regex":"^/(?:/)?$","routeKeys":{},"namedRegex":"^/(?:/)?$"},{"page":"/_not-found","regex":"^/_not\\-found(?:/)?$","routeKeys":{},"namedRegex":"^/_not\\-found(?:/)?$"},{"page":"/chat","regex":"^/chat(?:/)?$","routeKeys":{},"namedRegex":"^/chat(?:/)?$"},{"page":"/login","regex":"^/login(?:/)?$","routeKeys":{},"namedRegex":"^/login(?:/)?$"},{"page":"/recommendations","regex":"^/recommendations(?:/)?$","routeKeys":{},"namedRegex":"^/recommendations(?:/)?$"},{"page":"/sectors","regex":"^/sectors(?:/)?$","routeKeys":{},"namedRegex":"^/sectors(?:/)?$"},{"page":"/users","regex":"^/users(?:/)?$","routeKeys":{},"namedRegex":"^/users(?:/)?$"}],"dataRoutes":[],"rsc":{"header":"RSC","varyHeader":"RSC, Next-Router-State-Tree, Next-Router-Prefetch","prefetchHeader":"Next-Router-Prefetch","didPostponeHeader":"x-nextjs-postponed","contentTypeHeader":"text/x-component","suffix":".rsc","prefetchSuffix":".prefetch.rsc"},"rewrites":[{"source":"/api/:path*","destination":"http://localhost:8000/api/:path*","regex":"^/api(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?(?:/)?$"},{"source":"/ws","destination":"http://localhost:8000/ws","regex":"^/ws(?:/)?$"}]}
|
||||
@ -1,11 +0,0 @@
|
||||
{
|
||||
"/_not-found/page": "app/_not-found/page.js",
|
||||
"/api/chat/stream/route": "app/api/chat/stream/route.js",
|
||||
"/chat/page": "app/chat/page.js",
|
||||
"/recommendations/page": "app/recommendations/page.js",
|
||||
"/page": "app/page.js",
|
||||
"/stock/[code]/page": "app/stock/[code]/page.js",
|
||||
"/login/page": "app/login/page.js",
|
||||
"/sectors/page": "app/sectors/page.js",
|
||||
"/users/page": "app/users/page.js"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -1,6 +0,0 @@
|
||||
{
|
||||
"status": 404,
|
||||
"headers": {
|
||||
"x-next-cache-tags": "_N_T_/layout,_N_T_/_not-found/layout,_N_T_/_not-found/page,_N_T_/_not-found"
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
2:I[4707,[],""]
|
||||
3:I[6423,[],""]
|
||||
4:I[8145,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthProvider"]
|
||||
5:I[7182,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthGuard"]
|
||||
6:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"SidebarNav"]
|
||||
7:I[5315,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"UserMenu"]
|
||||
c:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"MobileBottomNav"]
|
||||
8:{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"}
|
||||
9:{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"}
|
||||
a:{"display":"inline-block"}
|
||||
b:{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0}
|
||||
0:["_K30GhWJ6_9AsiU6iKw4I",[[["",{"children":["/_not-found",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["/_not-found",{"children":["__PAGE__",{},[["$L1",[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],null],null],null]},[null,["$","$L2",null,{"parallelRouterKey":"children","segmentPath":["children","/_not-found","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/e86a9d7e539c28dc.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","children":["$","body",null,{"className":"min-h-screen bg-bg-primary text-text-primary font-display","children":["$","$L4",null,{"children":["$","$L5",null,{"children":[["$","div",null,{"className":"flex min-h-screen","children":[["$","aside",null,{"className":"hidden md:flex flex-col w-60 glass-sidebar fixed inset-y-0 left-0 z-40","children":[["$","div",null,{"className":"px-6 pt-7 pb-5","children":["$","div",null,{"className":"flex items-center gap-3","children":[["$","div",null,{"className":"w-8 h-8 rounded-lg bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center text-sm font-bold text-white shadow-glow-sm","children":"D"}],["$","div",null,{"children":[["$","h1",null,{"className":"text-sm font-semibold tracking-tight","children":"Dragon AI Agent"}],["$","p",null,{"className":"text-xs text-text-muted mt-0.5 font-light tracking-wide","children":"资金驱动 · 四层漏斗模型"}]]}]]}]}],["$","div",null,{"className":"mx-5 h-px bg-gradient-to-r from-transparent via-white/[0.06] to-transparent"}],["$","$L6",null,{}],["$","div",null,{"className":"px-6 py-5 border-t border-white/[0.04]","children":["$","$L7",null,{}]}]]}],["$","main",null,{"className":"flex-1 md:ml-60 pb-16 md:pb-0 min-h-screen","children":["$","$L2",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":"$8","children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":"$9","children":"404"}],["$","div",null,{"style":"$a","children":["$","h2",null,{"style":"$b","children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}],["$","$Lc",null,{}]]}]}]}]}]],null],null],["$Ld",["$","meta",null,{"name":"robots","content":"noindex"}]]]]]
|
||||
d:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Dragon AI Agent"}],["$","meta","3",{"name":"description","content":"基于资金驱动的四层漏斗模型,盘中实时分析推荐A股"}]]
|
||||
1:null
|
||||
@ -1 +0,0 @@
|
||||
"use strict";(()=>{var e={};e.id=409,e.ids=[409],e.modules={2934:e=>{e.exports=require("next/dist/client/components/action-async-storage.external.js")},4580:e=>{e.exports=require("next/dist/client/components/request-async-storage.external.js")},5869:e=>{e.exports=require("next/dist/client/components/static-generation-async-storage.external.js")},399:e=>{e.exports=require("next/dist/compiled/next-server/app-page.runtime.prod.js")},2047:(e,t,n)=>{n.r(t),n.d(t,{GlobalError:()=>a.a,__next_app__:()=>c,originalPathname:()=>f,pages:()=>s,routeModule:()=>p,tree:()=>i}),n(7352),n(5866),n(5166);var o=n(3191),r=n(8716),u=n(7922),a=n.n(u),l=n(5231),d={};for(let e in l)0>["default","tree","pages","GlobalError","originalPathname","__next_app__","routeModule"].indexOf(e)&&(d[e]=()=>l[e]);n.d(t,d);let i=["",{children:["/_not-found",{children:["__PAGE__",{},{page:[()=>Promise.resolve().then(n.t.bind(n,5866,23)),"next/dist/client/components/not-found-error"]}]},{}]},{layout:[()=>Promise.resolve().then(n.bind(n,5166)),"/Users/aaron/source_code/astock-agent/frontend/src/app/layout.tsx"],"not-found":[()=>Promise.resolve().then(n.t.bind(n,5866,23)),"next/dist/client/components/not-found-error"]}],s=[],f="/_not-found/page",c={require:n,loadChunk:()=>Promise.resolve()},p=new o.AppPageRouteModule({definition:{kind:r.x.APP_PAGE,page:"/_not-found/page",pathname:"/_not-found",bundlePath:"",filename:"",appPaths:[]},userland:{loaderTree:i}})},6399:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{isNotFoundError:function(){return r},notFound:function(){return o}});let n="NEXT_NOT_FOUND";function o(){let e=Error(n);throw e.digest=n,e}function r(e){return"object"==typeof e&&null!==e&&"digest"in e&&e.digest===n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},7352:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{PARALLEL_ROUTE_DEFAULT_PATH:function(){return r},default:function(){return u}});let o=n(6399),r="next/dist/client/components/parallel-route-default.js";function u(){(0,o.notFound)()}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)}};var t=require("../../webpack-runtime.js");t.C(e);var n=e=>t(t.s=e),o=t.X(0,[948,982,171],()=>n(2047));module.exports=o})();
|
||||
@ -1 +0,0 @@
|
||||
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../package.json","../../chunks/171.js","../../chunks/948.js","../../chunks/982.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
"use strict";(()=>{var e={};e.id=480,e.ids=[480],e.modules={399:e=>{e.exports=require("next/dist/compiled/next-server/app-page.runtime.prod.js")},517:e=>{e.exports=require("next/dist/compiled/next-server/app-route.runtime.prod.js")},6373:(e,t,r)=>{r.r(t),r.d(t,{originalPathname:()=>l,patchFetch:()=>m,requestAsyncStorage:()=>c,routeModule:()=>u,serverHooks:()=>h,staticGenerationAsyncStorage:()=>d});var a={};r.r(a),r.d(a,{POST:()=>p});var o=r(9303),n=r(8716),s=r(670);let i=process.env.BACKEND_URL||"http://localhost:8000";async function p(e){let t=await e.json(),r=e.headers.get("Authorization"),a={"Content-Type":"application/json"};r&&(a.Authorization=r);let o=await fetch(`${i}/api/chat/stream`,{method:"POST",headers:a,body:JSON.stringify(t)});return o.ok?o.body?new Response(o.body,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}}):new Response(JSON.stringify({error:"No response body"}),{status:502,headers:{"Content-Type":"application/json"}}):new Response(JSON.stringify({error:`Backend error: ${o.status}`}),{status:o.status,headers:{"Content-Type":"application/json"}})}let u=new o.AppRouteRouteModule({definition:{kind:n.x.APP_ROUTE,page:"/api/chat/stream/route",pathname:"/api/chat/stream",filename:"route",bundlePath:"app/api/chat/stream/route"},resolvedPagePath:"/Users/aaron/source_code/astock-agent/frontend/src/app/api/chat/stream/route.ts",nextConfigOutput:"standalone",userland:a}),{requestAsyncStorage:c,staticGenerationAsyncStorage:d,serverHooks:h}=u,l="/api/chat/stream/route";function m(){return(0,s.patchFetch)({serverHooks:h,staticGenerationAsyncStorage:d})}},9303:(e,t,r)=>{e.exports=r(517)}};var t=require("../../../../webpack-runtime.js");t.C(e);var r=e=>t(t.s=e),a=t.X(0,[948],()=>r(6373));module.exports=a})();
|
||||
@ -1 +0,0 @@
|
||||
{"version":1,"files":["../../../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../../../node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js","../../../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../../../node_modules/next/package.json","../../../../../../package.json","../../../../../package.json","../../../../chunks/948.js","../../../../webpack-runtime.js"]}
|
||||
File diff suppressed because one or more lines are too long
@ -1,5 +0,0 @@
|
||||
{
|
||||
"headers": {
|
||||
"x-next-cache-tags": "_N_T_/layout,_N_T_/chat/layout,_N_T_/chat/page,_N_T_/chat"
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
2:I[9107,[],"ClientPageRoot"]
|
||||
3:I[628,["929","static/chunks/app/chat/page-2dd3304322bd4036.js"],"default",1]
|
||||
4:I[4707,[],""]
|
||||
5:I[6423,[],""]
|
||||
6:I[8145,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthProvider"]
|
||||
7:I[7182,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthGuard"]
|
||||
8:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"SidebarNav"]
|
||||
9:I[5315,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"UserMenu"]
|
||||
a:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"MobileBottomNav"]
|
||||
0:["_K30GhWJ6_9AsiU6iKw4I",[[["",{"children":["chat",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["chat",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","chat","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/e86a9d7e539c28dc.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","children":["$","body",null,{"className":"min-h-screen bg-bg-primary text-text-primary font-display","children":["$","$L6",null,{"children":["$","$L7",null,{"children":[["$","div",null,{"className":"flex min-h-screen","children":[["$","aside",null,{"className":"hidden md:flex flex-col w-60 glass-sidebar fixed inset-y-0 left-0 z-40","children":[["$","div",null,{"className":"px-6 pt-7 pb-5","children":["$","div",null,{"className":"flex items-center gap-3","children":[["$","div",null,{"className":"w-8 h-8 rounded-lg bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center text-sm font-bold text-white shadow-glow-sm","children":"D"}],["$","div",null,{"children":[["$","h1",null,{"className":"text-sm font-semibold tracking-tight","children":"Dragon AI Agent"}],["$","p",null,{"className":"text-xs text-text-muted mt-0.5 font-light tracking-wide","children":"资金驱动 · 四层漏斗模型"}]]}]]}]}],["$","div",null,{"className":"mx-5 h-px bg-gradient-to-r from-transparent via-white/[0.06] to-transparent"}],["$","$L8",null,{}],["$","div",null,{"className":"px-6 py-5 border-t border-white/[0.04]","children":["$","$L9",null,{}]}]]}],["$","main",null,{"className":"flex-1 md:ml-60 pb-16 md:pb-0 min-h-screen","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}],["$","$La",null,{}]]}]}]}]}]],null],null],["$Lb",null]]]]
|
||||
b:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Dragon AI Agent"}],["$","meta","3",{"name":"description","content":"基于资金驱动的四层漏斗模型,盘中实时分析推荐A股"}]]
|
||||
1:null
|
||||
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/171.js","../../chunks/948.js","../../chunks/982.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,5 +0,0 @@
|
||||
{
|
||||
"headers": {
|
||||
"x-next-cache-tags": "_N_T_/layout,_N_T_/page,_N_T_/"
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
2:I[9107,[],"ClientPageRoot"]
|
||||
3:I[7449,["931","static/chunks/app/page-0a611a415022fe45.js"],"default",1]
|
||||
4:I[8145,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthProvider"]
|
||||
5:I[7182,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthGuard"]
|
||||
6:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"SidebarNav"]
|
||||
7:I[5315,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"UserMenu"]
|
||||
8:I[4707,[],""]
|
||||
9:I[6423,[],""]
|
||||
a:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"MobileBottomNav"]
|
||||
0:["_K30GhWJ6_9AsiU6iKw4I",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/e86a9d7e539c28dc.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","children":["$","body",null,{"className":"min-h-screen bg-bg-primary text-text-primary font-display","children":["$","$L4",null,{"children":["$","$L5",null,{"children":[["$","div",null,{"className":"flex min-h-screen","children":[["$","aside",null,{"className":"hidden md:flex flex-col w-60 glass-sidebar fixed inset-y-0 left-0 z-40","children":[["$","div",null,{"className":"px-6 pt-7 pb-5","children":["$","div",null,{"className":"flex items-center gap-3","children":[["$","div",null,{"className":"w-8 h-8 rounded-lg bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center text-sm font-bold text-white shadow-glow-sm","children":"D"}],["$","div",null,{"children":[["$","h1",null,{"className":"text-sm font-semibold tracking-tight","children":"Dragon AI Agent"}],["$","p",null,{"className":"text-xs text-text-muted mt-0.5 font-light tracking-wide","children":"资金驱动 · 四层漏斗模型"}]]}]]}]}],["$","div",null,{"className":"mx-5 h-px bg-gradient-to-r from-transparent via-white/[0.06] to-transparent"}],["$","$L6",null,{}],["$","div",null,{"className":"px-6 py-5 border-t border-white/[0.04]","children":["$","$L7",null,{}]}]]}],["$","main",null,{"className":"flex-1 md:ml-60 pb-16 md:pb-0 min-h-screen","children":["$","$L8",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L9",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}],["$","$La",null,{}]]}]}]}]}]],null],null],["$Lb",null]]]]
|
||||
b:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Dragon AI Agent"}],["$","meta","3",{"name":"description","content":"基于资金驱动的四层漏斗模型,盘中实时分析推荐A股"}]]
|
||||
1:null
|
||||
File diff suppressed because one or more lines are too long
@ -1,5 +0,0 @@
|
||||
{
|
||||
"headers": {
|
||||
"x-next-cache-tags": "_N_T_/layout,_N_T_/login/layout,_N_T_/login/page,_N_T_/login"
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
2:I[9107,[],"ClientPageRoot"]
|
||||
3:I[8991,["626","static/chunks/app/login/page-778febf452923618.js"],"default",1]
|
||||
4:I[4707,[],""]
|
||||
5:I[6423,[],""]
|
||||
6:I[8145,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthProvider"]
|
||||
7:I[7182,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthGuard"]
|
||||
8:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"SidebarNav"]
|
||||
9:I[5315,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"UserMenu"]
|
||||
a:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"MobileBottomNav"]
|
||||
0:["_K30GhWJ6_9AsiU6iKw4I",[[["",{"children":["login",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["login",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","login","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/e86a9d7e539c28dc.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","children":["$","body",null,{"className":"min-h-screen bg-bg-primary text-text-primary font-display","children":["$","$L6",null,{"children":["$","$L7",null,{"children":[["$","div",null,{"className":"flex min-h-screen","children":[["$","aside",null,{"className":"hidden md:flex flex-col w-60 glass-sidebar fixed inset-y-0 left-0 z-40","children":[["$","div",null,{"className":"px-6 pt-7 pb-5","children":["$","div",null,{"className":"flex items-center gap-3","children":[["$","div",null,{"className":"w-8 h-8 rounded-lg bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center text-sm font-bold text-white shadow-glow-sm","children":"D"}],["$","div",null,{"children":[["$","h1",null,{"className":"text-sm font-semibold tracking-tight","children":"Dragon AI Agent"}],["$","p",null,{"className":"text-xs text-text-muted mt-0.5 font-light tracking-wide","children":"资金驱动 · 四层漏斗模型"}]]}]]}]}],["$","div",null,{"className":"mx-5 h-px bg-gradient-to-r from-transparent via-white/[0.06] to-transparent"}],["$","$L8",null,{}],["$","div",null,{"className":"px-6 py-5 border-t border-white/[0.04]","children":["$","$L9",null,{}]}]]}],["$","main",null,{"className":"flex-1 md:ml-60 pb-16 md:pb-0 min-h-screen","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}],["$","$La",null,{}]]}]}]}]}]],null],null],["$Lb",null]]]]
|
||||
b:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Dragon AI Agent"}],["$","meta","3",{"name":"description","content":"基于资金驱动的四层漏斗模型,盘中实时分析推荐A股"}]]
|
||||
1:null
|
||||
@ -1 +0,0 @@
|
||||
(()=>{var e={};e.id=626,e.ids=[626],e.modules={2934:e=>{"use strict";e.exports=require("next/dist/client/components/action-async-storage.external.js")},4580:e=>{"use strict";e.exports=require("next/dist/client/components/request-async-storage.external.js")},5869:e=>{"use strict";e.exports=require("next/dist/client/components/static-generation-async-storage.external.js")},399:e=>{"use strict";e.exports=require("next/dist/compiled/next-server/app-page.runtime.prod.js")},8625:(e,t,r)=>{"use strict";r.r(t),r.d(t,{GlobalError:()=>n.a,__next_app__:()=>m,originalPathname:()=>u,pages:()=>c,routeModule:()=>p,tree:()=>d}),r(974),r(5166),r(5866);var s=r(3191),a=r(8716),o=r(7922),n=r.n(o),i=r(5231),l={};for(let e in i)0>["default","tree","pages","GlobalError","originalPathname","__next_app__","routeModule"].indexOf(e)&&(l[e]=()=>i[e]);r.d(t,l);let d=["",{children:["login",{children:["__PAGE__",{},{page:[()=>Promise.resolve().then(r.bind(r,974)),"/Users/aaron/source_code/astock-agent/frontend/src/app/login/page.tsx"]}]},{}]},{layout:[()=>Promise.resolve().then(r.bind(r,5166)),"/Users/aaron/source_code/astock-agent/frontend/src/app/layout.tsx"],"not-found":[()=>Promise.resolve().then(r.t.bind(r,5866,23)),"next/dist/client/components/not-found-error"]}],c=["/Users/aaron/source_code/astock-agent/frontend/src/app/login/page.tsx"],u="/login/page",m={require:r,loadChunk:()=>Promise.resolve()},p=new s.AppPageRouteModule({definition:{kind:a.x.APP_PAGE,page:"/login/page",pathname:"/login",bundlePath:"",filename:"",appPaths:[]},userland:{loaderTree:d}})},4558:(e,t,r)=>{Promise.resolve().then(r.bind(r,4146))},4146:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>i});var s=r(326),a=r(7577),o=r(5047),n=r(9260);function i(){let[e,t]=(0,a.useState)(""),[r,i]=(0,a.useState)(""),[l,d]=(0,a.useState)(""),[c,u]=(0,a.useState)(!1),{login:m}=(0,n.a)(),p=(0,o.useRouter)();async function x(t){if(t.preventDefault(),d(""),!e.trim()||!r.trim()){d("请输入用户名和密码");return}u(!0);try{await m(e,r),p.push("/")}catch(e){d(e instanceof Error?e.message:"登录失败,请重试")}finally{u(!1)}}return s.jsx("div",{className:"min-h-screen flex items-center justify-center bg-bg-primary",children:(0,s.jsxs)("div",{className:"max-w-sm w-full mx-4 p-8 rounded-2xl bg-white/[0.02] border border-white/[0.06] backdrop-blur-sm",children:[(0,s.jsxs)("div",{className:"flex flex-col items-center mb-8",children:[s.jsx("div",{className:"w-10 h-10 rounded-xl bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center text-base font-bold text-white shadow-glow-sm mb-4",children:"D"}),s.jsx("h1",{className:"text-lg font-semibold tracking-tight text-text-primary",children:"Dragon AI Agent"}),s.jsx("p",{className:"text-sm text-text-muted mt-1",children:"登录以继续"})]}),(0,s.jsxs)("form",{onSubmit:x,className:"space-y-4",children:[s.jsx("input",{type:"text",placeholder:"用户名",value:e,onChange:e=>t(e.target.value),className:"w-full bg-white/[0.03] border border-white/[0.06] rounded-xl px-4 py-3 text-sm text-text-primary focus:outline-none focus:ring-1 focus:ring-amber-500/30 placeholder-text-muted/40",autoComplete:"username"}),s.jsx("input",{type:"password",placeholder:"密码",value:r,onChange:e=>i(e.target.value),className:"w-full bg-white/[0.03] border border-white/[0.06] rounded-xl px-4 py-3 text-sm text-text-primary focus:outline-none focus:ring-1 focus:ring-amber-500/30 placeholder-text-muted/40",autoComplete:"current-password"}),s.jsx("button",{type:"submit",disabled:c,className:"w-full bg-gradient-to-r from-amber-500/20 to-amber-600/15 text-amber-400 rounded-xl py-3 text-sm font-medium hover:from-amber-500/30 hover:to-amber-600/25 transition-all duration-200 border border-amber-500/10 disabled:opacity-50 disabled:cursor-not-allowed",children:c?"登录中...":"登录"})]}),l&&s.jsx("p",{className:"mt-4 text-center text-xs text-amber-400/80",children:l})]})})}},974:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>s});let s=(0,r(8570).createProxy)(String.raw`/Users/aaron/source_code/astock-agent/frontend/src/app/login/page.tsx#default`)}};var t=require("../../webpack-runtime.js");t.C(e);var r=e=>t(t.s=e),s=t.X(0,[948,982,171],()=>r(8625));module.exports=s})();
|
||||
@ -1 +0,0 @@
|
||||
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/171.js","../../chunks/948.js","../../chunks/982.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{"version":1,"files":["../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../node_modules/next/dist/client/components/async-local-storage.js","../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../node_modules/next/dist/server/lib/trace/constants.js","../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../node_modules/next/package.json","../../../package.json","../../package.json","../chunks/171.js","../chunks/948.js","../chunks/982.js","../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,5 +0,0 @@
|
||||
{
|
||||
"headers": {
|
||||
"x-next-cache-tags": "_N_T_/layout,_N_T_/recommendations/layout,_N_T_/recommendations/page,_N_T_/recommendations"
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
2:I[9107,[],"ClientPageRoot"]
|
||||
3:I[7773,["70","static/chunks/app/recommendations/page-ea6294fe452e71ef.js"],"default",1]
|
||||
4:I[4707,[],""]
|
||||
5:I[6423,[],""]
|
||||
6:I[8145,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthProvider"]
|
||||
7:I[7182,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthGuard"]
|
||||
8:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"SidebarNav"]
|
||||
9:I[5315,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"UserMenu"]
|
||||
a:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"MobileBottomNav"]
|
||||
0:["_K30GhWJ6_9AsiU6iKw4I",[[["",{"children":["recommendations",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["recommendations",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","recommendations","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/e86a9d7e539c28dc.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","children":["$","body",null,{"className":"min-h-screen bg-bg-primary text-text-primary font-display","children":["$","$L6",null,{"children":["$","$L7",null,{"children":[["$","div",null,{"className":"flex min-h-screen","children":[["$","aside",null,{"className":"hidden md:flex flex-col w-60 glass-sidebar fixed inset-y-0 left-0 z-40","children":[["$","div",null,{"className":"px-6 pt-7 pb-5","children":["$","div",null,{"className":"flex items-center gap-3","children":[["$","div",null,{"className":"w-8 h-8 rounded-lg bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center text-sm font-bold text-white shadow-glow-sm","children":"D"}],["$","div",null,{"children":[["$","h1",null,{"className":"text-sm font-semibold tracking-tight","children":"Dragon AI Agent"}],["$","p",null,{"className":"text-xs text-text-muted mt-0.5 font-light tracking-wide","children":"资金驱动 · 四层漏斗模型"}]]}]]}]}],["$","div",null,{"className":"mx-5 h-px bg-gradient-to-r from-transparent via-white/[0.06] to-transparent"}],["$","$L8",null,{}],["$","div",null,{"className":"px-6 py-5 border-t border-white/[0.04]","children":["$","$L9",null,{}]}]]}],["$","main",null,{"className":"flex-1 md:ml-60 pb-16 md:pb-0 min-h-screen","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}],["$","$La",null,{}]]}]}]}]}]],null],null],["$Lb",null]]]]
|
||||
b:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Dragon AI Agent"}],["$","meta","3",{"name":"description","content":"基于资金驱动的四层漏斗模型,盘中实时分析推荐A股"}]]
|
||||
1:null
|
||||
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/171.js","../../chunks/948.js","../../chunks/982.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,5 +0,0 @@
|
||||
{
|
||||
"headers": {
|
||||
"x-next-cache-tags": "_N_T_/layout,_N_T_/sectors/layout,_N_T_/sectors/page,_N_T_/sectors"
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
2:I[9107,[],"ClientPageRoot"]
|
||||
3:I[9314,["542","static/chunks/app/sectors/page-41a82a8a8f795a23.js"],"default",1]
|
||||
4:I[4707,[],""]
|
||||
5:I[6423,[],""]
|
||||
6:I[8145,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthProvider"]
|
||||
7:I[7182,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthGuard"]
|
||||
8:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"SidebarNav"]
|
||||
9:I[5315,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"UserMenu"]
|
||||
a:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"MobileBottomNav"]
|
||||
0:["_K30GhWJ6_9AsiU6iKw4I",[[["",{"children":["sectors",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["sectors",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","sectors","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/e86a9d7e539c28dc.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","children":["$","body",null,{"className":"min-h-screen bg-bg-primary text-text-primary font-display","children":["$","$L6",null,{"children":["$","$L7",null,{"children":[["$","div",null,{"className":"flex min-h-screen","children":[["$","aside",null,{"className":"hidden md:flex flex-col w-60 glass-sidebar fixed inset-y-0 left-0 z-40","children":[["$","div",null,{"className":"px-6 pt-7 pb-5","children":["$","div",null,{"className":"flex items-center gap-3","children":[["$","div",null,{"className":"w-8 h-8 rounded-lg bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center text-sm font-bold text-white shadow-glow-sm","children":"D"}],["$","div",null,{"children":[["$","h1",null,{"className":"text-sm font-semibold tracking-tight","children":"Dragon AI Agent"}],["$","p",null,{"className":"text-xs text-text-muted mt-0.5 font-light tracking-wide","children":"资金驱动 · 四层漏斗模型"}]]}]]}]}],["$","div",null,{"className":"mx-5 h-px bg-gradient-to-r from-transparent via-white/[0.06] to-transparent"}],["$","$L8",null,{}],["$","div",null,{"className":"px-6 py-5 border-t border-white/[0.04]","children":["$","$L9",null,{}]}]]}],["$","main",null,{"className":"flex-1 md:ml-60 pb-16 md:pb-0 min-h-screen","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}],["$","$La",null,{}]]}]}]}]}]],null],null],["$Lb",null]]]]
|
||||
b:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Dragon AI Agent"}],["$","meta","3",{"name":"description","content":"基于资金驱动的四层漏斗模型,盘中实时分析推荐A股"}]]
|
||||
1:null
|
||||
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/171.js","../../chunks/948.js","../../chunks/982.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{"version":1,"files":["../../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../../node_modules/next/package.json","../../../../../package.json","../../../../package.json","../../../chunks/171.js","../../../chunks/948.js","../../../chunks/982.js","../../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,5 +0,0 @@
|
||||
{
|
||||
"headers": {
|
||||
"x-next-cache-tags": "_N_T_/layout,_N_T_/users/layout,_N_T_/users/page,_N_T_/users"
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
2:I[9107,[],"ClientPageRoot"]
|
||||
3:I[2688,["240","static/chunks/app/users/page-e66e56f48050576b.js"],"default",1]
|
||||
4:I[4707,[],""]
|
||||
5:I[6423,[],""]
|
||||
6:I[8145,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthProvider"]
|
||||
7:I[7182,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"AuthGuard"]
|
||||
8:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"SidebarNav"]
|
||||
9:I[5315,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"UserMenu"]
|
||||
a:I[3331,["448","static/chunks/448-92a7b932cf4502ac.js","185","static/chunks/app/layout-97bdd231e78ddf3f.js"],"MobileBottomNav"]
|
||||
0:["_K30GhWJ6_9AsiU6iKw4I",[[["",{"children":["users",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["users",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","users","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/e86a9d7e539c28dc.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"zh-CN","children":["$","body",null,{"className":"min-h-screen bg-bg-primary text-text-primary font-display","children":["$","$L6",null,{"children":["$","$L7",null,{"children":[["$","div",null,{"className":"flex min-h-screen","children":[["$","aside",null,{"className":"hidden md:flex flex-col w-60 glass-sidebar fixed inset-y-0 left-0 z-40","children":[["$","div",null,{"className":"px-6 pt-7 pb-5","children":["$","div",null,{"className":"flex items-center gap-3","children":[["$","div",null,{"className":"w-8 h-8 rounded-lg bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center text-sm font-bold text-white shadow-glow-sm","children":"D"}],["$","div",null,{"children":[["$","h1",null,{"className":"text-sm font-semibold tracking-tight","children":"Dragon AI Agent"}],["$","p",null,{"className":"text-xs text-text-muted mt-0.5 font-light tracking-wide","children":"资金驱动 · 四层漏斗模型"}]]}]]}]}],["$","div",null,{"className":"mx-5 h-px bg-gradient-to-r from-transparent via-white/[0.06] to-transparent"}],["$","$L8",null,{}],["$","div",null,{"className":"px-6 py-5 border-t border-white/[0.04]","children":["$","$L9",null,{}]}]]}],["$","main",null,{"className":"flex-1 md:ml-60 pb-16 md:pb-0 min-h-screen","children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}],["$","$La",null,{}]]}]}]}]}]],null],null],["$Lb",null]]]]
|
||||
b:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Dragon AI Agent"}],["$","meta","3",{"name":"description","content":"基于资金驱动的四层漏斗模型,盘中实时分析推荐A股"}]]
|
||||
1:null
|
||||
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/171.js","../../chunks/948.js","../../chunks/982.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user