Голосова підтримка в XML: Частина 1. Розробляємо програму прослуховування RSS-каналів (исходники), Різне, Програмування, статті

Введення


Цю статтю буде корисно прочитати всім, хто цікавиться перевагами використання голосових програм для читання RSS-стрічок. До того ж ви познайомитеся з основами VoiceXML і форматом RSS XML. Але головне, ви навчитеся:



Про цієї серії


Аудіо та, зокрема, голосові сервіси стають все більш популярні в Інтернет. Як приклади можуть служити всілякі музичні ресурси, а також Web-трансляції, доступні в онлайн. Статті нашої серії розповідають про способи поєднання голосових технологій і XML при розробці таких програм, як:



Основи VoiceXML


VoiceXML – це загальна назва для голосових даних XML, в той час як сам файловий формат називається VXML.


VXML особливо корисний при використанні спільно з браузером VoiceXML, що перетворює вміст файлу в мову (так зване Text-To-Speech або TTS-перетворення), а також здатним сприймати голосові команди (тобто мають функцію розпізнавання голосу).


У лістингу 1 показаний базовий формат файлу VXML.


Лістинг 1. Базовий формат файлів VXML





<?xml version=”1.0″?>
<vxml xmlns=”http://www.w3.org/2001/vxml” version=”2.0″>

</vxml>

Далі можна додавати елементи, надавати можливість вибору інформації і розбивати її на блоки. Дані для TTS розміщуються всередині тега <prompt>. У лістингу 2 показано, як можна описати просте речення на VXML для подальшого вимови.


Лістинг 2. Приклад файлу VXML





<?xml version=”1.0″ encoding=”UTF-8″?>
<vxml version=”2.1″>
<form>
<block>
<prompt>
I could ask you anything!
</prompt>
</block>
</form>
</vxml>

Якщо у відповідь на голосові запити очікується будь-яку дію користувача, то в елементах <prompt> можна або перерахувати список відповідей, коректно сприймаються системою розпізнавання мовлення, або ж запросити введення з телефонної клавіатури. Отримана інформація потім зберігається в змінних, так що можна використовувати звичайні умовні оператори (if / else) для формування відповідей.


Всі ці методи будуть продемонстровані як у даній статті, так і в наступних статтях серії.


Для запуску прикладів до статті вам знадобиться доступ до хостингу для розміщення файлів VXML, а також браузер VoiceXML з функціями TTS і розпізнавання мови. Як правило, подібні компоненти доступні через різного роду телефонні лінії. Наприклад, Voxeo надає голосової браузер, а також всі необхідні сервіси, зокрема, можливість додзвонюватися до ваших додатків зі стаціонарних телефонів, використовуючи спеціальний пін-код. Це здійснюється через спеціальний VoIP-сервіс на основі протоколу SIP (Session Initiation Protocol) або ж просто через Skype.


Формат файлів RSS


RSS (Really Simple Syndication) – це заснована на XML технологія, призначена для публікації інформації, часто використовуваної в блогах і подібних сайтах. Формат RSS дозволяє легко створювати списки статей або інших інформаційних блоків. Інформацію, що поступає по декількох каналах RSS можна агрегувати, в результаті виходить відформатований список статей, історій і т.д. разом з заголовком і відповідним URL, коротким змістом, а також класифікаторами для кожної із складових частин. Крім цього RSS-стрічка містить інформацію для класифікування всього каналу як єдиного цілого.


RSS – це всього лише один з багатьох XML-форматів для об’єднання даних з різних джерел. Незважаючи на те, що базова структура файла RSS досить проста, вона може сприйматися на перший погляд насилу, тому в лістингу 3 представлений дещо спрощений варіант.


Лістинг 3. Приклад структури RSS





<?xml version=”1.0″ encoding=”UTF-8″?>
<!– generator=”wordpress/2.0.4″ –>
<rss version=”2.0″
xmlns:content=”http://purl.org/rss/1.0/modules/content/”
xmlns:wfw=”http://wellformedweb.org/CommentAPI/”
xmlns:dc=”http://purl.org/dc/elements/1.1/”
>
<channel>
<title>MCslp</title>
<link>http://mcslp.com</link>
<description>News from the desk of Martin MC Brown</description>
<pubDate>Thu, 19 Apr 2007 08:14:30 +0000</pubDate>
<generator>http://wordpress.org/?v=2.0.4</generator>
<language>en</language>
<item>
<title>IBM developerWorks Podcast Interview</title>

</item>
<item>
<title>…</title>

</item>
</channel>
</rss>

Заголовна секція містить загальну інформацію про стрічку, як, наприклад, назва блогу (MCslp) або ж загальний опис матеріалу (“Новости з контори Мартіна Брауна”).


Також в лістингу 3 представлена ​​додаткова інформація про стрічку, така як дата публікації, відповідна даті генерації в разі динамічних RSS-каналів. Крім цього присутній окремий блок, що описує кожну статтю в стрічці.


У подібних блоках міститься заголовок статті, коротка резюмуюча інформація, а також більш детальна (або навіть повна) версія матеріалу. Останнє можливе за умови підтримки з боку RSS-каналу. Формат статті представлений у лістингу 4.


Лістинг 4. Елемент RSS-стрічки в XML





<item>
<title>IBM developerWorks Podcast Interview</title>
<link>http://mcslp.com/?p=250</link>
<comments>http://mcslp.com/?p=250#comments</comments>
<pubDate>Thu, 19 Apr 2007 08:14:28 +0000</pubDate>
<dc:creator>Martin MC Brown</dc:creator>
<category>Articles</category>
<category>Interviews</category>
<category>IBM developerWorks</category>
<category>Grids</category>
<guid isPermaLink=”false”>http://mcslp.com/?p=250</guid>
<description>
<![CDATA[
Summary
]]>
</description>
<content:encoded>
<![CDATA[
Full information
]]>
</content:encoded>
</item>

Якщо інформація подається у форматі VoiceXML, то деякі з цих елементів можуть ігноруватися. Існують певні обмеження на інформацію, призначену для голосового вимови. Наприклад, назви категорій, глобальні ідентифікатори guid і тому подібні елементи вимовляти не має сенсу.


Основний інтерес представляють такі складові стрічки, як заголовок всього каналу, а також назву і опис для кожної зі статей.


Розглянемо дуже простий спосіб перетворення файлу RSS в VoiceXML.


Застосування простого XSL-перетворення


Один з найпростіших способів перетворення XML-файла RSS у формат VXML полягає у використанні шаблону XSL. Правда, в деяких випадках це може виявитися непростим заняттям, особливо через обмежені і кілька заплутаних методів для вибірки елементів та логічного розгалуження в XSL. Але в цілому це непоганий варіант для швидкого вирішення проблеми.


У лістингу 5 показана проста таблиця стилів XSL, перетворююча елементи title і description вихідного файлу RSS у формат VXML. В результаті заголовки і вміст кожної з статей RSS-стрічки можуть бути озвучені.


Лістинг 5. Таблиця стилів XSL для перетворення RSS в VXML





<?xml version=”1.0″ encoding =”UTF-8″?>
<xsl:stylesheet version=”1.0″
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>
<xsl:output method=”xml” omit-xml-declaration=”no”/>
<xsl:template match=”/”>
<vxml version=”2.0″
xmlns=”http://www.w3.org/2001/vxml”>
<form id=”news”>
<xsl:for-each select=”rss/channel/item”>
<block>
<prompt>
<xsl:value-of select=”title” />
<break size=”small” />
<xsl:value-of select=”description” />
<break size=”medium” />
</prompt>
</block>
</xsl:for-each>
</form>
</vxml>
</xsl:template>
</xsl:stylesheet>

Шаблон XSL обробляє всі статті в RSS-стрічці, використовуючи для їх вибірки вирази XPath. Потім значення елементів title і description (заголовка та вмісту відповідно) поміщаються в блоки prompt, Спільні блоками break. Останні використовуються в VoiceXML для вставки пауз в висновок TTS.


Застосувати XSL-перетворення до XML-документу RSS можна за допомогою утиліти xsltproc. Результат перетворення стрічки новин BBC показаний в лістингу 6.


Лістинг 6. Створення файлу VXML за допомогою таблиці стилів XSL





$ xsltproc rsstovxml.xsl rss.xml
<?xml version=”1.0″?>
<vxml xmlns=”http://www.w3.org/2001/vxml” version=”2.0″>
<form id=”news”>
<block>
<prompt>Prince Harry not to serve in Iraq
<break size=”small”/>
Prince Harry will not be deployed in Iraq because of
the security threat, the head of the Army says.
<break size=”medium”/>
</prompt>
</block>

</form>
</vxml>

Як видно з лістингу, кожній статті RSS-стрічки відповідає окремий блок з заголовком, паузою і коротким змістом. Далі згенерований VXML-документ можна завантажити в голосовий браузер і прослухати. Але сам по собі цей результат не особливо застосуємо на практиці, тому що крім цього необхідно автоматично завантажувати і перетворювати вміст RSS-стрічки. Іншими словами, треба подумати, як динамічно надавати всю необхідну інформацію в VoiceXML.


Процес перетворення RSS в VoiceXML


Одна з проблем при використанні XSL – це простота і, як наслідок, обмеженість цього підходу, причому як в сенсі способів створення файлу VXML, так і в сенсі його вмісту. Для вирішення цієї проблеми можна використовувати мови програмування, наприклад, Java або Python, що дозволяють виконувати більш складні перетворення.


Перш ніж почати, уявімо собі логіку роботи простого RSS-браузера, як показано на малюнку 1.


Рисунок 1. Логіка роботи програми для перетворення RSS в VXML

Принцип роботи наступний: після отримання вхідного дзвінка, звонящему надається вибір з доступних RSS-каналів. Як тільки він вибрав канал, його вміст обробляється і створюється список заголовків всіх статей в стрічці. Таким чином абонент може вибрати і прослухати цікаві його статті.


Спочатку відбувається обробка RSS-стрічки і формування файлу VXML для прочитання вголос статей та створення основного набору інформації для озвучування.


Перетворення RSS в VoiceXML за допомогою Perl


Існує безліч Perl-модулів для обробки новинних стрічок, найбільш зручним з яких є XML::FeedPP. Модуль може обробляти будь-яку новинну стрічку, включаючи такі формати, як RSS, RDF і Atom. Крім цього модуль надає доступ до вмісту стрічки через спрощений інтерфейс.


Для розбору вмісту необхідно створити об’єкт типу XML::FeedPP і передати йому URL стрічки: my $feed = XML::FeedPP->new($feedurl);.


Решта інформації про стрічку, включаючи заголовок, може бути отримана через цей об’єкт верхнього рівня. Наприклад, заголовок виходить таким чином: $feed->title();.


Доступ безпосередньо до статей стрічки здійснюється в два етапи: спочатку необхідно отримати список статей за допомогою методу get_item(), А потім звертатися до їх змісту, викликаючи методи title(), description() і т.д.


У лістингу 7 показано, як можна скласти список новин для даної стрічки.


Лістинг 7. Приклад створення файлу VXML з RSS-стрічки за допомогою Perl





use XML::FeedPP;
my $feedurl
= “http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/uk/rss.xml”;
my $feed = XML::FeedPP->new($feedurl);
my ($selection) = (“”);
$selection = “<form><block>”;
$selection .= “<prompt>” . $feed->title() .
“<break size=”small”/></prompt>”;
foreach my $i ( $feed->get_item() )
{
next unless defined($i);
next unless ($i->link() =~ m/http/);
$selection
.= sprintf(“<prompt>%s.<break size=”small”/></prompt>”,
$i->title());
}
$selection .= “</block></form>”;
print <<EOF;
<?xml version=”1.0″ encoding =”UTF-8″?>
<!DOCTYPE vxml PUBLIC “-//W3C//DTD VOICEXML 2.1//EN”
“http://www.w3.org/TR/voicexml21/vxml.dtd”>
<vxml version=”2.1″ xmlns=”http://www/w3/org/2001/vxml”
xml:lang=”en-US”>
$selection
</vxml>
EOF

Скрипт в лістингу 7 складається з двох основних частин. Спочатку скрипт отримує на вхід вміст стрічки і створює блоки prompt на кожен новинний заголовок, зберігаючи висновок в строкової змінної. Потім сформована рядок цілком записується в файл VXML.


Скрипт перебирає всі новини в стрічці і додає у вихідний файл заголовки, розділені короткими паузами. Звичайно для цього завдання можна було використовувати повнофункціональний генератор XML, але оскільки файл має досить просту структуру, то досить простих операторів виводу для додавання в нього інформації.


Відзначте, що на даному етапі RSS-стрічка створена вручну, а результати перетворення видаються в стандартний потік виводу. Таким чином, якщо потрібно створити вихідний файл, то в нього треба просто перенаправити стандартний висновок. Отриманий файл VXML представлений у лістингу 8 (файл скорочений в інтересах економії місця).


Лістинг 8. Приклад VXML-файлу, згенерованого автоматично з RSS-стрічки





<vxml version=”2.1″ xmlns=”http://www/w3/org/2001/vxml”
xml:lang=”en-US”>
<form>
<block>
<prompt>
BBC News / UK / UK Edition
<break size=”small” />
</prompt>
<prompt>
Prince Harry not to serve in Iraq.
<break size=”small” />
</prompt>
<prompt>
Madeleine fighting fund launched.
<break size=”small” />
</prompt>

</block>
</form>
</vxml>

Якщо завантажити цей файл у відповідний сервіс VoiceXML і подзвонити, то у відповідь можна почути список новин, отриманих безпосередньо зі стрічки RSS.


Поки що можна тільки прослухати список заголовків новин. Звичайно, було б бажано крім заголовків мати можливість послухати і подробиці обраних новин.


Додавання можливості вибору новин


Щоб додати можливості вибору новин і прослуховування їх коротких версій (summary), необхідно передбачити декілька додаткових дій на етапі створення файлу VXML, а саме:



  1. Створити пронумерований список для вибору новин і передбачити можливість вибору елементів зі списку.
  2. Реалізувати можливість обробки вхідного параметра, що представляє собою номер новини для прослуховування. Параметр може бути в голосовому вигляді, але в даному випадку ми будемо використовувати формат DTMF.
  3. Помістити короткі версії новин в файл VXML.

Реалізувати першу дію досить просто: все що потрібно – це привласнити унікальний номер кожної новини і виводити його поряд з заголовком. Крім цього, необхідно, щоб пронумеровані заголовки точно відповідали змісту новин, що видаються за запитом користувача. Для цього будуть використовуватися дві часові строкових змінних: одна буде зберігати номер обраної новини, а інша – текст, який буде озвучений для користувача.


Для отримання та обробки введення з клавіатури можна використовувати спеціальний елемент field, передбачений в VXML: <field name=”select_num” type=”digits”>.


В цьому випадку система буде очікувати числового введення від користувача. Після цього відбудеться розбір числового блоку в VXML, і отримане число буде використано для вибору потрібної новини. Потім короткий зміст новини буде вимовлено вголос голосовим сервісом.


Розбір числового значення відбувається наступним чином: всі цифри числа послідовно вводяться у вигляді сигналів DTMF (Dual Tone Multi-Frequency), а потім поміщаються в спеціальну змінну: <assign name=”selection” expr=”select_num”/>.


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


Як тільки цифри введені, можна використовувати звичайний блок умовного переходу (if) Для вибору новини для прослуховування.


Повний варіант скрипта (знову на Perl) показаний в лістингу 9.


Лістинг 9. Повний текст скрипта на Perl





use XML::FeedPP;
my $feedurl
= “http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/uk/rss.xml”;
my $feed = XML::FeedPP->new($feedurl);
my ($selection,$detail,$counter) = (“”,””,0);
$selection = “<form id=”MainMenu”><field name=”select_num” type=”digits”>”;
$selection .= “<prompt>” . $feed->title() .
“<break size=”small”/></prompt>”;
$selection .= “<prompt>Please select a story from the
following list.</prompt>”;
foreach my $i ( $feed->get_item() )
{
next unless defined($i);
next unless ($i->link() =~ m/http/);
# Виведемо тільки 6 останній новин
last if ($counter++ >= 6);
if ($counter == 1)
{
$detail .= “<filled><assign name=”selection” expr=”select_num”/>”;
$detail .= “<if cond=”selection ==”$counter””>”;
}
else
{
$detail .= “<elseif cond=”selection ==”$counter””/>”;
}
$detail .= sprintf(“<prompt>%s. %s<break size=”small”/>
<reprompt/></prompt>”,$i->title(),$i->description());
$selection .= sprintf(“<prompt>%d: %s<break
size=”small”/></prompt>”,$counter,$i->title());
}
$selection .= “<noinput>Please select a number.
<reprompt/></noinput>”;
$selection .= “<nomatch>Please select a valid number.
<reprompt/></nomatch>”;
$selection .= “</field>”;
$detail .= “</if><clear
namelist=”select_num”/><reprompt/></filled></form>”;
print <<EOF;
<vxml version=”2.1″>
$selection
$detail
</vxml>
EOF

Згенерований файл VXML представлений у лістингу 10. Крім самих новин, у файлі показано, як обробляється вхідний параметр для вибору зі списку, а також як видаються підказки користувачеві, що полегшують роботу з системою.


Лістинг 10. Реалізація функції вибору новин за допомогою VXML





<vxml version=”2.1″>
<form id=”MainMenu”>
<field name=”select_num” type=”digits”>
<prompt>
BBC News / UK / UK Edition
<break size=”small” />
</prompt>
<prompt>
Please select a story from the following list.
</prompt>
<prompt>
1: Prince Harry not to serve in Iraq
<break size=”small” />
</prompt>
<prompt>
2: Madeleine fighting fund launched
<break size=”small” />
</prompt>
<prompt>
3: Salmond elected as first minister
<break size=”small” />
</prompt>
<prompt>
4: Sainsbury profits jump to £380m
<break size=”small” />
</prompt>
<prompt>
5: Police boo John Reid over pay
<break size=”small” />
</prompt>
<prompt>
6: Uncle jailed for owning death dog
<break size=”small” />
</prompt>
<noinput>
Please select a number.
<reprompt />
</noinput>
<nomatch>
Please select a valid number.
<reprompt />
</nomatch>
</field>
<filled>
<assign name=”selection” expr=”select_num” />
<if cond=”selection ==”1″”>
<prompt>
Prince Harry not to serve in Iraq. Prince Harry will
not be deployed in Iraq because of the security
threat, the head of the Army says.
<break size=”small” />
</prompt>
<elseif cond=”selection ==”2″” />
<prompt>
Madeleine fighting fund launched. A fighting fund is
launched to help cover escalating costs in the
search for missing Madeleine McCann.
<break size=”small” />
</prompt>
<elseif cond=”selection ==”3″” />
<prompt>
Salmond elected as first minister. Alex Salmond
makes history after becoming the first Nationalist
to be elected first minister of Scotland.
<break size=”small” />
</prompt>
<elseif cond=”selection ==”4″” />
<prompt>
Sainsbury profits jump to £380m. Sainsbury”s, the
supermarket chain that was the target of takeover
speculation, sees its full-year profits surge.
<break size=”small” />
</prompt>
<elseif cond=”selection ==”5″” />
<prompt>
Police boo John Reid over pay. Home Secretary John
Reid is booed over pay proposals at the Police
Federation”s annual conference.
<break size=”small” />
</prompt>
<elseif cond=”selection ==”6″” />
<prompt>
Uncle jailed for owning death dog. The uncle of a
five-year-old girl killed by a pit bull terrier is
jailed for eight weeks for owning an illegal dog.
<break size=”small” />
</prompt>
</if>
<clear namelist=”select_num” />
<reprompt />
</filled>
</form>
</vxml>

Завантаживши цей файл в VoiceXML-браузер, ви зможете не тільки слухати заголовки новин, а й вибрати ту, яку ви хочете прослухати більш докладно. Крім цього, після прослуховування існує можливість вибору іншої новини. За це відповідає останній блок у файлі (див. лістинг 11).


Лістинг 11. Запит на вибір наступної новини





<clear namelist=”select_num” />
<reprompt />

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


Незважаючи на те, що RSS-стрічка завантажується динамічно, скрипт як і раніше генерує статичний файл VXML, що містить новини для прослуховування. Для повної інтерактивності необхідно створювати його на льоту.


Створення VoiceXML з RSS-стрічок за допомогою сервлетов Java


До цього моменту можливості вибору новин були обмежені статичним файлом VXML. Для справжньої інтерактивності, він повинен генеруватися скриптом динамічно за запитом користувача. Т.к. більшість голосових браузерів звертаються до VXML-файлів по URL, все що потрібно – це розробити CGI або яке або ще Web-додаток для їх створення на льоту.


Це можна реалізувати за допомогою Perl-скриптів, представлених на лістингах 7 і 9, Але необхідно подбати про формування коректного заголовка HTTP-відповіді (text / xml) перед виведенням самого файлу VXML. Все що потрібно – це додати дві строчки в початок скрипта, як показано в лістингу 12.


Лістинг 12. Формування HTTP-заголовка в Perl-скрипті





use CGI qw/:standard/;
print header(-type => “text/xml”);

За допомогою цих інструкцій імпортується спеціальна бібліотека CGI, відповідальна за формування заголовків HTTP. Останнє ж вміст виведення – це все той же файл VXML, що й раніше.


На основі тих же принципів можна створювати VXML і на інших мовах програмування. Зокрема, в лістингу 13 показаний Java-сервлет, що генерує такий же документ VXML, як і перший Perl-скрипт (див. лістинг 7). Сервлет використовує бібліотеки Rome і JDOM для розбору RSS-стрічки і створення необхідного VXML-файла.


Лістинг 13. Створення голосових RSS-стрічок c допомогою VXML і JSP





import java.net.URL;
import java.util.Iterator;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
import javax.servlet.*;
import javax.servlet.http.*;
import com.sun.syndication.feed.module.Module;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
public class VXMLRSS extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
BufferedInputStream bis = null;
PrintWriter out = null;
try {
out = res.getWriter();
res.setContentType(“text/xml”);
printHeader(out);
printNews(out);
printFooter(out);
} finally {
if (out != null) out.close();
if (bis != null) bis.close();
}
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doGet(req, res);
}
private void printHeader(PrintWriter out) throws IOException {
out.println(“<?xml version=”1.0″ encoding=”UTF-8″?>”);
out.println(“<vxml version=”2.1″>”);
}
private void printNews(PrintWriter out) throws IOException {
try {
final URL feedUrl = new
URL(“http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/uk/rss.xml”);
final SyndFeedInput input = new SyndFeedInput();
final SyndFeed feed = input.build(new XmlReader(feedUrl));
out.println(“<form><block>” +
“<prompt>” +
feed.getTitle() +
“<break size=”small”/></prompt>”);
for (final Iterator iter = feed.getEntries().iterator();
iter.hasNext();)
{
out.println(“<prompt>” +
((SyndEntry)iter.next()).getTitle() +
“<break size=”small”/></prompt>”);
}
out.println(“</block></form>”);
}
catch (Exception ex) {
ex.printStackTrace();
System.out.println(“ERROR: ” + ex.getMessage());
}
}
private void printFooter(PrintWriter out) throws IOException {
out.println(“</vxml>”);
}
}

Основні кроки з розбору стрічки і генерації VXML залишилися точно такими ж, як і у випадку скриптів Perl. Замість використання одного статичного VXML-файлу, відбувається звернення до RSS-стрічці та створення VXML при запиті користувача.


Далі цей сервлет разом з необхідними JAR-файлами для JDOM і Rome, можна розгорнути в контейнері JSP, наприклад в Apache Tomcat, і використовувати його як основу вашого майбутнього VXML-додатки.


Динамічна генерація різних VXML-файлів


Крім озвучування будь-якої конкретної RSS-стрічки, можна надавати користувачеві список новинних каналів для прослуховування. Це також дає можливість додати інтерактивності додатку, а саме, вибирати, який скрипт і звідки викликати при виборі тієї чи іншої новини користувачем.


Для початку треба створити список RSS-стрічок, доступних для озвучування. У нашому прикладі використовується звичайний масив, але в принципі ця інформація може завантажуватися з якоїсь бази даних. Далі для кожної стрічки витягується її назву та опис, створюється необхідний пронумерований список, після чого скрипт чекає вибору користувача. Проте в цьому випадку, після отримання від користувача конкретного числа, скрипт викликає зовнішній обробник по URL (в даному випадку, самого себе), передаючи номер новинної стрічки в якості аргументу. На кінцевому етапі можна викликати додаткову функцію, видає список новин конкретної стрічки і дозволяє вибрати одну з них.


У лістингу 14 представлений повний код CGI-скрипта на Perl, що виконує перераховані вище дії.


Лістинг 14. CGI-скрипт





#!/usr/bin/perl
use XML::FeedPP;
use CGI qw/:standard/;
print header(-type => “text/xml”);
my ($feeds) = [“http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/uk/rss.xml”,
“http://mcslp.com/wp-rss2.php”];
if (param(“selection”) =~ m/[0-9]+/)
{
output_news_feed($feeds->[param(“selection”)]);
}
else
{
output_feed_list();
}
sub output_feed_list
{
my ($selection,$detail,$counter) = (“”,””,0);
$selection = “<form id=”MainMenu”><field name=”select_num”
type=”digits”>”;
$selection .= “<prompt>MCSLP News Feed
Reader<break size=”small”/></prompt>”;
$selection .= “<prompt>Please select a news source from the following
list.</prompt>”;
foreach my $feedurl (@{$feeds})
{
my $feed = XML::FeedPP->new($feedurl);
$counter++;
if ($counter == 1)
{
$detail .= “<filled><assign name=”selection”
expr=”select_num”/>”;
$detail .= “<if cond=”selection ==”$counter””>”;
}
else
{
$detail .= “<elseif cond=”selection ==”$counter””/>”;
}
$detail .= sprintf(“<goto next=”http://www.mcslp.com/
rsstovxmlopt.cgi?selection=%s”/>”,
$counter);
$selection .= sprintf(“<prompt>%d: %s<break
size=”small”/></prompt>”,$counter,$feed->title());
}
$selection .= “<noinput>Please select a number.
<reprompt/></noinput>”;
$selection .= “<nomatch>Please select a valid number.
<reprompt/></nomatch>”;
$selection .= “</field>”;
$detail .= “</if><clear
namelist=”select_num”/><reprompt/></filled></form>”;
print <<EOF;
<?xml version=”1.0″ encoding=”UTF-8″?>
<vxml version=”2.1″>
$selection
$detail
</vxml>
EOF
}
sub output_news_feed
{
my ($feedurl) = @_;
my $feed = XML::FeedPP->new($feedurl);
my ($selection,$detail,$counter) = (“”,””,0);
$selection = “<form id=”MainMenu”><field name=”select_num”
type=”digits”>”;
$selection .= “<prompt>” . $feed->title() .
“<break size=”small”/></prompt>”;
$selection .= “<prompt>Please select a story from the following
list.</prompt>”;
foreach my $i ( $feed->get_item() )
{
next unless defined($i);
next unless ($i->link() =~ m/http/);
last if ($counter++ >= 6);
if ($counter == 1)
{
$detail .= “<filled><assign name=”selection”
expr=”select_num”/>”;
$detail .= “<if cond=”selection ==”$counter””>”;
}
else
{
$detail .= “<elseif cond=”selection ==”$counter””/>”;
}
$detail .= sprintf(“<prompt>%s. %s<break
size=”small”/></prompt>”,$i->title(),$i->description());

$selection .= sprintf(“<prompt>%d: %s<break
size=”small”/></prompt>”,$counter,$i->title());
}
$selection .= “<noinput>Please select a number.
<reprompt/></noinput>”;
$selection .= “<nomatch>Please select a valid number.
<reprompt/></nomatch>”;
$selection .= “</field>”;
$detail .= “</if><clear
namelist=”select_num”/><reprompt/></filled></form>”;
print <<EOF;
<?xml version=”1.0″ encoding=”UTF-8″?>
<vxml version=”2.1″>
$selection
$detail
</vxml>
EOF
}


У прикладі мається на увазі, що один параметр використовується як для виведення всього списку стрічок, так і для вибору конкретної стрічки зі списку. У разі використання бази даних, швидше за все, буде потрібно присвоювати унікальний ідентифікатор кожної стрічці і використовувати його для вибору. Але загальний принцип залишається незмінним.


До речі кажучи, необхідного результату можна досягти використовуючи тільки VXML. В VXML можна додавати різні блоки form, а потім використовувати їх для виведення потрібних стрічок. Але на практиці створювати VXML-файли великого розміру, як правило, не варто, набагато краще використовувати скрипти для швидкої генерації невеликих обсягів VXML-даних на льоту.


Використовуючи таку динамічну генерацію VXML, слід подбати про те, щоб вона не уповільнювала роботу програми. Наприклад, вищенаведений скрипт безпосередньо звертається до кожної новинній стрічці, що може займати значний час. Використовуючи базу даних, можна завантажувати і виводити заголовок та короткий опис стрічок набагато швидше.


Крім цього, майте на увазі, що в разі динамічної генерації можуть знадобитися додаткові зусилля по обробці можливих помилок. Наприклад, в нашому випадку якщо яка-небудь зі стрічок недоступна, то скрипт виведе порожній список новин, в той час як повідомлення типу: “Вибачте, сервіс в даний час недоступний” було б значно інформативніше для користувача при виникненні такої ситуації.


Висновок


В даній статті були розглянуті різні підходи до генерування документів VXML, необхідних для прослуховування RSS-стрічок. Ми почали з простого варіанту на основі XSL, а потім перейшли до більш гнучким рішенням, використовують скрипти Perl і сервлети Java.


Самі по собі скрипти досить примітивні. Вся міць полягає в створеному VXML-вмісті, а також в голосовому браузері, що використовує VXML для надання голосового інтерфейсу. Крім цього, у статті розповідалося як забезпечувати певний рівень інтерактивності, використовуючи VXML спільно з динамічними скриптами. Все це дозволяє відносно легко розробляти досить складні голосові додатки.


Залишайтеся з нами, і в другої частини ми розробимо календар з голосовою підтримкою.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*