Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize Lemmatizer #502

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/fragmentarium/ui/LemmaSearchForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,22 @@ export const LemmaSearchForm = withData<
{
wordService: WordService
onChange: (name: string) => (name: string) => void
isDisabled?: boolean
placeholder?: string
},
{ lemmas: string },
LemmaOption[]
>(
({ data, wordService, onChange }) => {
({ data, wordService, onChange, isDisabled, placeholder }) => {
return (
<LemmaSelectionForm
wordService={wordService}
onChange={(query) => {
onChange('lemmas')(query.map((lemma) => lemma.value).join('+'))
}}
query={data}
isDisabled={isDisabled}
placeholder={placeholder}
/>
)
},
Expand Down
23 changes: 22 additions & 1 deletion src/fragmentarium/ui/fragment/CuneiformFragmentEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { FindspotService } from 'fragmentarium/application/FindspotService'
import { Session } from 'auth/Session'
import ColophonEditor from 'fragmentarium/ui/fragment/ColophonEditor'
import { Colophon } from 'fragmentarium/domain/Colophon'
import TabularAnnotationTool from './TabularAnnotationTool'

const ContentSection: FunctionComponent = ({
children,
Expand Down Expand Up @@ -47,6 +48,7 @@ type TabName =
| 'references'
| 'archaeology'
| 'colophon'
| 'annotation'

const tabNames: TabName[] = [
'display',
Expand All @@ -55,6 +57,7 @@ const tabNames: TabName[] = [
'references',
'archaeology',
'colophon',
'annotation',
]

function EditorTab({
Expand Down Expand Up @@ -92,6 +95,7 @@ function TabContentsMatcher({
references: () => ReferencesContents(props),
archaeology: () => ArchaeologyContents(props),
colophon: () => ColophonContents(props),
annotation: () => AnnotationContents(props),
}[name]()
}

Expand Down Expand Up @@ -127,7 +131,9 @@ export const EditorTabs: FunctionComponent<TabsProps> = ({
<Tabs
id={tabsId}
defaultActiveKey={
session.isAllowedToTransliterateFragments() ? 'edition' : 'display'
session.isAllowedToTransliterateFragments()
? 'annotation'
: 'display'
}
mountOnEnter={true}
className={
Expand Down Expand Up @@ -235,3 +241,18 @@ function ColophonContents(props: TabsProps): JSX.Element {

return <ColophonEditor updateColophon={updateColophon} {...props} />
}

function AnnotationContents(props: TabsProps): JSX.Element {
const updateFragmentAnnotation = async (fragment: Fragment) => {
console.log('Saved fragment!')
}
return (
<div className="annotation-tool__wrapper">
<TabularAnnotationTool
fragment={props.fragment}
wordService={props.wordService}
onSave={updateFragmentAnnotation}
/>
</div>
)
}
124 changes: 124 additions & 0 deletions src/fragmentarium/ui/fragment/TabularAnnotationTool.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { Fragment } from 'fragmentarium/domain/fragment'
import React, { Component } from 'react'
import { isTextLine } from 'transliteration/domain/type-guards'
// import DisplayToken from 'transliteration/ui/DisplayToken'
import { Token } from 'transliteration/domain/token'
import _ from 'lodash'
import { TextLine } from 'transliteration/domain/text-line'
import { Table } from 'react-bootstrap'
import lineNumberToString from 'transliteration/domain/lineNumberToString'
import './TokenAnnotationTool.sass'
import DisplayToken from 'transliteration/ui/DisplayToken'
import { LineNumber, LineNumberRange } from 'transliteration/domain/line-number'
import { LemmaSearchForm } from '../LemmaSearchForm'
import WordService from 'dictionary/application/WordService'

type Props = {
fragment: Fragment
wordService: WordService
onSave(fragment: Fragment): void
}

type AnnotationRow = {
lineNumber: LineNumber | LineNumberRange
lineIndex: number
token: Token
newUniqueLemma: string[]
tokenIndex: number
uniqueId: string
}

type AnnotationTable = AnnotationRow[]

export default class TokenAnnotationTool extends Component<Props, unknown> {
private annotationTable: AnnotationTable
fragment: Fragment

constructor(props: Props) {
super(props)
this.fragment = props.fragment
this.annotationTable = this.createAnnotationTable()
}

createAnnotationTable(): AnnotationTable {
const lines = this.props.fragment.text.allLines

return lines
.map((line, lineIndex) => ({ line, lineIndex }))
.filter((indexedLine) => isTextLine(indexedLine.line))
.flatMap((indexedLine) => {
const line = indexedLine.line as TextLine
return line.content.map((token, tokenIndex) => ({
lineNumber: line.lineNumber,
token,
tokenIndex,
uniqueId: _.uniqueId(),
lineIndex: indexedLine.lineIndex,
newUniqueLemma: [],
}))
})
}

LemmaEditor({
row,
wordService,
}: {
row: AnnotationRow
wordService: WordService
}): JSX.Element {
const lemmas = row.token.uniqueLemma || []
return !row.token.lemmatizable ? (
<></>
) : (
<LemmaSearchForm
wordService={wordService}
lemmas={lemmas.join('+') || ''}
onChange={() => () => console.log('something')}
placeholder="Add lemma..."
/>
)
}

render(): JSX.Element {
let lastLineNumber = ''
return (
<Table
bordered
size={'sm'}
className={'annotation-tool__table-annotator'}
>
<thead>
<tr>
<td>Line</td>
<td>Token</td>
<td>Lemma</td>
</tr>
</thead>
<tbody>
{this.annotationTable.map((row, index) => {
const lineNumber = lineNumberToString(row.lineNumber)
const displayRow = (
<tr key={index}>
<td>
{lineNumber !== lastLineNumber &&
`(${lineNumberToString(row.lineNumber)})`}
</td>
<td>
<DisplayToken token={row.token} isInPopover={true} />
</td>
<td>
<this.LemmaEditor
row={row}
wordService={this.props.wordService}
/>
</td>
</tr>
)
lastLineNumber = lineNumber
return displayRow
})}
</tbody>
</Table>
)
}
}
33 changes: 33 additions & 0 deletions src/fragmentarium/ui/fragment/TokenAnnotationTool.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.annotation-tool

&__table-annotator
width: unset
tbody
td:last-child
min-width: 10em

&__wrapper
max-height: 50%
overflow-y: auto
td
padding: 0
border-top: 0
tr.line-separator
height: 1em
border-top: 1px solid grey
.annotation-line
&__source
&__annotation-layer
font-size: .7em
.markable-token
white-space: nowrap
// border: 1px dashed orange
margin-right: 1em

&__checkbox-column
visibility: hidden
&:hover
visibility: visible !important
&__lemma-column
min-width: 10em
// white-space: nowrap
90 changes: 90 additions & 0 deletions src/fragmentarium/ui/fragment/TokenAnnotationTool.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { Component } from 'react'
import { Fragment } from 'fragmentarium/domain/fragment'
import { AbstractLine } from 'transliteration/domain/abstract-line'
import { isEmptyLine, isTextLine } from 'transliteration/domain/type-guards'
import DisplayControlLine from 'transliteration/ui/DisplayControlLine'
import { TextLine } from 'transliteration/domain/text-line'
import { lineComponents } from 'transliteration/ui/TransliterationLines'
import { AnnotationLine } from 'transliteration/ui/annotation-line-tokens'
import './TokenAnnotationTool.sass'
import { Table } from 'react-bootstrap'
import FragmentService from 'fragmentarium/application/FragmentService'
import WordService from 'dictionary/application/WordService'

type Props = {
fragment: Fragment
onSave(fragment: Fragment): void
fragmentService: FragmentService
wordService: WordService
}

export default class TokenAnnotationTool extends Component<Props, unknown> {
readonly fragment: Fragment

constructor(props: Props) {
super(props)
this.fragment = props.fragment
}

displayMarkableLine({
line,
lineIndex,
fragmentService,
wordService,
}: {
line: TextLine
lineIndex: number
fragmentService: FragmentService
wordService: WordService
}): JSX.Element {
return (
<AnnotationLine
line={line}
lineIndex={lineIndex}
fragmentService={fragmentService}
wordService={wordService}
/>
)
}

render(): JSX.Element {
const text = this.fragment.text

return (
<Table className={'annotation-tool'}>
<tbody>
{text.allLines
.filter((line) => !isEmptyLine(line))
.map((line: AbstractLine, index) => {
const LineComponent =
lineComponents.get(line.type) || DisplayControlLine

return (
<React.Fragment key={index}>
{isTextLine(line) ? (
<>
<this.displayMarkableLine
key={index}
line={line}
lineIndex={index}
fragmentService={this.props.fragmentService}
wordService={this.props.wordService}
/>
<tr className="line-separator"></tr>
</>
) : (
<tr key={index}>
<LineComponent
line={line}
columns={text.numberOfColumns}
/>
</tr>
)}
</React.Fragment>
)
})}
</tbody>
</Table>
)
}
}
9 changes: 6 additions & 3 deletions src/fragmentarium/ui/lemmatization/LemmaSelectionForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ type Props = {
query?: readonly LemmaOption[]
onChange: (query: readonly LemmaOption[]) => void
wordService: { searchLemma(query: string): Promise<readonly Word[]> }
placeholder?: string
isDisabled?: boolean
}
type State = {
query: ValueType<LemmaOption, true>
Expand Down Expand Up @@ -97,11 +99,11 @@ class LemmaSelectionForm extends Component<Props, State> {
}
}

Select = ({ label }: { label: string }): JSX.Element => {
Select = (): JSX.Element => {
return (
<AsyncSelect
aria-label={'Select lemmata'}
placeholder={label}
placeholder={this.props.placeholder || 'Lemmata'}
isClearable
loadOptions={this.loadOptions}
onInputChange={this.onInputChange}
Expand All @@ -111,12 +113,13 @@ class LemmaSelectionForm extends Component<Props, State> {
isMulti={true}
components={{ Option, MultiValueLabel }}
isOptionSelected={() => false}
isDisabled={this.props.isDisabled}
/>
)
}

render(): JSX.Element {
return <this.Select label={'Lemmata'} />
return <this.Select />
}
}

Expand Down
Loading
Loading