mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-24 03:52:50 -06:00
Use printname to make VoiceXML prompts.
This commit is contained in:
@@ -11,27 +11,32 @@
|
|||||||
module GF.Speech.GrammarToVoiceXML (grammar2vxml) where
|
module GF.Speech.GrammarToVoiceXML (grammar2vxml) where
|
||||||
|
|
||||||
import qualified GF.Canon.GFC as GFC
|
import qualified GF.Canon.GFC as GFC
|
||||||
import GF.Canon.CMacros (noMark)
|
import GF.Canon.AbsGFC (Term)
|
||||||
|
import GF.Canon.PrintGFC (printTree)
|
||||||
|
import GF.Canon.CMacros (noMark, strsFromTerm)
|
||||||
import GF.Canon.Unlex (formatAsText)
|
import GF.Canon.Unlex (formatAsText)
|
||||||
import GF.Compile.ShellState (StateGrammar,stateGrammarST,cncId)
|
import GF.Compile.ShellState (StateGrammar,stateGrammarST,cncId,grammar)
|
||||||
import GF.Grammar.Macros hiding (assign)
|
import GF.Data.Str (sstrV)
|
||||||
|
import GF.Grammar.Macros hiding (assign,strsFromTerm)
|
||||||
import GF.Grammar.Grammar (Fun)
|
import GF.Grammar.Grammar (Fun)
|
||||||
import GF.Grammar.Values (Tree)
|
import GF.Grammar.Values (Tree)
|
||||||
import GF.UseGrammar.GetTree (string2treeErr)
|
import GF.UseGrammar.GetTree (string2treeErr)
|
||||||
import GF.UseGrammar.Linear (linTree2strings)
|
import GF.UseGrammar.Linear (linTree2strings)
|
||||||
|
|
||||||
|
import GF.Infra.Ident
|
||||||
import GF.Infra.Modules
|
import GF.Infra.Modules
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
|
|
||||||
import GF.Data.XML
|
import GF.Data.XML
|
||||||
|
|
||||||
|
import Control.Monad (liftM)
|
||||||
import Data.List (isPrefixOf, find, intersperse)
|
import Data.List (isPrefixOf, find, intersperse)
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
|
|
||||||
import Debug.Trace
|
import Debug.Trace
|
||||||
|
|
||||||
-- | the main function
|
-- | the main function
|
||||||
grammar2vxml :: String -> StateGrammar -> String
|
grammar2vxml :: Ident -> StateGrammar -> String
|
||||||
grammar2vxml startcat gr = showsXMLDoc (skel2vxml name language startcat gr' qs) ""
|
grammar2vxml startcat gr = showsXMLDoc (skel2vxml name language startcat gr' qs) ""
|
||||||
where (name, gr') = vSkeleton (stateGrammarST gr)
|
where (name, gr') = vSkeleton (stateGrammarST gr)
|
||||||
qs = catQuestions gr (map fst gr')
|
qs = catQuestions gr (map fst gr')
|
||||||
@@ -40,25 +45,23 @@ grammar2vxml startcat gr = showsXMLDoc (skel2vxml name language startcat gr' qs)
|
|||||||
-- * VSkeleton: a simple description of the abstract syntax.
|
-- * VSkeleton: a simple description of the abstract syntax.
|
||||||
--
|
--
|
||||||
|
|
||||||
type VIdent = String
|
type VSkeleton = [(Ident, [(Ident, [Ident])])]
|
||||||
|
type VIdent = Ident
|
||||||
|
|
||||||
type VSkeleton = [(VIdent, [(VIdent, [VIdent])])]
|
vSkeleton :: GFC.CanonGrammar -> (VIdent,VSkeleton)
|
||||||
|
|
||||||
vSkeleton :: GFC.CanonGrammar -> (String,VSkeleton)
|
|
||||||
vSkeleton gr = (name,collectR rules [(c,[]) | c <- cats]) where
|
vSkeleton gr = (name,collectR rules [(c,[]) | c <- cats]) where
|
||||||
collectR rr hh =
|
collectR rr hh =
|
||||||
case rr of
|
case rr of
|
||||||
(fun,typ):rs -> case catSkeleton typ of
|
(fun,typ):rs -> case catSkeleton typ of
|
||||||
Ok (cats,cat) ->
|
Ok (cats,cat) ->
|
||||||
collectR rs (updateSkeleton (symid (snd cat)) hh (fun,
|
collectR rs (updateSkeleton (snd cat) hh (fun, map snd cats))
|
||||||
map (symid . snd) cats))
|
|
||||||
_ -> collectR rs hh
|
_ -> collectR rs hh
|
||||||
_ -> hh
|
_ -> hh
|
||||||
cats = [symid cat | (cat,GFC.AbsCat _ _) <- defs]
|
cats = [cat | (cat,GFC.AbsCat _ _) <- defs]
|
||||||
rules = [(symid fun, typ) | (fun,GFC.AbsFun typ _) <- defs]
|
rules = [(fun, typ) | (fun,GFC.AbsFun typ _) <- defs]
|
||||||
|
|
||||||
defs = concat [tree2list (jments m) | im@(_,ModMod m) <- modules gr, isModAbs m]
|
defs = concat [tree2list (jments m) | im@(_,ModMod m) <- modules gr, isModAbs m]
|
||||||
name = ifNull "UnknownModule" (symid . last) [n | (n,ModMod m) <- modules gr, isModAbs m]
|
name = ifNull (error "No abstract module") last [n | (n,ModMod m) <- modules gr, isModAbs m]
|
||||||
|
|
||||||
updateSkeleton :: VIdent -> VSkeleton -> (VIdent, [VIdent]) -> VSkeleton
|
updateSkeleton :: VIdent -> VSkeleton -> (VIdent, [VIdent]) -> VSkeleton
|
||||||
updateSkeleton cat skel rule =
|
updateSkeleton cat skel rule =
|
||||||
@@ -75,12 +78,23 @@ type CatQuestions = [(VIdent,String)]
|
|||||||
catQuestions :: StateGrammar -> [VIdent] -> CatQuestions
|
catQuestions :: StateGrammar -> [VIdent] -> CatQuestions
|
||||||
catQuestions gr cats = [(c,catQuestion gr c) | c <- cats]
|
catQuestions gr cats = [(c,catQuestion gr c) | c <- cats]
|
||||||
|
|
||||||
catQuestion :: StateGrammar -> VIdent -> String
|
catQuestion :: StateGrammar -> Ident -> String
|
||||||
catQuestion gr cat = err errHandler id (lin gr fun)
|
catQuestion gr cat = err errHandler id (getPrintname gr cat >>= term2string)
|
||||||
where fun = "quest_" ++ cat
|
where -- FIXME: use some better warning facility
|
||||||
errHandler e = trace ("GrammarToVoiceXML: " ++ e) fun
|
errHandler e = trace ("GrammarToVoiceXML: " ++ e) ("quest_"++prIdent cat)
|
||||||
-- FIXME: use some better warning facility
|
term2string = liftM sstrV . strsFromTerm
|
||||||
|
|
||||||
|
getPrintname :: StateGrammar -> Ident -> Err Term
|
||||||
|
getPrintname gr cat =
|
||||||
|
do m <- lookupModMod (grammar gr) (cncId gr)
|
||||||
|
i <- lookupInfo m cat
|
||||||
|
case i of
|
||||||
|
GFC.CncCat _ _ p -> return p
|
||||||
|
_ -> fail $ "getPrintname " ++ prIdent cat
|
||||||
|
++ ": Expected CncCat, got " ++ show i
|
||||||
|
|
||||||
|
|
||||||
|
{-
|
||||||
lin :: StateGrammar -> String -> Err String
|
lin :: StateGrammar -> String -> Err String
|
||||||
lin gr fun = do
|
lin gr fun = do
|
||||||
tree <- string2treeErr gr fun
|
tree <- string2treeErr gr fun
|
||||||
@@ -91,20 +105,21 @@ lin gr fun = do
|
|||||||
where c = cncId gr
|
where c = cncId gr
|
||||||
g = stateGrammarST gr
|
g = stateGrammarST gr
|
||||||
unt = formatAsText
|
unt = formatAsText
|
||||||
|
-}
|
||||||
|
|
||||||
getCatQuestion :: VIdent -> CatQuestions -> String
|
getCatQuestion :: VIdent -> CatQuestions -> String
|
||||||
getCatQuestion c qs =
|
getCatQuestion c qs =
|
||||||
fromMaybe (error "No question for category " ++ c) (lookup c qs)
|
fromMaybe (error "No question for category " ++ prIdent c) (lookup c qs)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- * Generate VoiceXML
|
-- * Generate VoiceXML
|
||||||
--
|
--
|
||||||
|
|
||||||
skel2vxml :: String -> String -> VIdent -> VSkeleton -> CatQuestions -> XML
|
skel2vxml :: VIdent -> String -> VIdent -> VSkeleton -> CatQuestions -> XML
|
||||||
skel2vxml name language start skel qs =
|
skel2vxml name language start skel qs =
|
||||||
vxml language ([startForm] ++ concatMap (uncurry (catForms gr qs)) skel)
|
vxml language ([startForm] ++ concatMap (uncurry (catForms gr qs)) skel)
|
||||||
where
|
where
|
||||||
gr = grammarURI name
|
gr = grammarURI (prIdent name)
|
||||||
startForm = Tag "form" [] [subdialog "sub" [("src", "#"++catFormId start)] []]
|
startForm = Tag "form" [] [subdialog "sub" [("src", "#"++catFormId start)] []]
|
||||||
|
|
||||||
grammarURI :: String -> String
|
grammarURI :: String -> String
|
||||||
@@ -113,42 +128,58 @@ grammarURI name = name ++ ".grxml"
|
|||||||
|
|
||||||
catForms :: String -> CatQuestions -> VIdent -> [(VIdent, [VIdent])] -> [XML]
|
catForms :: String -> CatQuestions -> VIdent -> [(VIdent, [VIdent])] -> [XML]
|
||||||
catForms gr qs cat fs =
|
catForms gr qs cat fs =
|
||||||
comments [cat ++ " category."]
|
comments [prIdent cat ++ " category."]
|
||||||
++ [cat2form gr qs cat fs]
|
++ [cat2form gr qs cat fs]
|
||||||
|
|
||||||
cat2form :: String -> CatQuestions -> VIdent -> [(VIdent, [VIdent])] -> XML
|
cat2form :: String -> CatQuestions -> VIdent -> [(VIdent, [VIdent])] -> XML
|
||||||
cat2form gr qs cat fs =
|
cat2form gr qs cat fs =
|
||||||
form (catFormId cat) $
|
form (catFormId cat) $
|
||||||
[var "value" (Just "{ name : '?' }"),
|
[var "value" (Just "{ name : '?' }"),
|
||||||
var "update" Nothing,
|
var "callbacks" Nothing,
|
||||||
blockCond "value.name != '?'" [assign (catFieldId cat) "value"],
|
blockCond "value.name != '?'" [assign (catFieldId cat) "value"],
|
||||||
|
block [doCallback "entered" cat [return_ [catFieldId cat]] []],
|
||||||
field (catFieldId cat) []
|
field (catFieldId cat) []
|
||||||
[promptString (getCatQuestion cat qs),
|
[promptString (getCatQuestion cat qs),
|
||||||
grammar (gr++"#"++catFormId cat),
|
vxmlGrammar (gr++"#"++catFormId cat),
|
||||||
nomatch [Data "I didn't understand you.", reprompt],
|
nomatch [Data "I didn't understand you.", reprompt],
|
||||||
help [Data ("help_"++cat)],
|
help [Data (mkHelpText cat)],
|
||||||
filled [] [if_else (catFieldId cat ++ ".name == '?'") [reprompt] feedback]]
|
filled [] [if_else (catFieldId cat ++ ".name == '?'")
|
||||||
|
[reprompt]
|
||||||
|
[doCallback "refined" cat [return_ [catFieldId cat]] []]]
|
||||||
|
]
|
||||||
]
|
]
|
||||||
++ concatMap (uncurry (fun2sub gr cat)) fs
|
++ concatMap (uncurry (fun2sub gr cat)) fs
|
||||||
++ [block [return_ [catFieldId cat]]]
|
++ [block [doCallback "done" cat [return_ [catFieldId cat]] [return_ [catFieldId cat]]]]
|
||||||
where feedback = [if_ ("typeof update != 'undefined' && !update("++string cat++","++ catFieldId cat ++ ")") [return_ [catFieldId cat]]]
|
|
||||||
|
mkHelpText :: VIdent -> String
|
||||||
|
mkHelpText cat = "help_"++ prIdent cat
|
||||||
|
|
||||||
fun2sub :: String -> VIdent -> VIdent -> [VIdent] -> [XML]
|
fun2sub :: String -> VIdent -> VIdent -> [VIdent] -> [XML]
|
||||||
fun2sub gr cat fun args = comments [fun ++ " : (" ++ concat (intersperse ", " args) ++ ") " ++ cat] ++ ss
|
fun2sub gr cat fun args =
|
||||||
|
comments [prIdent fun ++ " : ("
|
||||||
|
++ concat (intersperse ", " (map prIdent args))
|
||||||
|
++ ") " ++ prIdent cat] ++ ss
|
||||||
where
|
where
|
||||||
argNames = zip ["arg"++show n | n <- [0..]] args
|
argNames = zip ["arg"++show n | n <- [0..]] args
|
||||||
ss = map (uncurry mkSub) argNames
|
ss = map (uncurry mkSub) argNames
|
||||||
mkSub a t = subdialog s [("src","#"++catFormId t),("cond",catFieldId cat++".name == "++string fun)]
|
mkSub a t = subdialog s [("src","#"++catFormId t),
|
||||||
|
("cond",catFieldId cat++".name == "++string (prIdent fun))]
|
||||||
[param "value" (catFieldId cat++"."++a),
|
[param "value" (catFieldId cat++"."++a),
|
||||||
param "update" "update",
|
param "callbacks" "callbacks",
|
||||||
filled [] [assign (catFieldId cat++"."++a) (s++"."++catFieldId t)]]
|
filled [] [assign (catFieldId cat++"."++a) (s++"."++catFieldId t)]]
|
||||||
where s = fun ++ "_" ++ a
|
where s = prIdent fun ++ "_" ++ a
|
||||||
|
|
||||||
|
doCallback :: String -> VIdent -> [XML] -> [XML] -> XML
|
||||||
|
doCallback f cat i e =
|
||||||
|
if_else ("callbacks && " ++ cf ++ " && !" ++ cf ++ "("++string (prIdent cat)++","++ catFieldId cat ++ ")")
|
||||||
|
i e
|
||||||
|
where cf = "callbacks." ++ f
|
||||||
|
|
||||||
catFormId :: VIdent -> String
|
catFormId :: VIdent -> String
|
||||||
catFormId = (++ "_cat")
|
catFormId c = prIdent c ++ "_cat"
|
||||||
|
|
||||||
catFieldId :: VIdent -> String
|
catFieldId :: VIdent -> String
|
||||||
catFieldId = (++ "_field")
|
catFieldId c = prIdent c ++ "_field"
|
||||||
|
|
||||||
--
|
--
|
||||||
-- * VoiceXML stuff
|
-- * VoiceXML stuff
|
||||||
@@ -171,8 +202,8 @@ subdialog name attrs = Tag "subdialog" ([("name",name)]++attrs)
|
|||||||
filled :: [(String,String)] -> [XML] -> XML
|
filled :: [(String,String)] -> [XML] -> XML
|
||||||
filled = Tag "filled"
|
filled = Tag "filled"
|
||||||
|
|
||||||
grammar :: String -> XML
|
vxmlGrammar :: String -> XML
|
||||||
grammar uri = Tag "grammar" [("src",uri)] []
|
vxmlGrammar uri = Tag "grammar" [("src",uri)] []
|
||||||
|
|
||||||
prompt :: [XML] -> XML
|
prompt :: [XML] -> XML
|
||||||
prompt = Tag "prompt" []
|
prompt = Tag "prompt" []
|
||||||
@@ -243,26 +274,24 @@ string s = "'" ++ concatMap esc s ++ "'"
|
|||||||
where esc '\'' = "\\'"
|
where esc '\'' = "\\'"
|
||||||
esc c = [c]
|
esc c = [c]
|
||||||
|
|
||||||
|
{-
|
||||||
--
|
--
|
||||||
-- * List stuff
|
-- * List stuff
|
||||||
--
|
--
|
||||||
|
|
||||||
isListCat :: (VIdent, [(VIdent, [VIdent])]) -> Bool
|
isListCat :: (VIdent, [(VIdent, [VIdent])]) -> Bool
|
||||||
isListCat (cat,rules) = "List" `isPrefixOf` cat && length rules == 2
|
isListCat (cat,rules) = "List" `isPrefixOf` prIdent cat && length rules == 2
|
||||||
&& ("Base"++c) `elem` fs && ("Cons"++c) `elem` fs
|
&& ("Base"++c) `elem` fs && ("Cons"++c) `elem` fs
|
||||||
where c = elemCat cat
|
where c = drop 4 (prIdent cat)
|
||||||
fs = map fst rules
|
fs = map (prIdent . fst) rules
|
||||||
|
|
||||||
-- | Gets the element category of a list category.
|
|
||||||
elemCat :: VIdent -> VIdent
|
|
||||||
elemCat = drop 4
|
|
||||||
|
|
||||||
isBaseFun :: VIdent -> Bool
|
isBaseFun :: VIdent -> Bool
|
||||||
isBaseFun f = "Base" `isPrefixOf` f
|
isBaseFun f = "Base" `isPrefixOf` prIdent f
|
||||||
|
|
||||||
isConsFun :: VIdent -> Bool
|
isConsFun :: VIdent -> Bool
|
||||||
isConsFun f = "Cons" `isPrefixOf` f
|
isConsFun f = "Cons" `isPrefixOf` prIdent f
|
||||||
|
|
||||||
baseSize :: (VIdent, [(VIdent, [VIdent])]) -> Int
|
baseSize :: (VIdent, [(VIdent, [VIdent])]) -> Int
|
||||||
baseSize (_,rules) = length bs
|
baseSize (_,rules) = length bs
|
||||||
where Just (_,bs) = find (("Base" `isPrefixOf`) . fst) rules
|
where Just (_,bs) = find (isBaseFun . fst) rules
|
||||||
|
-}
|
||||||
@@ -270,7 +270,7 @@ customGrammarPrinter =
|
|||||||
\opts s -> let name = cncId s
|
\opts s -> let name = cncId s
|
||||||
start = getStartCatCF opts s
|
start = getStartCatCF opts s
|
||||||
in SRGS.srgsXmlPrinter name start opts (Just SISR.SISROld) Nothing $ stateCFG s)
|
in SRGS.srgsXmlPrinter name start opts (Just SISR.SISROld) Nothing $ stateCFG s)
|
||||||
,(strCI "vxml", \opts s -> let start = getStartCat opts s
|
,(strCI "vxml", \opts s -> let start = cfCat2Ident (startCatStateOpts opts s)
|
||||||
in grammar2vxml start s)
|
in grammar2vxml start s)
|
||||||
,(strCI "slf", \opts s -> let start = getStartCatCF opts s
|
,(strCI "slf", \opts s -> let start = getStartCatCF opts s
|
||||||
name = cncId s
|
name = cncId s
|
||||||
|
|||||||
Reference in New Issue
Block a user