-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathllm_api.py
More file actions
executable file
·177 lines (146 loc) · 8.84 KB
/
Copy pathllm_api.py
File metadata and controls
executable file
·177 lines (146 loc) · 8.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python
from __future__ import annotations
from dataclasses import dataclass
from typing import ClassVar
import requests
@dataclass
class OllamaSession:
"""Сессия для работы с Ollama API.
Args:
model: название модели
api_url: URL API endpoint
timeout: таймаут запроса в секундах
https_proxy: опциональный HTTPS forward-proxy (например, "https://proxy.example.com:8080")
"""
SYSTEM_PROMPT: ClassVar[str] = """
Ты составляешь краткую сводку сообщений из Telegram-чата или канала.
Выдели отдельные содержательные темы, которые встречаются в переданном фрагменте. Для каждой темы укажи только информацию, прямо содержащуюся в сообщениях:
* о чём шла речь;
* кто задал вопрос, если вопрос был;
* был ли получен ответ;
* в чём состоял ответ, вывод или результат обсуждения;
* какой существенной информацией поделились;
* что было анонсировано.
Объединяй сообщения об одной теме, даже если они расположены не подряд.
Не составляй общий обзор всего фрагмента вместо списка конкретных тем. Не описывай жанр, источник, автора, организацию или предполагаемое назначение текста, если это само по себе не было темой сообщений.
Запрещено:
* добавлять вступление, заключение, приветствие или обращение к пользователю;
* предлагать дальнейшую помощь;
* рассуждать о достоверности, правдоподобии, датах или возможных ошибках в исходном тексте;
* интерпретировать сообщения как прогноз, фантастику, симуляцию или альтернативную историю;
* добавлять сведения, которых нет в сообщениях;
* пересказывать каждое сообщение по отдельности;
* включать приветствия, шутки, реакции и малозначительные реплики.
Если в переданном фрагменте вопрос остался без ответа, напиши: «Ответа в переданном фрагменте нет».
Если содержательных тем нет, выведи:
### Темы обсуждения
Содержательных тем не обнаружено.
Используй строго следующий формат:
### Темы обсуждения
1. **Название темы** — краткое описание темы, заданных вопросов, полученных ответов и результата.
2. **Название темы** — краткое описание темы, заданных вопросов, полученных ответов и результата.
### Анонсы
* Краткое описание анонса.
Раздел «Анонсы» добавляй только при наличии явных анонсов.
Выводи только готовую сводку. Никакого текста до или после неё.
"""
model: str
api_url: str
timeout: int = 300
https_proxy: str | None = None
def get_summary(self, chat_history: str, chat_description: str = "") -> str | None:
payload = {
"model": self.model,
"messages": [
{
"role": "system",
"content": OllamaSession.SYSTEM_PROMPT
},
{
"role": "user",
"content": (
(f"О чате:\n\n```text\n{chat_description}\n```\n\n" if chat_description else "") +
"Проанализируй следующий фрагмент чата:\n\n"
"<chat>\n"
f"{chat_history}\n"
"</chat>"
)
}
],
"stream": False,
"think": False,
"options": {
"temperature": 0.1,
}
}
proxies = {"https": self.https_proxy} if self.https_proxy else None
try:
response = requests.post(
url=self.api_url,
json=payload,
timeout=self.timeout,
proxies=proxies
)
response.raise_for_status()
except requests.RequestException as error:
response_text = getattr(error.response, "text", "")
raise RuntimeError(
f"Ошибка запроса к Ollama: {error}\n{response_text}"
) from error
result = ""
try:
result = response.json()["message"]["content"]
except (ValueError, KeyError, TypeError):
raise RuntimeError(
f"Неожиданный формат ответа от Ollama: {response.text}"
)
return result
if __name__ == "__main__":
import os
from argparse import ArgumentParser
arg_parser = ArgumentParser(
description="Справка по запуску"
)
arg_parser.add_argument(
"url",
help="API URL"
)
arg_parser.add_argument(
"model",
help="название модели"
)
args = arg_parser.parse_args()
print(
OllamaSession(
model=args.model,
api_url=args.url,
).get_summary(
chat_description="Разговор двух друзей",
chat_history="""
[2026-07-22 00:00:11] Егор: Здорово, Никодим!
[2026-07-22 00:00:13] Никодим: Здорово, Егор!
[2026-07-22 00:00:16] Никодим: Откуда идёшь?
[2026-07-22 00:00:18] Егор: С Кудыкиных гор.
[2026-07-22 00:00:20] Никодим: А как у вас, Егор, поживают?
[2026-07-22 00:00:24] Егор: На босу ногу топор надевают, сапогом траву косят, в решете воду носят.
[2026-07-22 00:00:45] Егор: Наши сани едут сами, а лошади наши - с усами, бегают в подполье за мышами.
[2026-07-22 00:00:57] Никодим: Да ведь это кошки!
[2026-07-22 00:00:59] Егор: Комара тебе в лукошке!
[2026-07-22 00:01:02] Егор: Наши кошки живут в гнезде, летают везде. Прилетели во двор, завели разговор: "Кар, кар"
[2026-07-22 00:01:14] Никодим: Да ведь это вороны!
[2026-07-22 00:01:17] Егор: Мухомор тебе варёный!
[2026-07-22 00:01:22] Егор: Наша-то ворона ушаста, в огороды шастает часто. Скок да скок, через мосток, белым пятнышком - хвосток.
[2026-07-22 00:01:34] Никодим: Да ведь это зайчонок!
[2026-07-22 00:01:36] Егор: Огурцов тебе бочонок!
[2026-07-22 00:01:40] Егор: Нашего зайца все звери пугаются. Прошлой зимою в лютый мороз серый зайчище барана унёс.
[2026-07-22 00:01:53] Никодим: Да ведь это волк!
[2026-07-22 00:01:56] Егор: По лбу тебе щёлк!
[2026-07-22 00:01:59] Егор: Неужели не слыхал никогда ты, что волки у нас рогаты?! Волк трясёт бородой, пообедав лебедой.
[2026-07-22 00:02:10] Никодим: Да ведь это козлище!
[2026-07-22 00:02:13] Егор: Щелчков тебе тыща!
[2026-07-22 00:02:17] Егор: Наш козёл под корягу ушёл. Хвостом шевелит, ставить сети не велит.
[2026-07-22 00:02:26] Никодим: Да ведь это налим!
[2026-07-22 00:02:31] Егор: Нет, не налим! Мы про налима не так говорим.
[2026-07-22 00:02:37] Егор: Налим Никодим гордится собою, Налим Никодим носит шапку соболью, ни перед кем её не ломает и шуток тоже не понимает.
""")
)