Распознавание голоса Tinkoff Voicekit

Для обработки сохраненных аудифовайлов можно использовать сервис для распознавания аудио Tinkoff.

В Google Colab подгрузим нужные бибиотеки:

!pip install tinkoff-voicekit-client protobuf==3.20.3
!pip install pydub # установка библиотеки pydub

from pydub import AudioSegment

Посмотрим, что за параметры у загруженного аудиофайла:

# чтение из файла любого формата
music = AudioSegment.from_file(file='call.mp3', format='mp3')

print("Продолжительность аудио, сек:", music.duration_seconds)
print("Частота дискретизации:", music.frame_rate)
print("Количество каналов:", music.channels)

Результат:

Продолжительность аудио, сек: 90.0
Частота дискретизации: 16000
Количество каналов: 2

Обрежем первые 15 секунд аудио. На моей записи там гудки. Не влияет на распознавание. Можно и не делать.

# представление 15 секунд в миллисекундах
time_to_cut = 15 * 1000

# обрезка файла при помощи индексации
#music[time_to_cut:]
# сохраним фрагмент в файл с заданной миллисекунды
music[time_to_cut:].export('cutted.mp3', format='mp3')

Для использования сервиса Tinkoff VoiceKit необходима регистрация на платформе https://software.tinkoff.ru/auth/login/

После регистрации на балансе будет 1000 рублей, которые можно использовать для тестирования сервиса.

После регистрации необходимо создать и сохранить 2 ключа: API-key и SECRET-key.

  • API_KEY можно сгенерировать в личном кабинете в разделе VoiceKit в любой момент времени.
  • SECRET_KEY генерируется автоматически только при получении первого API_KEY, потом SECRET_KEY будет недоступен, поэтому крайне ВАЖНО сразу его сохранить.

Передаем параметры для авторизации:

import getpass

# передаем API_KEY
API_KEY = getpass.getpass("Tinkoff API Key:")
# передаем SECRET_KEY
SECRET_KEY = getpass.getpass("Tinkoff SECRET Key:")

Метод Recognize

Используется для распознавания аудиофайлов разных форматов (mp3, wav, s16). Для транскрибации текста метод принимает словарь параметров:

audio_config = {"encoding": "MPEG_AUDIO",  
                "sample_rate_hertz": 16000,
                "num_channels": 2}

"encoding" - кодировка, может быть: 'LINEAR16', 'ALAW', 'MULAW', 'LINEAR32F', 'RAW_OPUS', 'MPEG_AUDIO';
"sample_rate_hertz" - частота дискретизации записи;
"num_channels" - количество каналов записи (1 или 2).

Для распознавания речи используем следующий код:

from tinkoff_voicekit_client import ClientSTT
from pprint import pprint

# создаем клиент, передаем ключи
client = ClientSTT(API_KEY, SECRET_KEY)

# указываем параметры аудио
audio_config = {
    "encoding": "MPEG_AUDIO",
    "sample_rate_hertz": music.frame_rate,
    "num_channels": music.channels,
    "enable_automatic_punctuation": True,
    }

# вызываем метод recognize
response = client.recognize("cutted.mp3", audio_config)
pprint(response)

При распечатке данных возвращаемого объекта:

{'results': [{'alternatives': [{'confidence': -3.803578,
                                'transcript': 'Алло.',
                                'words': [{'confidence': 0.0,
                                           'end_time': '3.270s',
                                           'start_time': '3.060s',
                                           'word': 'алло'}]}],
              'channel': 1,
              'end_time': '3.270s',
              'start_time': '3.060s'},
             {'alternatives': [{'confidence': -4.384712,
                                'transcript': 'Здравствуйте, Алина.',
                                'words': [{'confidence': 0.0,
                                           'end_time': '4.320s',
                                           'start_time': '3.870s',
                                           'word': 'здравствуйте'},
                                          {'confidence': 0.0,
                                           'end_time': '4.710s',
                                           'start_time': '4.410s',
                                           'word': 'алина'}]}],
              'channel': 0,
              'end_time': '4.710s',
              'start_time': '3.870s'},
...
]}

В исходной записи звонок записан на два канала:

  • 0-й канал — то, что говорит менеджер.
  • 1-й канал — речь клиента.
for fragment in response['results']:
  alternatives = fragment['alternatives']
  for alternative in alternatives:
    str = ""
    if fragment['channel'] == 0:
      str += "Менеджер:"
    else:
      str += "Клиент:"
    str += " " + alternative["transcript"] + "\t[Start: " + fragment["start_time"] + ", End: " + fragment["end_time"] + "]"
    print(str)

Результат распознавания:

Клиент: Алло.	[Start: 3.060s, End: 3.270s]
Менеджер: Здравствуйте, Алина.	[Start: 3.870s, End: 4.710s]

Для удобства можно перевести время в секундах в миллисекунды, чтобы можно было оперативно прослушать фразу, которая плохо распозналась:

def strTimeToInt(strtime):
  strtime = strtime.replace("s","")
  return int(float(strtime)*1000)

strTimeToInt("3.060s")

for fragment in response['results']:
  alternatives = fragment['alternatives']
  for alternative in alternatives:
    text = ""
    if fragment['channel'] == 0:
      text += "Менеджер:"
    else:
      text += "Клиент:"
    start_time = str(strTimeToInt(fragment["start_time"]))
    end_time = str(strTimeToInt(fragment["end_time"]))
    text += " " + alternative["transcript"] + "\tmusic[" +  start_time + ":" + end_time + "]"
    print(text)

Тогда получаем:

Клиент: Алло.	music[3060:3270]
Менеджер: Здравствуйте, Алина.	music[3870:4710]

Вставляя код

music[3060:3270]

в cell Colab получаем возможность прослушать выбранный фрагмент.

Рубрика: IT рецепты | Оставить комментарий

FastAPI на Colab через ngrok и uvicorn на Python

Столкнулся тут с проблемкой. Нужно было запустить FastAPI через uvicorn. При этом обращения с сервера должны были идти на API OpenAI. Код писал на Python в VSCode. Запустить надо было по-быстрому. Нормальных VPN не нашел. «Спасибо» добрякам из Роскомнадзора…

В общем, как самый быстрый способ проверки работоспособностии работы OpenAI API с FastAPI получился такой:

  • На ПК установлен Yandex Disk. На нем создана папка проекта.
  • В VSCode проект на Python сохраняется на Yandex Disk.
  • В Colab во первых строках кода исходники проекта скачиваются в локальную папку и добавляются в путь для поиска модулей.
  • Как скачать и развернуть файлы проекта в Google Colab с Yandex Disk описано в другой статье.
  • Подготавливается FastAPI.
  • Поднимается ngrok.
  • Запускается uvicorn.

Для подготовки FastAPI к запуску пример кода:

!pip install fastapi nest-asyncio pyngrok uvicorn

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=['*'],
    allow_credentials=True,
    allow_methods=['*'],
    allow_headers=['*'],
)

# класс с типами данных параметров 
class Item(BaseModel): 
    text: str

# функция обработки get запроса + декоратор 
@app.get("/")
async def read_root():
    return {"message": "answer"}

@app.get("/api/access_counter")
async def get_accesscouner():
  counter = chunk.get_accesscouner()
  return {"access_counter": counter}

# функция обработки post запроса + декоратор 
@app.post("/api/get_answer")
async def get_answer(question: Item):
    answer = chunk.get_answer(query=question.text)
    return {"message": answer}

Далее поднимаем ngrok. Передаем токен полученный при регистрации на Ngrok и предварительно сохраненый в .env. Подгружаем его через load_dotenv из папки загруженными с Yandex Disk исходниками:

  dotenv_path = "/content/" + dirs[0] + "/.env"
  load_dotenv(dotenv_path)

и запускаем веб сервер uvicorn:

import nest_asyncio
from pyngrok import ngrok
import uvicorn

ngrok.set_auth_token(os.environ.get("NGROK_AUTHTOKEN"))

ngrok_tunnel = ngrok.connect(8000)
print('Public URL:', ngrok_tunnel.public_url)
nest_asyncio.apply()
uvicorn.run(app, port=8000)

Сервер uvicorn повисает на временно сгенерированном ngrok внешнем домене.

Для бесплатных пользователей при создании аккаунта на Ngrok предоставляется один домен, который нужно создать в консоли ngrok (CloudEdge -> Domains). Выглядит он как-то так: «xxx.ngrok-free.app». Несколько доменов можно создать, купив платную подписку, но с проплатой из России проблемки. 🙂

Веб сервер Uvicorn туннелируется (пробрасывается) из Colab наружу через Ngrok и становится доступным для обращений по сгенерированному на Ngrok доменному имени. При обращениях по доменному имени запросы перенаправляются через Ngrok в Colab на Uvicorn и ответы возвращаются обратно.

ngrok_tunnel = ngrok.connect(8000, domain="your_domain.ngrok-free.app")

Возможно, есть достойные альтернативы ngrok, но времени на эксперименты не было.

Public URL: https://bb2f-34-16-145-243.ngrok-free.app
INFO:     Started server process [23974]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     81.222.179.30:0 - "GET /api/access_counter HTTP/1.1" 200 OK
INFO:     81.222.179.30:0 - "GET /api/access_counter HTTP/1.1" 200 OK
INFO:     Shutting down
INFO:     Waiting for application shutdown.
INFO:     Application shutdown complete.
INFO:     Finished server process [23974]

К сожалению, ячейка Colab запускается не асинхронно, т.е. управление с неё не передается на следующую ячейку. Гипотетически можно это обойти, запустив сервер через командную строку.

Для простоты я для тестирования использовал Postman. Вот так выглядит отправка запроса к серверу поднятому через ngrok на Colab.

Нюансы отправки REST API с помощью JavaScript через Ngrok

При отправке GET запросов на сервер через ngrok наверняка столкнетесь с тем, что стандартный JavaScript запрос выдает ошибку вида:

"Unexpected token '<', \"<!DOCTYPE \"... is not valid JSON"

или

Unexpected token '<', \"<!DOCTYPE ";... is not valid JSON"

При этом POST запрос у меня почему-то проходил без вопросов. Я сломал всю голову, не понимая, что происходит, поскольку в браузере и в Postman возвращался нормальный JSON и только при запуске обращения к сервере через JavaScript возникала эта ошибка. Затем наткнулся на этот сервер: https://reqbin.com/post-online для проверки GET запросов. Подсунув туда URL на ngrok я получил в response HTML страницу, вместо JSON.

Странно, что при отправке запросов через Postman и другие сервера они всегда возвращали правильный JSON. Чтобы bypass ngrok browser warning нужно добавить в header строку:

'ngrok-skip-browser-warning': 'any'

Добавление нестандартного User-Agent, как указано в рекомендациях, проблему решает в https://reqbin.com/post-online, но при вызове в JavaScript возникает та-же ошибка. Рабочий JavaScript код для обхода ошибки:

&lt;script>
const url = 'https://xxx.ngrok-free.app/api/counter';
//const url = "https://jsonplaceholder.typicode.com/posts/1";
var headers = new Headers(
	{
        'User-Agent': 'PostmanRuntime/7.36.0',
        'Accept': 'application/json',
        'ngrok-skip-browser-warning': 'any',
        'Host': 'hugely-easy-pipefish.ngrok-free.app',
        'Content-Type': 'application/json'
  }
)
fetch(url, {
    method: "GET",
    headers: headers,  
    redirect: "follow"
  }
).then(response => {
    //console.log(response);
    return response.json();
  }
).then(data => {
    console.log(data);
  }  
).catch(error => {
    console.log(error.message);
  }
)
&lt;/script>

Запускать скрипт для отладки удобно в https://jsfiddle.net/. Если раскомментарить строчку console.log(response), то в консоли jsfiddle отобразится объект response со всеми свойствами и методами.

Рубрика: IT рецепты | Оставить комментарий

Скачивание данных с Yandex.Disk с помощью Python

При работе на Google Colab-е столкнулся с ситуацией, когда потребовалось скачать исходники разработанного модуля с Яндекс Диска (Yandex.Disk) на локальный диск Colab. Регистрация приложения для использования библиотеки YaDisk довольно небыстрая. Но можно сделать, если есть время. Ссылка.

Я пошел альтернативным способом, через выдирание параметров авторизации из опубликованной в Яндекс Диск ссылки. Так гораздо проще для простых реализаций.

При скачивании папки с Яндекс Диска в виде архива нужно извлечь папки. У меня все модули Python в одной папке, поэтому интересовала только корневая.

import zipfile, io, os, sys

#Извлекаем директории из архива
def getZipDirs(zip_f, isRootDirOnly = False, addPath = True):
  dirs = []
  for f in zip_f.namelist():
    zinfo = zip_f.getinfo(f)
    if zinfo.is_dir():
      if isRootDirOnly:     # Only root directories:
        # This is will work in any OS because the zip format specifies a forward slash.
        r_dir = f.split('/')
        r_dir = r_dir[0]
        if r_dir not in dirs:
          dirs.append(r_dir)
      else: # All directories:
          dirs.append(f)
  if addPath:
    for dir in dirs:
      sys.path.append(os.path.abspath('/content/' + dir + "/"))        
  return dirs

У функции скачивания файла с Yandex Disk два параметра:

  • url — путь к файлу или папке (например, https://disk.yandex.ru/d/rVVprjVVV2hS-w)
  • isZip — если передан путь к папке, то True, поскольку её содержимое вернется в Zip архиве. Если скачивание текстового файла, то False.

В этой функции архив сразу распаковывается на диск Colab и прописывается в путях для импортирования модуля.

import requests, sys

#url - путь к файлу или папке
#isZip - если передан путь к папке, то её содержимое вернется в Zip архиве
def loadTextFromYandexDisk(url: str, isZip = False):
  base_url = 'https://cloud-api.yandex.net/v1/disk/public/resources/download?'
  final_url = base_url + urlencode(dict(public_key=url))
  response = requests.get(final_url)
  download_url = response.json()['href']
  download_response = requests.get(download_url)
 
  if isZip:
    zip = zipfile.ZipFile(io.BytesIO(download_response.content))
    dirs = getZipDirs(zip, True)
    zip.extractall("/content/")
  else:  
    download_response.encoding = download_response.apparent_encoding
    return download_response.text 

Не забываем добавлять в начало кода код для автозагрузки модуля при обновлении исходников.

%load_ext autoreload
%autoreload 2 #Reload all modules (except those excluded by %aimport) every time before executing the Python code typed.
Рубрика: IT рецепты | Оставить комментарий

Соединение более 3-х силовых кабелей под клеммную колодку контактора/автомата

Иногда возникает необходимость под прижимной зажим контактора или автомата притянуть более 2-х силовых проводов. Например, в электрических котлах на каждую фазу может подключаться 3 реле (9 ступеней), соответственно, 3 провода надо завести под клеммник, что несколько противоречит требованиями ГОСТ/ПУЭ.

Если это разделка одного распределительного шкафа, то все довольно легко, достаточно использовать клеммные сборки или шины, вариантов много. Но что делать, если такую коммутацию надо сделать в серийном электроприборе, где цена лишнего компонента значительно скмзывается на розничной цене для потребителя? Каждый винтовой узел добавляет брака при сборке из-за недотяжки, разбалтывании при транспортировке, при вибрации внутри прибора и пр.

Самый простой вариант скоммутировать под одну клеммную колодку контактора/автомата три многожильных медных провода без нарушения ПУЭ/ГОСТ — использовать комбинацию концов НШВИ + НШВИ(2). При этом:

  1. П 3.4.7 ПУЭ «Присоединение двух медных жил кабеля под один винт не рекомендуется, а двух алюминиевых жил не допускается.». Материал коннектора у KBT: медь марки М1.
  2. Согласно ГОСТ 10434-82 «СОЕДИНЕНИЯ КОНТАКТНЫЕ ЭЛЕКТРИЧЕСКИЕ». 2.1.12. К каждому болту (винту) плоского вывода или к штыревому выводу рекомендуется присоединять НЕ БОЛЕЕ двух проводников, если иное не указано в стандартах или технических условиях на электротехнические устройства конкретных видов.
  3. Соответственно, оба стандарта НЕ РЕКОМЕНДУЮТ, но и НЕ ЗАПРЕЩАЮТ соединять два МЕДНЫХ кабеля.
  4. НШВИ(2) — это стандартный наконечник под два провода. Возможно, с этим и есть какие-то проблемы в части надежности такого способа соединения, но он вполне допустим.
  5. «К каждому болту (винту) плоского вывода или к штыревому выводу рекомендуется присоединять не более двух проводников». Многожильный проводник при заведении под клеммную колодку контактора, по-правилам, гильзуется, в т.ч. НШВИ. Соответственно, не запрещено вводить два НШВИ+НШВИ, хоть и не рекомендуется.
  6. При заведении вместо двух НШВИ+НШВИ двух наконечников НШВИ + НШВИ(2) под пластину клеммной колодки контактора вполне допустимо.

Однако, есть риск, что при опрессовке НШВИ и НШВИ(2) высоты опрессованных концов могут немного отличаться. При прижатии планкой может возникнуть чуть более худший контакт у одного из проводников и разогрев на больших токах в этом месте. Но это гипотеза. Она ровно также может быть при опрессовке двух концов НШВИ + НШВИ. 

Винтовое соединение, по опыту — это один из наиболее браконосных узлов при серийном производстве, поскольку его могут недотянуть, не исключено разбалтывание при транспортировке, при вибрации от работы насоса и пр. Чем меньше винтовых соединений, тем лучше.

При таком соединении 3-х проводов к каждой клемме контактора получается ВСЕГО!!! 3-и винтовых соединения по два конца НШВИ + НШВИ(2). Причем, в зависимости от типа реализации способа прижатия конца провода в контакторе, риски из-за разной толщины могут нивелироваться.

Соотвественно, такое решение:

  1. Не запрещено ГОСТ/ПУЭ, хоть и не является рекомендованным. 
  2. Минимум винтовых соединений, соответственно в разы сокращается брак.
  3. Очень дешевое. Переход на клеммные сборки — это приличный рост себестоимости готового изделия.
  4. Достаточно надежное при правильном исполнении: обжимка и затяжка.
  5. Наименее трудозатратное при сборке.
  6. Очень компактное.
  7. Проверенное годами эксплуатации. Брак из-за сборки минимальный. В ходе эксплуатции решение хорошо себя зарекомендовало при качественном контакторе, когда не экономят на меди и серебре.

Предположим, чтобы было красиво и правильно переходим на винтовые клеммные сборки или шины по одному проводу в гнездо, как полагается. Тогда:

  1. Есть 3 винта на контакторе + 3 винта на переход кабеля от контактора на клеммную сборку + 3 винта под каждый провод на одной фазе. Итого получаем: 3 + 3 + 3 * 3 фазы = 15 винтов.
  2. Кол-ва брака возрастает в несколько раз, поскольку на каждой затяжке винта увеличается риск получения нагрева.
  3. Хотя здесь нагрев будет другим. Он будет распределятся по значительно большей площади металла.
  4. Трудозатраты при сборке возрастают в 5 раз.

Казалось бы, решение оптимальное, ничему не противоречит, но нарекания при эксплуатации все-же случаются. Сам контактор при низком уровне серебра на контактах (возможно, что и при нормальном тоже) и/или при неполном соединении контактов при пониженном напряжении на катушке и пр. моментах — также разогревается.

Соответственно, имеем разогрев контакта контактора при срабатывании. Тепло от него по медной пластине передается на клеммник. К этому добавляется ещё разогрев клеммника контактора если плохо поджаты НШВИ. Эти две генерации тепла находятся близко друг от друга, увеличивая температуру разогрева, при малой площади теплоотведения.

На дорогих и качественных контакторах такого не происходит:

  • Медные проводники взяты с запасом, что позволяет рассеивать тепло.
  • На контатках достаточно серебра, чтобы контакт был хорошим и разогрев был минимальным.
  • Сам механизм прижатия вводимых кабелей обеспечивает плотное примыкание.

Чтобы нивелировать проблемы при некачественном контакторе напрашивается простое и дешевое решение — использовать повышенное сечение жилы кабеля подводимого к контактору. Например, если расчетное сечение 2,5 мм2, то использовать 4 мм2. С увеличением диаметра жилы увеличится и диаметр гильзы НШВИ. В совокупности это позволит:

  • Увеличить площадь контакта за счет большеей площади опрессованного наконечника.
  • Лучше отводить тепло от контакта контактора за счет большей площади сечения провода.
  • Распределять тепло более равномерно, чтобы не допускать перегревания изоляции.  

Клеммники на DIN рейку

Если делать более красивый вариант с клеммными сборками или шинами. Про количество винтовых соединений и роста брака из-за этого я уже написал. Однако, есть и плюсы:

  1. Если на контакторе только один НШВИ, контакт, несомненно, будет лучше из-за отсутствия перепада высот на двух наконечниках.
  2. Уменьшается риск неподжатия контактом клеммы контактора наконечника НШВИ. Это приведет к снижению разогрева.
  3. Кабель от контактора до клеммника рассеивает тепло. Его диаметр нужно брать с запасом. Например, вместо расчетных 2,5 мм2 брать 4 мм2, чтобы отводить тепло от контактора максимально эффективно.
  4. Появляется металл клеммника к которому приходит кабель от контактора, дополнительно рассеивая тепло. До него тепло вряд ли дойдет, но все-же…

Остается вопрос что делать с клеммными блоками. Если ставить качественные клеммные блоки, то их нужно много, поскольку только на клеммный блок с болтовым соединением можно завести два провода. Например, на такой https://youtu.be/XD5f-v9AjQQ?si=OS2nZ6PW_OKD-Dyi.

Остальные типы фиксиации в клеммныом блоке не позволят ввести два провода в одно гнездо. Хотя некоторые клеммники позволяют заводить по два провода с каждой стороны, но тогда, как правило, увеличивается количество винтовых соединений. Придется либо использовать НШВИ(2), либо увеличивать количество клеммных блоков, соединяя их заводской перемычкой. Итого получаем:

  • Нужны секции клемников, которые допускают установку перемычки.
  • Тогда на каждую фазу нам нужно две секции и перемычка на два клеммника.
  • Клеммник должен позволять заводить кабель 4 мм2 и 2,5 мм2, либо придется ставить два разных клеммника.
  • Соединяем два клеммника друг с другом заводской перемычкой.
  • Заводим один провод 4 мм2 от контактора.
  • Заводим 3 провода 2,5 мм2 в три оставшихся гнезда клеммника.
  • Итого на каждую фазу 6 секций клеммника и 3 перемычки на 2.
  • Ценник будет приличный.

Примерно вот так это выглядит на котле Lemax Pro Plus:

Можно использовать недорогой клеммник с болтовым соединением и гроверной шайбой для исключения разбалтывания от вибрации. Он существенно более трудозатратный при сборке, однако обеспечивает лучший контакт. Подгорать будет (если будет) более дешевый клеммник, а не контактор. Клеммник можно взять, например, такой:

Решение также не идеальное:

  1. С каждой стороны клеммы придется под болт загонять по 2 провода. Это будет также не рекомендуемым, но допустимым вариантом.
  2. Вот здесь показано, что до 2-х концов можно использовать https://youtu.be/XD5f-v9AjQQ?si=OS2nZ6PW_OKD-Dyi и это рекомендации от Феникса.
  3. Соответственно оконцовывать надо вот такими концами, поскольку U-образные не позволят обеспечить качественный контакт при накладывании друг на друга.
  4. Это, несомненно, более трудозатратный вариант при сборке, чем ввести провод в контактор и затянуть динамометрической отверткой.

Наконечники кольцевые изолированные с ПВХ манжетой

Хотя есть более компактное решение под тип наконечников нередко используемых на силовых реле. Так называемый «tab connector terminal block«. Он более «плотный» для компоновки.

Tab connector terminal block

Интересный вариант плотного клеммника с хорошей изоляцией, т.е. минимальным риском для монтажника, на DIN рейку с возможностью установки перемычки CTC4U (каталог):

Под вилки РПИ-М. Вроде такой:

Есть ещё вот такие power distubution blocks http://www.blox-electric.com/list/post/2385969/, но таких надо 3 шт. на каждую фазу и стоят они в районе 250 руб. При габаритах 66x27x46 займет немало места.

Насколько значительно улучшается качество контакта/снижается уровень брака в процессе эксплуатции при использовании дополнительных клеммных блоков сказать сложно. Но точно увеличивается себестоимость и увеличивается место под дополнительные компоненты.

Рубрика: Лайфхаки | Оставить комментарий

Проверка в AimyLogic создания дубликата записи смарт-процесса в Битрикс (REST API)

В продолжение другой статьи по теме интеграции Aimylogic c Битрикс рассмотрим как реализовать следующий алгоритм:

  • Клиент звонит и попадает на голосовой бот. Оставляет заявку в ServiceDesk (например, Битрикс).
  • Время обработки сервисным инженером заявки, созданной голосовым ботом, например, 2 дня.
  • Нетерпеливый пользователь, не дождавшись звонка от инженера, повторно звонит и попадает на голосового бота Aimylogic.
  • Голосовой бот должен посмотреть, за последнее время были ли созданы заявки от пользователя с того-же номера.
  • Если такие заявки есть, то голосовой бот должен успокоить клиента, сообщив, что в системе уже есть заявка. Звонок связан с новой проблемой или с ранее зарегистрированной.
  • Если клиент озвучит, что проблема другая, то должна создастся новая заявка.

Получение контакта клиента в Bitrix через REST API

Итак, Aimylogic определил с какого номера пришел звонок и ему нужно по этому номеру определить сервисные заявки для которых указан контакт с этим номером. Для определения есть ли клиент с указанным номером $client_phone в базе контактов Битриска используется следующий запрос:

https://xxxxxxxx.ru/rest/177/xxxxxxxxxxxx/crm.duplicate.findbycomm.json

{
"entity_type": "CONTACT",
"type": "PHONE",
"values": [ "$client_phone" ]
}

В ответе берем переменную $httpResponse.result в которой передается ID контакта.

Напомню, что добавляли смарт-процесс используя следующий POST запрос:

https://xxxxxxxxxxx.ru/rest/177/xxxxxxxxxxxxxxx/crm.item.add.json

{
"entityTypeId": "158",
"fields": {
"SOURCE_ID": "14",
"contactId": "$contact_id",
"ufCrm3_1680255422": "$equipment", 
"ufCrm3_1680254883": "$client_city",
"ufCrm3_1680261235": "$question",
"ufCrm3_1687168305": "$mobilePhone", 
"ufCrm3_1680261458": "$productiondate",
"ufCrm3_1697115862": "$equipment_state"
}
}

Соответственно, нам надо получить список смарт-процессов «сервисная заявка» у которых в поле «contactId» прописан полученный ранее ID контакта. Протестируем запрос в Postman на примере контакта с известным номером мобильного телефона. Получим несколько ID по номеру:

{
    "result": {
        "CONTACT": [
            14116,
            14118
        ]
    },
    "time": {
        "start": 1699808317.849979,
        "finish": 1699808317.890918,
        "duration": 0.0409390926361084,
        "processing": 0.004055976867675781,
        "date_start": "2023-11-12T19:58:37+03:00",
        "date_finish": "2023-11-12T19:58:37+03:00"
    }
}

Видим, что с указанным номером в Битриксе есть два контакта. Контакты были созданы через разные источники. Например, через форму обратной связи и обращение через голосового бота. Считаем, что это аномалия, которую надо устранить дополнительной проверкой, чтобы исключить дублирование при создании контактов с одним номером телефона.

Посмотрим как выглядит ответ для номера у которого точно один контакт в Битриксе:

{
    "result": {
        "CONTACT": [
            14111
        ]
    },
    "time": {
        "start": 1699809721.426188,
        "finish": 1699809721.46897,
        "duration": 0.04278206825256348,
        "processing": 0.005627155303955078,
        "date_start": "2023-11-12T20:22:01+03:00",
        "date_finish": "2023-11-12T20:22:01+03:00"
    }
}

Тот-же массив «CONTACT», т.е. нам достаточно в Aimylogic взять первый элемент в этом массиве.

function getContact(contacts) {
    
    try {
        $obj = JSON.parse(contacts);

        if ("CONTACT" in $obj) {
            if ($obj.CONTACT.length > 0)
            {
                $contact = $obj.CONTACT[0];
            }
        }
    } catch (e) {
        return -1   
    }
    return $contact
}

$contact = getContact($contacts)

Получение сервисной заявки (смарт-процесс) клиента в Bitrix через REST API

Чтобы получить сервисную заявку к которой привязан найденный контакт воспользуемся методом crm.item.list:

https://xxxxxxxxx.ru/rest/177/xxxxxxxxxxxxx/crm.item.list.json 

{
    "entityTypeId": 158,
    "filter": {
        "=contactId": "14111"
    }
}

После выполнения запроса к Битриксу получаем JSON в котором возвращается найденная сервисная заявка со всеми нужными нам полями. Полей много, поэтому заменил на …….

{
    "result": {
        "items": [
            {
                "id": 2214,
                "title": "Сервисная заявка #2214",
                "contactId": 14111,
........
                "entityTypeId": 158
            }
        ]
    },
    "total": 1,
    "time": {
        "start": 1699811918.669397,
        "finish": 1699811918.71892,
        "duration": 0.04952287673950195,
        "processing": 0.021754980087280273,
        "date_start": "2023-11-12T20:58:38+03:00",
        "date_finish": "2023-11-12T20:58:38+03:00"
    }
}

Чтобы сократить нагрузку на сервер и сократить трафик, можно выбирать в запросе только нужные поля:

{
    "entityTypeId": 158,
    "select": ["contactId", "stageId", "id", "createdTime"],
    "filter": {
        "=contactId": "14111" 
    }
}

Соответственно, создаем в AimyLogic HTTP запрос POST к методу crm.item.list.json и в body прописываем:

{
    "entityTypeId": 158,
    "filter": {
        "=contactId": "$contact"
    }
}

Результат $httpResponse.result помещаем в переменную $items. И далее обрабатываем полученный JSON следующим образом:

function getItem(items) {
    try {
        $obj = JSON.parse(items);

        if ($obj.items) {
            if ($obj.items.length > 0)
            {
                $item = $obj.items[0];
            }
        }
    } catch (e) {
        return -1
    }
    return $item
}

$item = getItem($items);
$item_created = -1;
if ($item != -1) {
    $item_id = $item.id;
    $item_created = $item.createdTime;
}

Все отрабатывает нормально. Получаем сервисную заявку и берем дату создания.

Определение срока давности сервисной заявки

Осталось найти разность между моментом, когда клиент позвонил повторно и датой ранее созданной сервисной заявки:

function getDateDifference(isoDateStr)
{
    try {
        $date1 = new Date(isoDateStr);
        $date2 = new Date();
        return ($date2.getTime() - $date1.getTime()) / (1000 * 3600 * 24); 
    } catch (e) {
        return Number.MAX_VALUE;
    }
}

if ($item_created != -1) {
    $daysdiff = getDateDifference($item_created);
}

Блоки кода целесообразно вставлять в блоки условий перед проверкой условия. Т.е. проверяем, что результат на выходе функции равен -1 и тогда отправляем на сообщение об ошибке, точнее отправляем клиента по стандартному маршруту, когда бот будет задавать ему перечень стандартных вопросов. По ветке else отправляем на следующий этап обработки.

Можно реализовать проверку на дату непосредственно в запросе на поиск нужных сервисных заявок (смарт-процессов). Для этого нам надо отфильтровать заявки у которых поле createdTime старше текущей даты не более, чем на n дней. Т.е. берем текущую дату, вычитаем n дней и смотрим все записи у которых createdTime больше полученной даты.

{
    "filter": {
        ">createdTime":"2020-03-19T02:00:00+02:00"
    }
} 

Пример финального запроса будет выглядеть следующим образом:

https://xxxxxxxxx.ru/rest/177/xxxxxxxxxxxxx/crm.item.list.json 

{
    "entityTypeId": 158,
    "select": ["contactId", "stageId", "id", "createdTime"],
    "filter": {
        "=contactId": "14111",
        ">createdTime": "2023-11-11T15:08:13+03:00" 
    }
}

Итак, после обработки полученной даты создания сервисной заявки получили разность дат в днях и можно принимать решения, озвучить клиенту, что он недавно создал заявку и она в обработке или позволить создать новую заявку. Можно дополнительно уточнить у клиента, обращение по старой заявке или какая-то новая проблема.

В этот запрос надо ещё добавить поиск только тех заявок у которых статус stageId удовлетворяет необходимым. Например, если stageId — SUCCESS, при этом дата создания заявки менее n дней назад, то:

  • Либо что-то пошло не так и у клиента возникли проблемы с этой заявкой. Тогда нужно спросить его об этом и сменить статус (переоткрыть), чтобы доделать.
  • Либо у клиента действительно все решено, но возник новый вопрос и надо создать новую заявку.

Поскольку здесь действия вариативные, нельзя включать в предфильтрацию stageId и фильтровать, например, только заявки у которых состояние SUCCESS.

Определение даты создания самой свежей сервисной заявки

Теперь нужно учесть момент, что у клиента с одним и тем-же номером телефона, но, например, несколькими контактами в Битриксе, может быть несколько сервисных заявок созданных в разное время. Соответственно, нужно пройтись по всем его заявкам и найти самую свежую. Гипотетически, если заявка была создана относительно недавно (в пределах 2-3 дней), то пользователь перезванивает по ней, поскольку сервиcные инженеры ещё не дошли.

После выполнения HTTP запроса на получение списка контактов, конвертируем в массив $contacts.

function getContact(contacts) {
    
    try {
        $obj = JSON.parse(contacts);

        if ("CONTACT" in $obj) {
            if ($obj.CONTACT.length > 0)
            {
                return $obj.CONTACT;
            }
        }
    } catch (e) {
        return -1   
    }
}

$contacts = getContact($contacts);

Склеиваем элементы массива в строку для передачи в HTTP POST запрос. Из id контактов должно получится что-то вроде: [«14116», «14118», «14142»]

//Функция склеивает массив в строку для POST запроса. Например, ["14116", "14118", "14142"]
function getContactsList(contacts)
{
    try {
        return "[\"" + contacts.join("\", \"") + "\"]";
    } catch (e)
    {
        return "[]";
    }
}

$contacts_str = getContactsList($contacts)

Теперь подаем результат в HTTP POST запрос Aimylogic.

{
    "entityTypeId": 158,
    "select": ["contactId", "stageId", "id", "createdTime"],
    "filter": {
        "=contactId": "$contacts_str",
        ">createdTime": "$minStartDate" 
    }
}

После выполнения запроса в переменной $items = $httpResponse.result будет JSON с массивом ВСЕХ сервисных заявок, которые привязаны к ВСЕМ номеру телефона клиента.

Ну и далее перебираем все даты создания сервисных заявок и находим сервисную заявку с наиболее близкой датой.

function getNewestItem(items) {
    try {
        $obj = JSON.parse(items);
        $lastDate = new Date(1975, 10, 16); //Инициализируем произвольной датой в прошлом. 

        $newest_item = -1;
        if ($obj.items) {
            if ($obj.items.length > 0)
            {
                for ($i = 0; $i &lt; $obj.items.length; $i++) {
                    try
                    {
                        $item = $obj.items[$i];
                        $item_currentDate = new Date($item.createdTime);
                        if ($item_currentDate > $lastDate)
                        {
                            $lastDate = $item_currentDate;
                            $newest_item = $item;
                        }
                    } catch (e) {                    
                    } 
                }
                return $newest_item;
            }
        }
        return -1;
    } catch (e) {
        return -1;
    }
}

$item = getNewestItem($items)

Высчитываем разность между датами, как делали это раньше. Для диагностики при отладке можно вывести информацию в блоке «Синтез речи»:

if ($item != -1) {
    $item_created = $item.createdTime;
    $date1 = new Date($item_created);
    $date2 = new Date();
    $daysdiff = getDateDifference($item_created);
}

Далее алгоритм Aimylogic затачиваем под проверку разницы дат и дополнительным вопросам, а уверен ли пользователь, что это не повторная заявка.

Рубрика: IT рецепты | Оставить комментарий

Мамы, дети и исключение отца

Что меня всегда угнетало в некоторых женщинах — это патологическая обидчивость и потом желание наказать безмолвием. Ну типа, прочувствуй свою вину сам. 🙂 Я слова не скажу, чтобы ты сам понял, какой-же ты негодяй. Не важно, что мужчина нередко не особо понимает на что именно взъелась супруга. С т.з. женщины это никак не влияет на воспитательный процесс. 🙂

В общем-то до какого-то возраста меня это задевало. Потом, уже после развода, особо перестало напрягать, хотя недоумение осталось.

Крайнее проявление такого подхода — приучение детей, дочерей в первую очередь, ровно к такому-же деструктивному подходу. Подход реально патологический, поскольку он не приводит к какой-то конструктивному диалогу, чтобы разобраться и найти компромисс. Это продавливание своей точки зрения психологически давящим способом — изоляцией.

Изгнание из социума в древности было одним из самых серьезных наказаний. Без общины человек с высокой вероятностью был обречен на смерть. Получается женщина выбирает самый антигуманный и наиболее действенный, с её точки зрения, подход, чтобы что-то продавить. Конечно, искать компромисс — куда более энергетически сложная задача.

В стае волков исключение особи из стаи фактически означало, что изгнанный будет питаться чем-то вроде лягушек. Загнать крупную добычу без соплеменников не получится. Нечто подобное было и у человека. Лиши его крова, огня и поддержки группы и выживать будет гораздо сложнее.

В расстановках по Берту Хеллингеру есть закон принадлежности, которому, по опыту автора, следуют системы. При его принудительном нарушении система пытается компенсировать исключение человека, перенося его линию поведения (или что-то, что визуально нами считывается как линия поведения) на другого с наименьшими связами с системой. Это, как правило, всегда дети, поскольку по закону порядка они наименее важны для системы, т.к. пришли в неё последними.

На обучении по бизнес-расстановкам Олег Вайнберг приводил такой пример. Если из середины стены (система) извлечь кирпич (элемент системы — человек), то она становится менее прочной. Система стремится залатать брешь, поэтому берет кирпич с самого верха стены (ребенок), у которого связи с другими элементами системы минимальны и ставит его на место извлеченного элемента. Своебразное самолечение. 🙂

Грубо говоря, женщина обиделись на мужа и решила стереть из своей памяти и памяти ребенка любое воспоминание о нем, оборвать все связи. Она начинает целенаправлено исключать любые упоминания и наказывать ребенка за то, что он вспоминает отца. Наказание может выражаться вот в таком вот уничижающем молчании, которое дает понять ребенку, что он совершил нечто постыдное и за это несет наказание в виде симуляции исключения.

С т.з. женщины, видимо, этот подход является целительным для ребенка. Ребенок же, залатывая брешь в системе (не знаю каким образом это происходит, психологи установили эмпирическим путем и лишь рассказывают гипотезы), будет неосознанно копировать элементы поведения исключенного. Ну т.е. хотите, чтобы ребенок повторял отца — исключите его из семьи, убрав всякое упоминание, уничтожив семейные фото, видео и пр.

В системе важно уважение ко всем, кто появился там ранее. «Можно осуждать грех человека, но нельзя осуждать человека». Человек не намеренно и осознанно делает какие-то действия, а из каких-то лучших, с его точки зрения и точки зрения системы, побуждений. То, что нам они кажутся худшими — это лишь наш угол зрения с которого мы обозреваем проявление. Если посмотреть под другим углом, то все может оказаться совершенно иным.

Например, сын напиваясь может таким образом демонстрировать любовь к отцу, который рано умер из-за церроза печени и был исключен из системы, поскольку маме думалось, что он намеренно себя так вел, чтобы её позлить. Исключен — это значит любые упоминания о нем были постыдными и карались соответственно. Причем, с т.з. женщины, мысль может быть прямолинейно-здравая, если перестать упоминать об отце-алкоголике, сын не пойдет его путем. На самом деле, все может быть с точностью до наоборот.

К чему я это все вспомнил. Завтра мой день рождения. Бывшая старательно вычеркнивала меня из памяти ребенка с момента нашего расставания. За все это время дочь ни разу не поздравила с ДР открыткой или SMS-кой. Хотя до развода отношения были хорошие. Я старался каждый раз на день её рождения отправить открытку, SMS маме и отправлял открытки почти из всех стран, где бывал. Понятно, что, скорее всего, ни одна открытка до дочери не дошла, перехваченная мамой. Я не забываю дочь, хотя прошло уже много лет с момента последнего общения. Влияние матери на ребенка очень сильное.

Когда лишаешься чего-то привычного, но ценного, начинаешь понимать, что не ценил и насколько это важно. Забавно, но сейчас самый душевный подарок на мой ДР была бы SMS с тексом, вроде: «Пап, с Днем Рождения». 🙂 Как «мало» надо для счастья.

Я бывал на разных психологических тренингах. На них, частенько, немало взрослых детей, которые до сих пор пытаются «переварить» подобную изоляцию родителями кого-то из членов семьи. Не обязательно это отец или мать, это могут быть какие-то близкие родственники: бабушки, дедушки, сестры, братья и пр., когда их исключили из-за несоотвествующего шабону родителей поведения. Грустно все это… Хотя, может в этом и состоит смысл жизни, чтобы сначала потерять, потом обрести вновь. 🙂

В общем, если нужно, чтобы ребенок немало времени потратил у психологов — исключите кого-то из близких и результат будет гарантирован. 🙁

Рубрика: О жизни, Отношения, Психология, Семья | Оставить комментарий

Путешествие в Иран. Тонкости туризма.

Захотелось мне посетить Иран. Мысль родилась ещё в 2022 году, но дошла до воплощения только к осени 2023. Интересно было посмотреть на страну, как экономика справилась с 30-ти летними санкциями, какие люди, какие возможности для бизнеса и т.д.

Я предпочитаю ездить самостоятельно («жикарем»), но поскольку оплатить что-либо картами из России было затруднительно, воспользовался услугами турпоператора. Наиболее выгодные условия были у Библиоглобуса, на сайте которой я и забронировал тур.

7 дней без визы обошлись в 107 тыр., что не дешево для одного человека, но другие компании предлагали от 160 тыр. и выше и ещё доплата за одноместное проживание. 🙂 Виза обошлась в 15 USD — оформление приглашения на получение визу — это ещё в России. И затем 70 USD оплата налом по прилету в Иран. Это при том, что с 1 августа 2023 уже был анонсирован безвизовый въезд для групп от 5 человек. К сожалению, на конец сентября 2023 к моменту поездки система была не отработана ни с той, ни с другой стороны. В Россию не въедешь без визы из Ирана и в Иран из России. Думаю, к 2024 году ситуация наладится и можно будет немного сэкономить.

Ещё одна бесполезная трата и здесь косяк целиком на Библиоглобусе — ПЦР тест. Он стоит порядка 1000 руб. и, как показала практика, совершенно не нужен. Никто при въезде в Иран ПЦР и/или температуру не проверяет и всяческих страстей про карантин и пр, что написаны на сайте Библиоглобуса, отсутствуют. Причем, одногрупница в туре сказала, что даже нашла официальное подтверждение где-то на сайте посольства Ирана.

Из минусов организации: у Библиоглобуса нельзя заранее приобрести симку. Как оказалось по прилету в Иран, другой туроператор такую возможность предлагал, выдавая симки по прилету.

По прилету до прохождения через таможню нужно зайти в офис где выдают визу, предъявить электронное приглашение, заплатить 70 USD и в обмен получить распечатанный листочек с визой. На нем штрих код и фото по которому в случае чего могут идентифицировать. Листочек никоим образом не вклеивается в паспорт, печатей на таможне при вылете/прилете не ставится, соответственно, выкинули листочек и, вроде как, нет документов подтверждающих посещение этой страны.

Забегая вперед скажу, что этот листочек нигде не потребовался. При вылете его не спрашивают. Наверняка все данные о дате прилета человека и сроке действия визы есть в системе и таможенник их видит. Срок на который дают визу, очень короткий, буквально на несколько дней больше заявленных сроков пребывания в стране.

Также по прилету можно купить местную страховку. Как мне объяснили — она недорогая и иметь её полезно, наряду с медицинской страховкой, которую делает туроператор. Смысл в том, что при возникновении инцидента в Иране, российская страховая компания не сможет перевести деньги в медучреждение Ирана из-за санкционных ограничений. Поэтому пострадавший сначала сам оплачивает лечение и по прилету в Россию страховая компания возмещает затраты. При наличии страховки купленной на месте, вроде как, таких сложностей нет. Но официального подтверждения у меня нет, так что пересказываю то, что услышал в очереди на таможню. 🙂

Прохождение таможни — довольно длительная процедура. Хотя людей было сравнительно немного, прилет поздно ночью, но очередь продвигалась довольно медленно. Но самая долгая процедура — на Гоа, впрочем, там и людей прилетает в разы больше. Никаких проблем с таможенниками в Ирене не было. Непосредственно прохождение через них очень быстрое, глупых вопросов про «цель приезда» и пр. не задают. 🙂

Встреча в аэропорту

У Библиоглобуса партнер со стороны Ирана — компания «Nadia Parvaz»: info@nadiaparvaz.com. Сайт: www.nadiaparvaz.com

Nadia Parvaz, info@nadiaparvaz.com, www.nadiaparvaz.com
Tel:021-41579,Postal Code: 1965614111
4th Floor, Leo Mall Complex, Fereshteh Avenue, Tehran, Iran Горячая линия: +98 910 589 67 23, +98 912 337 03 55

При прилете встречает русскоговорящий иранский гид, весьма опытный, как оказалось. Контакты гида, с его согласия, скидываю. Человек порядочный, говорит по-русски довольно хорошо, внимательный. E-mail: mohammadghavidel@yahoo.co.

Из минусов встречи, которые выяснились позже, но хорошо было бы их знать при прилете:

  • Интернет в Иране в большинстве отелей очень медленный. Из-за того, что приходится практически всегда пользоваться VPN — скорость становится ещё хуже. Поэтому лучше сразу в аэропорту приобрести симку местного оператора Irancell. Тур очень плотный и в отель мы приезжали достаточно поздно, поэтому и речи не могло быть, чтобы искать офис Irancell в городах пребывания и успеть до закрытия.
  • Поменять USD/EUR на местную наличку можно не во всех городах, а деньги нужны сразу, поскольку обеды в тур не включены. Поэтому 50 USD стоит поменять сразу в аэропорту, но не в банковских обменниках, где курс неважный. Возле обменников крутятся менялы, которые дают курс существенно лучше. В городах курс у менял ещё лучше, но тут выбирать не приходится. Чтобы плотно пообедать в ресторанчике с шведским столом нужно порядка 8 USD на человека.
  • С менялами есть некоторые риски, что обсчитают, поскольку при обмене 50 долларов единомоментно становишся миллионером, а банкноты непривычные. Курс 1 USD у менял порядка 45 тыс. риалов (IRR). 50 USD — порядка 2,250 млн IRR.
  • Гид предлагает также карты местных банков с зачислением денег из офиса, т.е. отдаешь USD гиду, он пишет в офис туроператора и те пополняют карту по какому-то курсу. Опробовать этот способ не получилось. Девчонки в группе дружно возразили против такого способа оплаты, опасаясь, что на местных рынках не получится расплатится. Хотя, по факту оказалось, что даже у мелких лавочников есть беспроводной терминал для оплаты картой. При этом в некоторых местах оплатить налом сложнее. Хотя и не так проблематично, как в Китае.

Люди

Во всех своих поездах мне наиболее интересны люди. Персы/иранцы мне понравились. 🙂 На мой взгляд вполне себе добродушный народ. Не агрессивный. Когда мы обращались за помощью к местным, даже если они не могли толком говорить на английском — пытались помочь. Были те, кто говорил на русском. К россиянам относятся хорошо. Собственно, в поездках мы пересекались только с группами вездесущих китайцев. 🙂

В городах мало людей, просящих милостыню. Вполне возможно, что это афганцы. Такие люди есть, но не настолько настырные, как в Египте или Индии.

Очень мало курящих. Практически нет. Возможно, отчасти поэтому чисто. 🙂

Пока что для местных русские скорее редкость. Некоторые просили сфотографироваться с нами. 🙂 Подозреваю, что из-за наших девчонок, небрежно носивших платки. 🙂 Мы c удовольствием фоткались с местными.

Чувствуется, что немало хорошо образованных. Есть книжные магазины. Молодежь не втыкает повсеместно в мобильники. 🙂 Возможно, из-за необходимости поднимать VPN. 🙂

То, что инженерные кадры в Иране на достойно высоком уровне подтверждает факт, что сейчас не менее 90 процентов всех автокомпонентов Иран производит самостоятельно. Россия к такому показателю стремится подойти к 2035 году. 

Вместе с тем, Россия нужна Ирану гораздо больше. В среднесрочной перспективе Иран мог бы заместить парк древних гражданских самолетов Airbus, используемых на авиалиниях в Иране, на российские самолеты Sukhoi Superjet 100 и МС-21, продолжить строительство АЭС в Бушере, обновить железнодорожное сообщение и многое другое.

В Иране, визуально, ИТ находится на более низком, в сравнении с Россией, уровне. Примерно на европейском. 🙂 В этом направлении совместный бизнес также весьма интересен, если успеть раньше вездесущих китайцев. 🙂

Собственно, у русских движуха и креатив начинается, когда кто-то начинает ограничивать размеренную жизнь. 🙂

Деньги

с наличкой в Иране непривычно. Мне не доводилось в поездках встречаться со столь своеобразной системой. Популярная банкнота у менял — 500.000 купюра иранского риала (IRR). Она встречается в двух вариантах: новый и старый образец.

В торговле, например, в кафе, ценник могут называть в туманах. Это не какая-то другая валюта, просто 1 туман равен 10 риалам. Соответственно, если называют цену в туманах, то надо умножать на 10, чтобы получить риалы. Например, 100 туманов — 1000 риалов.

Но путаница на этом не заканчивается. На новых банкнотах указаны две цифры, например 500.000 и 50, где 50 — это номинал банкноты в туманах, но только здесь 1 туман равен 10 000 реалов. На новых банкнотах четыре ноля IRR указаны отличающимся шрифтом, более бледным.

500.000 IRR — это порядка 11,5 USD на 09.2023. В ресторанах с шведским столом обычно ценник в районе 400.000 IRR ~ 8 USD. Набор блюд разнообразный, просто ужраться. 🙂 Все пересчеты очень примерные. Сначала мы предполагали, что гид возит нас по дорогим ресторанам для туристов. Но когда выходили вечерами поужинать самостоятельно и сами выбирали местные заведения — порядок цен был схожим.

Другая свежая ходовая бумажка — 1.000.000 IRR или 100 новых туманов или около 23 USD.

В общем, внимательнее, если будете менять у менял. Лучше с помощью гида менять.

По ценам в музеи, посещение мечети или иного музея что-то в районе 100.000 IRR, т.е. ~2,3 USD. Самый дорогой музей был в Тегеране — Дворец Голестан — 600.000 IRR, но там собраны порядка 20 музеев с одним входом.

VPN

Без VPN по местному интернет мало куда можно попасть. Работает e-mail, но не работают все популярные мессенджеры и многие российские сайты, например, соцсети.

PPTP корпоративный VPN также не работает. Так что приготовьтесь к цифровому детоксу. 🙂

Перед отъездом в Иран нужно накачать на мобильный различные бесплатные VPN клиенты. Одного недостаточно, поскольку в одном отеле может работать один VPN клиент, а в другом — иной.

Гид использовал Ostrich VPN. У меня нормально работали TOP VPN, Tondo VPN. Lantern, AdGuard VPN. Всего у меня стояло 17 VPN клиентов. Пробовал не все. На некоторых закончился триал ещё с поездки в Китай.

Хороший вариант — подключить роуминговый тариф на российском мобильном операторе. Например, на Tele2 нормально работали все мессенджеры, без VPN. Аналогично на Мегафоне на тарифе для мессенджеров 200 руб. в сутки. Шаринг интернета нормально отрабатывает, как при этом считается тариф — лучше уточнить в офисе оператора. Билайн тоже нормально работал. МТС не работал совсем.

Цифры и даты

В Иране есть ряд непривычных моментов, с которыми больше нигде не сталкивался.

Во-первых, разница с Москвой всего 30 мин. Довольно непривычный сдвиг часовых поясов. Первый раз с таким сталкиваюсь.

Во-вторых — персидские цифры вместо привычных «современных». Счет из ресторана на семерых. Поели на 37 лямов IRR. 🙂

Хорошо хоть финальная сумма указана привычными цифрами. 🤣 Кстати, далеко не во всех заведениях это так. В этом счете циферки за конкретные позиции и количество — персидскими цифрами.

В одном кафе цифры в меню были написаны от руки. Это вообще жесть. Особенно, когда официанты в таких заведениях не говорят по английски от слова совсем. Выручает калькулятор, на котором местные набирают цифру счета. 🤣

Третий непривычный момент в Иране — летоисчисление. Оно у них не по привычному для нас григорианскому календарю, а по иранскому или солнечная хиджра. Это астрономический солнечный календарь, который используется в качестве официального календаря в Иране и Афганистане. Календарь был разработан группой из 8 астрономов под руководством Омара Хайяма.

Фото из салона лайнера на котором возвращались из Шираза в Тегеран. Нынче в Иране 1402 год. Авиакомпания на фото основана в 1305 году, т.е. в 1926 году. 97 лет авиакомпании — нехилый такой срок. Интересно, конечно, на чем летали? 🙂 Это к слову о продвинутости Ирана.

Отели

Отели в Иране весьма неплохие. Наиболее колоритный отель в г. Йазд.

В других городах отели европейские, ничего примечательного. Чисто, хорошие завтраки, шведский стол. Блюда во всех отелях примерно одинаковые. Наиболее разнообразный завтрак был в Тегеране, в бывшем отеле Ibis, в аэропорту.

На завтрак из мясного максимум нарезанные сосиски с омлетом. Фрукты в сентябре, которые подают в отеле: финики, арбузы и дыни. Дыни сравнительно редко. Блинчики в редких местах. Довольно вкусный мягкий сыр во всех отелях. Чай из пакетиков и порошковый кофе. Везде были соки. В общем, завтраки достойные.

Из особенностей отметил, что в Иране, как и в Китае в туалете отсуствуют ёршики для унитаза. Благо, в туалетах этих стран есть смеситель для биде и можно напором промыть унитаз. 🙂

При самостоятельном бронировании отелей по ссылкам с форумов мне попался разве что один сайт: HostelWorld. Во всех остальных привычных сервисах Иран отсутствует как класс.

Хорошо было бы, чтобы наши сервисы Sutochno.ru, Tvil.ru, QQrenta.ru, Avito.ru и пр. активнее проработали отели Ирана, чтобы они присутствовали в их сервисах.

Транспорт

Мы с группой перемещались на новеньком микроавтобусе иранского производителя Iran Khodro под брендом «VANA». Моё фото:

Фото из Интернет:

Дизайн выглядит современно. Сравним с Газелью:

Это притом, что в списке https://en.wikipedia.org/wiki/Iran_Khodro_Diesel упоминается, что, похоже, какие-то модели ГАЗели иранский завод выпускал.

Микроавтобус VANA удобный: высокий потолок, кондиционер, удобные сиденья, приличный дизайн как снаружи, так и в салоне и пр.

В Тегеране было немало новых автобусов Iran Khodro, наряду с убитыми Mercedes, Volvo и пр.

На дорогах помимо легковых машин Iran_Khodro и SAIPA немало Renault и Peugeot. Иранская реинкарнация Renaul Logan называется Tondar 90 и выглядит вот так:

По информации с Autonews:

Renault Logan первого поколения производился в Иране на заводе компании SAIPA с 2007 по 2018 год под названием Renault Tondar 90. После усиления западных санкций в отношении Ирана сборка остановилась. В 2020 году SAIPA анонсировала проект P90, в рамках которого планировалось радикально обновить внешность и техническую часть Tondar 90. 

Судя по свежему виду этих машин, сборка не остановилась. 🙂

Машины в пробках в Тегеране преимущественно уровня Renault Tondar, так что либо люди не особо зажиточные, либо не кичатся этим, как в Москве. 🙂

В городах очень много мотоциклов. Не как в Китае, где преимущественно электрические. Бензин в Иране очень дешевый, поэтому никаких электробайков. Байкеры норовят проехать по тротуарам или по узким пространствам рынков. Делают это довольно виртуозно, хотя и реально стремно на это смотреть. Шлемы и средства защиты у всей этой толпы байкеров отсутствуют.

В туре мы перемещались по городам: Тегеран -> Эсфахан -> Йезд -> Шираз и уже на самолете внутренним рейсом в Тегеран.

Дороги в Иране весьма добротные. Между городами скорость авто приличная. Выбоин нет. Не трясет. Машина идет ровно. В окне, обычно, постоянные виды пустыни, виды однообразные, так что спится очень хорошо.

Города

Что стоит отметить, в городах очень чисто. Вот фото из метро в Ширазе:

Собственно, в городах такая чистота практически везде. Даже на второстепенных улочках. Но, что несколько раздражает, как и в городах Узбекистана, вдоль улиц идут открытые канавы. Так что надо смотреть под ноги.

В Тегеране очень пробочно. Сам город по архитектуре мне не особо понравился. Здания в городах скорее относительно современной архитектуры. И островками вкрапления исторических зданий.

Собственно, в городах привычно.

Зашел в подъезд посмотреть, инфраструктура старенькая, но все чисто. Счетчики электричества и газа у входа в подъезд. Все чисто. Никаких графити и пр. на зданиях.

О женщинах

За рулем машин немало женщин. Так что стереотип, что женщины в Иране бесправные и сидят по домам не соответствует действительности.

Девчонки носят джинсы, не сильно запариваясь тем, чтобы скрывать лодыжки. Некоторые предпочитают длинные юбки — выглядит женственно. Платки нередко на плечах, как будто спали с головы. Назидательный патруль в Иране не столь активен. Главным образом их представители есть в мечетях и других исторических зданиях. На улицах их не заметно.

Попадается довольно яркая жизнерадостная одежда. По крайней мере, платки можно найти всех цветов и оттенков.

Фото из Интернет:

Аэропорт

В Тегеране несколько аэропортов. Местные авиалинии прилетают в аэропорт Мехрабад, примерно в 9 км от центра города. Международные рейсы — в международный аэропорт Имама Хомейни примерно в 40 км от центра города. Трансфер не близкий.

Из аэропорта Имама Хомейни вылеты на табло были во все арабские страны. Так что о каких-то санкциях говорить можно только в разрезе того, что не было видно прямых рейсов в европейские страны.

Важный момент на который нужно обратить внимание при возвращении в Россию. Когда заходишь в аэропорт в Тегеране, практически сразу натыкаешься на гигансткую змейку очереди. Это лишь очередь на первый секьюрити чек. Очередь двигается довольно шустро, но вылет был около 4 часов утра. Скорее всего в это время народу меньше, однако, чтобы дойти до первого пункта охраны потребовалось более 40 минут.

Проверка мужчин и женщин раздельная. Досмотр женщин длится существенно дольше, чем мужчин. В общем, времени на это уходит немало, поэтому гид рекомендовал прибыть в аэропорт за 3,5 часа.

После прохождения досмотра стандартная регистрация на рейс. Затем паспортный контроль для определенных гейтов, нескольких, но не всех, как обычно в аэропортах. Второй паспортный контроль ничем не примечателен. Также раздельная проверка мужчин и женщин, но проходит относительно быстро, т.к. людей вылетающих через гейты обслуживаемые пунктом проверки, значительно меньше.

Очередь, как и при прилете, движется медленно. После паспортного контроля сразу попадаешь в магазинчики duty free. И уже из duty free, пройдя через второй security check, попадаешь в зону вылета, где есть несколько скромных магазинчиков.

В остальном, все как обычно. Загрузились на самолет, 4 часа лету и в Москве.

Рубрика: О жизни, Путешествия | Оставить комментарий