Maximize Qdrant utilization: richer memory payloads, filtered retrieval, and qdrant health in metrics API
This commit is contained in:
3
app.py
3
app.py
@@ -6,7 +6,7 @@ from datetime import datetime, timedelta
|
||||
import threading
|
||||
from db import init_db, SessionLocal, BotDecision, TradeExecution, CuratedInsight
|
||||
from bot import start_scheduler, run_cycle, curate_cycle
|
||||
from services import account_snapshot
|
||||
from services import account_snapshot, qdrant_memory_health
|
||||
|
||||
app = FastAPI(title="alpaca-llm-bot-v1")
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
@@ -94,6 +94,7 @@ def api_metrics(hours: int = 72):
|
||||
"cumulativeNotional": t_values,
|
||||
},
|
||||
"leaderboard": leaderboard,
|
||||
"qdrant": qdrant_memory_health(),
|
||||
}
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
4
bot.py
4
bot.py
@@ -125,9 +125,11 @@ def run_cycle():
|
||||
|
||||
# learning memory + notes + orchestration signal
|
||||
qdrant_add_memory(symbol, f"{symbol} {decision['action']} conf={decision['confidence']} reason={decision['reason']}", {
|
||||
"memory_type": "execution",
|
||||
"status": drow.status,
|
||||
"action": decision["action"],
|
||||
"confidence": decision["confidence"],
|
||||
"outcome_score": 1 if ok else -1,
|
||||
"ts": datetime.utcnow().isoformat(),
|
||||
})
|
||||
trilium_log(
|
||||
@@ -145,9 +147,11 @@ def run_cycle():
|
||||
|
||||
# store non-trade decisions too for memory
|
||||
qdrant_add_memory(symbol, f"{symbol} decision={decision['action']} conf={decision['confidence']} status={drow.status}", {
|
||||
"memory_type": "decision",
|
||||
"status": drow.status,
|
||||
"action": decision["action"],
|
||||
"confidence": decision["confidence"],
|
||||
"outcome_score": 0 if drow.status in {"skipped", "risk_blocked"} else (-1 if drow.status=="failed" else 1),
|
||||
"ts": datetime.utcnow().isoformat(),
|
||||
})
|
||||
|
||||
|
||||
49
services.py
49
services.py
@@ -34,8 +34,15 @@ def qdrant_add_memory(symbol: str, text: str, payload: dict):
|
||||
if not vec:
|
||||
return False
|
||||
qdrant_ensure_collection(len(vec))
|
||||
enriched = {
|
||||
"symbol": symbol,
|
||||
"text": text[:2000],
|
||||
"memory_type": payload.get("memory_type", "decision"),
|
||||
"created_at": int(time.time()),
|
||||
**payload,
|
||||
}
|
||||
body = {
|
||||
"points": [{"id": str(uuid.uuid4()), "vector": vec, "payload": {"symbol": symbol, "text": text[:2000], **payload}}]
|
||||
"points": [{"id": str(uuid.uuid4()), "vector": vec, "payload": enriched}]
|
||||
}
|
||||
try:
|
||||
r = requests.put(f"{settings.qdrant_url}/collections/{settings.qdrant_collection}/points", json=body, timeout=15)
|
||||
@@ -44,11 +51,21 @@ def qdrant_add_memory(symbol: str, text: str, payload: dict):
|
||||
return False
|
||||
|
||||
|
||||
def qdrant_similar(symbol: str, query_text: str, limit: int = 5):
|
||||
def qdrant_similar(symbol: str, query_text: str, limit: int = 8):
|
||||
vec = _embed(query_text)
|
||||
if not vec:
|
||||
return []
|
||||
body = {"vector": vec, "limit": limit, "with_payload": True}
|
||||
body = {
|
||||
"vector": vec,
|
||||
"limit": limit,
|
||||
"with_payload": True,
|
||||
"filter": {
|
||||
"should": [
|
||||
{"key": "symbol", "match": {"value": symbol}},
|
||||
{"key": "memory_type", "match": {"value": "macro"}}
|
||||
]
|
||||
}
|
||||
}
|
||||
try:
|
||||
r = requests.post(f"{settings.qdrant_url}/collections/{settings.qdrant_collection}/points/search", json=body, timeout=15)
|
||||
if not r.ok:
|
||||
@@ -56,8 +73,14 @@ def qdrant_similar(symbol: str, query_text: str, limit: int = 5):
|
||||
out = []
|
||||
for p in r.json().get("result", []):
|
||||
pl = p.get("payload", {})
|
||||
if pl.get("symbol") in (symbol, None):
|
||||
out.append({"score": p.get("score", 0), "text": pl.get("text", ""), "status": pl.get("status", "")})
|
||||
out.append({
|
||||
"score": p.get("score", 0),
|
||||
"text": pl.get("text", ""),
|
||||
"status": pl.get("status", ""),
|
||||
"action": pl.get("action", ""),
|
||||
"confidence": pl.get("confidence", None),
|
||||
"outcome_score": pl.get("outcome_score", None),
|
||||
})
|
||||
return out
|
||||
except Exception:
|
||||
return []
|
||||
@@ -233,6 +256,22 @@ def trilium_log(title: str, body: str):
|
||||
return False
|
||||
|
||||
|
||||
def qdrant_memory_health():
|
||||
try:
|
||||
r = requests.get(f"{settings.qdrant_url}/collections/{settings.qdrant_collection}", timeout=10)
|
||||
if not r.ok:
|
||||
return {"ok": False, "status": r.status_code}
|
||||
j = r.json().get("result", {})
|
||||
return {
|
||||
"ok": True,
|
||||
"collection": settings.qdrant_collection,
|
||||
"points_count": j.get("points_count"),
|
||||
"indexed_vectors_count": j.get("indexed_vectors_count"),
|
||||
}
|
||||
except Exception as e:
|
||||
return {"ok": False, "error": str(e)[:160]}
|
||||
|
||||
|
||||
def n8n_emit(event: dict):
|
||||
if not settings.n8n_webhook:
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user