neogram 9.3__tar.gz → 9.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: neogram
3
- Version: 9.3
3
+ Version: 9.3.2
4
4
  Summary: neogram is a lightweight Python module for working with the Telegram Bot API and AI. It combines simple Telegram workflows with powerful features like text and image generation, translation, and more.
5
5
  Author: SiriLV
6
6
  Author-email: siriteamrs@gmail.com
@@ -14,6 +14,7 @@ Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: requests>=2.32.5
16
16
  Requires-Dist: bs4>=0.0.2
17
+ Requires-Dist: curl_cffi>=0.14.0
17
18
  Dynamic: author
18
19
  Dynamic: author-email
19
20
  Dynamic: classifier
@@ -25,7 +26,7 @@ Dynamic: requires-dist
25
26
  Dynamic: requires-python
26
27
  Dynamic: summary
27
28
 
28
- # 📚 Документация neogram v9.3
29
+ # 📚 Документация neogram v9.3.01
29
30
 
30
31
  **Установка:**
31
32
 
@@ -88,7 +89,7 @@ bot = Bot(token="YOUR_TOKEN", timeout=60)
88
89
  * `translate(text, lang)`: Перевод текста (через Google Translate).
89
90
  * `short_url(long_url)`: Сокращение ссылок (clck.ru).
90
91
  * `gen_ai_response(model, messages)`: Генерация ответа (Qwen/GPT OSS).
91
- * `gen_gpt(messages)`: Генерация через ItalyGPT.
92
+ * `perplexity_ask(model, query)`: Генерация через PerplexityAI
92
93
  * `encode_base64(path)`: Кодирование файла в base64.
93
94
  * `run_in_bg(func, ...)`: Запуск функции в отдельном потоке.
94
95
 
@@ -1,4 +1,4 @@
1
- # 📚 Документация neogram v9.3
1
+ # 📚 Документация neogram v9.3.01
2
2
 
3
3
  **Установка:**
4
4
 
@@ -61,7 +61,7 @@ bot = Bot(token="YOUR_TOKEN", timeout=60)
61
61
  * `translate(text, lang)`: Перевод текста (через Google Translate).
62
62
  * `short_url(long_url)`: Сокращение ссылок (clck.ru).
63
63
  * `gen_ai_response(model, messages)`: Генерация ответа (Qwen/GPT OSS).
64
- * `gen_gpt(messages)`: Генерация через ItalyGPT.
64
+ * `perplexity_ask(model, query)`: Генерация через PerplexityAI
65
65
  * `encode_base64(path)`: Кодирование файла в base64.
66
66
  * `run_in_bg(func, ...)`: Запуск функции в отдельном потоке.
67
67
 
@@ -1,5 +1,6 @@
1
- import requests, json, base64, threading, re, bs4
1
+ import requests, json, base64, threading, re, bs4, uuid
2
2
  from typing import Union, BinaryIO
3
+ from curl_cffi.requests import Session
3
4
 
4
5
  #Блок - Нейросети
5
6
  class OnlySQ:
@@ -56,28 +57,28 @@ class OnlySQ:
56
57
  print(f"OnlySQ(get_models): {e}")
57
58
  return []
58
59
 
59
- def generate_answer(self, model: str = "gpt-5.2-chat", messages: dict = None) -> str:
60
+ def generate_answer(self, model: str = "gpt-5.2-chat", messages: dict = None, key: str = "openai") -> str:
60
61
  """Генерация ответа с использованием onlysq"""
61
62
  try:
62
63
  if messages is None:
63
64
  raise ValueError("Забыли указать messages")
64
65
  else:
65
66
  payload = {"model": model, "request": {"messages": messages}}
66
- response = requests.post("http://api.onlysq.ru/ai/v2", json=payload, headers={"Authorization":"Bearer openai"})
67
+ response = requests.post("http://api.onlysq.ru/ai/v2", json=payload, headers={"Authorization": f"Bearer {key}"})
67
68
  response.raise_for_status()
68
69
  return response.json()["choices"][0]["message"]["content"]
69
70
  except Exception as e:
70
71
  print(f"OnlySQ(generate_answer): {e}")
71
72
  return "Error"
72
73
 
73
- def generate_image(self, model: str = "flux", prompt: str = None, ratio: str = "16:9", filename: str = 'image.png') -> bool:
74
+ def generate_image(self, model: str = "flux", prompt: str = None, ratio: str = "16:9", filename: str = 'image.png', key: str = "openai") -> bool:
74
75
  """Генерация фотографии с использованием onlysq"""
75
76
  try:
76
77
  if prompt is None:
77
78
  raise ValueError("Забыли указать prompt")
78
79
  else:
79
80
  payload = {"model": model, "prompt": prompt, "ratio": ratio}
80
- response = requests.post("https://api.onlysq.ru/ai/imagen", json=payload, headers={"Authorization":"Bearer openai"})
81
+ response = requests.post("https://api.onlysq.ru/ai/imagen", json=payload, headers={"Authorization": f"Bearer {key}"})
81
82
  if response.status_code == 200:
82
83
  img_bytes = base64.b64decode(response.json()["files"][0])
83
84
  with open(filename, 'wb') as f:
@@ -186,20 +187,161 @@ class Deef:
186
187
  print(f"Deef(gen_ai_response): {e}")
187
188
  return {"reasoning": "Error", "answer": "Error", "status": "unknown", "cluster_info": None}
188
189
 
189
- def gen_gpt(self, messages: list = None) -> str:
190
- """Генерация текста с помощью GPT-4o"""
191
- try:
192
- if messages is None:
193
- raise ValueError("Забыли указать messages")
194
- else:
195
- r = requests.post("https://italygpt.it/api/chat", json={"messages": messages, "stream": True}, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", "Accept": "text/event-stream"})
196
- if r.status_code == 200:
197
- return r.text
198
- else:
199
- return "Error"
200
- except Exception as e:
201
- print(f"Deef(gen_gpt): {e}")
202
- return "Error"
190
+ def perplexity_ask(self, model: str, query: str) -> dict:
191
+ """
192
+ Вывод: словари с ключом 'type' и данными:
193
+ - {"type": "text", "content": "..."}
194
+ - {"type": "sources", "sources": [...]}
195
+ - {"type": "reasoning", "content": "...", "status": "thinking"|"done"}
196
+ - {"type": "media", "items": [...]}
197
+ - {"type": "followups", "followups": [...]}
198
+ - {"type": "finish", "reason": "stop"}
199
+ """
200
+ MODELS = [
201
+ "turbo", "gpt41", "gpt5", "gpt5_thinking", "o3",
202
+ "o3pro", "claude2", "claude37sonnetthinking", "claude40opus", "claude40opusthinking",
203
+ "claude41opusthinking", "claude45sonnet", "claude45sonnetthinking", "experimental", "grok",
204
+ "grok4", "gemini2flash", "pplx_pro", "pplx_pro_upgraded", "pplx_alpha",
205
+ "pplx_beta", "comet_max_assistant", "o3_research", "o3pro_research", "claude40sonnet_research",
206
+ "claude40sonnetthinking_research", "claude40opus_research", "claude40opusthinking_research", "o3_labs", "o3pro_labs",
207
+ "claude40sonnetthinking_labs", "claude40opusthinking_labs", "o4mini", "o1", "gpt4o",
208
+ "gpt45", "gpt4", "o3mini", "claude35haiku", "llama_x_large",
209
+ "mistral", "claude3opus", "gemini", "pplx_reasoning", "r1"]
210
+ BASE_URL = "https://www.perplexity.ai"
211
+ if model not in MODELS:
212
+ model = MODELS[0]
213
+ frontend_uid = str(uuid.uuid4())
214
+ frontend_context_uuid = str(uuid.uuid4())
215
+ visitor_id = str(uuid.uuid4())
216
+ headers = {
217
+ "accept": "text/event-stream",
218
+ "accept-language": "en-US,en;q=0.9",
219
+ "cache-control": "no-cache",
220
+ "content-type": "application/json",
221
+ "origin": BASE_URL,
222
+ "referer": f"{BASE_URL}/",
223
+ "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
224
+ "x-perplexity-request-reason": "perplexity-query-state-provider"}
225
+ with Session(headers=headers, timeout=300, impersonate="chrome") as session:
226
+ resp = session.get(f"{BASE_URL}/api/auth/session")
227
+ user_id = resp.json().get("user", {}).get("id")
228
+ if model == "auto":
229
+ model = "pplx_pro" if user_id else "turbo"
230
+ data = {
231
+ "params": {
232
+ "attachments": [],
233
+ "language": "en-US",
234
+ "timezone": "America/New_York",
235
+ "followup_source": "link",
236
+ "search_focus": "internet",
237
+ "source": "default",
238
+ "sources": ["edgar", "social", "web", "scholar"],
239
+ "frontend_uuid": frontend_uid,
240
+ "mode": "concise",
241
+ "model_preference": model,
242
+ "visitor_id": visitor_id,
243
+ "frontend_context_uuid": frontend_context_uuid,
244
+ "prompt_source": "user",
245
+ "query_source": "followup",
246
+ "use_schematized_api": True,
247
+ "supported_block_use_cases": [
248
+ "answer_modes", "media_items", "knowledge_cards", "inline_entity_cards",
249
+ "place_widgets", "finance_widgets", "prediction_market_widgets", "sports_widgets",
250
+ "flight_status_widgets", "news_widgets", "shopping_widgets", "jobs_widgets",
251
+ "search_result_widgets", "inline_images", "inline_assets", "placeholder_cards",
252
+ "diff_blocks", "inline_knowledge_cards", "entity_group_v2", "refinement_filters",
253
+ "canvas_mode", "maps_preview", "answer_tabs", "price_comparison_widgets",
254
+ "preserve_latex", "generic_onboarding_widgets", "in_context_suggestions"
255
+ ],
256
+ "version": "2.18"
257
+ }, "query_str": query}
258
+ response = session.post(f"{BASE_URL}/rest/sse/perplexity_ask", json=data)
259
+ if response.status_code >= 400:
260
+ raise Exception(f"HTTP {response.status_code}")
261
+ content = response.content
262
+ if isinstance(content, bytes):
263
+ content = content.decode('utf-8')
264
+ full_response = ""
265
+ full_reasoning = ""
266
+ sources_sent = False
267
+ for line in content.split('\n'):
268
+ line = line.strip()
269
+ if not line.startswith('data: '):
270
+ continue
271
+ data_str = line[6:]
272
+ if not data_str or data_str == '[DONE]':
273
+ continue
274
+ try:
275
+ json_data = json.loads(data_str)
276
+ except json.JSONDecodeError:
277
+ continue
278
+ for block in json_data.get("blocks", []):
279
+ intended_usage = block.get("intended_usage", "")
280
+ if intended_usage == "sources_answer_mode":
281
+ sources_block = block.get("sources_mode_block", {})
282
+ web_results = sources_block.get("web_results", [])
283
+ if web_results and not sources_sent:
284
+ yield {"type": "sources", "sources": web_results}
285
+ sources_sent = True
286
+ continue
287
+ if intended_usage == "media_items":
288
+ media_block = block.get("media_block", {})
289
+ media_items = media_block.get("media_items", [])
290
+ if media_items:
291
+ items = []
292
+ for item in media_items:
293
+ items.append({
294
+ "media_type": item.get("medium", "unknown"),
295
+ "url": item.get("url", ""),
296
+ "title": item.get("name", ""),
297
+ "width": item.get("image_width"),
298
+ "height": item.get("image_height")
299
+ })
300
+ yield {"type": "media", "items": items}
301
+ continue
302
+ if intended_usage in ("pro_search_steps", "plan"):
303
+ plan_block = block.get("plan_block", {})
304
+ if plan_block:
305
+ goals = plan_block.get("goals", [])
306
+ progress = plan_block.get("progress", "")
307
+ for goal in goals:
308
+ if isinstance(goal, str) and goal:
309
+ yield {"type": "reasoning", "content": goal, "status": "thinking"}
310
+ if progress == "DONE":
311
+ yield {"type": "reasoning", "content": "", "status": "done"}
312
+ diff_block = block.get("diff_block", {})
313
+ if diff_block.get("field") == "plan_block":
314
+ for patch in diff_block.get("patches", []):
315
+ if patch.get("path", "").startswith("/goals"):
316
+ value = patch.get("value", "")
317
+ if isinstance(value, str) and value:
318
+ new_reasoning = value[len(full_reasoning):] if value.startswith(full_reasoning) else value
319
+ if new_reasoning:
320
+ full_reasoning = value if value.startswith(full_reasoning) else full_reasoning + value
321
+ yield {"type": "reasoning", "content": new_reasoning, "status": "thinking"}
322
+ continue
323
+ if intended_usage != "ask_text_0_markdown":
324
+ continue
325
+ diff_block = block.get("diff_block", {})
326
+ if diff_block.get("field") != "markdown_block":
327
+ continue
328
+ for patch in diff_block.get("patches", []):
329
+ value = patch.get("value", "")
330
+ if isinstance(value, dict) and "chunks" in value:
331
+ text = "".join(value.get("chunks", []))
332
+ if text and len(text) > len(full_response):
333
+ new_text = text[len(full_response):]
334
+ full_response = text
335
+ yield {"type": "text", "content": new_text}
336
+ elif patch.get("op") == "add" and isinstance(value, str) and value:
337
+ full_response += value
338
+ yield {"type": "text", "content": value}
339
+ if "related_query_items" in json_data:
340
+ followups = [i.get("text", "") for i in json_data["related_query_items"]]
341
+ if followups:
342
+ yield {"type": "followups", "followups": followups}
343
+ if json_data.get("status") == "COMPLETED":
344
+ yield {"type": "finish", "reason": "stop"}
203
345
 
204
346
 
205
347
  class ChatGPT:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: neogram
3
- Version: 9.3
3
+ Version: 9.3.2
4
4
  Summary: neogram is a lightweight Python module for working with the Telegram Bot API and AI. It combines simple Telegram workflows with powerful features like text and image generation, translation, and more.
5
5
  Author: SiriLV
6
6
  Author-email: siriteamrs@gmail.com
@@ -14,6 +14,7 @@ Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: requests>=2.32.5
16
16
  Requires-Dist: bs4>=0.0.2
17
+ Requires-Dist: curl_cffi>=0.14.0
17
18
  Dynamic: author
18
19
  Dynamic: author-email
19
20
  Dynamic: classifier
@@ -25,7 +26,7 @@ Dynamic: requires-dist
25
26
  Dynamic: requires-python
26
27
  Dynamic: summary
27
28
 
28
- # 📚 Документация neogram v9.3
29
+ # 📚 Документация neogram v9.3.01
29
30
 
30
31
  **Установка:**
31
32
 
@@ -88,7 +89,7 @@ bot = Bot(token="YOUR_TOKEN", timeout=60)
88
89
  * `translate(text, lang)`: Перевод текста (через Google Translate).
89
90
  * `short_url(long_url)`: Сокращение ссылок (clck.ru).
90
91
  * `gen_ai_response(model, messages)`: Генерация ответа (Qwen/GPT OSS).
91
- * `gen_gpt(messages)`: Генерация через ItalyGPT.
92
+ * `perplexity_ask(model, query)`: Генерация через PerplexityAI
92
93
  * `encode_base64(path)`: Кодирование файла в base64.
93
94
  * `run_in_bg(func, ...)`: Запуск функции в отдельном потоке.
94
95
 
@@ -1,2 +1,3 @@
1
1
  requests>=2.32.5
2
2
  bs4>=0.0.2
3
+ curl_cffi>=0.14.0
@@ -2,13 +2,13 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='neogram',
5
- version='9.3',
5
+ version='9.3.2',
6
6
  description='neogram is a lightweight Python module for working with the Telegram Bot API and AI. It combines simple Telegram workflows with powerful features like text and image generation, translation, and more.',
7
7
  author='SiriLV',
8
8
  author_email='siriteamrs@gmail.com',
9
9
  packages=find_packages(),
10
10
  python_requires='>=3.10',
11
- install_requires=['requests>=2.32.5', 'bs4>=0.0.2'],
11
+ install_requires=['requests>=2.32.5', 'bs4>=0.0.2', 'curl_cffi>=0.14.0'],
12
12
  classifiers=[
13
13
  'Programming Language :: Python :: 3',
14
14
  'Programming Language :: Python :: 3.10',
File without changes
File without changes
File without changes
File without changes