Initial AlphaPulse implementation: news crawler and Binance klines

- Backend (FastAPI, SQLAlchemy 2, Alembic): single-admin cookie auth,
  news/crawler/market APIs with SSE and WebSocket streaming
- Crawler (Scrapy + Scrapy-Redis): wscn_news, wscn_live, cls_depth,
  cls_telegraph spiders, idempotent upserts with revisions, raw response
  archiving, per-source subprocess supervision, restart and backoff
- Market worker: full-history Binance spot/USD-M kline backfill,
  realtime WS stream, hourly and on-reconnect catch-up
- Frontend (Vue 3, Element Plus, UnoCSS, KLineChart): news feed,
  crawler console with live logs, Binance-style chart page
- Deploy: docker compose, nginx site, migrate and daily backup scripts
This commit is contained in:
eezd committed 2026-10-13 13:32:55 +08:00
commit aabc81ba5b
88 files changed
+12603

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
import dayjs from "dayjs"
export function formatTime(value: string | null | undefined, pattern = "MM-DD HH:mm:ss") {
return value ? dayjs(value).format(pattern) : "-"
}
/** HTML 转纯文本行;DOMParser 解析的文档不会执行脚本 */
export function htmlToLines(html: string): string[] {
const marked = html.replace(/<br\s*\/?>|<\/(?:p|div|li|h\d)>/gi, "\n")
const text = new DOMParser().parseFromString(marked, "text/html").body.textContent ?? ""
return text.split("\n").map(line => line.trim()).filter(Boolean)
}
export interface DiffLine {
type: "same" | "add" | "del"
text: string
}
/** 基于最长公共子序列的逐行对比 */
export function diffLines(before: string[], after: string[]): DiffLine[] {
const n = before.length
const m = after.length
const lcs = Array.from({ length: n + 1 }, () => Array.from<number>({ length: m + 1 }).fill(0))
for (let i = n - 1; i >= 0; i--) {
for (let j = m - 1; j >= 0; j--)
lcs[i][j] = before[i] === after[j] ? lcs[i + 1][j + 1] + 1 : Math.max(lcs[i + 1][j], lcs[i][j + 1])
}
const result: DiffLine[] = []
let i = 0
let j = 0
while (i < n && j < m) {
if (before[i] === after[j]) {
result.push({ type: "same", text: before[i] })
i++
j++
} else if (lcs[i + 1][j] >= lcs[i][j + 1]) {
result.push({ type: "del", text: before[i++] })
} else {
result.push({ type: "add", text: after[j++] })
}
}
while (i < n) result.push({ type: "del", text: before[i++] })
while (j < m) result.push({ type: "add", text: after[j++] })
return result
}