Spaces:
Sleeping
Sleeping
| async def trading_decision(request: Dict[str, Any]): | |
| """ | |
| FIXED: Get trading decision based on sentiment classification. | |
| Uses ElKulako/cryptobert (classification model) instead of generation. | |
| Logic: | |
| - BULLISH/POSITIVE label -> BUY | |
| - BEARISH/NEGATIVE label -> SELL | |
| - NEUTRAL or error -> HOLD | |
| Always returns valid JSON (never crashes with 500). | |
| """ | |
| try: | |
| symbol = request.get("symbol", "").strip().upper() | |
| context = request.get("context", "").strip() | |
| if not symbol: | |
| raise HTTPException(status_code=400, detail="Symbol is required") | |
| # Build analysis text | |
| if context: | |
| analysis_text = f"{symbol} {context}" | |
| else: | |
| analysis_text = f"{symbol} market analysis" | |
| # Default safe response | |
| default_response = { | |
| "success": True, | |
| "available": False, | |
| "decision": "HOLD", | |
| "confidence": 0.5, | |
| "rationale": "Unable to analyze sentiment - defaulting to HOLD for safety", | |
| "symbol": symbol, | |
| "model": "fallback", | |
| "context_provided": bool(context), | |
| "timestamp": datetime.now().isoformat() | |
| } | |
| try: | |
| from ai_models import _registry, MODEL_SPECS, ModelNotAvailable | |
| # Try to use the trading model (crypto_trading_lm -> ElKulako/cryptobert) | |
| trading_key = "crypto_trading_lm" | |
| if trading_key not in MODEL_SPECS: | |
| logger.warning("Trading model key not found in MODEL_SPECS") | |
| return default_response | |
| try: | |
| # Get the classification pipeline (lazy loaded) | |
| pipe = _registry.get_pipeline(trading_key) | |
| spec = MODEL_SPECS[trading_key] | |
| # Run classification | |
| result = pipe(analysis_text[:512]) | |
| if isinstance(result, list) and result: | |
| result = result[0] | |
| label = result.get("label", "NEUTRAL").upper() | |
| score = result.get("score", 0.5) | |
| # FIXED LOGIC: Map label to trading decision | |
| decision = "HOLD" # Default | |
| if "BULLISH" in label or "POSITIVE" in label or "LABEL_2" in label: | |
| decision = "BUY" | |
| elif "BEARISH" in label or "NEGATIVE" in label or "LABEL_0" in label: | |
| decision = "SELL" | |
| else: | |
| decision = "HOLD" | |
| # Build rationale | |
| sentiment_word = "bullish" if decision == "BUY" else ("bearish" if decision == "SELL" else "neutral") | |
| rationale = f"Model detected {sentiment_word} sentiment (label: {label}, confidence: {score:.2f})" | |
| if context: | |
| rationale += f" based on: {context[:200]}" | |
| return { | |
| "success": True, | |
| "available": True, | |
| "decision": decision, | |
| "confidence": float(score), | |
| "rationale": rationale, | |
| "symbol": symbol, | |
| "model": spec.model_id, | |
| "sentiment": sentiment_word, | |
| "raw_label": label, | |
| "context_provided": bool(context), | |
| "timestamp": datetime.now().isoformat() | |
| } | |
| except ModelNotAvailable as e: | |
| logger.warning(f"Trading model not available: {e}") | |
| default_response["error"] = f"Model unavailable: {str(e)[:100]}" | |
| default_response["note"] = "Model in cooldown or failed to load" | |
| return default_response | |
| except ImportError: | |
| logger.error("ai_models module not available") | |
| default_response["error"] = "AI models module not available" | |
| return default_response | |
| except Exception as e: | |
| logger.warning(f"Sentiment analysis failed: {e}") | |
| default_response["error"] = f"Analysis failed: {str(e)[:100]}" | |
| default_response["note"] = "Using default HOLD signal due to analysis failure" | |
| return default_response | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| logger.error(f"Trading decision endpoint error: {e}") | |
| # Never crash - always return valid JSON | |
| return { | |
| "success": True, | |
| "available": False, | |
| "error": f"Endpoint error: {str(e)[:100]}", | |
| "decision": "HOLD", | |
| "confidence": 0.5, | |
| "rationale": "Error occurred during analysis - defaulting to HOLD for safety", | |
| "symbol": request.get("symbol", "UNKNOWN"), | |
| "timestamp": datetime.now().isoformat() | |
| } | |