====== Язык программирования Python ======
* [[Все что должен знать DevOps про Python]]
* [[https://habr.com/ru/articles/277679/|Пишем shell скрипты на Python и можно ли заменить им Bash]]
* [[https://github.com/rupertsworld/frontend-backend|Basic Web Frontend/Backend Demo]]
* [[https://code.tutsplus.com/ru/using-celery-with-django-for-background-task-processing--cms-28732t|Использование Celery с Django для обработки фоновых задач]]
===== Виртуальная среда Python =====
* [[https://blog.sedicomm.com/2021/06/29/chto-takoe-venv-i-virtualenv-v-python-i-kak-ih-ispolzovat/|Что такое venv и virtualenv в Python, и как их использовать]]
* [[https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/|Install packages in a virtual environment using pip and venv]]
* [[https://habr.com/ru/articles/593529/|Poetry — прекрасная альтернатива pip (шпаргалка)]]
* [[https://habr.com/ru/articles/828016/|UV. Обзор пакетного менеджера Python]]
# python3 -V
# apt install python3-venv
$ python3 -m venv ~/venv1
$ source ~/venv1/bin/activate
(venv1) $ which python
(venv1) $ which ansible
(venv1) $ deactivate
===== Интерактивная оболочка REPL (Read-Eval-Print Loop) =====
(venv1) # python
>>> import os
>>> print ("Hello " + os.environ.get('USER') + "!")
* [[https://ru.wikipedia.org/wiki/IPython]]
(venv1) # pip install ipython
* [[https://jupyter.org/try-jupyter/notebooks/?path=notebooks/Intro.ipynb|try-jupyter/notebooks]]
* [[https://matplotlib.org/stable/tutorials/pyplot.html|Pyplot tutorial]]
===== Web приложение =====
* [[https://webadventures.ru/sravnenie-wsgi-serverov-uvicorn-i-gunicorn/|Сравнение WSGI-серверов:uvicorn и Gunicorn]]
==== Flask Gunicorn ====
* [[#Виртуальная среда Python]]
* [[https://habr.com/ru/articles/750312/|Python декораторы на максималках. Универсальный рецепт по написанию и аннотированию от мала до велика]]
* [[https://www.workroom-productions.com/serving-a-directory-with-flask/|Publishing a Directory with Flask]]
* [[https://python.ivan-shamaev.ru/run-install-deploy-flask-web-app-docker-dockerfile-compose/|Создание Web-приложения Flask и деплой с помощью Docker Compose & Dockerfile]]
* [[https://blog.miguelgrinberg.com/post/running-your-flask-application-over-https|Running Your Flask Application Over HTTPS]]
* [[https://docs.python.org/3/library/configparser.html|configparser — Configuration file parser]]
(venv1) :~$ pip install Flask
(venv1) :~$ mkdir -p pywebd/; cd $_
(venv1) :~/pywebd$ cat app.py
from flask import Flask, send_from_directory
import os
import configparser
config = configparser.ConfigParser()
config.read('/etc/pywebd/pywebd.conf')
if 'PYWEBD_DOC_ROOT' in os.environ:
pywebd_doc_root = os.environ.get('PYWEBD_DOC_ROOT')
else:
pywebd_doc_root = config['default']['DocumentRoot']
app = Flask(__name__)
@app.route('/')
def index():
return send_from_directory(pywebd_doc_root, 'index.html')
@app.route('/')
def sendstuff(path):
print(path)
return send_from_directory(pywebd_doc_root, path)
if __name__ == "__main__":
if 'PYWEBD_PORT' in os.environ: pywebd_port = os.environ.get('PYWEBD_PORT')
else: pywebd_port = config['default']['Listen']
app.run(host="0.0.0.0", port=pywebd_port, debug=True)
# app.run(ssl_context=('/etc/pywebd/pywebd.crt', '/etc/pywebd/pywebd.key'), debug=True, host='0.0.0.0', port=pywebd_port)
# mkdir -p /etc/pywebd/
# cat /etc/pywebd/pywebd.conf
[default]
DocumentRoot = /var/www/
Listen = 4080
# #cp /root/wild.crt /etc/pywebd/pywebd.crt
# #cp /root/wild.key /etc/pywebd/pywebd.key
* [[Средства программирования shell#Ресурсы Web сервера на shell]]
(venv1) :~/pywebd$ #export PYWEBD_PORT=4443
(venv1) :~/pywebd$ #export PYWEBD_DOC_ROOT=/var/www/html/
(venv1) :~/pywebd$ #PYWEBD_PORT=4080 PYWEBD_DOC_ROOT=/var/www/ python app.py
(venv1) :~/pywebd$ python app.py
(venv1) :~/pywebd$ pip freeze | tee requirements.txt
(venv1) :~/pywebd$ #pip install gunicorn
(venv1) :~/pywebd$ #gunicorn app:app --bind 0.0.0.0:8000
(venv1) :~/pywebd$ #cat gunicorn.conf.py
import os
import configparser
myconfig = configparser.ConfigParser()
myconfig.read('/etc/pywebd/pywebd.conf')
if 'PYWEBD_PORT' in os.environ: pywebd_port = os.environ.get('PYWEBD_PORT')
else: pywebd_port = myconfig['default']['Listen']
#certfile = "/etc/pywebd/pywebd.crt"
#keyfile = "/etc/pywebd/pywebd.key"
bind = '0.0.0.0:' + pywebd_port
(venv1) :~/pywebd$ # gunicorn -c gunicorn.conf.py app:app
==== FastAPI Uvicorn ====
* [[https://python-poetry.org/docs/basic-usage/]]
* [[https://habr.com/ru/articles/593529/|Poetry — прекрасная альтернатива pip (шпаргалка)]]
server# ###docker run -ti --rm --name pywebd2 python:3.11-alpine sh
/ # ### pip install poetry
server# apt install python3-poetry; export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring #https://stackoverflow.com/questions/74438817/poetry-failed-to-unlock-the-collection
/ # poetry new pywebd2
/ # cd pywebd2
/pywebd2 # poetry add fastapi dotenv uvicorn ###gunicorn
/pywebd2 # more pyproject.toml
/pywebd2 # cat app.py
from fastapi import FastAPI
from dotenv import load_dotenv
import os
CONST_VER = "ver1.1"
hostname = os.uname().nodename
load_dotenv()
pywebd_message = os.environ.get('PYWEBD_MESSAGE')
app = FastAPI()
@app.get("/")
async def home():
return {"data": f"{pywebd_message} from {hostname} app {CONST_VER}"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
/pywebd2 # cat .env
PYWEBD_MESSAGE="Hello World!!!"
* [[https://tproger.ru/articles/testiruem-na-python-unittest-i-pytest-instrukcija-dlja-nachinajushhih|Тестируем на Python: unittest и pytest. Инструкция для начинающих]]
* [[https://habr.com/ru/articles/349860/|Регулярные выражения в Python от простого к сложному. Подробности, примеры, картинки, упражнения]]
* [[https://regex101.com/|Online Regular expression tester with syntax highlighting]]
/pywebd2 # cat tests/test_ver_format.py
import app, re
assert re.match(r'^ver\d+\.\d+$', app.CONST_VER),"Incorrect VER format"
/pywebd2 # poetry run python3 -m unittest
/pywebd2 # #export PYWEBD_MESSAGE="Another message"
/pywebd2 # poetry run python3 app.py
/pywebd2 # poetry run uvicorn app:app --reload --host 0.0.0.0 --port 4080
* [[https://github.com/benoitc/gunicorn/issues/2154|TypeError: __call__() missing 1 required positional argument: 'send']]
/pywebd2 # ###poetry run gunicorn app:app --bind 0.0.0.0:6080 -k uvicorn.workers.UvicornWorker
===== Zabbix LLD приложение =====
* [[https://askubuntu.com/questions/244378/running-python-file-in-terminal|Running Python File in Terminal]]
* [[https://pythonworld.ru/moduli/modul-subprocess.html|Модуль subprocess]]
* [[https://habr.com/ru/articles/488112/|Понимание итераторов в Python]]
* [[https://www.geeksforgeeks.org/python-find-dictionary-matching-value-in-list/|Find dictionary matching value in list - Python]]
* [[https://docs-python.ru/tutorial/vstroennye-funktsii-interpretatora-python/funktsija-next/|Функция next() в Python, следующий элемент итератора]]
==== Пример 1 ====
gate# apt install python3-xmltodict/stable
gate# cat /etc/zabbix/dhcp-pools.py
#!/usr/bin/env python3
# Example usage:
# ./dhcp-pools.py
# ./dhcp-pools.py LAN1 defined|used
from sys import argv
import subprocess, xmltodict, json
p = subprocess.Popen("/usr/bin/dhcpd-pools -f x", stdout=subprocess.PIPE, shell=True)
(output, err) = p.communicate()
p_status = p.wait()
o = xmltodict.parse(output)
#print (o)
if len(argv)==1:
r=[]
for i in o['dhcpstatus']['shared-network']:
s={}
s["{#POOLNAME}"]=i['location']
r.insert(1,s)
print(json.dumps(r))
else:
LANNAME=argv[1]
USDEF=argv[2]
res = next((sub for sub in o['dhcpstatus']['shared-network'] if sub['location'] == LANNAME), None)
print(res[USDEF])
==== Пример 2 ====
# cat /usr/local/bin/asterisk.chansip.discovery.py
#!/usr/bin/env python3
import subprocess, io, json
result=[]
proc = subprocess.Popen('/usr/sbin/asterisk -x "sip show users" | tail -n +2 | cut -d" " -f1', stdout=subprocess.PIPE, shell=True)
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
#print(line.rstrip())
s={}
s["{#CHANNAME}"]="SIP/"+line.rstrip()
result.insert(1,s)
print(json.dumps(result))
Вариант от DeepSeek
# cat /usr/local/bin/asterisk.chansip.discovery.ds.py
#!/usr/bin/env python3
import subprocess
import json
# Запускаем команду и сразу получаем вывод
output = subprocess.check_output(
'/usr/sbin/asterisk -x "sip show users" | tail -n +2 | cut -d" " -f1',
shell=True,
text=True
)
# Формируем список словарей в одну строку
result = [{"{#CHANNAME}": f"SIP/{line.strip()}"} for line in output.splitlines() if line.strip()]
# Выводим результат в формате JSON
print(json.dumps(result))
===== Zabbix API приложение =====
* [[https://www.zabbix.com/documentation/current/en/manual/api]]
* [[https://sbcode.net/zabbix/zabbix-api-python-example/]]
* [[https://forum.checkmk.com/t/rest-api-python-question-how-to-use-variables-in-json-post-in-key-and-value/34652]]
(venv1) server:~# pip install requests
(venv1) server:~# cat zab_set_map_name.py
#!/usr/bin/env python3
import requests
import json
from sys import argv
if len(argv) != 3 :
print("You must set argument!!!\nExample: python zab_set_map_name.py 2 \"ISP 1\"")
quit()
MAPID = argv[1]
MAPNAME = argv[2]
ZABBIX_API_URL = "http://127.0.0.1/zabbix/api_jsonrpc.php"
UNAME = "Admin"
PWORD = "zabbix"
print("\nLogin user {} to Zabbiz API".format(UNAME))
r = requests.post(ZABBIX_API_URL,
json={
"jsonrpc": "2.0",
"method": "user.login",
"params": {
"username": UNAME,
"password": PWORD},
"id": 1
})
print(json.dumps(r.json(), indent=4, sort_keys=True))
AUTHTOKEN = r.json()["result"]
#print("Rename Map with ID", MAPID, "to", MAPNAME)
print(f"Rename Map with ID {MAPID} to {MAPNAME}")
r = requests.post(ZABBIX_API_URL,
headers={'Authorization': 'Bearer ' + AUTHTOKEN},
json={
"jsonrpc": "2.0",
"method": "map.update",
"params": {
"sysmapid": MAPID,
"name": MAPNAME
},
"id": 2
})
print(json.dumps(r.json(), indent=4, sort_keys=True))
print("\nLogout user")
r = requests.post(ZABBIX_API_URL,
headers={'Authorization': 'Bearer ' + AUTHTOKEN},
json={
"jsonrpc": "2.0",
"method": "user.logout",
"params": {},
"id": 2,
})
print(json.dumps(r.json(), indent=4, sort_keys=True))
(venv1) server:~# chmod +x zab_set_map_name.py
(venv1) server:~# ./zab_set_map_name.py 2 "ISP 1"
===== CRUD Rest API приложение =====
* [[https://dev.to/francescoxx/python-crud-rest-api-using-flask-sqlalchemy-postgres-docker-docker-compose-3kh4|Python CRUD Rest API using Flask, SQLAlchemy, Postgres, Docker, Docker Compose]]
===== Дополнительные материалы =====
* [[https://pypi.org/project/ansible-output-parser/]]
* [[https://www.cyberciti.biz/faq/python-run-external-command-and-get-output/]]
* [[https://selectel.ru/blog/tutorials/how-to-develop-fastapi-application/]]
==== Доступ к каталогу по http ====
* [[https://gist.github.com/SeanPesce/af5f6b7665305b4c45941634ff725b7a|SeanPesce/https_server.py]]
dir$ python3 -m http.server 80
==== wav_and_ogg.py ====
* [[Перекодировка звука#Перекодировка в ogg формат]]
$ pip install pydub #audioop-lts
import sys
from pydub import AudioSegment
def wav_to_ogg(file_path_wo_ext):
audio = AudioSegment.from_wav(f"{file_path_wo_ext}.wav")
audio.export(f"{file_path_wo_ext}.ogg", format="ogg", codec="libopus", bitrate="24k")
print(f"Файл успешно конвертирован и сохранен как: {file_path_wo_ext}.ogg")
def ogg_to_wav(file_path_wo_ext):
audio = AudioSegment.from_ogg(f"{file_path_wo_ext}.ogg")
audio = audio.set_channels(1)
audio = audio.set_frame_rate(8000)
audio = audio.set_sample_width(2)
audio.export(f"{file_path_wo_ext}.wav", format="wav")
print(f"Файл успешно конвертирован и сохранен как: {file_path_wo_ext}.wav")
if __name__ == "__main__":
target_file = sys.argv[1]
# wav_to_ogg(target_file)
# ogg_to_wav(target_file)
$ python wav_and_ogg.py speech
==== speech_and_text.py ====
* [[Yandex AI]]
* [[Yandex SpeechKit#Проверка распознавания речи]]
import os
import sys
import requests
API_KEY = os.getenv("YANDEX_API_KEY")
FOLDER_ID = os.getenv("YANDEX_FOLDER_ID")
def speech_to_text(file_path):
url = f"https://stt.api.cloud.yandex.net/speech/v1/stt:recognize?folderId={FOLDER_ID}"
headers = {
"Authorization": f"Api-Key {API_KEY}",
"Content-Type": "audio/ogg; codecs=opus",
}
params = {"lang": "ru-RU"}
with open(file_path, "rb") as f:
audio_data = f.read()
response = requests.post(
url, headers=headers, params=params, data=audio_data, timeout=15
)
result_json = response.json()
text = result_json.get("result", "")
return text
def text_to_speech(text, output_file_path):
url = "https://tts.api.cloud.yandex.net/speech/v1/tts:synthesize"
headers = {
"Authorization": f"Api-Key {API_KEY}"
}
data = {
"text": text,
"lang": "ru-RU",
"voice": "marina",
"format": "oggopus",
"folderId": FOLDER_ID
}
response = requests.post(url, headers=headers, data=data, timeout=15)
if response.status_code == 200:
with open(output_file_path, "wb") as f:
f.write(response.content)
print(f"Файл успешно сохранен: {output_file_path}")
else:
print(f"Ошибка API: {response.status_code} - {response.text}")
if __name__ == "__main__":
file_name = sys.argv[1]
# text = speech_to_text(file_name)
# print(text)
# text = sys.argv[2]
# text_to_speech(text, file_name)
==== request_to_my_ollama.py ====
$ pip install openai
from openai import OpenAI
client = OpenAI(
base_url="http://val.bmstu.ru:8080/v1",
api_key="1234567890abcdefg"
)
response = client.chat.completions.create(
model="ornith-1.5:9b",
messages=[
{"role": "user", "content": "Привет! Напиши короткий приветственный текст."}
],
temperature=0.7
)
print(response.choices[0].message.content)
==== request_to_llm.py ====
* [[Yandex AI]]
$ pip install yandex-ai-studio-sdk
import sys
import os
from yandex_ai_studio_sdk import AIStudio
def request_to_llm(user_request, system_prompt, context_messages=None):
sdk = AIStudio(
folder_id=os.getenv("YANDEX_FOLDER_ID"),
auth=os.getenv("YANDEX_API_KEY")
)
messages = [{"role": "system", "text": system_prompt}]
if context_messages:
messages.extend(context_messages)
messages.append({"role": "user", "text": user_request})
#model = sdk.chat.completions("yandexgpt")
model = sdk.chat.completions("aliceai-llm")
model = model.configure(temperature=0.3, max_tokens=1500)
response = model.run(messages)
text = response.choices[0].text
return text
if __name__ == "__main__":
system_prompt = (
"Ты — ассистент.\n"
"Отвечай кратко.\n"
)
chat_context = []
#chat_context = [
# {"role": "user", "text": "Привет! Меня зовут Алексей, я программист."},
# {"role": "assistant", "text": "Привет, Алексей! Рад знакомству. Чем могу помочь?"}
#]
while True:
try:
user_request = input("Введите ваш вопрос: ")
except (KeyboardInterrupt, EOFError):
print("\nСессия завершена!")
sys.exit(0)
reply_text = request_to_llm(user_request, system_prompt, chat_context)
print(reply_text)
chat_context.append({"role": "user", "text": user_request})
chat_context.append({"role": "assistant", "text": reply_text})
==== openai_request_to_llm.py ====
$ pip install openai
export BASE_URL=http://val.bmstu.ru:8080/v1
export API_KEY=1234567890abcdefg
export MODEL_ID=ornith-1.5:9b
export BASE_URL=https://ai.api.cloud.yandex.net/v1
export API_KEY=...
export MODEL_ID=gpt://b1gg4j6ru4esprat3uu7/deepseek-v4-flash/latest
import sys
import os
from openai import OpenAI
BASE_URL = os.environ["BASE_URL"]
API_KEY = os.environ["API_KEY"]
MODEL_ID = os.environ["MODEL_ID"]
def request_to_llm(user_request, system_prompt, context_messages=None):
client = OpenAI(
base_url=BASE_URL,
api_key=API_KEY
)
messages = [{"role": "system", "content": system_prompt}]
if context_messages:
messages.extend(context_messages)
messages.append({"role": "user", "content": user_request})
response = client.chat.completions.create(
model=MODEL_ID,
messages=messages,
temperature=0.7
)
text = response.choices[0].message.content
return text
if __name__ == "__main__":
system_prompt = (
"Ты — ассистент.\n"
"Отвечай кратко.\n"
)
chat_context = []
while True:
try:
user_request = input("Введите ваш вопрос: ")
except (KeyboardInterrupt, EOFError):
print("\nСессия завершена!")
sys.exit(0)
reply_text = request_to_llm(user_request, system_prompt, chat_context)
print(reply_text)
chat_context.append({"role": "user", "content": user_request})
chat_context.append({"role": "assistant", "content": reply_text})
==== agent_rand_hello.py ====
import os
import sys
import random
from yandex_ai_studio_sdk import AIStudio
sdk = AIStudio(
folder_id=os.getenv("YANDEX_FOLDER_ID"),
auth=os.getenv("YANDEX_API_KEY")
)
# 2. Локальная Python-функция
def get_random_lucky_number() -> int:
return random.randint(1, 100)
# Регистрируем инструмент через метод sdk.tools.function
lucky_number_tool = sdk.tools.function(
parameters={
"type": "object",
"properties": {}
},
name="lucky_number",
description="Используй эту функцию, когда пользователь просит назвать его счастливое число."
)
# 3. Инициализируем модель через chat.completions
model = sdk.chat.completions("yandexgpt").configure(
temperature=0.3,
tools=[lucky_number_tool]
)
# Начальный запрос пользователя
messages = [
{"role": "user", "content": "Привет! Назови мое счастливое число на сегодня и пожелай удачи разнообразно."}
]
#messages = [
# {"role": "user", "content": "Привет! Пожелай удачи разнообразно."}
#]
print("Отправка первого запроса агенту...")
response = model.run(messages)
# Извлекаем первый вариант ответа из кортежа
choice = response.choices[0]
if hasattr(choice, 'tool_calls') and choice.tool_calls:
print(f"-> Агент запросил вызов инструмента.")
formatted_tool_calls = []
for call in choice.tool_calls:
if call.function.name == "lucky_number":
tool_result = get_random_lucky_number()
print(f"-> Результат локальной функции: {tool_result}")
# Простой подход: добавляем результат как ответ пользователя
messages.append({
"role": "user",
"content": f"Результат выполнения функции lucky_number: {tool_result}"
})
# Отправляем обновленную историю обратно модели
print("Отправка результата выполнения функции обратно агенту...")
# В run() передаем только messages, tools уже настроены
final_response = model.run(messages=messages)
print("\nИтоговый ответ AI агента:")
print(final_response.choices[0].text)
else:
print("\nОтвет модели:")
print(choice.text)
==== ari_echo_talk_detect.py ====
root#
mkdir -p /var/spool/asterisk/recording/
chown -R asterisk:asterisk /var/spool/asterisk/recording/
chmod -R 775 /var/spool/asterisk/recording/
$ pip install websocket-client requests
* Отключение TALK_DETECT
...
- #"maxDuration": 29,
- #"terminateOn": "#",
+ "maxDuration": 29,
+ "terminateOn": "#",
...
- #start_recording(channel_id)
+ start_recording(channel_id)
# or
- detect_speech(channel_id)
+ #detect_speech(channel_id)
import json
import requests
import websocket
ARI_USER = "asterisk"
ARI_PASS = "asterisk"
BASE_URL = "http://localhost:8088/ari"
AUTH = (ARI_USER, ARI_PASS)
def detect_speech(channel_id):
print(f"Запускаем TALK_DETECT для канала {channel_id}...")
talk_url = f"{BASE_URL}/channels/{channel_id}/variable"
# 2000 мс тишины для завершения фразы, 500 мс речи для начала
talk_payload = {
"variable": "TALK_DETECT(set)",
"value": "2000,500"
}
response = requests.post(talk_url, json=talk_payload, auth=AUTH)
print(f"Статус-код ответа: {response.status_code}")
print(f"Текст ответа: {response.text}")
def undetect_speech(channel_id):
print(f"Отключаем TALK_DETECT для канала {channel_id}...")
talk_url = f"{BASE_URL}/channels/{channel_id}/variable"
talk_payload = {
"variable": "TALK_DETECT(set)",
"value": "remove"
}
response = requests.post(talk_url, json=talk_payload, auth=AUTH)
print(f"Статус-код ответа: {response.status_code}")
print(f"Текст ответа: {response.text}")
def start_recording(channel_id):
print(f"Включаем запись для канала {channel_id}")
record_url = f"{BASE_URL}/channels/{channel_id}/record"
recording_name = f"rec_{channel_id}"
record_payload = {
"name": recording_name,
"format": "wav",
"ifExists": "overwrite",
#"maxDuration": 29,
#"terminateOn": "#",
#"beep": True,
}
requests.post(record_url, params=record_payload, auth=AUTH)
def stop_recording(channel_id):
print(f"Останавливаем запись для канала {channel_id}")
recording_name = f"rec_{channel_id}"
stop_url = f"{BASE_URL}/recordings/live/{recording_name}/stop"
requests.post(stop_url, auth=AUTH)
def on_message(wsapp, message):
event = json.loads(message)
event_type = event.get("type")
# Сценарий 1: Звонок поступил -> Отвечаем и воспроизводим beep
if event_type == "StasisStart":
channel_id = event.get("channel", {}).get("id")
print(f"Отвечаем на звонок {channel_id}")
requests.post(f"{BASE_URL}/channels/{channel_id}/answer", auth=AUTH)
#start_recording(channel_id)
# or
detect_speech(channel_id)
# Сценарий N
elif event_type == "ChannelTalkingStarted":
channel_id = event.get("channel", {}).get("id")
print(f"Обнаружена речь в канале {channel_id}! Начинаем запись...")
start_recording(channel_id)
# Сценарий N
elif event_type == "ChannelTalkingFinished":
channel_id = event.get("channel", {}).get("id")
print(f"Обнаружено молчание в канале {channel_id}")
stop_recording(channel_id)
undetect_speech(channel_id)
# Сценарий N: Запись завершилась -> Проигрываем её обратно
elif event_type == "RecordingFinished":
recording_data = event.get("recording", {})
recording_name = recording_data.get("name")
target_uri = recording_data.get("target_uri", "")
channel_id = target_uri.split("channel:")[1]
print(f"Запись {recording_name} готова! Проигрываем её обратно в канал {channel_id}...")
play_url = f"{BASE_URL}/channels/{channel_id}/play"
play_payload = {
"media": f"recording:{recording_name}"
}
response = requests.post(play_url, params=play_payload, auth=AUTH)
print("Ответ ARI на воспроизведение:", response.status_code)
# Сценарий N: Воспроизведение завершено (бип или записанный голос)
elif event_type == "PlaybackFinished":
playback_data = event.get("playback", {})
media_uri = playback_data.get("media_uri", "")
target_uri = playback_data.get('target_uri', '')
channel_id = target_uri.split("channel:")[1]
#start_recording(channel_id)
# or
detect_speech(channel_id)
# Сценарий N: Абонент повесил трубку -> Удаляем файл
elif event_type == "StasisEnd":
channel_id = event.get("channel", {}).get("id")
recording_name = f"rec_{channel_id}"
print(f"Звонок {channel_id} завершен абонентом. Удаляем файл записи...")
delete_url = f"{BASE_URL}/recordings/stored/{recording_name}"
requests.delete(delete_url, auth=AUTH)
def on_error(ws, error):
print(f"Произошла ошибка: {error}")
wsapp = websocket.WebSocketApp(
f"ws://localhost:8088/ari/events?api_key={ARI_USER}:{ARI_PASS}&app=my-first-app",
on_message=on_message,
on_error=on_error
)
wsapp.run_forever()
==== ari_chat.py ====
import json
import requests
import websocket
import os
ARI_USER = "asterisk"
ARI_PASS = "asterisk"
BASE_URL = "http://localhost:8088/ari"
AUTH = (ARI_USER, ARI_PASS)
REC_PATH = "/var/spool/asterisk/recording/"
SYSTEM_PROMPT = (
"Ты — ассистент.\n"
"Отвечай кратко.\n"
"Не спрашивай когда напомнить.\n"
)
COMPRESS_PROMPT = (
"Ты — инструмент оптимизации контекста. Проанализируй историю диалога. "
"Удали выполненные дела, приветствия и воду. Сформулируй ОДНО лаконичное "
"сообщение от лица пользователя, в котором отражена только актуальная суть "
"и невыполненные задачи/оставшиеся вопросы на текущий момент."
)
# Структура: {channel_id: [{"role": "user", "text": "..."}, {"role": "assistant", "text": "..."}]}
channel_contexts = {}
channel_caller_numbers = {}
def get_channel_context(channel_id):
if channel_id not in channel_contexts:
channel_contexts[channel_id] = []
return channel_contexts[channel_id]
def update_channel_context(channel_id, user_request, agent_response):
context = get_channel_context(channel_id)
context.append({"role": "user", "text": user_request})
context.append({"role": "assistant", "text": agent_response})
return context
def load_context(caller_number):
file_path = f"{REC_PATH}{caller_number}.json"
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
return []
def save_context(caller_number, context):
file_path = f"{REC_PATH}{caller_number}.json"
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(context, f, ensure_ascii=False, indent=2)
def start_recording(channel_id):
print(f"Включаем запись для канала {channel_id} на 29 секунд...")
record_url = f"{BASE_URL}/channels/{channel_id}/record"
recording_name = f"rec_{channel_id}"
record_payload = {
"name": recording_name,
"format": "wav",
"ifExists": "overwrite",
"maxDuration": 29,
"terminateOn": "#",
"beep": True,
}
requests.post(record_url, params=record_payload, auth=AUTH)
def get_caller_number(channel_id):
url = f"{BASE_URL}/channels/{channel_id}"
response = requests.get(url, auth=AUTH, timeout=5)
channel_info = response.json()
caller_number = channel_info.get("caller", {}).get("number")
return caller_number
def on_message(wsapp, message):
event = json.loads(message)
event_type = event.get("type")
# Сценарий 1: Звонок поступил
if event_type == "StasisStart":
channel_id = event.get("channel", {}).get("id")
print(f"Отвечаем на звонок {channel_id}")
requests.post(f"{BASE_URL}/channels/{channel_id}/answer", auth=AUTH)
channel_caller_numbers[channel_id]=get_caller_number(channel_id)
channel_contexts[channel_id] = load_context(channel_caller_numbers[channel_id])
start_recording(channel_id)
# Сценарий 2: Запись вопроса завершилась -> Проигрываем ответ
elif event_type == "RecordingFinished":
recording_data = event.get("recording", {})
recording_name = recording_data.get("name")
target_uri = recording_data.get("target_uri", "")
channel_id = target_uri.split("channel:")[1]
caller_number = channel_caller_numbers[channel_id]
print(f"Номер звонящего в RecordingFinished: {caller_number}")
import wav_and_ogg
import speech_and_text
wav_and_ogg.wav_to_ogg(f"{REC_PATH}{recording_name}")
user_request = speech_and_text.speech_to_text(f"{REC_PATH}{recording_name}.ogg")
print(f"user_request: {user_request}")
if user_request:
context = get_channel_context(channel_id)
import request_to_llm
agent_response = request_to_llm.request_to_llm(user_request, SYSTEM_PROMPT, context)
#agent_response = user_request
print(agent_response)
update_channel_context(channel_id, user_request, agent_response)
print("Текущий контекст:")
from pprint import pprint
pprint(channel_contexts[channel_id])
speech_and_text.text_to_speech(agent_response,f"{REC_PATH}{recording_name}.response.ogg")
wav_and_ogg.ogg_to_wav(f"{REC_PATH}{recording_name}.response")
print(f"Запись {recording_name} готова! Проигрываем её обратно в канал {channel_id}...")
play_url = f"{BASE_URL}/channels/{channel_id}/play"
play_payload = {
#"media": f"recording:{recording_name}"
"media": f"recording:{recording_name}.response"
}
response = requests.post(play_url, params=play_payload, auth=AUTH)
print("Ответ ARI на воспроизведение:", response.status_code)
# Сценарий 3: Воспроизведение завершено
elif event_type == "PlaybackFinished":
playback_data = event.get("playback", {})
media_uri = playback_data.get("media_uri", "")
target_uri = playback_data.get('target_uri', '')
channel_id = target_uri.split("channel:")[1]
start_recording(channel_id)
# Сценарий 4: Абонент повесил трубку
elif event_type == "StasisEnd":
channel_id = event.get("channel", {}).get("id")
context = get_channel_context(channel_id)
caller_number = channel_caller_numbers[channel_id]
print(f"Номер звонящего в StasisEnd: номер {caller_number} канал {channel_id}")
print(f"Сжатие контекста")
import request_to_llm
agent_response = request_to_llm.request_to_llm("Сожми контекст", COMPRESS_PROMPT, context)
print(agent_response)
context = [{"role": "user", "text": agent_response}]
print(f"Сохранение контекста и удаление медиа файлов")
save_context(caller_number,context)
import glob
recording_name = f"rec_{channel_id}"
file_mask = f"{REC_PATH}{recording_name}*"
matched_files = glob.glob(file_mask)
for file_path in matched_files:
os.remove(file_path)
print(f"Файл удален: {file_path}")
def on_error(ws, error):
print(f"Произошла ошибка: {error}")
wsapp = websocket.WebSocketApp(
f"ws://localhost:8088/ari/events?api_key={ARI_USER}:{ARI_PASS}&app=my-first-app",
on_message=on_message,
on_error=on_error
)
wsapp.run_forever()
==== ari_chat_talk_detect.py ====
import os
import json
import requests
import websocket
ARI_USER = "asterisk"
ARI_PASS = "asterisk"
BASE_URL = "http://localhost:8088/ari"
AUTH = (ARI_USER, ARI_PASS)
REC_PATH = "/var/spool/asterisk/recording/"
SYSTEM_PROMPT = (
"Ты — ассистент.\n"
"Отвечай кратко.\n"
"Не спрашивай когда напомнить.\n"
)
COMPRESS_PROMPT = (
"Ты — инструмент оптимизации контекста. Проанализируй историю диалога. "
"Удали выполненные дела, приветствия и воду. Сформулируй ОДНО лаконичное "
"сообщение от лица пользователя, в котором отражена только актуальная суть "
"и невыполненные задачи/оставшиеся вопросы на текущий момент."
)
# Структура: {channel_id: [{"role": "user", "text": "..."}, {"role": "assistant", "text": "..."}]}
channel_contexts = {}
channel_caller_numbers = {}
def load_context(caller_number):
file_path = f"{REC_PATH}{caller_number}.json"
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
return []
def save_context(caller_number, context):
file_path = f"{REC_PATH}{caller_number}.json"
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(context, f, ensure_ascii=False, indent=2)
def get_caller_number(channel_id):
url = f"{BASE_URL}/channels/{channel_id}"
response = requests.get(url, auth=AUTH, timeout=5)
channel_info = response.json()
caller_number = channel_info.get("caller", {}).get("number")
return caller_number
def get_channel_context(channel_id):
if channel_id not in channel_contexts:
channel_contexts[channel_id] = []
return channel_contexts[channel_id]
def update_channel_context(channel_id, user_request, agent_response):
context = get_channel_context(channel_id)
context.append({"role": "user", "text": user_request})
context.append({"role": "assistant", "text": agent_response})
return context
def detect_speech(channel_id):
print(f"Запускаем TALK_DETECT для канала {channel_id}...")
talk_url = f"{BASE_URL}/channels/{channel_id}/variable"
# 1000 мс тишины для завершения фразы, 500 мс речи для начала
talk_payload = {
"variable": "TALK_DETECT(set)",
"value": "1000,500"
}
response = requests.post(talk_url, json=talk_payload, auth=AUTH)
print(f"Статус-код ответа: {response.status_code}")
print(f"Текст ответа: {response.text}")
def undetect_speech(channel_id):
print(f"Отключаем TALK_DETECT для канала {channel_id}...")
talk_url = f"{BASE_URL}/channels/{channel_id}/variable"
talk_payload = {
"variable": "TALK_DETECT(set)",
"value": "remove"
}
response = requests.post(talk_url, json=talk_payload, auth=AUTH)
print(f"Статус-код ответа: {response.status_code}")
print(f"Текст ответа: {response.text}")
def play_beep(channel_id):
print(f"Проигрываем сигнал перед записью в канал {channel_id}...")
play_url = f"{BASE_URL}/channels/{channel_id}/play"
play_payload = {"media": "sound:beep"}
requests.post(play_url, params=play_payload, auth=AUTH)
def start_recording(channel_id):
print(f"Включаем запись для канала {channel_id}")
record_url = f"{BASE_URL}/channels/{channel_id}/record"
recording_name = f"rec_{channel_id}"
record_payload = {
"name": recording_name,
"format": "wav",
"ifExists": "overwrite",
#"maxDuration": 29,
#"terminateOn": "#",
#"beep": True,
}
requests.post(record_url, params=record_payload, auth=AUTH)
def stop_recording(channel_id):
print(f"Останавливаем запись для канала {channel_id}")
recording_name = f"rec_{channel_id}"
stop_url = f"{BASE_URL}/recordings/live/{recording_name}/stop"
requests.post(stop_url, auth=AUTH)
def on_message(wsapp, message):
event = json.loads(message)
event_type = event.get("type")
# Сценарий 1: Звонок поступил -> Отвечаем и воспроизводим beep
if event_type == "StasisStart":
channel_id = event.get("channel", {}).get("id")
print(f"Отвечаем на звонок {channel_id}")
requests.post(f"{BASE_URL}/channels/{channel_id}/answer", auth=AUTH)
channel_caller_numbers[channel_id]=get_caller_number(channel_id)
channel_contexts[channel_id] = load_context(channel_caller_numbers[channel_id])
play_beep(channel_id)
#start_recording(channel_id)
# or
#detect_speech(channel_id)
# Сценарий N
elif event_type == "ChannelTalkingStarted":
channel_id = event.get("channel", {}).get("id")
print(f"Обнаружена речь в канале {channel_id}! Начинаем запись...")
start_recording(channel_id)
# Сценарий N
elif event_type == "ChannelTalkingFinished":
channel_id = event.get("channel", {}).get("id")
print(f"Обнаружено молчание в канале {channel_id}")
stop_recording(channel_id)
undetect_speech(channel_id)
# Сценарий N: Запись завершилась -> Проигрываем её обратно
elif event_type == "RecordingFinished":
recording_data = event.get("recording", {})
recording_name = recording_data.get("name")
target_uri = recording_data.get("target_uri", "")
channel_id = target_uri.split("channel:")[1]
import wav_and_ogg
import speech_and_text
wav_and_ogg.wav_to_ogg(f"{REC_PATH}{recording_name}")
user_request = speech_and_text.speech_to_text(f"{REC_PATH}{recording_name}.ogg")
print(f"user_request: {user_request}")
if user_request:
context = get_channel_context(channel_id)
import request_to_llm
agent_response = request_to_llm.request_to_llm(user_request, SYSTEM_PROMPT, context)
#agent_response = user_request
print(agent_response)
update_channel_context(channel_id, user_request, agent_response)
print("Текущий контекст:")
from pprint import pprint
pprint(channel_contexts[channel_id])
speech_and_text.text_to_speech(agent_response,f"{REC_PATH}{recording_name}.response.ogg")
wav_and_ogg.ogg_to_wav(f"{REC_PATH}{recording_name}.response")
print(f"Запись {recording_name} готова! Проигрываем её обратно в канал {channel_id}...")
play_url = f"{BASE_URL}/channels/{channel_id}/play"
play_payload = {
#"media": f"recording:{recording_name}"
"media": f"recording:{recording_name}.response"
}
response = requests.post(play_url, params=play_payload, auth=AUTH)
print("Ответ ARI на воспроизведение:", response.status_code)
# Сценарий N: Воспроизведение завершено (бип или записанный голос)
elif event_type == "PlaybackFinished":
playback_data = event.get("playback", {})
media_uri = playback_data.get("media_uri", "")
target_uri = playback_data.get('target_uri', '')
channel_id = target_uri.split("channel:")[1]
#start_recording(channel_id)
# or
#detect_speech(channel_id)
if media_uri == "sound:beep":
print(f"Сигнал завершен. Начинаем запись для канала {channel_id}...")
detect_speech(channel_id)
elif "recording:rec_" in media_uri:
print(f"Воспроизведение записи завершено. Идем на новый круг для канала {channel_id}...")
play_beep(channel_id)
# Сценарий N: Абонент повесил трубку -> Удаляем файл
elif event_type == "StasisEnd":
channel_id = event.get("channel", {}).get("id")
#print(f"Звонок {channel_id} завершен абонентом. Удаляем файл записи...")
#recording_name = f"rec_{channel_id}"
#delete_url = f"{BASE_URL}/recordings/stored/{recording_name}"
#requests.delete(delete_url, auth=AUTH)
context = get_channel_context(channel_id)
caller_number = channel_caller_numbers[channel_id]
print(f"Номер звонящего в StasisEnd: номер {caller_number} канал {channel_id}")
print(f"Сжатие контекста")
import request_to_llm
agent_response = request_to_llm.request_to_llm("Сожми контекст", COMPRESS_PROMPT, context)
print(agent_response)
context = [{"role": "user", "text": agent_response}]
print(f"Сохранение контекста и удаление медиа файлов")
save_context(caller_number,context)
import glob
recording_name = f"rec_{channel_id}"
file_mask = f"{REC_PATH}{recording_name}*"
matched_files = glob.glob(file_mask)
for file_path in matched_files:
os.remove(file_path)
print(f"Файл удален: {file_path}")
def on_error(ws, error):
print(f"Произошла ошибка: {error}")
wsapp = websocket.WebSocketApp(
f"ws://localhost:8088/ari/events?api_key={ARI_USER}:{ARI_PASS}&app=my-first-app",
on_message=on_message,
on_error=on_error
)
wsapp.run_forever()
===== Черновик =====
(venv1) root@server:~/ai# cat agent_email_or_cal.py
import os
import sys
#import random
import re
import json
from yandex_ai_studio_sdk import AIStudio
sdk = AIStudio(
folder_id=os.getenv("YANDEX_FOLDER_ID"),
auth=os.getenv("YANDEX_API_KEY")
)
# Функция для интеграции с календарем
def add_to_calendar(task_title: str):
"""
Ваша кастомная функция для добавления события в календарь.
"""
print(f"[Вызов функции]: Успешно добавлено в календарь: '{task_title}'")
# Примеры для тестирования (раскомментируйте нужный для проверки):
user_request = "Привет! Слушай, отправь пожалуйста письмо Ивану с отчетом."
#user_request = "Напомни мне завтра в 15:00 созвониться с коллегами по проекту."
# Расширяем системный промт для обработки двух типов команд
system_prompt = (
"Ты — ассистент, который анализирует команды пользователя и классифицирует их.\n"
"Определи, что просит сделать пользователь. Ответь строго в формате JSON.\n"
"Схема ответа JSON должна содержать следующие поля:\n"
"- 'intent': строка, может принимать значения: 'send_email', 'add_calendar' или 'unknown'.\n"
"- 'recipient_name': имя получателя (строка), если intent == 'send_email', иначе null.\n"
"- 'calendar_task': текст напоминания (строка), если intent == 'add_calendar', иначе null."
)
messages = [
{"role": "system", "text": system_prompt},
{"role": "user", "text": user_request}
]
# Вызываем модель YandexGPT
model = sdk.chat.completions("yandexgpt").configure(
temperature=0.3
)
response = model.run(messages)
match = re.search(r"\{.*\}", response.choices[0].text, re.DOTALL)
result_text = match.group(0)
#print(result_text)
#sys.exit()
try:
# Парсим JSON-ответ от модели
data = json.loads(result_text)
intent = data.get("intent")
# Сценарий 1: Отправка письма
if intent == "send_email":
recipient = data.get("recipient_name")
if recipient:
print(f"Обнаружена команда отправки письма. Получатель: {recipient}")
else:
print("Обнаружена команда отправки письма, но имя получателя не указано.")
# Сценарий 2: Добавление в календарь
elif intent == "add_calendar":
task = data.get("calendar_task")
if task:
print("Обнаружена команда календаря. Вызываю функцию...")
add_to_calendar(task)
else:
print("Обнаружена команда календаря, но текст напоминания пуст.")
# Сценарий 3: Команда не распознана
else:
print("Команда не распознана или не требует автоматических действий.")
except json.JSONDecodeError:
print("Ошибка парсинга ответа модели:", result_text)
$ cat request_to_llm_with_tools.py
import sys
import os
import random
from yandex_ai_studio_sdk import AIStudio
#from rich import inspect
def request_to_llm_with_tools(user_request, system_prompt, context_messages=None, tools=None):
sdk = AIStudio(
folder_id=os.getenv("YANDEX_FOLDER_ID"),
auth=os.getenv("YANDEX_API_KEY")
)
sdk_tools = []
for item in tools:
tool = sdk.tools.function(
parameters={"type": "object","properties": {}},
name=item["func_name"],
description=item["description"]
)
sdk_tools.append(tool)
messages = [{"role": "system", "text": system_prompt}]
if context_messages:
messages.extend(context_messages)
messages.append({"role": "user", "text": user_request})
#model = sdk.chat.completions("yandexgpt")
model = sdk.chat.completions("aliceai-llm")
model = model.configure(
temperature=0.3,
max_tokens=1500,
tools=sdk_tools
)
#inspect(messages, methods=True)
#inspect(messages)
response = model.run(messages)
#inspect(response, methods=True)
choice = response.choices[0]
if choice.tool_calls:
return choice.tool_calls[0].function.name
else:
return choice.text
if __name__ == "__main__":
system_prompt = (
"Ты — ассистент.\n"
"Отвечай кратко.\n"
)
chat_context = []
#chat_context = [
# {"role": "user", "text": "Привет! Меня зовут Алексей, я программист."},
# {"role": "assistant", "text": "Привет, Алексей! Рад знакомству. Чем могу помочь?"}
#]
# Определяем функцию для инструмента
def get_random_number() -> int:
return random.randint(1, 100)
def get_random_fruit() -> str:
words = ["яблоко", "банан", "апельсин", "груша", "киви"]
return random.choice(words)
#print(get_random_number())
#print(get_random_fruit())
func_list = [
{
"func_name": "random_number",
"description": "Используй эту функцию, когда пользователь просит назвать его счастливое число."
},
{
"func_name": "random_fruit",
"description": "Используй эту функцию, когда пользователь просит назвать его любимый фрукт."
}
]
while True:
try:
user_request = input("Введите ваш вопрос: ")
except (KeyboardInterrupt, EOFError):
print("\nСессия завершена!")
sys.exit(0)
reply_text = request_to_llm_with_tools(user_request, system_prompt, chat_context, func_list)
if 'random_number' in reply_text:
print(get_random_number())
elif 'random_fruit' in reply_text:
print(get_random_fruit())
else:
print(reply_text)
chat_context.append({"role": "user", "text": user_request})
chat_context.append({"role": "assistant", "text": reply_text})
(venv1) root@server:~/ai# cat agent_email_or_cal_2.py
import os
import sys
import re
import json
from yandex_ai_studio_sdk import AIStudio
sdk = AIStudio(
folder_id=os.getenv("YANDEX_FOLDER_ID"),
auth=os.getenv("YANDEX_API_KEY")
)
# Функция-заглушка для отправки письма
def send_email(recipient_name: str, subject: str, body: str):
"""
Заглушка для отправки письма.
В реальном проекте здесь был бы код для отправки через SMTP или API почтового сервиса.
"""
print("\n" + "="*50)
print(f"[ОТПРАВКА ПИСЬМА]")
print(f"Получатель: {recipient_name}")
print(f"Тема: {subject}")
print(f"Тело письма:\n{body}")
print("="*50 + "\n")
print("[Заглушка] Письмо успешно отправлено (симуляция)")
# Функция для интеграции с календарем
def add_to_calendar(task_title: str):
"""
Ваша кастомная функция для добавления события в календарь.
"""
print(f"[Вызов функции]: Успешно добавлено в календарь: '{task_title}'")
# Функция для определения интента (что хочет пользователь)
def detect_intent(user_request: str):
"""
Первый этап: определяем намерение пользователя.
"""
system_prompt_intent = (
"Ты — ассистент, который анализирует команды пользователя и классифицирует их.\n"
"Определи, что просит сделать пользователь. Ответь строго в формате JSON.\n"
"Схема ответа JSON должна содержать только одно поле:\n"
"- 'intent': строка, может принимать значения: 'send_email', 'add_calendar' или 'unknown'.\n"
"\nПримеры:\n"
"Запрос: 'Отправь письмо Ивану с отчетом' -> {\"intent\": \"send_email\"}\n"
"Запрос: 'Напомни мне завтра в 15:00 созвониться' -> {\"intent\": \"add_calendar\"}\n"
"Запрос: 'Какая сегодня погода?' -> {\"intent\": \"unknown\"}"
)
messages = [
{"role": "system", "text": system_prompt_intent},
{"role": "user", "text": user_request}
]
model = sdk.chat.completions("yandexgpt").configure(temperature=0.1)
response = model.run(messages)
match = re.search(r"\{.*\}", response.choices[0].text, re.DOTALL)
if match:
try:
data = json.loads(match.group(0))
return data.get("intent", "unknown")
except json.JSONDecodeError:
return "unknown"
return "unknown"
# Функция для обработки отправки письма
def process_email(user_request: str):
"""
Второй этап: если определили, что нужно отправить письмо,
запрашиваем у модели составление темы и тела.
"""
system_prompt_email = (
"Ты — ассистент, который помогает составлять деловые письма.\n"
"Проанализируй запрос пользователя и составь письмо.\n"
"Ответь строго в формате JSON со следующими полями:\n"
"- 'recipient_name': имя получателя (строка). Извлеки из запроса.\n"
"- 'subject': тема письма (строка). Составь краткую и понятную тему.\n"
"- 'body': тело письма (строка). Напиши вежливое, содержательное письмо.\n"
"\nПравила:\n"
"- Тема должна быть краткой и отражать суть письма (максимум 5-7 слов)\n"
"- Тело письма должно быть вежливым, структурированным и соответствовать запросу\n"
"- Используй стандартный деловой тон\n"
"- Если в запросе не указано имя получателя, используй 'Уважаемый коллега'\n"
"\nПример:\n"
"Запрос: 'Отправь Ивану отчет по продажам за май'\n"
"Ответ: {\"recipient_name\": \"Иван\", \"subject\": \"Отчет по продажам за май\", \"body\": \"Здравствуйте, Иван!\\n\\nНаправляю вам отчет по продажам за май месяц. В отчете вы найдете детальную информацию по каждому региону и сравнительный анализ с прошлым месяцем.\\n\\nС уважением,\\nАссистент\"}"
)
messages = [
{"role": "system", "text": system_prompt_email},
{"role": "user", "text": user_request}
]
model = sdk.chat.completions("yandexgpt").configure(temperature=0.3)
response = model.run(messages)
match = re.search(r"\{.*\}", response.choices[0].text, re.DOTALL)
if match:
try:
data = json.loads(match.group(0))
return data
except json.JSONDecodeError:
return None
return None
# Функция для обработки добавления в календарь
def process_calendar(user_request: str):
"""
Второй этап: если определили, что нужно добавить в календарь,
запрашиваем у модели составление напоминания.
"""
system_prompt_calendar = (
"Ты — ассистент, который помогает создавать напоминания для календаря.\n"
"Проанализируй запрос пользователя и составь четкое напоминание.\n"
"Ответь строго в формате JSON с одним полем:\n"
"- 'calendar_task': текст напоминания (строка). Составь конкретное, понятное описание события.\n"
"\nПравила:\n"
"- Напоминание должно быть четким и конкретным\n"
"- Включай дату и время, если они указаны в запросе\n"
"- Формулируй как действие, которое нужно выполнить\n"
"\nПример:\n"
"Запрос: 'Напомни мне завтра в 15:00 созвониться с коллегами по проекту'\n"
"Ответ: {\"calendar_task\": \"Завтра в 15:00 созвониться с коллегами по проекту\"}"
)
messages = [
{"role": "system", "text": system_prompt_calendar},
{"role": "user", "text": user_request}
]
model = sdk.chat.completions("yandexgpt").configure(temperature=0.2)
response = model.run(messages)
match = re.search(r"\{.*\}", response.choices[0].text, re.DOTALL)
if match:
try:
data = json.loads(match.group(0))
return data
except json.JSONDecodeError:
return None
return None
# Основная логика
def main():
# Примеры для тестирования
#user_request = "Привет! Слушай, отправь пожалуйста письмо Ивану с отчетом по продажам за май."
user_request = "Напомни мне завтра в двенадцать созвониться с коллегами по проекту."
print(f"Запрос пользователя: {user_request}\n")
print("Обработка запроса...\n")
# Шаг 1: Определяем намерение
intent = detect_intent(user_request)
print(f"Определенное намерение: {intent}")
# Шаг 2: Обрабатываем в зависимости от намерения
if intent == "send_email":
print("\nСоставляю письмо...")
email_data = process_email(user_request)
if email_data:
recipient = email_data.get("recipient_name")
subject = email_data.get("subject")
body = email_data.get("body")
if subject and body:
print(f"✓ Письмо составлено успешно")
print(f" Получатель: {recipient}")
print(f" Тема: {subject}")
# Отправляем письмо
send_email(recipient, subject, body)
else:
print("✗ Не удалось составить письмо: недостаточно данных")
else:
print("✗ Ошибка при составлении письма")
elif intent == "add_calendar":
print("\nСоставляю напоминание...")
calendar_data = process_calendar(user_request)
if calendar_data:
task = calendar_data.get("calendar_task")
if task:
print(f"✓ Напоминание составлено: {task}")
add_to_calendar(task)
else:
print("✗ Не удалось составить напоминание")
else:
print("✗ Ошибка при составлении напоминания")
else:
print("\nКоманда не распознана. Я не могу обработать этот запрос.")
if __name__ == "__main__":
main()