Часть от второй части
This commit is contained in:
@@ -371,8 +371,112 @@ calculateExpression (a, op, b) = (operationToOperator op) a b
|
||||
|
||||
|
||||
\subsection{Часть 2: Синтаксический анализ текста и генерация фраз}
|
||||
|
||||
|
||||
|
||||
\subsubsection{Функция splitText}
|
||||
|
||||
На первом этапе необходимо разделить текст на предложения и слова. Предложения определяются с помощью разделителей \texttt{.!?;:()}. В словах удаляются небуквенные символы и цифры. Код функции \texttt{splitText}, ответственной за разбиение текста и очистку слов, представлен в листинге~\ref{lst:splitText}. Функция принимает на вход строку -- исходный текст, а возвращает список предложений, где каждое предложение представлено в виде списка слов.
|
||||
|
||||
\begin{lstlisting}[caption={Функция splitText для разбора текста на предложения и слова}, label={lst:splitText}]
|
||||
splitText :: String -> [[String]]
|
||||
splitText text = filter (not . null) $ map (processSentence . words) (splitSentences text)
|
||||
where
|
||||
splitSentences :: String -> [String]
|
||||
splitSentences [] = []
|
||||
splitSentences s =
|
||||
let (sentence, rest) = break isSeparator s
|
||||
rest' = dropWhile isSeparator rest
|
||||
in if null sentence
|
||||
then splitSentences rest'
|
||||
else sentence : splitSentences rest'
|
||||
|
||||
isSeparator :: Char -> Bool
|
||||
isSeparator c = c `elem` ".!?;:()"
|
||||
|
||||
processSentence :: [String] -> [String]
|
||||
processSentence = filter (not . null) . map cleanWord
|
||||
|
||||
cleanWord :: String -> String
|
||||
cleanWord = map toLower . filter isLetter
|
||||
\end{lstlisting}
|
||||
|
||||
\subsubsection{Функция buildDictionary}
|
||||
|
||||
На основе полученных предложений строится словарь, где ключами являются либо отдельные слова, либо пары слов, а значениями — списки возможных продолжений (следующее слово или пара слов для триграмм). Для этого используются биграммы и триграммы. Код функции \texttt{buildDictionary}, формирующей словарь представлен в листинге~\ref{lst:buildDictionary}.
|
||||
|
||||
\begin{lstlisting}[caption={Функция buildDictionary для формирования словаря N-грамм}, label={lst:buildDictionary}]
|
||||
buildDictionary :: [[String]] -> Map String [String]
|
||||
buildDictionary sentences =
|
||||
let bigrams = [ (w1, w2) | s <- sentences, (w1:w2:_) <- tails s ]
|
||||
trigrams = [ (w1, w2, w3) | s <- sentences, (w1:w2:w3:_) <- tails s ]
|
||||
singleKeys = foldr (\(w1, w2) acc -> Map.insertWith (++) w1 [w2] acc) Map.empty bigrams
|
||||
singleKeys' = foldr (\(w1, w2, w3) acc -> Map.insertWith (++) w1 [w2 ++ " " ++ w3] acc) singleKeys trigrams
|
||||
doubleKeys = foldr (\(w1, w2, w3) acc -> Map.insertWith (++) (w1 ++ " " ++ w2) [w3] acc) Map.empty trigrams
|
||||
combined = Map.unionWith (++) singleKeys' doubleKeys
|
||||
in Map.map nub combined
|
||||
\end{lstlisting}
|
||||
|
||||
|
||||
\subsubsection{Функция generatePhrase}
|
||||
|
||||
Программа случайным образом формирует фразу длиной от 2 до 15 слов, используя словарь. На каждом шаге выбирается случайное продолжение, пока не будут исчерпаны возможные варианты или не достигнута заданная длина. Код функции для генерации фразы приведён в листинге~\ref{lst:generatePhrase}.
|
||||
|
||||
\begin{lstlisting}[caption={Функция generatePhrase для генерации фразы}, label={lst:generatePhrase}]
|
||||
generatePhrase :: Map String [String] -> String -> StdGen -> [String]
|
||||
generatePhrase dict start initGenState =
|
||||
let (len, initGenState') = randomR (2,15 :: Int) initGenState
|
||||
in reverse $ gp start [] len initGenState'
|
||||
where
|
||||
gp :: String -> [String] -> Int -> StdGen -> [String]
|
||||
gp key acc n genState
|
||||
| n <= 0 = acc
|
||||
| otherwise =
|
||||
case Map.lookup key dict of
|
||||
Nothing -> acc
|
||||
Just [] -> acc
|
||||
Just vals ->
|
||||
let (i, newGenState) = randomR (0, length vals - 1) genState
|
||||
next = vals !! i
|
||||
in gp next (next:acc) (n - length (words next)) newGenState
|
||||
\end{lstlisting}
|
||||
|
||||
Функция \texttt{processInput} (листинг~\ref{lst:processInput}) проверяет, существует ли введённое пользователем слово(или пара слов) в словаре, и если да — генерирует фразу.
|
||||
|
||||
\begin{lstlisting}[caption={Функция processInput для обработки пользовательского ввода}, label={lst:processInput}]
|
||||
processInput :: Map String [String] -> String -> IO ()
|
||||
processInput dict input =
|
||||
if Map.member input dict then
|
||||
newStdGen >>= \gen ->
|
||||
putStrLn $ unwords $ generatePhrase dict input gen
|
||||
else
|
||||
putStrLn "Нет в словаре"
|
||||
\end{lstlisting}
|
||||
|
||||
\subsubsection{Функция twoModelsDialog}
|
||||
|
||||
Реализован режим, в котором две модели N-грамм, построенные на разных текстах, обмениваются сообщениями. Начальное слово или пару слов задаёт пользователь, затем модели по очереди генерируют ответы, основываясь на словах, из которых состоит последнее сообщение их собеседника. Код, реализующий диалог, представлен в листинге~\ref{lst:twoModelsDialog}.
|
||||
|
||||
\begin{lstlisting}[caption={Функция twoModelsDialog для организации диалога между двумя моделями}, label={lst:twoModelsDialog}]
|
||||
twoModelsDialog :: Map String [String] -> Map String [String] -> String -> Int -> IO ()
|
||||
twoModelsDialog dict1 dict2 start m =
|
||||
newStdGen >>= \gen ->
|
||||
let first = generatePhrase dict1 start gen
|
||||
in putStrLn ("Модель 1: (" ++ start ++ ") " ++ unwords first) >>
|
||||
loop dict1 dict2 first m
|
||||
where
|
||||
loop :: Map String [String] -> Map String [String] -> [String] -> Int -> IO ()
|
||||
loop _ _ _ 0 = return ()
|
||||
loop d1 d2 prev i =
|
||||
putStr "Модель 2: " >>
|
||||
dialogStep d2 prev >>= \resp ->
|
||||
if null resp then return () else
|
||||
putStr "Модель 1: " >>
|
||||
dialogStep d1 resp >>= \resp2 ->
|
||||
if null resp2 then return () else
|
||||
loop d1 d2 resp2 (i-1)
|
||||
\end{lstlisting}
|
||||
|
||||
Данный подход позволяет динамически генерировать фразы и организовывать имитацию диалога между двумя текстовыми моделями, что служит демонстрацией возможностей построенной системы N-грамм.
|
||||
|
||||
|
||||
|
||||
\newpage
|
||||
|
||||
Reference in New Issue
Block a user