feat(frontend): add always-visible '重新生成分析' button per module\nfix(backend): inject dependency context for single-module generation (final_conclusion placeholders)
This commit is contained in:
parent
1e904eb7f4
commit
8b5d5f5777
@ -669,13 +669,77 @@ async def generate_analysis(
|
|||||||
# Initialize analysis client with configured model
|
# Initialize analysis client with configured model
|
||||||
client = AnalysisClient(api_key=api_key, base_url=base_url, model=model)
|
client = AnalysisClient(api_key=api_key, base_url=base_url, model=model)
|
||||||
|
|
||||||
|
# Prepare dependency context for single-module generation
|
||||||
|
# If the requested module declares dependencies, generate them first and inject their outputs
|
||||||
|
context = {}
|
||||||
|
try:
|
||||||
|
dependencies = analysis_cfg.get("dependencies", []) or []
|
||||||
|
if dependencies:
|
||||||
|
# Load full modules config to resolve dependency graph
|
||||||
|
analysis_config_full = load_analysis_config()
|
||||||
|
modules_config = analysis_config_full.get("analysis_modules", {})
|
||||||
|
|
||||||
|
# Collect all transitive dependencies
|
||||||
|
all_required = set()
|
||||||
|
|
||||||
|
def collect_all_deps(mod_name: str):
|
||||||
|
for dep in modules_config.get(mod_name, {}).get("dependencies", []) or []:
|
||||||
|
if dep not in all_required:
|
||||||
|
all_required.add(dep)
|
||||||
|
collect_all_deps(dep)
|
||||||
|
|
||||||
|
for dep in dependencies:
|
||||||
|
all_required.add(dep)
|
||||||
|
collect_all_deps(dep)
|
||||||
|
|
||||||
|
# Build subgraph and topologically sort
|
||||||
|
graph = {name: [d for d in (modules_config.get(name, {}).get("dependencies", []) or []) if d in all_required] for name in all_required}
|
||||||
|
in_degree = {u: 0 for u in graph}
|
||||||
|
for u, deps in graph.items():
|
||||||
|
for v in deps:
|
||||||
|
in_degree[v] += 1
|
||||||
|
queue = [u for u, deg in in_degree.items() if deg == 0]
|
||||||
|
order = []
|
||||||
|
while queue:
|
||||||
|
u = queue.pop(0)
|
||||||
|
order.append(u)
|
||||||
|
for v in graph.get(u, []):
|
||||||
|
in_degree[v] -= 1
|
||||||
|
if in_degree[v] == 0:
|
||||||
|
queue.append(v)
|
||||||
|
if len(order) != len(graph):
|
||||||
|
# Fallback: if cycle detected, just use any order
|
||||||
|
order = list(all_required)
|
||||||
|
|
||||||
|
# Generate dependencies in order
|
||||||
|
completed = {}
|
||||||
|
for mod in order:
|
||||||
|
cfg = modules_config.get(mod, {})
|
||||||
|
dep_ctx = {d: completed.get(d, "") for d in (cfg.get("dependencies", []) or [])}
|
||||||
|
dep_client = AnalysisClient(api_key=api_key, base_url=base_url, model=cfg.get("model", model))
|
||||||
|
dep_result = await dep_client.generate_analysis(
|
||||||
|
analysis_type=mod,
|
||||||
|
company_name=company_name,
|
||||||
|
ts_code=ts_code,
|
||||||
|
prompt_template=cfg.get("prompt_template", ""),
|
||||||
|
financial_data=financial_data,
|
||||||
|
context=dep_ctx,
|
||||||
|
)
|
||||||
|
completed[mod] = dep_result.get("content", "") if dep_result.get("success") else ""
|
||||||
|
|
||||||
|
context = {dep: completed.get(dep, "") for dep in dependencies}
|
||||||
|
except Exception:
|
||||||
|
# Best-effort context; if anything goes wrong, continue without it
|
||||||
|
context = {}
|
||||||
|
|
||||||
# Generate analysis
|
# Generate analysis
|
||||||
result = await client.generate_analysis(
|
result = await client.generate_analysis(
|
||||||
analysis_type=analysis_type,
|
analysis_type=analysis_type,
|
||||||
company_name=company_name,
|
company_name=company_name,
|
||||||
ts_code=ts_code,
|
ts_code=ts_code,
|
||||||
prompt_template=prompt_template,
|
prompt_template=prompt_template,
|
||||||
financial_data=financial_data
|
financial_data=financial_data,
|
||||||
|
context=context,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"[API] Analysis generation completed, success={result.get('success')}")
|
logger.info(f"[API] Analysis generation completed, success={result.get('success')}")
|
||||||
|
|||||||
@ -1491,6 +1491,7 @@ export default function ReportPage() {
|
|||||||
: '待开始'}
|
: '待开始'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* 失败时的“重新分析”按钮(兼容原逻辑) */}
|
||||||
{state.error && !state.loading && (
|
{state.error && !state.loading && (
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@ -1502,6 +1503,18 @@ export default function ReportPage() {
|
|||||||
重新分析
|
重新分析
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
{/* 新增:始终可见的“重新生成分析”按钮 */}
|
||||||
|
{!state.loading && (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => retryAnalysis(analysisType)}
|
||||||
|
disabled={currentAnalysisTask !== null}
|
||||||
|
>
|
||||||
|
<RotateCw className="size-4" />
|
||||||
|
重新生成分析
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{state.error && (
|
{state.error && (
|
||||||
|
|||||||
@ -8,3 +8,4 @@ echo "All pm2 applications stopped."
|
|||||||
echo "Deleting all pm2 processes..."
|
echo "Deleting all pm2 processes..."
|
||||||
pm2 delete all
|
pm2 delete all
|
||||||
echo "All pm2 processes deleted."
|
echo "All pm2 processes deleted."
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user