Geração de texto em russo por modelos

Quando eu estava começando a trabalhar no meu jogo de texto, decidi que uma de suas principais características deveria ser belas descrições artísticas das ações dos personagens. Em parte, eu queria "salvar", porque não sabia como agendá-lo. Salvar não funcionou, mas resultou na biblioteca Python ( github , pypi ) para gerar textos, levando em consideração a dependência das palavras e seus recursos gramaticais.

Por exemplo, no modelo:
[Herói] [passou | herói] passou por um pátio discreto e de repente [notou | herói] crianças brincando. Eles corriam com espadas de madeira, paus e máscaras de monstros. De repente, um dos jogadores parou, colocou [toy | hero.weapon | vn] [hero.weapon | vn] , gritou: “ [eu | herói] [grande | herói] [herói] ! Pegue! - e correu para a "besta". Caíram no chão, pularam os braços e as pernas e depois se levantaram, tiraram as máscaras e riram. [Grunhido | herói] e [ele mesmo | herói] [Herói] , mas não [ começou | herói] dirigido ao pequenino.
Podemos obter o seguinte texto (as palavras em mudança estão em negrito):
Hallr passou por um pátio discreto e de repente notou crianças brincando. Eles corriam com espadas de madeira, paus e máscaras de monstros. De repente, um dos jogadores parou, estendeu uma espada dourada de brinquedo e gritou: “ Eu sou um ótimo Hallr ! Pegue! - e correu para a "besta". Caíram no chão, pularam os braços e as pernas e depois se levantaram, tiraram as máscaras e riram. O próprio Hallr riu , mas não foi para o pequeno.
Ou assim:
Fievara passou por um pátio discreto e de repente notou crianças brincando. Eles corriam com espadas de madeira, paus e máscaras de monstros. De repente, um dos jogadores parou, colocou um brinquedo de catarro e gritou: “ Eu sou o grande Fievara ! Pegue! - e correu para a "besta". Caíram no chão, pularam os braços e as pernas e depois se levantaram, tiraram as máscaras e riram. A própria Fievara resmungou , mas não foi para o pequeno.

Reservas para casais
Isenção de responsabilidade 1 . Eu não sou linguista e a biblioteca foi escrita "para trabalhar" e não "para corresponder exatamente a todas as regras da língua". Portanto, peço desculpas antecipadamente por imprecisões na terminologia ou por uma interpretação incompleta das regras do idioma russo.

Isenção 2 . A biblioteca foi desenvolvida há cerca de 5 anos, agora podem aparecer meios alternativos de geração de texto (ou aumentar para um estado normal). Por exemplo, algo interessante pode estar no software para localização.

Sobre a complexidade da geração de texto


A língua russa é complexa em muitos de seus aspectos. Em particular, as palavras têm um grande número de formas morfológicas. Por exemplo, os adjetivos podem ter uma forma completa e curta, variando por sexo, número, caso, animação e grau de comparação. A escolha de um formulário específico depende de outras palavras na frase. Dizemos "mulher bonita", mas "homem bonito". A palavra “bonito” neste caso depende das palavras “homem” / “mulher” - sua forma é determinada pelo gênero da palavra principal.

Portanto, as dificuldades começam quando tentamos entrar em contato com alguém com base em seu sexo. Ao compilar textos para sites, cartas, jogos, é preciso criar uma redação muito clara (evitando o sexo do usuário), escrever vários textos ao mesmo tempo ou usar linguagens de marcação de vários graus de versatilidade.

Eu queria algo mais do que uma simples dependência do gênero do jogador, e mesmo assim os próprios usuários poderiam adicionar novos textos (e o usuário "médio" é bastante analfabeto, como todos sabemos :-)). Portanto, não encontrando o software certo, decidi fazer isso sozinho.

Recursos da biblioteca


O UTG (gerador de texto universal - não é um nome muito modesto) permite criar modelos para gerar texto com o seguinte:

  • variáveis ​​(por exemplo, nome do personagem);
  • dependências de palavras em variáveis ​​(por exemplo, um adjetivo em um substantivo);
  • Dependências de algumas variáveis ​​em outras;
  • Propriedades explícitas de palavras e variáveis ​​(por exemplo, você pode especificar que o nome do caractere seja inserido no caso pai);

Ao gerar texto a partir de um modelo:

  • As propriedades necessárias da palavra principal são transferidas para palavras dependentes. Por exemplo, o sexo de um substantivo é transferido para o adjetivo.
  • A forma das palavras dependentes é consistente com os números (levando em consideração a forma das palavras dependentes).
  • As preposições são modificadas se necessário (por exemplo, sobre mim / sobre você), o pretexto para isso deve ser marcado.

Adicionalmente implementado:

  • Um dicionário para armazenar as palavras necessárias.
  • Um repositório de modelos para armazená-los por tipo e escolher aleatórios.

A biblioteca “sabe” sobre a existência de substantivos, adjetivos, pronomes, verbos, particípios, números, preposições e “aspas” (texto imutável).

As seguintes propriedades das palavras são levadas em consideração: parte da fala, caso, animação, número, gênero, forma verbal, hora, pessoa, tipo, categoria de adjetivo, grau de adjetivo, grau de adjetivo, categoria de pronome, voz, forma de preposição, forma adjetiva, forma de particípio, forma substantiva ( além da forma normal, os substantivos têm uma contagem ).

Formato do modelo e exemplo de uso


Vejamos um modelo simples:
Ontem [mob] [mordido | mob] [herói | ext] .
Dependendo dos valores das variáveis, o modelo pode aparecer como uma frase:
Ontem, uma hiena mordeu Hallre.
so e so:
Os vaga-lumes morderam um fantasma ontem.
Considere o modelo em mais detalhes:

  • - texto simples.
  • [mob] - uma variável, em vez da qual o nome do monstro é substituído.
  • [|mob] - uma palavra dependente de uma variável, parte de suas propriedades será alterada dependendo das propriedades do nome do monstro (por exemplo, um número). O gerador de texto reconhece automaticamente as propriedades da forma da palavra e tenta salvá-las (por exemplo, o tempo decorrido será reconhecido e salvo, para que você não precise especificá-lo).
  • [hero|] - uma variável, em vez da qual o nome do herói é substituído. Além disso, é indicado que o nome deve estar no caso acusativo.

Mais modelos de amostra.
Alguns exemplos técnicos podem ser encontrados em testes .

Se você estiver interessado em mais exemplos, poderá vê-los no site de brinquedos. Um link para ele pode ser encontrado vasculhando meu perfil ou escrevendo em um site pessoal.

As palavras variáveis ​​e dependentes no modelo são destacadas de forma idêntica e têm o seguinte formato:

  • [ - colchete de abertura.
  • dependente de palavra ou identificador de variável. O gerador primeiro verifica a presença de uma variável com esse nome; se não houver, a palavra é pesquisada no dicionário.
  • | - barra vertical - separador, necessário se especificarmos propriedades adicionais.
  • da variável - a variável da qual o formato da palavra depende pode estar ausente.
  • | - barra vertical - separador, necessário se especificarmos propriedades adicionais.
  • - uma descrição da forma exigida da palavra (maiúsculas e minúsculas, sexo e assim por diante). Uma lista deles pode ser encontrada nas páginas do projeto no github e pypi.
  • ] É o colchete de fechamento.

Você pode especificar quaisquer propriedades adicionais que desejar, elas serão aplicadas na ordem da definição, por exemplo:

[ 1| 2|,| 3|,,]

Na maioria dos casos, os seguintes formatos são suficientes:

  • [] - insira uma variável na forma normal (por exemplo, um substantivo no caso nominativo do singular).
  • [|] - insira uma variável com as propriedades especificadas.
  • [|] - insira uma palavra, combinando-a com uma variável (por exemplo, o adjetivo "beautiful" com um substantivo em gender e case).
  • [||] - insira uma palavra, combinando-a com uma variável e especificando propriedades adicionais.

Observe:

  • A especificação de propriedades para palavras e variáveis ​​é válida apenas no local de inserção; portanto, para obter a frase "herói bonito", devemos indicar o caso acusativo explicitamente para duas palavras: [|hero|] [hero|] .
  • O gerador de texto pode "adivinhar" as propriedades da palavra por sua forma, por exemplo, na frase [hero] [|hero] você pode omitir o tempo do verbo.
  • As propriedades especificadas posteriormente substituem as propriedades especificadas anteriormente. Por exemplo, na frase [|hero] [hero|] , o acusativo do adjetivo não será estabelecido, pois será substituído pelo caso nominativo do variável herói.
  • Uma lista de propriedades de palavras pode ser encontrada nas páginas da biblioteca no github e pypi.

Exemplo de código
Necessário Python 3

Instalação

 pip install utg python -m unittest discover utg 

Código

 from utg import relations as r from utg import dictionary from utg import words from utg import templates from utg import constructors ####################################### #     ####################################### coins_forms = [#   '', '', '', '', '', '', #   '', '', '', '', '', '', #   (  , #     autofill_missed_forms) '', '', '', '', '', ''] # : ,   coins_properties = words.Properties(r.ANIMALITY.INANIMATE, r.GENDER.FEMININE) #      ,    coins_word = words.Word(type=r.WORD_TYPE.NOUN, forms=coins_forms, properties=coins_properties) #        . #      , #          : # - utg.data.WORDS_CACHES # - utg.data.INVERTED_WORDS_CACHES ############################## #     ############################## #       # (     utg.data.WORDS_CACHES[r.WORD_TYPE.VERB]) action_forms = (['', '', '', '', ''] + [''] * 15) # : ,   action_properties = words.Properties(r.ASPECT.PERFECTIVE, r.VOICE.DIRECT) action_word = words.Word(type=r.WORD_TYPE.VERB, forms=action_forms, properties=action_properties) #       (  ) action_word.autofill_missed_forms() ############################################## #       ############################################## test_dictionary = dictionary.Dictionary(words=[coins_word, action_word]) ################ #   ################ template = templates.Template() # externals —  ,      template.parse('[Npc] [|npc] [hero|] [coins] [|coins|].', externals=('hero', 'npc', 'coins')) ############################## #    ############################## hero_forms = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] # : ,   hero_properties = words.Properties(r.ANIMALITY.ANIMATE, r.GENDER.MASCULINE) hero = words.WordForm(words.Word(type=r.WORD_TYPE.NOUN, forms=hero_forms, properties=hero_properties)) npc_forms = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] # : ,   npc_properties = words.Properties(r.ANIMALITY.ANIMATE, r.GENDER.FEMININE) npc = words.WordForm(words.Word(type=r.WORD_TYPE.NOUN, forms=npc_forms, properties=npc_properties)) ########################## #   ########################## result = template.substitute(externals={'hero': hero, 'npc': npc, 'coins': constructors.construct_integer(125)}, dictionary=test_dictionary) ########################## #  ########################## result == '   125 .' 

Sobre dicionários


Como você deve ter notado, o UTG requer a formação de um dicionário. Isso é feito "pelas mãos", pois no momento do desenvolvimento:

  • Não encontrei dicionários morfológicos qualitativos geralmente acessíveis.
  • A biblioteca de pymorphy ainda era a primeira versão e, muitas vezes, era apertada (especialmente no caso acusativo), motivo pelo qual tive que abandoná-la.

Se você deseja usar um gerador com muitas palavras, antes de conduzi-lo manualmente, tente usar o pymorphy2 ou procure um dicionário pronto e exporte-o.

Total


Espero que a biblioteca seja útil.

Se você tem idéias para o seu desenvolvimento (ou, melhor ainda, um desejo de participar) - escreva em uma mensagem pessoal, faça solicitações, publique bugs no github.

Source: https://habr.com/ru/post/pt471278/


All Articles