язык_программирования_python

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
язык_программирования_python [2026/07/11 09:13]
val [request_to_agent.py]
язык_программирования_python [2026/07/13 15:52] (current)
val [ari_chat.py]
Line 1: Line 1:
 ====== Язык программирования Python ====== ====== Язык программирования Python ======
 +
 +  * [[Все что должен знать DevOps про Python]]
  
   * [[https://​habr.com/​ru/​articles/​277679/​|Пишем shell скрипты на Python и можно ли заменить им Bash]]   * [[https://​habr.com/​ru/​articles/​277679/​|Пишем shell скрипты на Python и можно ли заменить им Bash]]
Line 538: Line 540:
         chat_context.append({"​role":​ "​user",​ "​text":​ user_request})         chat_context.append({"​role":​ "​user",​ "​text":​ user_request})
         chat_context.append({"​role":​ "​assistant",​ "​text":​ reply_text})         chat_context.append({"​role":​ "​assistant",​ "​text":​ reply_text})
 +</​code>​
 +
 +==== ari_rec.py ====
 +<​code>​
 +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()
 </​code>​ </​code>​
  
Line 556: Line 688:
 SYSTEM_PROMPT = ( SYSTEM_PROMPT = (
     "Ты — ассистент.\n"​     "Ты — ассистент.\n"​
-    "​Отвечай кратко, проси продолжить диалог.\n"+    "​Отвечай кратко.\n"​
 ) )
  
Line 562: Line 694:
 # Структура:​ {channel_id:​ [{"​role":​ "​user",​ "​text":​ "​..."​},​ {"​role":​ "​assistant",​ "​text":​ "​..."​}]} # Структура:​ {channel_id:​ [{"​role":​ "​user",​ "​text":​ "​..."​},​ {"​role":​ "​assistant",​ "​text":​ "​..."​}]}
 channel_contexts = {} channel_contexts = {}
 +channel_caller_numbers = {}
  
 def get_channel_context(channel_id):​ def get_channel_context(channel_id):​
Line 573: Line 706:
     context.append({"​role":​ "​assistant",​ "​text":​ agent_response})     context.append({"​role":​ "​assistant",​ "​text":​ agent_response})
     return context     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):​ def start_recording(channel_id):​
Line 581: Line 726:
         "​name":​ recording_name,​         "​name":​ recording_name,​
         "​format":​ "​wav",​         "​format":​ "​wav",​
 +        "​ifExists":​ "​overwrite",​
         "​maxDuration":​ 5,         "​maxDuration":​ 5,
         "​terminateOn":​ "#",​         "​terminateOn":​ "#",​
-        "ifExists": ​"​overwrite"​+        "beep": ​True,
     }     }
     requests.post(record_url,​ params=record_payload,​ auth=AUTH)     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): def on_message(wsapp,​ message):
Line 591: Line 744:
     event_type = event.get("​type"​)     event_type = event.get("​type"​)
  
-    # Сценарий 1: Звонок поступил ​-> Отвечаем и включаем запись+    # Сценарий 1: Звонок поступил
     if event_type == "​StasisStart":​     if event_type == "​StasisStart":​
         channel_id = event.get("​channel",​ {}).get("​id"​)         channel_id = event.get("​channel",​ {}).get("​id"​)
Line 598: Line 751:
         requests.post(f"​{BASE_URL}/​channels/​{channel_id}/​answer",​ auth=AUTH)         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)         start_recording(channel_id)
  
Line 606: Line 761:
         target_uri = recording_data.get("​target_uri",​ ""​)         target_uri = recording_data.get("​target_uri",​ ""​)
         channel_id = target_uri.split("​channel:"​)[1]         channel_id = target_uri.split("​channel:"​)[1]
 +
 +        caller_number = channel_caller_numbers[channel_id]
 +        print(f"​Номер звонящего в RecordingFinished:​ {caller_number}"​)
  
         import wav_and_ogg         import wav_and_ogg
Line 614: Line 772:
         print(user_request)         print(user_request)
  
-        import request_to_agent 
         context = get_channel_context(channel_id)         context = get_channel_context(channel_id)
-        agent_response = request_to_agent.request_to_agent(user_request,​ SYSTEM_PROMPT,​ context) 
-        print(agent_response) 
  
 +        import request_to_agent
 +        agent_response = request_to_agent.request_to_agent(user_request,​ SYSTEM_PROMPT,​ context)
         #​agent_response = user_request         #​agent_response = user_request
 +
 +        print(agent_response)
  
         update_channel_context(channel_id,​ user_request,​ agent_response)         update_channel_context(channel_id,​ user_request,​ agent_response)
  
-        '''​ 
         print("​Текущий контекст:"​)         print("​Текущий контекст:"​)
         from pprint import pprint         from pprint import pprint
         pprint(channel_contexts)         pprint(channel_contexts)
-        '''​ 
  
         speech_and_text.text_to_speech(agent_response,​f"​{REC_PATH}{recording_name}.response.ogg"​)         speech_and_text.text_to_speech(agent_response,​f"​{REC_PATH}{recording_name}.response.ogg"​)
Line 641: Line 798:
         print("​Ответ ARI на воспроизведение:",​ response.status_code)         print("​Ответ ARI на воспроизведение:",​ response.status_code)
  
-    # Сценарий 3: Воспроизведение завершено ​-> Возвращаемся в режим записи...+    # Сценарий 3: Воспроизведение завершено
     elif event_type == "​PlaybackFinished":​     elif event_type == "​PlaybackFinished":​
         playback_data = event.get("​playback",​ {})         playback_data = event.get("​playback",​ {})
 +        media_uri = playback_data.get("​media_uri",​ ""​)
         target_uri = playback_data.get('​target_uri',​ ''​)         target_uri = playback_data.get('​target_uri',​ ''​)
         channel_id = target_uri.split("​channel:"​)[1]         channel_id = target_uri.split("​channel:"​)[1]
  
-        print(f"​Воспроизведение завершено. Возвращаемся в режим записи..."​) 
         start_recording(channel_id)         start_recording(channel_id)
  
-        '''​ +    # Сценарий 4: Абонент повесил ​трубку
-        print(f"​Вешаем трубку ​для channel_id {channel_id}"​) +
-        hangup_url = f"​{BASE_URL}/​channels/​{channel_id}"​ +
-        requests.delete(hangup_url,​ auth=AUTH) +
-        '''​ +
     elif event_type == "​StasisEnd":​     elif event_type == "​StasisEnd":​
         channel_id = event.get("​channel",​ {}).get("​id"​)         channel_id = event.get("​channel",​ {}).get("​id"​)
-        ​print(f"​Звонок завершен пользователем анал {channel_id}). Очистка ресурсов...")+ 
 +        context = get_channel_context(channel_id) 
 +        caller_number = channel_caller_numbers[channel_id] 
 +        ​print(f"​Номер звонящего в StasisEnd: ​номер {caller_number} канал {channel_id}") 
 + 
 +        print(f"​Сохранение контекста и удаление медиа файлов") 
 + 
 +        save_context(caller_number,​context) 
         import glob         import glob
         recording_name = f"​rec_{channel_id}"​         recording_name = f"​rec_{channel_id}"​
язык_программирования_python.1783750388.txt.gz · Last modified: 2026/07/11 09:13 by val