В прошлой части мы научились применять технологию Microsoft Agent в web-страничках. В этот раз мы будем работать с Delphi. Убедитесь, что установлены все необходимые компоненты (см. первую часть) и можно отправляться в увлекательное путешествие по миру MsAgent. Запустите Delphi и в меню «Component» выберите пункт «Import ActiveX Control…». В появившемся диалоговом окне нужно выделить строку «Microsoft Agent Control…» и нажать кнопку «Install». Далее произойдёт стандартный процесс установки нового компонента. После окончания инсталляции создайте новое приложение и поместите на форму полученный компонент – Agent1:TAgent (он должен находиться на закладке ActiveX).
Вот этот вот почти «ноль-ноль-семь» будет помогать нам создавать приложения, которые будут работать с технологией MsAgent. Начнём с небольшого примера, с маленького костяка, который можно будет использовать при разработке более сложных программ.
Установите свойству Connected компонента Agent1 значение True, затем объявите две глобальные переменные:
Var
//для хранения персонажа Character: IAgentCtlCharacterEx;
//для получения состояния персонажа
Request: IAgentCtlRequest; Для события OnCreate формы запишите процедуру:
procedure TForm1.FormCreate(Sender: TObject);
begin
//загружаем персонаж «Джин» Request := Agent1.Characters.Load(‘genie’, ‘genie.acs’);
//получаем объект персонажа Джин
Character := Agent1.Characters.Character(‘genie’)as IAgentCtlCharacterEx;
//Джин появляется
Request := Character.Show(False);
//Джин здоровается и вкратце рассказывает о себе
Request := Character.Speak(‘Здравствуйте! ‘+Сharacter.Description, EmptyParam);
//Джин играет анимацию «Greet»
Request:=Character.Play(‘Greet’);
end;
При закрытии формы нужно выгрузить персонаж:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin Agent1.Characters.Unload(‘genie’);
end;
Если запустить эту программу, то вместе с формой появится Джин, который поздоровается и на несколько секунд застынет в приветственном поклоне. Теперь будем дополнять данный пример.
Как уже упоминалось в первой части, персонажи умеют проигрывать различные анимации, при этом для каждого персонажа могут определяться свои анимации. Поэтому иногда требуется получить все допустимые анимации для персонажа, что и делает следующая процедура: Procedure GetAgentAnim(st: TStrings);
var AnEnum: IEnumVariant; flag: Cardinal; V: OleVariant;
begin
//получаем интерфейс анимаций агента AnEnum := (Character.AnimationNames.Enum) as IEnumVariant;
//Сбрасываем указатель списка на начало
AnEnum.Reset;
//перебираем все анимации и добавляем их в наш список
repeat AnEnum.Next(1, V, flag);
if (VarToStr(V) ») then
st.Add(V);
until (flag = 0);
end; Давайте проверим работоспособность данной процедуры. Добавьте на форму кнопку Button1 и список ListBox1. Дайте заголовок кнопке «Список анимаций» и запишите процедуру обработки её нажатия: procedure TForm1.Button1Click(Sender: TObject);
begin GetAgentAnim(ListBox1.Items);
end;
Данная процедура записывает список анимаций загруженного персонажа в компонент ListBox1. А теперь сделаем так, чтобы при двойном щелчке мышкой по ListBox’у Джин проигрывал выбранную анимацию:
procedure TForm1.ListBox1DblClick(Sender: TObject);
begin Request := Character.Play(ListBox1.Items[ListBox1.ItemIndex]);
end;
Теперь посмотрим, зачем нам переменная Request (её мы объявили как глобальную). Именно она служит для синхронизации действий персонажа (либо персонажей, если их несколько). Интерфейс IAgentCtlRequest имеет одно очень полезное свойство – Status. В зависимости от состояния запроса, который в данный момент выполняет персонаж, это свойство принимает следующие значения:
Status | Пояснения 0 Запрос успешно выполнен 1 Запрос «провалился» 2 Запрос не выполняется, т.к. ждёт завершения обработки других запросов 3 Запрос прерван
4 Запрос обрабатывается
На основе этой таблички легко написать процедуру, которая будет дожидаться выполнения всех запросов к персонажу, а затем вернёт программе управление:
procedure WaitFor(Request:IAgentCtlRequest);
begin
repeat Application.ProcessMessages; Status := Request.Status;
until (Request.Status 2) and (Request.Status 4);
end;
Для примера добавьте на форму кнопку «Пример WaitFor»:
procedure TForm1.Button3Click(Sender: TObject);
begin
//Джин произносит фразу Request := Character.Speak(‘Доброе утро’, EmptyParam);
{waitfor(Request);}
//Показываем сообщение ShowMessage(‘Всё’);
end;
Если нажать на кнопку, то Джин начнёт говорить и сразу же появится сообщение. А если снять комментарии со строки waitfor(Request);, то сообщение появится только после того, как Джин закончит говорить. А сейчас «научим» Джина вслух произносить текущее время. Для этого ему нельзя подсунуть строку типа «21 час 44 минуты 32 секунды», эту строку он произнесёт так: «двадцать один час, сорок четвёртого минуты, тридцать второго секунды». В связи с этим, Джину нужно полностью «разжевать», что именно он должен произносить. Так что будем давать ему такую строку: «21 час, 44 минуты, 30 две секунды». Т.е. число, стоящее в женском роде (32 секунды), разделяем на составляющие (30 две секунды).
Добавьте на форму очередную кнопку «Сколько времени?» и запишите следующую процедуру:
procedure TForm1.Button1Click(Sender: TObject);
var buf, str: string; Hour, Min, Sec, Msec: Word; Hours, Mins, Secs: string; hs, ms, ss: string; DT: TDateTime;
begin
hs := »; ms := »; ss := »;
//узнаём текущее время
DT := Now;
//разбиваем его на составляющие
DecodeTime(DT, Hour, Min, Sec, MSec);
//смотрим, какое окончание должно быть у слова «час»
case hour of 2..4, 22, 23: hs := ‘а’; 0, 5..20: hs := ‘ов’;
end;
//окончание слова «минута»
case min of 1, 21, 31, 41, 51: ms := ‘а’; 2..4, 22..24, 32..34, 42..44, 52..54: ms := ‘ы’;
end;
//окончание слова «секунда»
case sec of 1, 21, 31, 41, 51: ss := ‘а’; 2..4, 22..24, 32..34, 42..44, 52..54: ss := ‘ы’;
end;
//часы не будем преобразовывать, т.к. слово «час» мужского рода hours := inttostr(hour);
//при необходимости разбиваем минуты на слова
mins := inttostr(min);
if (mins[length(mins)] = ‘1’) and (min 11) then
begin
if (min > 10) then buf := mins[1] + ‘0 ‘
else buf:=»; mins := buf + ‘одна’;
end
else
begin
if (mins[length(mins)]=’2′) and (min12) then
begin
if (min>10) then buf:=mins[1]+’0 ‘
else buf:=»; mins := buf + ‘две’;
end
end;
//при необходимости разбиваем секунды на слова secs := inttostr(sec);
if (secs[length(secs)]=’1′) and (sec11) then
begin
if (sec>10) then buf := secs[1] + ‘0 ‘
else buf := »; secs := buf + ‘одна’;
end
else
begin
if (secs[length(secs)]=’2′) and(sec12) then
begin
if (sec>10) then buf := secs[1] + ‘0 ‘
else buf:=»; secs := buf + ‘две’;
end;
end;
//составляем строку, которую должен произнести Джин str := hours + ‘ час’ + hs+ ‘, ‘ + mins + ‘ минут’ + ms + ‘, ‘ + secs + ‘ секунд’ + ss;
//Джин произносит строку str, а над ним отображается текущее время (рис.1)
Request := Character.Speak(‘\Pit=18400\\Spd=100\\Map=»‘+str+'»=»‘+timetostr(DT)+'»\’,EmptyParam);
end;
Напоследок рассмотрим некоторые параметры голосового движка. На один компьютер можно установить поддержку нескольких языков. Чтобы переключаться между ними, нужно изменять параметр персонажа LanguageID. В таблице приведены идентификаторы к некоторым языкам. Символ «$» означает, что число представлено в шестнадцатеричной системе счисления.
Пример: Character.LanguageID := $409; – переключаемся на английский язык. Ещё можно изменять сам голос. Для этого есть свойство TTSModeID. Ниже приведён список голосов для русского и английского языков.
Пример:
Сharacter.TTSModeID:='{06377F80-D48E-11d1-B17B-0020AFED142E}’; –
устанавливает женский голос для русского языка. Так что можете поиздеваться над Джином, заставляя его разговаривать женским голосом.
На сегодня всё, в следующей части мы научимся управлять Джином при помощи голосовых команд.
Иван Ширко
ishyrko@gmail.com