修复ai
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
"""AI 日复盘 / 周复盘:附图收集(各实例共用)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import uuid
|
||||
from typing import Callable, List, Optional, Sequence
|
||||
|
||||
from journal_chart_lib import (
|
||||
JOURNAL_CHART_ANCHOR_CLOSE,
|
||||
JOURNAL_CHART_DEFAULT_LIMIT,
|
||||
JOURNAL_CHART_DEFAULT_TF1,
|
||||
JOURNAL_CHART_DEFAULT_TF2,
|
||||
normalize_chart_timeframe,
|
||||
)
|
||||
|
||||
|
||||
def collect_images_for_ai_review(
|
||||
rows: Sequence,
|
||||
upload_folder: str,
|
||||
*,
|
||||
build_chart_if_missing: Optional[Callable] = None,
|
||||
) -> List[str]:
|
||||
"""
|
||||
收集传给视觉模型的本地图片路径。
|
||||
- 优先 journal_entries.image 已存附图;
|
||||
- 若无附图且提供 build_chart_if_missing,则临时生成 K 线图。
|
||||
"""
|
||||
paths: List[str] = []
|
||||
seen = set()
|
||||
upload_folder = os.path.abspath(upload_folder or "")
|
||||
for row in rows or []:
|
||||
candidate = None
|
||||
try:
|
||||
keys = row.keys() if hasattr(row, "keys") else []
|
||||
except Exception:
|
||||
keys = []
|
||||
img = row["image"] if "image" in keys else None
|
||||
if img:
|
||||
candidate = os.path.join(upload_folder, str(img).strip())
|
||||
elif build_chart_if_missing:
|
||||
try:
|
||||
candidate = build_chart_if_missing(row)
|
||||
except Exception:
|
||||
candidate = None
|
||||
if not candidate:
|
||||
continue
|
||||
candidate = os.path.abspath(candidate)
|
||||
if os.path.isfile(candidate) and candidate not in seen:
|
||||
seen.add(candidate)
|
||||
paths.append(candidate)
|
||||
return paths
|
||||
|
||||
|
||||
def build_journal_ai_chart_path(
|
||||
row,
|
||||
upload_folder: str,
|
||||
*,
|
||||
order_chart_enabled: bool,
|
||||
normalize_exchange_symbol_fn: Callable[[str], str],
|
||||
generate_chart_fn: Callable,
|
||||
local_datetime_to_ms_fn: Callable[[str], Optional[int]],
|
||||
now_ts_ms_fn: Callable[[], int],
|
||||
) -> Optional[str]:
|
||||
"""无已存附图时,按复盘记录开平仓时间临时生成 K 线图路径。"""
|
||||
if not order_chart_enabled:
|
||||
return None
|
||||
try:
|
||||
keys = row.keys() if hasattr(row, "keys") else []
|
||||
except Exception:
|
||||
return None
|
||||
coin = (row["coin"] if "coin" in keys else "") or ""
|
||||
coin = str(coin).strip()
|
||||
if not coin:
|
||||
return None
|
||||
try:
|
||||
symbol = normalize_exchange_symbol_fn(coin)
|
||||
except Exception:
|
||||
return None
|
||||
open_dt = row["open_datetime"] if "open_datetime" in keys else ""
|
||||
close_dt = row["close_datetime"] if "close_datetime" in keys else ""
|
||||
entry_ms = local_datetime_to_ms_fn(open_dt)
|
||||
exit_ms = local_datetime_to_ms_fn(close_dt)
|
||||
if not entry_ms:
|
||||
return None
|
||||
row_tf = row["tf"] if "tf" in keys else ""
|
||||
tf1 = normalize_chart_timeframe(row_tf) or JOURNAL_CHART_DEFAULT_TF1
|
||||
tf2 = JOURNAL_CHART_DEFAULT_TF2 if tf1 != JOURNAL_CHART_DEFAULT_TF2 else "1h"
|
||||
row_id = str(row["id"] if "id" in keys else "")[:8] or uuid.uuid4().hex[:8]
|
||||
marker = {
|
||||
"entry_ts_ms": entry_ms,
|
||||
"exit_ts_ms": exit_ms,
|
||||
"chart_anchor": JOURNAL_CHART_ANCHOR_CLOSE,
|
||||
"now_ts_ms": int(now_ts_ms_fn()),
|
||||
}
|
||||
fname = f"ai_rev_{row_id}_{uuid.uuid4().hex[:6]}.png"
|
||||
saved = generate_chart_fn(
|
||||
symbol,
|
||||
f"AI复盘 {coin}",
|
||||
timeframes=[tf1, tf2],
|
||||
limit=JOURNAL_CHART_DEFAULT_LIMIT,
|
||||
out_dir=upload_folder,
|
||||
filename=fname,
|
||||
marker_payload=marker,
|
||||
marker_timeframes={tf1, tf2},
|
||||
layout="vertical",
|
||||
)
|
||||
if not saved:
|
||||
return None
|
||||
path = os.path.join(upload_folder, saved)
|
||||
return path if os.path.isfile(path) else None
|
||||
Reference in New Issue
Block a user