KashefTech commited on
Commit
d5764b1
·
verified ·
1 Parent(s): 8a5ff09

Delete llm_sender_unified.py

Browse files
Files changed (1) hide show
  1. llm_sender_unified.py +0 -334
llm_sender_unified.py DELETED
@@ -1,334 +0,0 @@
1
- """
2
- 🤖 LLM Sender Unified Module
3
- ماژول یکپارچه برای ارسال به ChatGPT و Grok
4
- ✨ با پشتیبانی از GPT-5 models و رفع مشکل temperature
5
- """
6
-
7
- import requests
8
- import os
9
- import logging
10
- from typing import Optional
11
- import time
12
- from abc import ABC, abstractmethod
13
-
14
- logging.basicConfig(level=logging.INFO)
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- class LLMSender(ABC):
19
- """کلاس پایه برای ارسال به مدل‌های مختلف LLM"""
20
-
21
- def __init__(self, api_key: Optional[str] = None, model: str = None):
22
- self.api_key = api_key
23
- self.model = model
24
- self.base_url = ""
25
-
26
- @abstractmethod
27
- def get_default_model(self) -> str:
28
- """مدل پیش‌فرض"""
29
- pass
30
-
31
- @abstractmethod
32
- def get_base_url(self) -> str:
33
- """URL پایه API"""
34
- pass
35
-
36
- def set_api_key(self, api_key: str):
37
- """تنظیم کلید API"""
38
- self.api_key = api_key
39
- logger.info("✅ کلید API تنظیم شد")
40
-
41
- def set_model(self, model: str):
42
- """تغییر مدل"""
43
- self.model = model
44
- logger.info(f"✅ مدل تغییر یافت به: {model}")
45
-
46
- def _uses_max_completion_tokens(self) -> bool:
47
- """بررسی اینکه آیا مدل از max_completion_tokens استفاده می‌کند"""
48
- models_with_completion_tokens = [
49
- 'gpt-5', # تمام مدل‌های GPT-5
50
- 'gpt-5.1' # GPT-5.1
51
- ]
52
- return any(self.model.startswith(prefix) for prefix in models_with_completion_tokens)
53
-
54
- def _requires_default_temperature(self) -> bool:
55
- """بررسی اینکه آیا مدل فقط temperature=1 را قبول می‌کند"""
56
- models_requiring_default_temp = [
57
- 'gpt-5', # تمام مدل‌های GPT-5
58
- 'o1' # تمام مدل‌های O1
59
- ]
60
- return any(self.model.startswith(prefix) for prefix in models_requiring_default_temp)
61
-
62
- def send_simple(self, text: str, lang: str = 'fa') -> str:
63
- """ارسال ساده بدون system message سفارشی"""
64
- system_msg = (
65
- "شما یک تحلیلگر متخصص هستید. متن حاوی کدهای ناشناس است. "
66
- "به درخواست‌ها با دقت و حرفه‌ای پاسخ دهید."
67
- if lang == 'fa'
68
- else "You are a professional analyst. The text contains anonymous codes. "
69
- "Answer requests accurately and professionally."
70
- )
71
-
72
- return self.send(text, system_msg=system_msg, lang=lang)
73
-
74
- def send(
75
- self,
76
- text: str,
77
- system_msg: Optional[str] = None,
78
- max_tokens: int = 2000,
79
- temperature: float = 0.7,
80
- timeout: int = 60,
81
- lang: str = 'fa',
82
- retry_count: int = 3
83
- ) -> str:
84
- """ارسال متن به LLM با کنترل کامل"""
85
- try:
86
- # بررسی اولیه
87
- if not text or not text.strip():
88
- error_msg = "متن خالی است!" if lang == 'fa' else "Text is empty!"
89
- logger.error(f"❌ {error_msg}")
90
- return f"❌ {error_msg}"
91
-
92
- if not self.api_key:
93
- error_msg = "کلید API تنظیم نشده است!" if lang == 'fa' else "API Key not configured!"
94
- logger.error(f"❌ {error_msg}")
95
- return f"❌ {error_msg}"
96
-
97
- # تنظیم system message پیش‌فرض
98
- if system_msg is None:
99
- system_msg = (
100
- "شما یک تحلیلگر مالی حرفه‌ای هستید. متن حاوی کدهای ناشناس است. "
101
- "به سوالات با دقت پاسخ دهید."
102
- if lang == 'fa'
103
- else "You are a professional financial analyst. The text contains anonymous codes. "
104
- "Answer questions accurately."
105
- )
106
-
107
- # تهیه headers
108
- headers = {
109
- "Authorization": f"Bearer {self.api_key}",
110
- "Content-Type": "application/json"
111
- }
112
-
113
- # ✨ تنظیم temperature مناسب
114
- if self._requires_default_temperature():
115
- actual_temperature = 1.0
116
- if temperature != 1.0:
117
- logger.info(f"⚠️ مدل {self.model} فقط temperature=1 را قبول می‌کند")
118
- else:
119
- actual_temperature = temperature
120
-
121
- # ساخت request body
122
- data = {
123
- "model": self.model,
124
- "messages": [
125
- {"role": "system", "content": system_msg},
126
- {"role": "user", "content": text}
127
- ],
128
- "temperature": actual_temperature
129
- }
130
-
131
- # ✨ انتخاب پارامتر مناسب برای max tokens
132
- if self._uses_max_completion_tokens():
133
- data["max_completion_tokens"] = max_tokens
134
- else:
135
- data["max_tokens"] = max_tokens
136
-
137
- # ارسال با retry mechanism
138
- for attempt in range(retry_count):
139
- try:
140
- logger.info(f"📤 ارسال درخواست به {self.__class__.__name__} (تلاش {attempt + 1}/{retry_count})...")
141
-
142
- response = requests.post(
143
- self.base_url,
144
- headers=headers,
145
- json=data,
146
- timeout=timeout
147
- )
148
-
149
- # پردازش پاسخ موفق
150
- if response.status_code == 200:
151
- result = response.json()
152
- llm_response = result['choices'][0]['message']['content']
153
- logger.info("✅ پاسخ دریافت شد")
154
- return llm_response
155
-
156
- # پردازش خطاهای مختلف
157
- elif response.status_code == 429: # Rate limiting
158
- wait_time = 5 * (attempt + 1)
159
- logger.warning(f"⚠️ Rate limit | صبر: {wait_time} ثانیه")
160
- if attempt < retry_count - 1:
161
- time.sleep(wait_time)
162
- continue
163
- else:
164
- return (
165
- "❌ سهمیه API تمام شده است. لطفاً بعداً تلاش کنید."
166
- if lang == 'fa'
167
- else "❌ API quota exceeded. Please try later."
168
- )
169
-
170
- elif response.status_code == 401:
171
- return (
172
- "❌ کلید API نامعتبر است!"
173
- if lang == 'fa'
174
- else "❌ Invalid API key!"
175
- )
176
-
177
- elif response.status_code in [502, 503, 504]: # Server errors
178
- wait_time = 2 * (attempt + 1)
179
- logger.warning(f"⚠️ Server error {response.status_code} | صبر: {wait_time} ثانیه")
180
- if attempt < retry_count - 1:
181
- time.sleep(wait_time)
182
- continue
183
- else:
184
- return (
185
- f"❌ خطای سرور: {response.status_code}"
186
- if lang == 'fa'
187
- else f"❌ Server error: {response.status_code}"
188
- )
189
-
190
- else:
191
- # خطای دیگر
192
- try:
193
- error_data = response.json() if response.content else {}
194
- if isinstance(error_data, dict):
195
- error_msg = error_data.get('error', {}).get('message', response.text)
196
- else:
197
- error_msg = str(error_data)
198
- except:
199
- error_msg = response.text[:200]
200
-
201
- logger.error(f"❌ API Error: {error_msg}")
202
- return f"❌ API Error: {error_msg}"
203
-
204
- except requests.exceptions.Timeout:
205
- logger.warning("⚠️ Timeout | صبر: 3 ثانیه و تلاش مجدد")
206
- if attempt < retry_count - 1:
207
- time.sleep(3)
208
- continue
209
- else:
210
- return (
211
- "❌ خطای اتصال: timeout"
212
- if lang == 'fa'
213
- else "❌ Connection error: timeout"
214
- )
215
-
216
- except requests.exceptions.ConnectionError as e:
217
- logger.warning("⚠️ Connection error | صبر: 2 ثانیه و تلاش مجدد")
218
- if attempt < retry_count - 1:
219
- time.sleep(2)
220
- continue
221
- else:
222
- return (
223
- f"❌ خطای اتصال: {str(e)}"
224
- if lang == 'fa'
225
- else f"❌ Connection error: {str(e)}"
226
- )
227
-
228
- except Exception as e:
229
- logger.error(f"❌ خطای غیرمنتظره: {str(e)}")
230
- return (
231
- f"❌ خطا در ارتباط با LLM: {str(e)}"
232
- if lang == 'fa'
233
- else f"❌ Error connecting to LLM: {str(e)}"
234
- )
235
-
236
-
237
- class ChatGPTSender(LLMSender):
238
- """کلاس برای ارسال به ChatGPT"""
239
-
240
- def __init__(self, api_key: Optional[str] = None, model: str = "gpt-4o-mini"):
241
- raw_key = api_key or os.getenv("OPENAI_API_KEY", "")
242
- cleaned_key = raw_key.strip() if raw_key else ""
243
-
244
- super().__init__(cleaned_key, model)
245
- self.base_url = self.get_base_url()
246
-
247
- if not self.api_key:
248
- logger.warning("⚠️ کلید OpenAI API تنظیم نشده است!")
249
-
250
- def get_default_model(self) -> str:
251
- return "gpt-4o-mini"
252
-
253
- def get_base_url(self) -> str:
254
- return "https://api.openai.com/v1/chat/completions"
255
-
256
-
257
- class GrokSender(LLMSender):
258
- """کلاس برای ارسال به Grok (xAI)"""
259
-
260
- def __init__(self, api_key: Optional[str] = None, model: str = "grok-beta"):
261
- raw_key = api_key or os.getenv("XAI_API_KEY", "")
262
- cleaned_key = raw_key.strip() if raw_key else ""
263
-
264
- super().__init__(cleaned_key, model)
265
- self.base_url = self.get_base_url()
266
-
267
- if not self.api_key:
268
- logger.warning("⚠️ کلید xAI API تنظیم نشده است!")
269
-
270
- def get_default_model(self) -> str:
271
- return "grok-beta"
272
-
273
- def get_base_url(self) -> str:
274
- return "https://api.x.ai/v1/chat/completions"
275
-
276
-
277
- def create_llm_sender(
278
- provider: str = "chatgpt",
279
- api_key: Optional[str] = None,
280
- model: Optional[str] = None
281
- ) -> LLMSender:
282
- """ایجاد LLM sender بر اساس provider"""
283
- provider = provider.lower()
284
-
285
- if provider == "chatgpt":
286
- if model is None:
287
- model = "gpt-4o-mini"
288
- return ChatGPTSender(api_key=api_key, model=model)
289
-
290
- elif provider == "grok":
291
- if model is None:
292
- model = "grok-beta"
293
- return GrokSender(api_key=api_key, model=model)
294
-
295
- else:
296
- raise ValueError(f"Provider نامعتبر: {provider}")
297
-
298
-
299
- # ✅ مدل‌های موجود (اصلاح شده)
300
- AVAILABLE_MODELS = {
301
- "chatgpt": [
302
- "gpt-5.1", # ✅ بهترین GPT-5
303
- "gpt-5", # ✅ GPT-5 پایه
304
- "gpt-4.1",
305
- "gpt-4o-mini",
306
- "gpt-4o",
307
- "gpt-4-turbo",
308
- "gpt-3.5-turbo"
309
- ],
310
- "grok": [
311
- "grok-3-mini",
312
- "grok-3",
313
- "grok-2-1212"
314
- ]
315
- }
316
-
317
-
318
- if __name__ == "__main__":
319
- print("=" * 60)
320
- print("🤖 LLM Sender - نسخه اصلاح شده")
321
- print("✨ رفع مشکل temperature برای GPT-5")
322
- print("=" * 60)
323
-
324
- # تست
325
- print("\n🧪 تست مدل‌ها:")
326
- test_models = ['gpt-5', 'gpt-5.1', 'gpt-4o']
327
- for model in test_models:
328
- sender = create_llm_sender("chatgpt", model=model)
329
- uses_completion = sender._uses_max_completion_tokens()
330
- requires_default_temp = sender._requires_default_temperature()
331
-
332
- print(f"\n مدل: {model}")
333
- print(f" • max_tokens: {'max_completion_tokens' if uses_completion else 'max_tokens'}")
334
- print(f" • temperature: {'1.0 (default only)' if requires_default_temp else '0.7 (custom)'}")