directory.lua 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. --[[
  2. FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
  3. Copyright (C) 2005/2006, Anthony Minessale II <anthm@freeswitch.org>
  4. Version: MPL 1.1
  5. The contents of this file are subject to the Mozilla Public License Version
  6. 1.1 (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.mozilla.org/MPL/
  9. Software distributed under the License is distributed on an "AS IS" basis,
  10. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. for the specific language governing rights and limitations under the
  12. License.
  13. The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
  14. The Initial Developer of the Original Code is
  15. Anthony Minessale II <anthm@freeswitch.org>
  16. Portions created by the Initial Developer are Copyright (C)
  17. the Initial Developer. All Rights Reserved.
  18. Contributor(s):
  19. Brian West <brian@freeswitch.org>
  20. Example for Speech Enabled LUA Applications.
  21. ]]
  22. -- Used in parse_xml
  23. function parseargs_xml(s)
  24. local arg = {}
  25. string.gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a)
  26. arg[w] = a
  27. end)
  28. return arg
  29. end
  30. -- Turns XML into a lua table.
  31. function parse_xml(s)
  32. local stack = {};
  33. local top = {};
  34. table.insert(stack, top);
  35. local ni,c,label,xarg, empty;
  36. local i, j = 1, 1;
  37. while true do
  38. ni,j,c,label,xarg, empty = string.find(s, "<(%/?)(%w+)(.-)(%/?)>", i);
  39. if not ni then
  40. break
  41. end
  42. local text = string.sub(s, i, ni-1);
  43. if not string.find(text, "^%s*$") then
  44. table.insert(top, text);
  45. end
  46. if empty == "/" then
  47. table.insert(top, {label=label, xarg=parseargs_xml(xarg), empty=1});
  48. elseif c == "" then
  49. top = {label=label, xarg=parseargs_xml(xarg)};
  50. table.insert(stack, top);
  51. else
  52. local toclose = table.remove(stack);
  53. top = stack[#stack];
  54. if #stack < 1 then
  55. error("nothing to close with "..label);
  56. end
  57. if toclose.label ~= label then
  58. error("trying to close "..toclose.label.." with "..label);
  59. end
  60. table.insert(top, toclose);
  61. end
  62. i = j+1;
  63. end
  64. local text = string.sub(s, i);
  65. if not string.find(text, "^%s*$") then
  66. table.insert(stack[stack.n], text);
  67. end
  68. if #stack > 1 then
  69. error("unclosed "..stack[stack.n].label);
  70. end
  71. return stack[1];
  72. end
  73. function dump(o)
  74. if type(o) == 'table' then
  75. local s = '{ '
  76. for k,v in pairs(o) do
  77. if type(k) ~= 'number' then k = '"'..k..'"' end
  78. s = s .. '['..k..'] = ' .. dump(v) .. ','
  79. end
  80. return s .. '} '
  81. else
  82. return tostring(o)
  83. end
  84. end
  85. -- Used to parse the XML results.
  86. function getResults(s)
  87. local xml = parse_xml(s);
  88. local stack = {}
  89. local top = {}
  90. -- freeswitch.consoleLog("crit", "\n" .. dump(xml) .. "\n");
  91. table.insert(stack, top)
  92. top = {grammar=xml[2].xarg.grammar, score=xml[2].xarg.confidence, text=xml[2][1][1][1]}
  93. table.insert(stack, top)
  94. return top;
  95. end
  96. -- This is the input callback used by dtmf or any other events on this session such as ASR.
  97. function onInput(s, type, obj)
  98. freeswitch.consoleLog("info", "Callback with type " .. type .. "\n");
  99. if (type == "dtmf") then
  100. freeswitch.consoleLog("info", "DTMF Digit: " .. obj.digit .. "\n");
  101. else if (type == "event") then
  102. local event = obj:getHeader("Speech-Type");
  103. if (event == "begin-speaking") then
  104. freeswitch.consoleLog("info", "\n" .. obj:serialize() .. "\n");
  105. -- Return break on begin-speaking events to stop playback of the fire or tts.
  106. return "break";
  107. end
  108. if (event == "detected-speech") then
  109. freeswitch.consoleLog("info", "\n" .. obj:serialize() .. "\n");
  110. if (obj:getBody()) then
  111. -- Pause speech detection (this is on auto but pausing it just in case)
  112. session:execute("detect_speech", "pause");
  113. -- Parse the results from the event into the results table for later use.
  114. results = getResults(obj:getBody());
  115. end
  116. return "break";
  117. end
  118. end
  119. end
  120. end
  121. --Used to map returned names to extension numbers
  122. extensions = {
  123. ["anthony"] = 3000,
  124. ["michael"] = 3001,
  125. ["brian"] = 3002
  126. }
  127. -- Create the empty results table.
  128. results = {};
  129. -- Answer the call.
  130. session:answer();
  131. -- Define TTS Engine
  132. session:set_tts_params("flite", "slt");
  133. -- Register the input callback
  134. session:setInputCallback("onInput");
  135. -- Sleep a little bit to give media time to be fully up.
  136. session:sleep(200);
  137. session:speak("Welcome to the directory.");
  138. -- Start the detect_speech app. This attaches the bug to fire events
  139. session:execute("detect_speech", "pocketsphinx directory directory");
  140. -- Magic happens here.
  141. -- It would be ok to loop like 3 times and error to the operator if this doesn't work or revert to reading names off with TTS.
  142. while (session:ready() == true) do
  143. session:sleep(100);
  144. -- Who are they looking for?
  145. session:speak("Say the name of the person you're trying to reach.");
  146. -- This sleep is what blocks till the detected-speech event. This has to give you enough time to speak plus get the results.
  147. session:sleep(3000);
  148. session:sleep(3000);
  149. -- If the results aren't null and we have an extension in the table.
  150. if (results.text ~= nil and extensions[results.text] ~= nil) then
  151. -- Letting the caller know we are trying.
  152. session:speak("Please hold while I transfer your call.");
  153. -- It's critical to stop the detect_detect otherwise it will continue to fire speech events and waste resources.
  154. session:execute("detect_speech", "stop");
  155. -- Transfer the call to the extension out of the lua table.
  156. session:execute("transfer", extensions[results.text] .. " XML default");
  157. end
  158. -- We didn't have them in our directory table.
  159. session:speak("Sorry, I don't have that person listed, please try again.");
  160. -- Clear any results we have just in case.
  161. results = {};
  162. -- Resume detect_speech.
  163. session:execute("detect_speech", "resume");
  164. end