Skip to content

Commit

Permalink
Fixed renderingf of text file thumbnail.
Browse files Browse the repository at this point in the history
  • Loading branch information
JSv4 committed Oct 14, 2024
1 parent 4a9178a commit d351376
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 41 deletions.
3 changes: 3 additions & 0 deletions config/graphql/graphene_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,13 @@ class AnalysisType(AnnotatePermissionsForReadMixin, DjangoObjectType):

def resolve_full_annotation_list(self, info, document_id=None):


results = self.annotations.all()
if document_id is not None:
document_pk = from_global_id(document_id)[1]
logger.info(f"Resolve full annotations for analysis {self.id} with doc {document_pk}")
results = results.filter(document_id=document_pk)

return results

class Meta:
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/components/annotator/DocumentAnnotator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ export const DocumentAnnotator = ({
variables: {
documentId: opened_document.id,
corpusId: opened_corpus.id,
...(selected_analysis
? { analysisId: selected_analysis.id }
: { analysisId: "__none__" }),
},
});
}
Expand Down Expand Up @@ -484,6 +487,9 @@ export const DocumentAnnotator = ({
variables: {
documentId: opened_document.id,
corpusId: opened_corpus.id,
...(selected_analysis
? { analysisId: selected_analysis.id }
: { analysisId: "__none__" }),
},
});
}
Expand Down
122 changes: 106 additions & 16 deletions frontend/src/components/annotator/renderers/txt/TxtAnnotator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ const AnnotatedSpan = styled.span<{
const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
text,
annotations,
searchResults,
getSpan,
visibleLabels,
availableLabels,
Expand All @@ -147,6 +148,7 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
selectedAnnotations,
setSelectedAnnotations,
showStructuralAnnotations,
selectedSearchResultIndex,
}) => {
const [hoveredSpanIndex, setHoveredSpanIndex] = useState<number | null>(null);
const [editModalOpen, setEditModalOpen] = useState(false);
Expand All @@ -168,7 +170,7 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
const handleMouseLeave = useCallback(() => {
hideLabelsTimeout.current = setTimeout(() => {
setHoveredSpanIndex(null);
}, 200); // Adjust delay as needed
}, 1000); // Adjust delay as needed
}, []);

const handleLabelMouseEnter = useCallback(() => {
Expand All @@ -181,7 +183,7 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
const handleLabelMouseLeave = useCallback(() => {
hideLabelsTimeout.current = setTimeout(() => {
setHoveredSpanIndex(null);
}, 200); // Adjust delay as needed
}, 2000); // Adjust delay as needed
}, []);

const handleLabelClick = useCallback(
Expand All @@ -201,6 +203,8 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
end: number;
text: string;
annotations: ServerSpanAnnotation[];
isSearchResult?: boolean;
isSelectedSearchResult?: boolean;
}[]
>([]);

Expand All @@ -222,19 +226,25 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
end: number;
text: string;
annotations: ServerSpanAnnotation[];
isSearchResult?: boolean;
isSelectedSearchResult?: boolean;
}[] = [];

const addSpan = (
start: number,
end: number,
annotations: ServerSpanAnnotation[]
annotations: ServerSpanAnnotation[],
isSearchResult = false,
isSelectedSearchResult = false
) => {
if (start >= end) return;
newSpans.push({
start,
end,
text: text.slice(start, end),
annotations,
isSearchResult,
isSelectedSearchResult,
});
};

Expand All @@ -243,6 +253,10 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
annotationBoundaries.add(ann.json.start);
annotationBoundaries.add(ann.json.end);
});
searchResults.forEach((result) => {
annotationBoundaries.add(result.start_index);
annotationBoundaries.add(result.end_index);
});
annotationBoundaries.add(0);
annotationBoundaries.add(text.length);

Expand All @@ -254,10 +268,31 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
const spanAnnotations = sortedAnnotations.filter(
(ann) => ann.json.start < spanEnd && ann.json.end > spanStart
);
addSpan(spanStart, spanEnd, spanAnnotations);
const isSearchResult = searchResults.some(
(result) =>
result.start_index <= spanStart && result.end_index >= spanEnd
);
const isSelectedSearchResult =
isSearchResult &&
selectedSearchResultIndex !== undefined &&
searchResults[selectedSearchResultIndex].start_index <= spanStart &&
searchResults[selectedSearchResultIndex].end_index >= spanEnd;
addSpan(
spanStart,
spanEnd,
spanAnnotations,
isSearchResult,
isSelectedSearchResult
);
}
setSpans(newSpans);
}, [annotations, text, visibleLabels]);
}, [
annotations,
text,
visibleLabels,
searchResults,
selectedSearchResultIndex,
]);

useEffect(() => {
const calculateLabelPositions = () => {
Expand Down Expand Up @@ -406,6 +441,52 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
calculateLabelPositions();
}, [hoveredSpanIndex, spans, showStructuralAnnotations, selectedAnnotations]);

interface Corner {
x: number;
y: number;
distance?: number;
}

const getClosestCorner = (
labelX: number,
labelY: number,
spanRect: DOMRect,
containerRect: DOMRect,
scrollLeft: number,
scrollTop: number
): Corner => {
const corners: Corner[] = [
{
x: spanRect.left - containerRect.left + scrollLeft,
y: spanRect.top - containerRect.top + scrollTop,
},
{
x: spanRect.right - containerRect.left + scrollLeft,
y: spanRect.top - containerRect.top + scrollTop,
},
{
x: spanRect.left - containerRect.left + scrollLeft,
y: spanRect.bottom - containerRect.top + scrollTop,
},
{
x: spanRect.right - containerRect.left + scrollLeft,
y: spanRect.bottom - containerRect.top + scrollTop,
},
];

return corners.reduce(
(closest, corner) => {
const distance = Math.sqrt(
Math.pow(labelX - corner.x, 2) + Math.pow(labelY - corner.y, 2)
);
return distance < (closest.distance ?? Infinity)
? { ...corner, distance }
: closest;
},
{ x: 0, y: 0, distance: Infinity } as Corner
);
};

return (
<>
<PaperContainer
Expand All @@ -419,7 +500,12 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
}}
>
{spans.map((span, index) => {
const { text: spanText, annotations: spanAnnotations } = span;
const {
text: spanText,
annotations: spanAnnotations,
isSearchResult,
isSelectedSearchResult,
} = span;

const spanStyle: React.CSSProperties = {};

Expand Down Expand Up @@ -463,6 +549,12 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
const borderColor =
selectedAnnotationsForSpan[0]?.annotationLabel.color || "#000";

if (isSearchResult) {
spanStyle.backgroundColor = isSelectedSearchResult
? "#FFFF00"
: "#FFFF99";
}

return (
<AnnotatedSpan
key={index}
Expand Down Expand Up @@ -517,16 +609,14 @@ const TxtAnnotator: React.FC<TxtAnnotatorProps> = ({
const scrollLeft = containerElement?.scrollLeft ?? 0;
const scrollTop = containerElement?.scrollTop ?? 0;

const endX =
spanRect.left -
containerRect.left +
scrollLeft +
spanRect.width / 2;
const endY =
spanRect.top -
containerRect.top +
scrollTop +
spanRect.height / 2;
const { x: endX, y: endY } = getClosestCorner(
x + width / 2,
y + height / 2,
spanRect,
containerRect,
scrollLeft,
scrollTop
);

const labelCenterX = x + width / 2;
const labelCenterY = y + height / 2;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.16 on 2024-10-12 04:29

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("annotations", "0019_rename_label_type_annotation_annotation_type"),
]

operations = [
migrations.RemoveConstraint(
model_name="annotationlabel",
name="Only install one label of given name for each analyzer_id PER user (no duplicates)",
),
migrations.AddConstraint(
model_name="annotationlabel",
constraint=models.UniqueConstraint(
fields=("analyzer", "text", "creator", "label_type"),
name="Only install one label of given name for each analyzer_id PER user (no duplicates)",
),
),
]
2 changes: 1 addition & 1 deletion opencontractserver/annotations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class Meta:

constraints = [
django.db.models.UniqueConstraint(
fields=["analyzer", "text", "creator"],
fields=["analyzer", "text", "creator", "label_type"],
name="Only install one label of given name for each analyzer_id PER user (no duplicates)",
)
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.16 on 2024-10-12 04:29

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("documents", "0010_document_processing_finished_and_more"),
]

operations = [
migrations.AlterField(
model_name="document",
name="page_count",
field=models.IntegerField(blank=True, default=0),
),
]
2 changes: 1 addition & 1 deletion opencontractserver/documents/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Document(BaseOCModel):
null=True,
)
page_count = django.db.models.IntegerField(
default=-1, # insane default to make it easy to find unhandled docs
default=0,
null=False,
blank=True,
)
Expand Down
20 changes: 10 additions & 10 deletions opencontractserver/shared/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ def wrapper(self, *args, **kwargs):
delay = min(INITIAL_DELAY + (retry_count * DELAY_INCREMENT), MAX_DELAY)
logger.info(f"\tNew delay: {delay}")

# If we've reached MAX_DELAY, reset the retry count
if delay >= MAX_DELAY:
delay = INITIAL_DELAY
# If we've reached MAX_DELAY, STOP.
if delay < MAX_DELAY:
# delay = INITIAL_DELAY

logger.info("Starting retry...")
raise self.retry(countdown=delay)
logger.info("Starting retry...")
raise self.retry(countdown=delay)

try:
# Retrieve necessary file contents
Expand Down Expand Up @@ -179,7 +179,7 @@ def wrapper(self, *args, **kwargs):

# Convert to appropriate form of annotation depending on the document type...
# FOR application/pdf... we want token annotations
if doc.file_type == "application/pdf":
if doc.file_type in ["application/pdf"]:
# Convert (TextSpan, str) pairs to OpenContractsAnnotationPythonType
logger.info(f"Create Annotation Linked to {corpus_id}")
span, label = span_label_pair
Expand Down Expand Up @@ -211,11 +211,11 @@ def wrapper(self, *args, **kwargs):
resulting_annotations.append(annot)

# FOR application/txt... we want span-based annotations
elif doc.file_type == "application/txt":
elif doc.file_type in ["application/txt"]:
logger.info(f"Create Annotation Linked to {corpus_id}")
span, label = span_label_pair
label, _ = AnnotationLabel.objects.get_or_create(
text=annotation_data["annotationLabel"],
text=label,
label_type=LabelType.SPAN_LABEL,
creator=analysis.creator,
analyzer=analysis.analyzer,
Expand All @@ -226,8 +226,8 @@ def wrapper(self, *args, **kwargs):
document=doc,
analysis=analysis,
annotation_label=label,
page=annotation_data["page"],
raw_text=annotation_data["rawText"],
page=1,
raw_text=pdf_text_extract[ span['start']:span['end']],
annotation_type=LabelType.SPAN_LABEL,
json={"start": span['start'], "end": span['end']},
creator=analysis.creator,
Expand Down
Loading

0 comments on commit d351376

Please sign in to comment.