Поиск данных через gRPC API
Перед началом работы
Для работы с API Yandex Cloud потребуется Git, Python 3.6 или старше и пакет grpcio-tools
. Узнайте, как установить Python
Чтобы искать данные с помощью gRPC API Yandex Cloud:
-
В консоли управления создайте сервисный аккаунт.
-
Добавьте сервисный аккаунт в пространство с ролью
Data editor
. Это позволит сервисному аккаунту загружать данные в SpeechSense. -
Чтобы аутентифицироваться в API Yandex Cloud, создайте API-ключ или IAM-токен для сервисного аккаунта.
-
Склонируйте репозиторий API Yandex Cloud
:git clone https://github.com/yandex-cloud/cloudapi
-
Установите пакет
grpcio-tools
с помощью менеджера пакетов pip :pip install grpcio-tools
- Загрузите аудиозаписи или чаты в SpeechSense.
Найти данные
-
Перейдите в папку с репозиторием API Yandex Cloud, создайте папку
search_data
, сгенерируйте в ней код интерфейса клиента и перейдите в папкуsearch_data
:Bashcd <путь_к_папке_cloudapi> && \ mkdir search_data && \ python3 -m grpc_tools.protoc -I . -I third_party/googleapis \ --python_out=./search_data/ \ --grpc_python_out=./search_data/ \ google/api/http.proto \ google/api/annotations.proto \ yandex/cloud/api/operation.proto \ google/rpc/status.proto \ yandex/cloud/operation/operation.proto \ yandex/cloud/validation.proto \ yandex/cloud/speechsense/v1/*.proto \ yandex/cloud/speechsense/v1/*/*.proto cd search_data
-
В папке
search_data
создайте Python-скриптsearch_data.py
, который выполняет поиск диалогов в SpeechSense.Пример скрипта search_data.py с фильтрацией и полнотекстовым поиском
import argparse import re from datetime import datetime from typing import NamedTuple import grpc from google.protobuf.field_mask_pb2 import FieldMask from google.protobuf.json_format import MessageToJson from yandex.cloud.speechsense.v1 import search_pb2 from yandex.cloud.speechsense.v1 import talk_service_pb2 from yandex.cloud.speechsense.v1 import talk_service_pb2_grpc class IntRangeFilter(NamedTuple): key: str lower_bound: int lb_inclusive: bool upper_bound: int ub_inclusive: bool def parse_int_range(s: str) -> IntRangeFilter: pattern = r'(-?\d+)(<=|<)(\w+)(<=|<)(-?\d+)' match = re.match(pattern, s) if not match: raise ValueError(f"Could not parse int range from: '{s}'") lower_bound = int(match.group(1)) lower_bound_inclusive = match.group(2) == "<=" key = match.group(3) upper_bound_inclusive = match.group(4) == "<=" upper_bound = int(match.group(5)) return IntRangeFilter( key=key, lower_bound=lower_bound, lb_inclusive=lower_bound_inclusive, upper_bound=upper_bound, ub_inclusive=upper_bound_inclusive ) def build_search_request( organization_id: str, space_id: str, connection_id: str, project_id: str, query=None, from_date=None, to_date=None, match_filter=None, classifier_filter=None, page_size=100, page_token='') -> talk_service_pb2.SearchTalkRequest: request = talk_service_pb2.SearchTalkRequest( organization_id=organization_id, space_id=space_id, connection_id=connection_id, project_id=project_id, page_size=page_size, page_token=page_token ) # Добавление запроса полнотекстового поиска if query: request.query.text = query # Добавление фильтра по дате if from_date: date_filter = search_pb2.DateRangeFilter() date_filter.from_value.FromDatetime(datetime.fromisoformat(from_date)) request.filters.append(search_pb2.Filter(key="userMeta.date", date_range=date_filter)) if to_date: date_filter = search_pb2.DateRangeFilter() date_filter.to_value.FromDatetime(datetime.fromisoformat(to_date)) request.filters.append(search_pb2.Filter(key="userMeta.date", date_range=date_filter)) # Добавление match-фильтра if match_filter: key, value = match_filter.split(':') # kлюч/значение any_match_filter = search_pb2.AnyMatchFilter() any_match_filter.values.append(value) request.filters.append(search_pb2.Filter(key=key, any_match=any_match_filter)) # Добавление фильтра классификатора if classifier_filter: filter_values = parse_int_range(classifier_filter) int_range_filter = search_pb2.IntRangeFilter() int_range_filter.from_value.value=filter_values.lower_bound int_range_filter.to_value.value=filter_values.upper_bound int_range_filter.bounds_inclusive.from_inclusive=filter_values.lb_inclusive int_range_filter.bounds_inclusive.to_inclusive=filter_values.ub_inclusive request.filters.append( search_pb2.Filter(key='talk.classifiers.' + filter_values.key + '.count', int_range=int_range_filter)) return request # Для аутентификации с IAM-токеном замените параметр api_key на iam_token def print_talks( api_key: str, organization_id: str, space_id: str, connection_id: str, project_id: str, query=None, from_date=None, to_date=None, match_filter=None, classifier_filter=None ): credentials = grpc.ssl_channel_credentials() channel = grpc.secure_channel('api.speechsense.yandexcloud.net:443', credentials) talk_service_stub = talk_service_pb2_grpc.TalkServiceStub(channel) page_token = '' while True: search_request = build_search_request( organization_id=organization_id, space_id=space_id, connection_id=connection_id, project_id=project_id, query=query, from_date=from_date, to_date=to_date, match_filter=match_filter, classifier_filter=classifier_filter, page_token=page_token) # Поиск ID подходящих диалогов search_response = talk_service_stub.Search(search_request, metadata=( ('authorization', f'Api-Key {api_key}'), # Для аутентификации с IAM-токеном передавайте заголовок # ('authorization', f'Bearer {iam_token}'), )) page_token = search_response.next_page_token # print(f'found falks {search_response.talks_count}') # По умолчанию будут возвращены только базовые поля диалога. # Для включения результатов анализа необходимо дополнительно передать их в запрос fields_to_include = FieldMask( paths=['transcription', 'speech_statistics', 'silence_statistics', 'interrupts_statistics', 'conversation_statistics', 'points', 'text_classifiers']) # Запрос полных данных диалогов по ID get_request = talk_service_pb2.GetTalkRequest( organization_id=organization_id, space_id=space_id, connection_id=connection_id, project_id=project_id, talk_ids=search_response.talk_ids, results_mask=fields_to_include ) get_response = talk_service_stub.Get(get_request, metadata=( ('authorization', f'Api-Key {api_key}'), # Для аутентификации с IAM-токеном передавайте заголовок # ('authorization', f'Bearer {iam_token}'), )) # Печать диалогов for talk in get_response.talk: print(MessageToJson(talk, ensure_ascii=False)) # Если токен пустой, мы долистали до последней страницы результата if not page_token: break if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--key', required=True, help='API key or IAM token', type=str) parser.add_argument('--organization-id', required=True, help='Organization ID', type=str) parser.add_argument('--space-id', required=True, help='Space ID', type=str) parser.add_argument('--connection-id', required=True, help='Connection ID', type=str) parser.add_argument('--project-id', required=True, help='Project ID', type=str) parser.add_argument('--query', required=False, help='Full-text search query', type=str) parser.add_argument('--match-filter', required=False, help='Simple match filter in format key:value', type=str) parser.add_argument('--classifier-filter', required=False, help='range for classifier X in format fromValue</<=X</<=toValue', type=str) parser.add_argument('--before', required=False, help='Search for talks before timestamp', type=str) parser.add_argument('--after', required=False, help='Search for talks after timestamp', type=str) args = parser.parse_args() print_talks(args.key, args.organization_id, args.space_id, args.connection_id, args.project_id, query=args.query, from_date=args.after, to_date=args.before, match_filter=args.match_filter, classifier_filter=args.classifier_filter)
-
Задайте API-ключ сервисного аккаунта:
export API_KEY=<API-ключ_сервисного_аккаунта>
Если вы используете IAM-токен, передайте его вместо API-ключа:
export IAM_TOKEN=<IAM-токен_сервисного_аккаунта>
-
Запустите скрипт
search_data.py
с нужными параметрами:python3 search_data.py \ --organization-id <идентификатор_организации> \ --space-id <идентификатор_пространства> \ --connection-id <идентификатор_подключения> \ --project-id <идентификатор_проекта> \ --key ${API_KEY}
Где:
--organization-id
— идентификатор организации, в которой выполняется запрос. Чтобы получить идентификатор, перейдите в сервис Cloud Center и нажмите кнопку под названием организации, в разделе .--space-id
— идентификатор пространства, в котором выполняется запрос. Чтобы получить идентификатор, перейдите в сервис SpeechSense , откройте страницу нужного пространства и нажмите кнопку ID.--connection-id
— идентификатор подключения, в котором выполняется запрос. Чтобы получить идентификатор, перейдите в сервис SpeechSense , откройте страницу нужного пространства, на вкладке Подключение откройте страницу нужного подключения и нажмите кнопку ID.--project-id
— идентификатор проекта, в котором выполняется запрос. Чтобы получить идентификатор, перейдите в сервис SpeechSense , откройте страницу нужного пространства, на вкладке Проекты откройте страницу нужного проекта и нажмите кнопку ID.--key
— API-ключ для аутентификации. Если вы используете IAM-токен, укажите переменную окруженияIAM_TOKEN
вместоAPI_KEY
.
В результате работы скрипта на экран будут выведены данные в JSON-формате.
Параметры запросов
Search-запрос
-
Query
— это полнотекстовый поиск, который позволяет искать по текстовой расшифровке аудиозаписи и текстовым сообщениям чата. -
Filter
— позволяет искать по метаданным пользователя, классификаторам, резюме диалога, статистикам.В
Filter
, передайте характеристику диалога, по которой производится фильтрация, в полеkey
:-
userMeta.<имя_поля>
— фильтрация по метаданным пользователя. Здесь<имя_поля>
— это поле метаданных пользователя, которое было указано при загрузке диалога. Пример:userMeta.date
. Тип фильтра должен соответствовать тому типу поля метаданных, который вы указали при создании подключения. -
talk.classifiers.<имя_классификатора>.count
— фильтрация по классификаторам. -
talk.summarization.points.<идентификатор_вопроса>
— фильтрация по резюме диалога. Идентификаторы вопросов из резюме диалога вы можете посмотреть в ответе get-запроса. -
Поиск по статистикам:
-
Для аудио:
talk.statistics.duration_seconds
— длительность диалога, в секундах.talk.statistics.simultaneous_silence.duration_seconds
— длительность одновременной тишины, в секундах.talk.statistics.simultaneous_silence.ratio
— доля одновременной тишины.talk.statistics.simultaneous_silence.max_duration_seconds
— максимальная длительность одновременной тишины, в секундах.talk.statistics.silence.duration_seconds
— длительность тишины клиента или оператора, в секундах.talk.statistics.silence.ratio
— доля тишины клиента или оператора.talk.statistics.simultaneous_speech.duration_seconds
— длительность одновременной речи, в секундах.talk.statistics.simultaneous_speech.ratio
— доля одновременной речи.talk.statistics.simultaneous_speech.max_duration_seconds
— максимальная длительность одновременной речи, в секундах.talk.statistics.speech.duration_seconds
— длительность речи клиента или оператора, в секундах.talk.statistics.speech.ratio
— доля речи клиента или оператора.talk.statistics.interrupts.count
— количество прерываний собеседника.talk.statistics.phrases.count
— количество фраз в диалоге.talk.statistics.words.count
— количество слов в диалоге.talk.statistics.letters.count
— количество символов в диалоге.talk.statistics.words.count_per_second
— количество слов в секунду.talk.statistics.letters.count_per_second
— количество символов в секунду.talk.statistics.interrupts.duration_seconds
— длительность прерываний одним из участников речи другого участника, в секундах.
-
Для чатов:
talk.statistics.duration_seconds
— длительность диалога, в секундах.talk.statistics.reactions.count
— количество реакций оператора на сообщения клиента.talk.statistics.reactions.first_duration_seconds
— длительность первой реакции оператора на сообщение клиента, в секундах.talk.statistics.reactions.min_duration_seconds
— минимальная длительность реакции, в секундах.talk.statistics.reactions.max_duration_seconds
— максимальная длительность реакции, в секундах.talk.statistics.phrases.count
— количество фраз в диалоге.talk.statistics.words.count
— количество слов в диалоге.talk.statistics.letters.count
— количество символов в диалоге.
-
-
В Filter
и Query
можно передать канал в параметре channel_number
. Для полнотекстового поиска это означает, что поиск ведется только по текстовой расшифровке аудиозаписи для указанного канала. Для фильтров это означает, что фильтрация происходит по метаданным, срабатываниям классификатора или статистикам, относящимся к данному каналу.
В подключениях для чатов нумерация каналов следующая:
0
— канал оператора;1
— канал клиента;2
— канал бота.
В подключениях для аудио нумерация каналов предустановлена.
Другие виды фильтров в search-запросе:
AnyMatchFilter
— определяет, встречается ли значение из фильтра в метаданных, классификаторах, статистиках, резюме диалога. Например, фильтр с параметрамиkey = userMeta.ticket_id
иvalues = [123, 345]
вернет диалоги, у которых в поле метаданныхticket_id
передано значение123
или345
.IntRangeFilter
— проверяет, что заданное целочисленное значение попадает в диапазон, указанный в фильтре. Подходит для фильтрации по классификаторам, полям метаданных целочисленного типа и статистикам со значениями целочисленного типа.DoubleRangeFilter
— проверяет, что заданное число с плавающей точкой попадает в диапазон, указанный в фильтре. Подходит для фильтрации по классификаторам, полям метаданных и статистикам со значениями с плавающей точкой.BooleanFilter
— проверяет, что значение по ключу типаboolean
имеет подходящее значение (True
илиFalse
). Подходит для поиска по резюме диалога и полям метаданных типаboolean
.
Подробнее о параметрах search-запроса см. в справочнике API.
Get-запрос
В get-запросе важным параметром является маска результатов — поле fields_to_include
. Если параметр fields_to_include
не передан, вернется только базовая информация о диалоге: идентификаторы проекта, подключения и пространства, когда и кем создан и изменен, а также метаданные, добавленные при загрузке диалога.
Чтобы выгрузить дополнительную информацию, передайте в маске нужные ключи:
transcription
— текстовая расшифровка аудиозаписи или текстовые сообщения из чата.speech_statistics
— статистика речи.silence_statistics
— статистика пауз в диалоге.interrupts_statistics
— статистика прерываний собеседника.conversation_statistics
— статистика диалога.points
— резюме диалога.text_classifiers
— статистика по классификаторам (тегам).
Подробнее о параметрах get-запроса см. в справочнике API.