diff --git a/packages/cwrc-leafwriter/src/dialogs/entityLookups/types.ts b/packages/cwrc-leafwriter/src/dialogs/entityLookups/types.ts index 915e2548005082c9901d078f9a561e12f6216bde..8b379cec757cd2db2c94104b6cd6e4eab29ed2de 100644 --- a/packages/cwrc-leafwriter/src/dialogs/entityLookups/types.ts +++ b/packages/cwrc-leafwriter/src/dialogs/entityLookups/types.ts @@ -13,7 +13,7 @@ export type NamedEntityType = | 'title' | 'thing' | 'concept'; -export type Authority = 'dbpedia' | 'geonames' | 'getty' | 'lgpn' | 'viaf' | 'wikidata'; +export type Authority = 'dbpedia' | 'geonames' | 'getty' | 'lgpn' | 'viaf' | 'wikidata' | 'gnd'; export type LookupService = 'LINCS' | 'internal' | 'custom'; export interface AuthorityService { diff --git a/packages/cwrc-leafwriter/src/overmind/editor/state.ts b/packages/cwrc-leafwriter/src/overmind/editor/state.ts index 840e5f10e7f36c4dc6ba4913b16c2514f0a61c0d..bbdf7cb3d351639d27857a4a933f3b9b33d8d798 100644 --- a/packages/cwrc-leafwriter/src/overmind/editor/state.ts +++ b/packages/cwrc-leafwriter/src/overmind/editor/state.ts @@ -8,6 +8,7 @@ import { lgpnFind, viafFind, wikidataFind, + gndFind } from '../lookups/services'; // eslint-disable-next-line @typescript-eslint/consistent-type-definitions @@ -142,6 +143,14 @@ export const state: EditorStateType = { name: 'LGPN', priority: 5, lookupService: 'internal', + },gnd: { + enabled: true, + entities: { person: true, place: true, organization: true, title: true, rs: true }, + find: gndFind, + id: 'gnd', + name: 'GND', + priority: 5, + lookupService: 'internal', }, }, }; diff --git a/packages/cwrc-leafwriter/src/overmind/lookups/services/gnd.ts b/packages/cwrc-leafwriter/src/overmind/lookups/services/gnd.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3663f0db0c5428950fa467f962f0910432764ad --- /dev/null +++ b/packages/cwrc-leafwriter/src/overmind/lookups/services/gnd.ts @@ -0,0 +1,80 @@ +import axios from 'axios'; +import type { AuthorityLookupResult } from '../../../dialogs/entityLookups/types'; +import { log } from './../../../utilities'; +import { type AuthorityLookupParams } from './type'; + +type NamedEntityType = 'Person' | 'PlaceOrGeographicName' | 'CorporateBody' | 'Work' | 'SubjectHeading'; + +interface Doc { + id: string; + preferredName: string; + biographicalOrHistoricalInformation: string[]; +} + +interface GNDResults { + member: Doc[]; +} + +const baseURL = 'https://lobid.org/gnd'; +const FORMAT = 'json'; +const MAX_HITS = 25; // default: 100; but it breaks at 45+ +const timeout = 3_000; + +const axiosInstance = axios.create({ baseURL, timeout }); + +export const find = async ({ query, type }: AuthorityLookupParams) => { + if (type === 'person') return await callGND(query, 'Person'); + if (type === 'place') return await callGND(query, 'PlaceOrGeographicName'); + if (type === 'organization') return await callGND(query, 'CorporateBody'); + if (type === 'title') return await callGND(query, 'Work'); + if (type === 'rs') return await callGND(query, 'SubjectHeading'); + if (type === 'thing') return await callGND(query, 'SubjectHeading'); + if (type === 'concept') return await callGND(query, 'SubjectHeading'); + + log.warn(`GND: Entity type ${type} invalid`); +}; + +const callGND = async (query: string, type: NamedEntityType) => { + const encodeQueryString = encodeURIComponent(query); + + const params = new URLSearchParams({ + q: query, + filter: "type:" + type, + format: FORMAT, + size: MAX_HITS.toString(), + }); + + const urlQuery = `search?${params}`; + + const response = await axiosInstance.get<GNDResults>(urlQuery).catch((error) => { + return { + status: 500, + statusText: `The request exeeded the timeout (${timeout})`, + data: undefined, + }; + }); + + if (response.status >= 400) { + const errorMsg = ` + Something wrong with the call to lobid-gnd, possibly a problem with the network or the server. + HTTP error: ${response.statusText} + `; + log.warn(errorMsg); + return []; + } + + const data = response.data; + if (!data) return []; + + // const mapResponse = responseJson.docs.map( + const results: AuthorityLookupResult[] = data.member.map(( entry:Doc ) => { + //? assuming first instance of description, name and uri; + const description = entry.biographicalOrHistoricalInformation?.[0] ?? 'No description available'; + const name = entry.preferredName ?? ''; + const uri = entry.id; + + return { description, id: uri ?? '', name, repository: 'gnd', query, type, uri: uri ?? '' }; + }); + + return results; +}; diff --git a/packages/cwrc-leafwriter/src/overmind/lookups/services/index.ts b/packages/cwrc-leafwriter/src/overmind/lookups/services/index.ts index 0a3f957f7579b3a36e0a094a9dcbb7952398abb7..557bd4c7b896c77abbe7bd3f63d184eed9f6715b 100644 --- a/packages/cwrc-leafwriter/src/overmind/lookups/services/index.ts +++ b/packages/cwrc-leafwriter/src/overmind/lookups/services/index.ts @@ -4,3 +4,4 @@ export { find as gettyFind } from './getty'; export { find as lgpnFind } from './lgpn'; export { find as viafFind } from './viaf'; export { find as wikidataFind } from './wikidata'; +export { find as gndFind} from './gnd';