Update LLM.py
Browse files
LLM.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# LLM.py (V19.
|
| 2 |
import os, traceback, json, time, re
|
| 3 |
import httpx
|
| 4 |
from datetime import datetime
|
|
@@ -21,6 +21,15 @@ try:
|
|
| 21 |
except ImportError:
|
| 22 |
NewsFetcher = None
|
| 23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
# (تحديث الإعدادات الافتراضية لتطابق NVIDIA)
|
| 25 |
LLM_API_URL = os.getenv("LLM_API_URL", "https://integrate.api.nvidia.com/v1")
|
| 26 |
LLM_API_KEY = os.getenv("LLM_API_KEY") # (هذا هو المفتاح الذي سيتم استخدامه)
|
|
@@ -47,10 +56,10 @@ class LLMService:
|
|
| 47 |
api_key=LLM_API_KEY,
|
| 48 |
timeout=CLIENT_TIMEOUT
|
| 49 |
)
|
| 50 |
-
print(f"✅ [LLMService V19.
|
| 51 |
print(f" -> Endpoint: {LLM_API_URL}")
|
| 52 |
except Exception as e:
|
| 53 |
-
print(f"❌ [LLMService V19.
|
| 54 |
traceback.print_exc()
|
| 55 |
raise
|
| 56 |
|
|
@@ -58,6 +67,11 @@ class LLMService:
|
|
| 58 |
self.r2_service: Optional[R2Service] = None
|
| 59 |
self.learning_hub: Optional[LearningHubManager] = None
|
| 60 |
self.news_fetcher: Optional[NewsFetcher] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
async def _call_llm(self, prompt: str) -> Optional[str]:
|
| 63 |
"""
|
|
@@ -65,11 +79,7 @@ class LLMService:
|
|
| 65 |
إجراء استدعاء API للنموذج الضخم (يستخدم الآن "detailed thinking on" كـ system prompt).
|
| 66 |
"""
|
| 67 |
|
| 68 |
-
# 🔴 --- START OF CHANGE (V19.2) --- 🔴
|
| 69 |
-
# (استخدام "detailed thinking on" كـ system prompt كما طلبت)
|
| 70 |
system_prompt = "detailed thinking on"
|
| 71 |
-
# (تم نقل جميع التعليمات الأخرى إلى الـ User Prompt)
|
| 72 |
-
# 🔴 --- END OF CHANGE --- 🔴
|
| 73 |
|
| 74 |
payload = {
|
| 75 |
"model": LLM_MODEL,
|
|
@@ -216,7 +226,7 @@ class LLMService:
|
|
| 216 |
|
| 217 |
async def re_analyze_trade_async(self, trade_data: Dict[str, Any], current_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
| 218 |
"""
|
| 219 |
-
(محدث
|
| 220 |
يستدعي النموذج الضخم لإعادة تحليل صفقة مفتوحة (Reflector Brain).
|
| 221 |
"""
|
| 222 |
symbol = trade_data.get('symbol', 'UNKNOWN')
|
|
@@ -232,11 +242,15 @@ class LLMService:
|
|
| 232 |
# 2. (V8.1) جلب أحدث الأخبار (باستخدام NewsFetcher المخصص)
|
| 233 |
latest_news_text = "News data unavailable for re-analysis."
|
| 234 |
latest_news_score = 0.0
|
|
|
|
|
|
|
|
|
|
| 235 |
if self.news_fetcher:
|
| 236 |
latest_news_text = await self.news_fetcher.get_news_for_symbol(symbol)
|
| 237 |
-
if self.
|
| 238 |
-
vader_scores = self.
|
| 239 |
latest_news_score = vader_scores.get('compound', 0.0)
|
|
|
|
| 240 |
|
| 241 |
current_data['latest_news_text'] = latest_news_text
|
| 242 |
current_data['latest_news_score'] = latest_news_score
|
|
@@ -344,7 +358,6 @@ class LLMService:
|
|
| 344 |
* Relative 24h Net Flow (vs Daily Volume): {relative_net_flow_24h_percent:+.2f}%
|
| 345 |
"""
|
| 346 |
|
| 347 |
-
# 🔴 --- START OF CHANGE (V19.2) --- 🔴
|
| 348 |
# (تم دمج جميع التعليمات هنا في رسالة الـ user)
|
| 349 |
task_prompt = f"""
|
| 350 |
CONTEXT:
|
|
@@ -376,7 +389,6 @@ OUTPUT (JSON Object ONLY):
|
|
| 376 |
"exit_profile": "Aggressive" or "Standard" or "Patient"
|
| 377 |
}}
|
| 378 |
"""
|
| 379 |
-
# 🔴 --- END OF CHANGE --- 🔴
|
| 380 |
|
| 381 |
# (نرسل فقط task_prompt لأنه يحتوي الآن على كل شيء)
|
| 382 |
return task_prompt
|
|
@@ -442,7 +454,6 @@ OUTPUT (JSON Object ONLY):
|
|
| 442 |
* Latest News (VADER: {latest_news_score:.3f}): {latest_news_text[:300]}...
|
| 443 |
"""
|
| 444 |
|
| 445 |
-
# 🔴 --- START OF CHANGE (V19.2) --- 🔴
|
| 446 |
# (دمج جميع التعليمات في رسالة الـ user)
|
| 447 |
task_prompt = f"""
|
| 448 |
CONTEXT:
|
|
@@ -473,6 +484,5 @@ OUTPUT (JSON Object ONLY):
|
|
| 473 |
"new_take_profit": (float or null, required if action is 'UPDATE_TRADE')
|
| 474 |
}}
|
| 475 |
"""
|
| 476 |
-
# 🔴 --- END OF CHANGE --- 🔴
|
| 477 |
|
| 478 |
return task_prompt
|
|
|
|
| 1 |
+
# LLM.py (V19.3 - NVIDIA Engine + Vader Fix)
|
| 2 |
import os, traceback, json, time, re
|
| 3 |
import httpx
|
| 4 |
from datetime import datetime
|
|
|
|
| 21 |
except ImportError:
|
| 22 |
NewsFetcher = None
|
| 23 |
|
| 24 |
+
# 🔴 --- START OF CHANGE (V19.3) --- 🔴
|
| 25 |
+
# (استيراد VADER هنا أيضاً للـ type hinting)
|
| 26 |
+
try:
|
| 27 |
+
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
|
| 28 |
+
except ImportError:
|
| 29 |
+
SentimentIntensityAnalyzer = None
|
| 30 |
+
# 🔴 --- END OF CHANGE --- 🔴
|
| 31 |
+
|
| 32 |
+
|
| 33 |
# (تحديث الإعدادات الافتراضية لتطابق NVIDIA)
|
| 34 |
LLM_API_URL = os.getenv("LLM_API_URL", "https://integrate.api.nvidia.com/v1")
|
| 35 |
LLM_API_KEY = os.getenv("LLM_API_KEY") # (هذا هو المفتاح الذي سيتم استخدامه)
|
|
|
|
| 56 |
api_key=LLM_API_KEY,
|
| 57 |
timeout=CLIENT_TIMEOUT
|
| 58 |
)
|
| 59 |
+
print(f"✅ [LLMService V19.3] مهيأ. النموذج: {LLM_MODEL}")
|
| 60 |
print(f" -> Endpoint: {LLM_API_URL}")
|
| 61 |
except Exception as e:
|
| 62 |
+
print(f"❌ [LLMService V19.3] فشل تهيئة AsyncOpenAI: {e}")
|
| 63 |
traceback.print_exc()
|
| 64 |
raise
|
| 65 |
|
|
|
|
| 67 |
self.r2_service: Optional[R2Service] = None
|
| 68 |
self.learning_hub: Optional[LearningHubManager] = None
|
| 69 |
self.news_fetcher: Optional[NewsFetcher] = None
|
| 70 |
+
|
| 71 |
+
# 🔴 --- START OF CHANGE (V19.3) --- 🔴
|
| 72 |
+
# (إضافة متغير VADER)
|
| 73 |
+
self.vader_analyzer: Optional[SentimentIntensityAnalyzer] = None
|
| 74 |
+
# 🔴 --- END OF CHANGE --- 🔴
|
| 75 |
|
| 76 |
async def _call_llm(self, prompt: str) -> Optional[str]:
|
| 77 |
"""
|
|
|
|
| 79 |
إجراء استدعاء API للنموذج الضخم (يستخدم الآن "detailed thinking on" كـ system prompt).
|
| 80 |
"""
|
| 81 |
|
|
|
|
|
|
|
| 82 |
system_prompt = "detailed thinking on"
|
|
|
|
|
|
|
| 83 |
|
| 84 |
payload = {
|
| 85 |
"model": LLM_MODEL,
|
|
|
|
| 226 |
|
| 227 |
async def re_analyze_trade_async(self, trade_data: Dict[str, Any], current_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
| 228 |
"""
|
| 229 |
+
(محدث V19.3)
|
| 230 |
يستدعي النموذج الضخم لإعادة تحليل صفقة مفتوحة (Reflector Brain).
|
| 231 |
"""
|
| 232 |
symbol = trade_data.get('symbol', 'UNKNOWN')
|
|
|
|
| 242 |
# 2. (V8.1) جلب أحدث الأخبار (باستخدام NewsFetcher المخصص)
|
| 243 |
latest_news_text = "News data unavailable for re-analysis."
|
| 244 |
latest_news_score = 0.0
|
| 245 |
+
|
| 246 |
+
# 🔴 --- START OF CHANGE (V19.3) --- 🔴
|
| 247 |
+
# (استخدام self.vader_analyzer الذي تم حقنه)
|
| 248 |
if self.news_fetcher:
|
| 249 |
latest_news_text = await self.news_fetcher.get_news_for_symbol(symbol)
|
| 250 |
+
if self.vader_analyzer and latest_news_text: # (التحقق من المحلل المُمرر)
|
| 251 |
+
vader_scores = self.vader_analyzer.polarity_scores(latest_news_text)
|
| 252 |
latest_news_score = vader_scores.get('compound', 0.0)
|
| 253 |
+
# 🔴 --- END OF CHANGE --- 🔴
|
| 254 |
|
| 255 |
current_data['latest_news_text'] = latest_news_text
|
| 256 |
current_data['latest_news_score'] = latest_news_score
|
|
|
|
| 358 |
* Relative 24h Net Flow (vs Daily Volume): {relative_net_flow_24h_percent:+.2f}%
|
| 359 |
"""
|
| 360 |
|
|
|
|
| 361 |
# (تم دمج جميع التعليمات هنا في رسالة الـ user)
|
| 362 |
task_prompt = f"""
|
| 363 |
CONTEXT:
|
|
|
|
| 389 |
"exit_profile": "Aggressive" or "Standard" or "Patient"
|
| 390 |
}}
|
| 391 |
"""
|
|
|
|
| 392 |
|
| 393 |
# (نرسل فقط task_prompt لأنه يحتوي الآن على كل شيء)
|
| 394 |
return task_prompt
|
|
|
|
| 454 |
* Latest News (VADER: {latest_news_score:.3f}): {latest_news_text[:300]}...
|
| 455 |
"""
|
| 456 |
|
|
|
|
| 457 |
# (دمج جميع التعليمات في رسالة الـ user)
|
| 458 |
task_prompt = f"""
|
| 459 |
CONTEXT:
|
|
|
|
| 484 |
"new_take_profit": (float or null, required if action is 'UPDATE_TRADE')
|
| 485 |
}}
|
| 486 |
"""
|
|
|
|
| 487 |
|
| 488 |
return task_prompt
|