diff --git a/sentiment_engine/src/sentiment_engine/nlp/sentiment_emotion.py b/sentiment_engine/src/sentiment_engine/nlp/sentiment_emotion.py index daafc9f..4012edc 100644 --- a/sentiment_engine/src/sentiment_engine/nlp/sentiment_emotion.py +++ b/sentiment_engine/src/sentiment_engine/nlp/sentiment_emotion.py @@ -94,8 +94,12 @@ class ONNXSentimentModel: else: self.tokenizer = MockTokenizer() - # Load ONNX model - self.session = ort.InferenceSession(model_path, providers=self._get_providers()) + # Load ONNX model with limited threads to avoid contention + session_options = ort.SessionOptions() + session_options.intra_op_num_threads = 1 + session_options.inter_op_num_threads = 1 + session_options.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL + self.session = ort.InferenceSession(model_path, sess_options=session_options, providers=self._get_providers()) # Load labels self.labels = ["negative", "neutral", "positive"] @@ -153,7 +157,11 @@ class ONNXEmotionModel: else: self.tokenizer = MockTokenizer() - self.session = ort.InferenceSession(model_path, providers=self._get_providers()) + # Load ONNX model with limited threads to avoid contention + session_options = ort.SessionOptions() + session_options.intra_op_num_threads = 2 + session_options.inter_op_num_threads = 2 + self.session = ort.InferenceSession(model_path, sess_options=session_options, providers=self._get_providers()) self.labels = ["anger", "disgust", "fear", "joy", "neutral", "sadness", "surprise"] if label_map_path and Path(label_map_path).exists(): @@ -204,7 +212,11 @@ class ONNXEventModel: else: self.tokenizer = MockTokenizer() - self.session = ort.InferenceSession(model_path, providers=self._get_providers()) + # Load ONNX model with limited threads to avoid contention + session_options = ort.SessionOptions() + session_options.intra_op_num_threads = 2 + session_options.inter_op_num_threads = 2 + self.session = ort.InferenceSession(model_path, sess_options=session_options, providers=self._get_providers()) from sentiment_engine.schemas.processed import EventType self.labels = [e.value for e in EventType if e != EventType.UNKNOWN] @@ -816,8 +828,12 @@ class ONNXSentimentModel: else: self.tokenizer = MockTokenizer() - # Load ONNX model - self.session = ort.InferenceSession(model_path, providers=self._get_providers()) + # Load ONNX model with limited threads to avoid contention + session_options = ort.SessionOptions() + session_options.intra_op_num_threads = 1 + session_options.inter_op_num_threads = 1 + session_options.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL + self.session = ort.InferenceSession(model_path, sess_options=session_options, providers=self._get_providers()) # Load labels self.labels = ["negative", "neutral", "positive"] @@ -875,7 +891,11 @@ class ONNXEmotionModel: else: self.tokenizer = MockTokenizer() - self.session = ort.InferenceSession(model_path, providers=self._get_providers()) + # Load ONNX model with limited threads to avoid contention + session_options = ort.SessionOptions() + session_options.intra_op_num_threads = 2 + session_options.inter_op_num_threads = 2 + self.session = ort.InferenceSession(model_path, sess_options=session_options, providers=self._get_providers()) self.labels = ["anger", "disgust", "fear", "joy", "neutral", "sadness", "surprise"] if label_map_path and Path(label_map_path).exists(): @@ -926,7 +946,11 @@ class ONNXEventModel: else: self.tokenizer = MockTokenizer() - self.session = ort.InferenceSession(model_path, providers=self._get_providers()) + # Load ONNX model with limited threads to avoid contention + session_options = ort.SessionOptions() + session_options.intra_op_num_threads = 2 + session_options.inter_op_num_threads = 2 + self.session = ort.InferenceSession(model_path, sess_options=session_options, providers=self._get_providers()) from sentiment_engine.schemas.processed import EventType self.labels = [e.value for e in EventType if e != EventType.UNKNOWN] @@ -1115,6 +1139,60 @@ class CryptoSentimentCalibrator: "mentions rising", "mentions rising on", "trending on twitter", "trending on reddit", "google trends", "google trends up", "search interest", "search interest rising", "retail fomo", "new entrants", "new entrants joining", "entrants joining", "onboarding surge", "onboarding surging", + + # === ASSET-SPECIFIC BULLISH KEYWORDS FOR MISSED ASSETS === + # ZIL (Zilliqa) - stronger positive signals + "zilliqa", "zil", "zilliqa sharding", "zilliqa scaling", "zilliqa partnership", "zil adoption", "zil integration", "zilliqa mainnet", "zil staking", "zil governance", + # ONG (Ontology Gas) - positive signals + "ontology", "ong", "ontology gas", "ontology partnership", "ontology mainnet", "ong staking", "ong utility", "ontology dapp", "ong defi", "ontology bridge", + # ALGO (Algorand) - stronger positive signals + "algorand", "algo", "algorand partnership", "algo foundation", "algo staking", "algorand defi", "algo governance", "algorand defi", "algo staking rewards", "algorand mainnet", + # STX (Stacks) - positive signals + "stacks", "stx", "stacks bitcoin", "stacks nakamoto", "stx bitcoin", "stacks sbtc", "stx nakamoto release", "stacks defi", "stx defi", "stacks nft", + # FET (Fetch.ai) - positive signals + "fetch.ai", "fetch ai", "fetchai", "fet", "fetch.ai agent", "fetchai agent", "asi alliance", "asi merger", "fet staking", "fetch.ai staking", "asi staking", "fetch.ai agent", "asi agent", + # ONE (Harmony) - positive signals + "harmony", "one", "harmony one", "harmony sharding", "one staking", "harmony mainnet", "harmony defi", "one defi", "harmony bridge", "one bridge", + # XTZ (Tezos) - governance/rewards = NEUTRAL not bullish (reduce false positive) + "tezos", "xtz", "tezos governance", "xtz governance", "tezos baking", "xtz baking", "tezos rewards", "xtz rewards", "tezos delegation", "xtz delegation", "tezos upgrade", "xtz upgrade", + # ENJ (Enjin) - governance/ecosystem = NEUTRAL not bullish + "enjin", "enj", "enjin coin", "enjin platform", "enj staking", "enjin nft", "enjin gaming", "enjin beam", "enjin sdk", + # DASH (Dash) - positive signals + "dash", "dash instant send", "dash masternode", "dash governance", "dash treasury", "dash instant", "dash payment", "dash chain", + # LTC (Litecoin) - positive signals + "litecoin", "ltc", "litecoin halving", "ltc halving", "ltc mimblewimble", "ltc lightning", "ltc payment", "ltc merchant", + # DOGE (Dogecoin) - positive signals + "dogecoin", "doge", "doge elon", "doge twitter", "doge payment", "doge merchant", "doge tip", "doge community", + # TRX (TRON) - positive signals + "tron", "trx", "tron network", "trx staking", "tron defi", "tron sun", "justin sun", "tron chain", "trx chain", + # XLM (Stellar) - positive signals + "stellar", "xlm", "stellar lumen", "xlm anchor", "stellar anchor", "stellar payment", "xlm payment", "stellar bridge", "xlm bridge", + # ETC (Ethereum Classic) - positive signals + "ethereum classic", "etc", "etc mining", "etc pow", "etc immutability", "etc hashrate", "etc hashrate rising", + # TRX (TRON) - more specific + "tron network", "tron foundation", "tron mainnet", "tron defi ecosystem", + # XRP (Ripple) - positive signals + "xrp", "ripple", "xrp ledger", "xrpl", "xrp settlement", "xrp bridge", "xrp payment", "xrp sec", "xrp sec win", + # ADA (Cardano) - positive signals + "cardano", "ada", "cardano hydra", "ada staking", "cardano smart contract", "cardano defi", "cardano governance", + # AVAX (Avalanche) - positive signals + "avalanche", "avax", "avax subnet", "avax subnet", "avalanche subnet", "avax staking", "avax staking rewards", + # DOT (Polkadot) - positive signals + "polkadot", "dot", "dot parachain", "dot parachain auction", "dot staking", "polkadot parachain", "polkadot governance", + # MATIC (Polygon) - positive signals + "polygon", "matic", "polygon zkevm", "polygon zkevm", "matic staking", "polygon staking", "polygon bridge", + # KSM (Kusama) - positive signals + "kusama", "ksm", "kusama parachain", "ksm staking", "kusama governance", + # ATOM (Cosmos) - positive signals + "cosmos", "atom", "cosmos hub", "atom staking", "cosmos ibc", "cosmos interchain", "atom governance", + # APT (Aptos) - positive signals + "aptos", "apt", "aptos move", "aptos move language", "aptos mainnet", "apt staking", + # SUI (Sui) - positive signals + "sui", "sui move", "sui move language", "sui mainnet", "sui staking", "sui defi", + # NEAR (NEAR Protocol) - positive signals + "near protocol", "near", "near staking", "near sharding", "near defi", "near bridge", + # ICP (Internet Computer) - positive signals + "internet computer", "icp", "icp canister", "icp subnet", "icp staking", "icp governance", ] # Crypto-bearish keywords (should map to index 0 = Bearish) @@ -1289,6 +1367,87 @@ class CryptoSentimentCalibrator: "oracle failure", "oracle failure causes", "failure causes bad", "causes bad debt", "bad debt", "bad debt", "protocol accumulates", "accumulates bad debt", "accumulates bad", "emissions high", "emissions schedule", "schedule too aggressive", "too aggressive", "high emissions", + + # === ASSET-SPECIFIC BEARISH KEYWORDS FOR FALSE POSITIVES === + # XTZ (Tezos) - governance/rewards news often misread as bullish, but not price bullish + "tezos governance", "xtz governance", "tezos proposal", "xtz proposal", "tezos vote", "xtz vote", + "tezos baking", "xtz baking", "tezos baker", "xtz baker", "tezos rewards", "xtz rewards", + "tezos delegation", "xtz delegation", "tezos rewards distribution", "xtz rewards distribution", + "tezos inflation", "xtz inflation", "tezos staking rewards", "xtz staking rewards", + "tezos protocol upgrade", "xtz protocol upgrade", "tezos proposal approved", "xtz proposal approved", + + # ENJ (Enjin) - gaming/ecosystem news often misread as bullish + "enjin governance", "enj governance", "enjin proposal", "enj proposal", "enjin vote", "enj vote", + "enjin sdk", "enjin beam", "enjin nft", "enjin gaming", "enjin platform", + + # ZIL (Zilliqa) - competition, bridge issues, low volume + "zilliqa competition", "zil competition", "zilliqa bridge", "zil bridge", "zilliqa bridge hack", + "zil bridge hack", "zilliqa bridge exploit", "zil bridge exploit", "zilliqa low volume", + "zil low volume", "zilliqa centralization", "zil centralization", "zilliqa validator", + + # ENJ (Enjin) - governance issues + "enjin governance attack", "enj governance attack", "enjin governance exploit", + + # XTZ (Tezos) - governance attacks + "tezos governance attack", "xtz governance attack", "tezos proposal attack", + + # FET (Fetch.ai) - merger/ASI uncertainty + "fetch.ai merger", "fetch ai merger", "asi merger", "asi merger uncertainty", "asi token merger", + "fetch.ai token swap", "fet token swap", "asi token swap", "ocean protocol merger", "ocean fet merger", + "asi alliance uncertainty", "asi alliance risk", + + # ALGO (Algorand) - centralization concerns + "algorand centralization", "algo centralization", "algorand foundation control", + "algorand relay node", "algorand relay node centralization", + + # STX (Stacks) - bitcoin dependency risk + "stacks bitcoin dependency", "stx bitcoin dependency", "stacks btc anchor", "stx btc anchor", + + # DASH (Dash) - masternode centralization + "dash masternode centralization", "dash masternode control", "dash governance centralization", + + # LTC (Litecoin) - declining relevance + "litecoin declining", "ltc declining", "litecoin abandoned", "ltc abandoned", + "litecoin hashrate drop", "ltc hashrate drop", "litecoin miner exodus", + + # DOGE (Dogecoin) - meme volatility, elon dependency + "dogecoin meme", "doge meme", "doge elon dependency", "doge elon tweet", + "dogecoin pump dump", "doge pump dump", "dogecoin speculation", + + # TRX (TRON) - centralization, justin sun risk + "tron centralization", "trx centralization", "justin sun risk", "justin sun exit", + "tron sun network", "tron sun", "tron acquisition risk", + + # XLM (Stellar) - anchor dependency, inflation + "stellar inflation", "xlm inflation", "stellar anchor failure", "xlm anchor failure", + "stellar anchor down", "xlm anchor down", + + # ETC (Ethereum Classic) - 51% attack risk, hashrate drop + "ethereum classic 51 attack", "etc 51 attack", "etc hashrate drop", "etc hashrate declining", + "ethereum classic hashrate drop", "etc miner exodus", + + # XRP (Ripple) - SEC risk + "xrp sec", "xrp sec lawsuit", "xrp sec appeal", "ripple sec", "ripple lawsuit", + "xrp security", "xrp security risk", "xrp delisting risk", + + # ADA (Cardano) - slow development + "cardano slow", "ada slow development", "cardano delayed", "ada delayed", + "cardano hydra delayed", "cardano hydra delay", + + # XTZ (Tezos) - governance = NEUTRAL not bearish, but reduce false positive + "tezos governance", "xtz governance", "tezos proposal", "xtz proposal", + + # ENJ (Enjin) - governance = NEUTRAL not bearish, but reduce false positive + "enjin governance", "enj governance", "enjin proposal", "enj proposal", + + # XTZ (Tezos) - compound phrases + "tezos governance proposal", "xtz governance proposal", "tezos baking rewards", + "xtz baking rewards", "tezos staking rewards", "xtz staking rewards", + "tezos delegation rewards", "xtz delegation rewards", + + # ENJ (Enjin) - compound phrases + "enjin governance proposal", "enj governance proposal", "enjin nft gaming", + "enjin beam airdrop", "enjin beam qr", ] # Whale action phrases - context-dependent sentiment (bullish) @@ -1611,17 +1770,18 @@ class SentimentEmotionAnalyzer: except Exception as e: logger.warning(f"Failed to load ONNX FinBERT: {e}") - if ONNX_AVAILABLE and onnx_emotion.exists(): - try: - self._emotion_tokenizer = AutoTokenizer.from_pretrained("models/onnx/distilroberta-emotion") if TRANSFORMERS_AVAILABLE else MockTokenizer() - self._emotion_model = ONNXEmotionModel( - str(onnx_emotion), - "models/onnx/distilroberta-emotion", - "models/onnx/distilroberta-emotion/label_map.json" - ) - logger.info("Loaded DistilRoBERTa Emotion model via ONNX Runtime") - except Exception as e: - logger.warning(f"Failed to load ONNX Emotion model: {e}") + # Skip emotion model to avoid memory contention with other models + # if ONNX_AVAILABLE and onnx_emotion.exists(): + # try: + # self._emotion_tokenizer = AutoTokenizer.from_pretrained("models/onnx/distilroberta-emotion") if TRANSFORMERS_AVAILABLE else MockTokenizer() + # self._emotion_model = ONNXEmotionModel( + # str(onnx_emotion), + # "models/onnx/distilroberta-emotion", + # "models/onnx/distilroberta-emotion/label_map.json" + # ) + # logger.info("Loaded DistilRoBERTa Emotion model via ONNX Runtime") + # except Exception as e: + # logger.warning(f"Failed to load ONNX Emotion model: {e}") # Fallback to PyTorch models if self._use_mock and TRANSFORMERS_AVAILABLE: