Skip to content

Commit

Permalink
refactor: replace annotation service with nlp service
Browse files Browse the repository at this point in the history
  • Loading branch information
Reddine committed Nov 25, 2024
1 parent b16d3fe commit c917ea7
Show file tree
Hide file tree
Showing 21 changed files with 580 additions and 709 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ The **environment variables** descriptions:
| ESLINT_NO_DEV_ERRORS | ✅ Used | 🚫 Ignored | When set to `true`, ESLint errors are converted to warnings during development. As a result, ESLint output will no longer appear in the error overlay. |
| NEXT_PUBLIC_BACKEND_URL | ✅ Used | ✅ Used | ORKG backend endpoint (use http://localhost:8080/ when running the backend locally) |
| NEXT_PUBLIC_SIMILARITY_SERVICE_URL | ✅ Used | ✅ Used | ORKG similarity service endpoint (use http://localhost:5000/ when running the service locally) |
| NEXT_PUBLIC_ANNOTATION_SERVICE_URL | ✅ Used | ✅ Used | ORKG annotation service endpoint |
| NEXT_PUBLIC_SIMILAR_PAPER_URL | ✅ Used | ✅ Used | ORKG [similar papers](https://gitlab.com/TIBHannover/orkg/orkg-simpaper-api) service endpoint |
| NEXT_PUBLIC_NLP_SERVICE_URL | ✅ Used | ✅ Used | ORKG [NLP service](https://gitlab.com/TIBHannover/orkg/nlp/orkg-nlp-api) endpoint |
| NEXT_PUBLIC_GROBID_URL | ✅ Used | ✅ Used | GROBID service endpoint (More details in ORKG annotation repository) |
Expand Down
1 change: 0 additions & 1 deletion default.env
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ NEXT_PUBLIC_URL=https://www.orkg.org
NEXT_PUBLIC_BACKEND_URL=https://sandbox.orkg.org/
NEXT_PUBLIC_SIMILARITY_SERVICE_URL=https://sandbox.orkg.org/simcomp/
NEXT_PUBLIC_SIMILAR_PAPER_URL=https://orkg.org/simpaper/api/
NEXT_PUBLIC_ANNOTATION_SERVICE_URL=http://localhost:7000/
NEXT_PUBLIC_NLP_SERVICE_URL=https://sandbox.orkg.org/nlp/api/
NEXT_PUBLIC_DATACITE_URL=https://api.test.datacite.org/dois
NEXT_PUBLIC_GROBID_URL=https://orkg.org/grobid/
Expand Down
22 changes: 20 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"prop-types": "^15.8.1",
"qs": "^6.11.1",
"randomcolor": "^0.6.2",
"rangy": "^1.3.1",
"rangy": "^1.3.2",
"rc-tabs": "^12.5.10",
"rc-tree": "^5.7.2",
"rdf": "github:Reddine/node-rdf",
Expand Down Expand Up @@ -175,6 +175,8 @@
"@types/leaflet": "^1.9.12",
"@types/node": "^20.4.9",
"@types/pluralize": "^0.0.32",
"@types/randomcolor": "^0.5.9",
"@types/rangy": "^0.0.38",
"@types/react": "^18.2.20",
"@types/react-copy-to-clipboard": "^5.0.7",
"@types/react-csv": "^1.1.10",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,78 +1,88 @@
import { useRef } from 'react';
import PropTypes from 'prop-types';
import { OptionType } from 'components/Autocomplete/types';
import AnnotationTooltip from 'components/ViewPaper/AbstractAnnotatorModal/AnnotationTooltip';
import rangy from 'rangy';
import { useSelector, useDispatch } from 'react-redux';
import { FC, ReactElement, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Range, RootStore } from 'slices/types';
import { createAnnotation } from 'slices/viewPaperSlice';
import AnnotationTooltip from 'components/ViewPaper/AbstractAnnotatorModal/AnnotationTooltip';

function getAllIndexes(arr, val) {
function getAllIndexes(arr: string, val: string) {
const indexes = [];
let i = -1;
while ((i = arr.indexOf(val, i + 1)) !== -1) {
indexes.push(i);
let nextIndex = arr.indexOf(val, i + 1);
while (nextIndex !== -1) {
indexes.push(nextIndex);
i = nextIndex;
nextIndex = arr.indexOf(val, i + 1);
}
return indexes;
}

function AbstractAnnotator(props) {
const annotatorRef = useRef(null);
type AbstractAnnotatorProps = {
predicateOptions: OptionType[];
getPredicateColor: (id: string) => string;
};

const AbstractAnnotator: FC<AbstractAnnotatorProps> = ({ predicateOptions, getPredicateColor }) => {
const annotatorRef = useRef<HTMLDivElement>(null);

const dispatch = useDispatch();

const abstract = useSelector((state) => state.viewPaper.abstract);
const ranges = useSelector((state) => state.viewPaper.ranges);
const { abstract, ranges } = useSelector((state: RootStore) => state.viewPaper);

const renderCharNode = (charIndex) => (
const renderCharNode = (charIndex: number) => (
<span key={`c${charIndex}`} data-position={charIndex}>
{abstract[charIndex]}
</span>
);

const getRange = (charPosition) =>
ranges &&
Object.values(ranges).find(
(range) => charPosition >= range.start && charPosition <= range.end && range.certainty >= props.certaintyThreshold,
);
const getRange = (charPosition: number) =>
ranges && Object.values(ranges).find((range) => charPosition >= range.start && charPosition <= range.end);

const tooltipRenderer = (lettersNode, range) => (
const tooltipRenderer = (lettersNode: ReactElement[], range: Range) => (
<AnnotationTooltip
key={`${range.id}`}
range={range}
lettersNode={lettersNode}
classOptions={props.classOptions}
getClassColor={props.getClassColor}
predicateOptions={predicateOptions}
getPredicateColor={getPredicateColor}
/>
);

const getAnnotatedText = () => {
const annotatedText = [];
for (let charPosition = 0; charPosition < abstract.length; charPosition++) {
for (let charPosition = 0; charPosition < abstract.length; charPosition += 1) {
const range = getRange(charPosition);
const charNode = renderCharNode(charPosition);
if (!range) {
if (range) {
const annotationGroup = [charNode];
let rangeCharPosition = charPosition + 1;
for (; rangeCharPosition < range.end + 1; rangeCharPosition += 1) {
annotationGroup.push(renderCharNode(rangeCharPosition));
charPosition = rangeCharPosition;
}
annotatedText.push(tooltipRenderer(annotationGroup, range));
} else {
annotatedText.push(charNode);
continue;
}
const annotationGroup = [charNode];
let rangeCharPosition = charPosition + 1;
for (; rangeCharPosition < parseInt(range.end) + 1; rangeCharPosition++) {
annotationGroup.push(renderCharNode(rangeCharPosition));
charPosition = rangeCharPosition;
}
annotatedText.push(tooltipRenderer(annotationGroup, range));
}
return annotatedText;
};

const handleMouseUp = () => {
if (!annotatorRef.current) {
return null;
}
// Get the selection
// @ts-expect-error: rangy is not typed
const sel = rangy.getSelection(annotatorRef.current);
if (sel.isCollapsed) {
return null;
}
// Get position of the node at which the user started selecting
let start = parseInt(sel.anchorNode.parentNode.dataset.position);
let start = parseInt((sel.anchorNode?.parentNode as HTMLElement)?.dataset.position ?? '', 10);
// Get position of the node at which the user stopped selecting
let end = parseInt(sel.focusNode.parentNode.dataset.position);
let end = parseInt((sel.focusNode?.parentNode as HTMLElement)?.dataset.position ?? '', 10);
// Get the text within the selection
const text = sel.toString();
if (!text.length) {
Expand All @@ -97,20 +107,21 @@ function AbstractAnnotator(props) {
start,
end,
text,
class: { id: null, label: null },
predicate: { id: null, label: null },
certainty: 1,
isEditing: false,
};
dispatch(createAnnotation(range));
window.getSelection().empty();
window?.getSelection()?.empty();
return null;
};

const annotatedText = getAnnotatedText();
return (
<div>
<div
role="textbox"
tabIndex="0"
tabIndex={0}
onMouseUp={handleMouseUp}
id="annotatedText"
className="mt-4"
Expand All @@ -121,12 +132,6 @@ function AbstractAnnotator(props) {
</div>
</div>
);
}
};

export default AbstractAnnotator;

AbstractAnnotator.propTypes = {
certaintyThreshold: PropTypes.number,
classOptions: PropTypes.array.isRequired,
getClassColor: PropTypes.func.isRequired,
};
Loading

0 comments on commit c917ea7

Please sign in to comment.