Este repositório constrói um wrapper python fino em torno do OpenCCG usando a ontologia GUM-space, pronto para ser executado dentro de um contêiner docker. Você pode encontrar uma versão ao vivo em litmus.informatik.uni-bremen.de/openccg.
Após um docker-compose up
inicial, o serviço pode ser consultado usando uma solicitação POST simples, por exemplo, usando curl:
$ curl --data "Take the cup." "localhost/openccg/parse?graphs"
{"version": "2.2.0", "application": "web-openccg", "uuid": "3bafdaf8-cc9c-4fdf-b455-c9687babba49", "sentence": "take the cup", "parses": ..., "http_status": 200, "json_parses": ..., "graphs": ...}
O campo "gráficos" só é incluído se o parâmetro URL graphs
estiver presente.
Por exemplo, usando solicitações Python:
import requests
# Without graphs
print ( requests . post ( 'http://localhost/openccg/parse' , data = { 'sentence' : 'Take the cup.' }). json ())
# With graphs
print ( requests . post ( 'http://localhost/openccg/parse' ,
data = { 'sentence' : 'Take the cup.' },
params = { 'graphs' : True }). json ())
Devido à forma como hospedamos o OpenCCG por trás do nginx no litmus, os URLs para web-openccg são todos prefixados com "openccg". No entanto, para os dois endpoints importantes ( /
para a GUI e /parse
para a API), existem redirecionamentos em vigor. Para curl, isso significa curl -L --data "Take the cup." localhost/parse
também funcionará (observe o argumento -L
( --location
)).
Observe que não está pronto para produção, pois é muito lento e não otimizado: em vez de manter uma (ou várias) instâncias do OpenCCG em execução para consultá-las mais rapidamente, cada solicitação gera uma instância individual do OpenCCG.
Para consultar o serviço visualmente, basta abrir seu navegador em http://localhost/openccg. Caso contrário, use solicitações curl, wget ou, por exemplo, python para consultar web-openccg por meio da linha de comando ou de seu aplicativo.
Se o seu cliente permite construir o corpo da sua solicitação manualmente, como curl, basta colocar a frase dentro:
curl --data "Take the cup." localhost/openccg/parse
No entanto, muitas estruturas de alto nível, como solicitações python, geralmente usam um mecanismo de valor-chave para postar dados. Neste caso, use a sentence
chave:
requests.post('http://localhost/openccg/parse', data={'sentence': 'Take the cup.'})
Para ver um exemplo abaixo.
A resposta é um objeto JSON e sempre contém estes campos:
version
: a versão do objeto JSON.application
: Sempre "web-openccg", isso é útil se você agregar análises de diferentes serviços.uuid
: um ID exclusivo para esta resposta. Isto só será útil se você planeja integrar a ferramenta de alguma forma.http_status
: o status HTTP da solicitação.Caso tenha sido fornecida uma frase durante a solicitação, estes campos estarão presentes:
sentence
: a frase de entrada limpa (todas em minúsculas, pontuação removida, ...).Se existir pelo menos uma análise bem-sucedida, estes campos serão incluídos:
parses
: Um dicionário de identificadores de análise (por exemplo, "np") para análises reais conforme o OpenCCG os gera.json_parses
: uma versão das saídas do OpenCCG em um JSON simples. Isso é produzido por meio de uma gramática personalizada para TatSu. Para detalhes veja abaixo. Cada valor de dicionário individual é uma lista de Nominais, Variáveis e/ou Funções.graphs
: um dicionário de identificadores de análise para strings de pontos. Eles podem ser renderizados usando o graphviz – a GUI online os renderiza automaticamente. Nota: As chaves são compartilhadas entre parses
, json_parses
e graphs
, portanto, você pode pesquisar facilmente a saída original para uma análise JSON e vice-versa.
Se ocorrer um erro, o campo de erro estará presente:
error
: uma descrição do erro.Versão atual: 2.3.0
O formato JSON para as análises OpenCCG pode ser determinado a partir do exemplo acima ou inspecionando cuidadosamente o OpenCCG.ebnf totalmente digitado.
Existem três tipos diferentes de objetos: Nominal, Variável e Função. A especificação semântica completa (o arquivo JSON) pode ser uma única entidade de qualquer um dos três tipos ou uma lista de Nominais. Se encontrarmos análises que sejam listas de variáveis ou papéis, a gramática será estendida. Abra um problema se encontrar frases que não podem ser analisadas corretamente.
Um nominal é como uma variável especial, descreve o “tema principal” da frase. Como são praticamente iguais (na verdade, possuem regras de análise muito semelhantes), o formato JSON os representa com uma estrutura idêntica:
{
"__class__" : " Variable " ,
"name" : " x1 " ,
"type" : " gum-OrientationChange " ,
"roles" : []
}
__class__
é Variable
ou Nominal
.name
é a variável nomeada usada pelo OpenCCG, é uma letra seguida de um número, por exemplo x1
ou w12
.type
é um especificador GUM que denota o tipo da variável. Também pode ser null
, se o tipo não for especificado.roles
é uma lista de funções conforme descrito abaixo. Uma Função define todas as propriedades que uma Variável ou Nominal pode ter. Segue uma estrutura muito semelhante:
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : ...
}
__class__
: Role
.type
: o tipo de função. Isso determina as possibilidades target
.target
: o valor da função. Isso pode ser várias coisas diferentes, veja abaixo. Se o tipo for entity
, o alvo será uma instância, como "cup" ou "slm-Taking". Se o tipo tiver um prefixo seguido por um travessão, por exemplo, gs-hasSpatialModality
ou gs-direction
, então o alvo será uma Variable
; na coruja, isso seria um ObjectProperty. Se o tipo for qualquer outra string, o alvo será uma string atômica, por exemplo, o tipo det
pode ter o alvo the
, enquanto o tipo quant
pode ter o alvo singular
.
A maioria dos serviços da web usa a porta 80 como porta padrão, assim como o web-openccg.
Para alterar a porta, ajuste o arquivo docker-compose e altere a linha da porta de "80:80"
para sua porta no lado esquerdo (mas mantenha o 80 à direita), por exemplo para configurar o serviço na porta 9043 , você mudaria para "9043:80"
.
Antes de iniciar o desenvolvimento, você precisa construir o contêiner docker usando:
make build
Esta etapa também inclui alguns arquivos baixados durante o processo de construção em seu diretório ./webopenccg/static local. As cópias são feitas porque o servidor de desenvolvimento monta o diretório, que sobrescreve os arquivos que estão disponíveis apenas dentro do container, mas não no sistema host.
Para iniciar o contêiner docker de desenvolvimento, use o Makefile:
make run
O servidor de desenvolvimento se liga à porta 5000 e usa o ambiente de depuração flask. Além disso, o contêiner docker iniciado com make run
vincula o diretório do aplicativo para que o recarregamento do flask funcione corretamente.
Para compilar a gramática OpenCCG.ebnf, execute:
make
Um exemplo de resposta para a frase “Pegue o copo”. é:
{
"version" : " 2.2.0 " ,
"application" : " web-openccg " ,
"uuid" : " ecae8222-af9b-4185-a508-efa8be33c7e6 " ,
"sentence" : " take the cup " ,
"parses" : {
"smain" : " @x1:gum-OrientationChange( <mood>imp ^ <gs-direction>(x2:gs-GeneralizedLocation ^ <gs-hasSpatialModality>(w2:slm-Cup ^ cup ^ <det>the ^ <ident>specific ^ <quant>singular)) ^ <gum-processInConfiguration>(w0:slm-Moving ^ slm-Taking)) " ,
"smain/0" : " @x1:gum-OrientationChange( <mood>imp ^ <gs-direction>(x2:gs-GeneralizedLocation ^ <gs-hasSpatialModality>(w2:slm-Cup ^ cup ^ <det>the ^ <ident>specific ^ <quant>singular)) ^ <gum-processInConfiguration>(w0:slm-Taking ^ slm-Taking)) " ,
"smain/.r" : " @x1:gs-AffectingDirectedMotion( <mood>imperative ^ <gs-route>x2 ^ <gum-actee>(w2:slm-Cup ^ cup ^ <det>the ^ <ident>specific ^ <quant>singular) ^ <gum-processInConfiguration>(w0:slm-Moving ^ slm-Taking)) " ,
"smain/.r/0" : " @x1:gs-AffectingDirectedMotion( <mood>imperative ^ <gs-route>x2 ^ <gum-actee>(w2:slm-Cup ^ cup ^ <det>the ^ <ident>specific ^ <quant>singular) ^ <gum-processInConfiguration>(w0:slm-Taking ^ slm-Taking)) "
},
"http_status" : 200 ,
"json_parses" : {
"smain" : {
"__class__" : " Nominal " ,
"type" : " gum-OrientationChange " ,
"name" : " x1 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " mood " ,
"target" : " imp "
},
{
"__class__" : " Role " ,
"type" : " gs-direction " ,
"target" : {
"__class__" : " Variable " ,
"type" : " gs-GeneralizedLocation " ,
"name" : " x2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " gs-hasSpatialModality " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Cup " ,
"name" : " w2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " cup "
},
{
"__class__" : " Role " ,
"type" : " det " ,
"target" : " the "
},
{
"__class__" : " Role " ,
"type" : " ident " ,
"target" : " specific "
},
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : " singular "
}
]
}
}
]
}
},
{
"__class__" : " Role " ,
"type" : " gum-processInConfiguration " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Moving " ,
"name" : " w0 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " slm-Taking "
}
]
}
}
]
},
"smain/0" : {
"__class__" : " Nominal " ,
"type" : " gum-OrientationChange " ,
"name" : " x1 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " mood " ,
"target" : " imp "
},
{
"__class__" : " Role " ,
"type" : " gs-direction " ,
"target" : {
"__class__" : " Variable " ,
"type" : " gs-GeneralizedLocation " ,
"name" : " x2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " gs-hasSpatialModality " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Cup " ,
"name" : " w2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " cup "
},
{
"__class__" : " Role " ,
"type" : " det " ,
"target" : " the "
},
{
"__class__" : " Role " ,
"type" : " ident " ,
"target" : " specific "
},
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : " singular "
}
]
}
}
]
}
},
{
"__class__" : " Role " ,
"type" : " gum-processInConfiguration " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Taking " ,
"name" : " w0 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " slm-Taking "
}
]
}
}
]
},
"smain/.r" : {
"__class__" : " Nominal " ,
"type" : " gs-AffectingDirectedMotion " ,
"name" : " x1 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " mood " ,
"target" : " imperative "
},
{
"__class__" : " Role " ,
"type" : " gs-route " ,
"target" : {
"__class__" : " Variable " ,
"type" : null ,
"name" : " x2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " gum-actee " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Cup " ,
"name" : " w2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " cup "
},
{
"__class__" : " Role " ,
"type" : " det " ,
"target" : " the "
},
{
"__class__" : " Role " ,
"type" : " ident " ,
"target" : " specific "
},
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : " singular "
}
]
}
},
{
"__class__" : " Role " ,
"type" : " gum-processInConfiguration " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Moving " ,
"name" : " w0 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " slm-Taking "
}
]
}
}
]
}
}
]
},
"smain/.r/0" : {
"__class__" : " Nominal " ,
"type" : " gs-AffectingDirectedMotion " ,
"name" : " x1 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " mood " ,
"target" : " imperative "
},
{
"__class__" : " Role " ,
"type" : " gs-route " ,
"target" : {
"__class__" : " Variable " ,
"type" : null ,
"name" : " x2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " gum-actee " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Cup " ,
"name" : " w2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " cup "
},
{
"__class__" : " Role " ,
"type" : " det " ,
"target" : " the "
},
{
"__class__" : " Role " ,
"type" : " ident " ,
"target" : " specific "
},
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : " singular "
}
]
}
},
{
"__class__" : " Role " ,
"type" : " gum-processInConfiguration " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Taking " ,
"name" : " w0 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " slm-Taking "
}
]
}
}
]
}
}
]
}
},
"graphs" : {
"smain": "strict graph "" {ntnode [label="\N"];ntsubgraph cluster_x1 {nttgraph [fillcolor=lightskyblue,ntttlabel="x1: gum-OrientationChange",ntttstyle=filledntt];nttsubgraph "cluster_gs-direction" {ntttgraph [fillcolor=honeydew,nttttlabel="gs-direction",nttttstyle=fillednttt];ntttsubgraph cluster_x2 {nttttgraph [fillcolor=lightblue,ntttttlabel="x2: gs-GeneralizedLocation",ntttttstyle=filledntttt];nttttsubgraph "cluster_gs-hasSpatialModality" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gs-hasSpatialModality",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w2 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w2: slm-Cup",ntttttttstyle=filledntttttt];nttttttw2tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> cup|<det> the|<ident> specific|<quant> singular}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttt}ntt}nttsubgraph "cluster_gum-processInConfiguration" {ntttgraph [fillcolor=honeydew,nttttlabel="gum-processInConfiguration",nttttstyle=fillednttt];ntttsubgraph cluster_w0 {nttttgraph [fillcolor=lightblue,ntttttlabel="w0: slm-Moving",ntttttstyle=filledntttt];nttttw0tttt [fillcolor=aliceblue,ntttttlabel="{<entity> slm-Taking}",ntttttshape=Mrecord,ntttttstyle=filled];nttt}ntt}nttx1tt [fillcolor=aliceblue,ntttlabel="{<mood> imp}",ntttshape=Mrecord,ntttstyle=filled];nt}n}n",
"smain/0": "strict graph "" {ntnode [label="\N"];ntsubgraph cluster_x1 {nttgraph [fillcolor=lightskyblue,ntttlabel="x1: gum-OrientationChange",ntttstyle=filledntt];nttsubgraph "cluster_gs-direction" {ntttgraph [fillcolor=honeydew,nttttlabel="gs-direction",nttttstyle=fillednttt];ntttsubgraph cluster_x2 {nttttgraph [fillcolor=lightblue,ntttttlabel="x2: gs-GeneralizedLocation",ntttttstyle=filledntttt];nttttsubgraph "cluster_gs-hasSpatialModality" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gs-hasSpatialModality",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w2 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w2: slm-Cup",ntttttttstyle=filledntttttt];nttttttw2tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> cup|<det> the|<ident> specific|<quant> singular}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttt}ntt}nttsubgraph "cluster_gum-processInConfiguration" {ntttgraph [fillcolor=honeydew,nttttlabel="gum-processInConfiguration",nttttstyle=fillednttt];ntttsubgraph cluster_w0 {nttttgraph [fillcolor=lightblue,ntttttlabel="w0: slm-Taking",ntttttstyle=filledntttt];nttttw0tttt [fillcolor=aliceblue,ntttttlabel="{<entity> slm-Taking}",ntttttshape=Mrecord,ntttttstyle=filled];nttt}ntt}nttx1tt [fillcolor=aliceblue,ntttlabel="{<mood> imp}",ntttshape=Mrecord,ntttstyle=filled];nt}n}n",
"smain/.r": "strict graph "" {ntnode [label="\N"];ntsubgraph cluster_x1 {nttgraph [fillcolor=lightskyblue,ntttlabel="x1: gs-AffectingDirectedMotion",ntttstyle=filledntt];nttsubgraph "cluster_gs-route" {ntttgraph [fillcolor=honeydew,nttttlabel="gs-route",nttttstyle=fillednttt];ntttsubgraph cluster_x2 {nttttgraph [fillcolor=lightblue,ntttttlabel=None,ntttttstyle=filledntttt];nttttsubgraph "cluster_gum-actee" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gum-actee",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w2 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w2: slm-Cup",ntttttttstyle=filledntttttt];nttttttw2tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> cup|<det> the|<ident> specific|<quant> singular}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttttsubgraph "cluster_gum-processInConfiguration" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gum-processInConfiguration",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w0 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w0: slm-Moving",ntttttttstyle=filledntttttt];nttttttw0tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> slm-Taking}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttt}ntt}nttx1tt [fillcolor=aliceblue,ntttlabel="{<mood> imperative}",ntttshape=Mrecord,ntttstyle=filled];nt}n}n",
"smain/.r/0": "strict graph "" {ntnode [label="\N"];ntsubgraph cluster_x1 {nttgraph [fillcolor=lightskyblue,ntttlabel="x1: gs-AffectingDirectedMotion",ntttstyle=filledntt];nttsubgraph "cluster_gs-route" {ntttgraph [fillcolor=honeydew,nttttlabel="gs-route",nttttstyle=fillednttt];ntttsubgraph cluster_x2 {nttttgraph [fillcolor=lightblue,ntttttlabel=None,ntttttstyle=filledntttt];nttttsubgraph "cluster_gum-actee" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gum-actee",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w2 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w2: slm-Cup",ntttttttstyle=filledntttttt];nttttttw2tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> cup|<det> the|<ident> specific|<quant> singular}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttttsubgraph "cluster_gum-processInConfiguration" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gum-processInConfiguration",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w0 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w0: slm-Taking",ntttttttstyle=filledntttttt];nttttttw0tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> slm-Taking}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttt}ntt}nttx1tt [fillcolor=aliceblue,ntttlabel="{<mood> imperative}",ntttshape=Mrecord,ntttstyle=filled];nt}n}n"
}
}
Visualização de exemplo (apenas a parte principal mostrada):