From 3197bdc01f11e1eb71de90950b3e8e890e97d3f8 Mon Sep 17 00:00:00 2001 From: lennertvandevelde Date: Tue, 21 Apr 2026 11:17:35 +0200 Subject: [PATCH 1/3] OPS-3943 add AI metadata api documentation --- assets/ai_scripts/.env-template | 12 + assets/ai_scripts/download_meemoo_ai_data.py | 87 ++++ .../download_meemoo_raw_ai_files.py | 81 ++++ docs/integratie/ai-metadata-api.md | 433 ++++++++++++++++++ 4 files changed, 613 insertions(+) create mode 100644 assets/ai_scripts/.env-template create mode 100644 assets/ai_scripts/download_meemoo_ai_data.py create mode 100644 assets/ai_scripts/download_meemoo_raw_ai_files.py create mode 100644 docs/integratie/ai-metadata-api.md diff --git a/assets/ai_scripts/.env-template b/assets/ai_scripts/.env-template new file mode 100644 index 00000000..c8794be8 --- /dev/null +++ b/assets/ai_scripts/.env-template @@ -0,0 +1,12 @@ +# hasura endpoint url +ENDPOINT=https://services.viaa.be/ai-results/v1/graphql +# bearer token url +TOKEN_ENDPOINT=https://oas.hetarchief.be/token +# token expiration in seconds +EXPIRES_IN=86400 +# number of tasks in one page for a hasura query +PAGE_SIZE=1000 + +# FILL IN THESE VALUES IN THE COPIED .env FILE +USER_EMAIL= +PASSWORD= \ No newline at end of file diff --git a/assets/ai_scripts/download_meemoo_ai_data.py b/assets/ai_scripts/download_meemoo_ai_data.py new file mode 100644 index 00000000..613770d8 --- /dev/null +++ b/assets/ai_scripts/download_meemoo_ai_data.py @@ -0,0 +1,87 @@ +import os +from pathlib import Path + +from dotenv import load_dotenv +from utils.auth import get_bearer_token +from utils.constants import OUTPUT_DIR +from utils.hasura import yield_results_pages +from utils.inout import write_page_data +from utils.queries import ( + FACE_IMAGE_MATCHES_QUERY, + FACE_IMAGE_TASKS_QUERY, + FACE_MATCHES_QUERY, + FACE_TASKS_QUERY, + NER_TASKS_QUERY, + REFSET_PERSONS_QUERY, + SPEECH_TASKS_QUERY, +) + +VIEW_TO_ID_TYPE_MAPPER = { + 'face_matches': 'cluster_uuid', + 'face_image_matches': 'cluster_uuid', + 'face_tasks': 'task_id', + 'face_image_tasks': 'task_id', + 'ner_tasks': 'task_id', + 'refset_persons': 'id', + 'speech_tasks': 'task_id', +} +VIEW_TO_QUERY_MAPPER = { + 'face_matches': FACE_MATCHES_QUERY, + 'face_image_matches': FACE_IMAGE_MATCHES_QUERY, + 'face_tasks': FACE_TASKS_QUERY, + 'face_image_tasks': FACE_IMAGE_TASKS_QUERY, + 'ner_tasks': NER_TASKS_QUERY, + 'refset_persons': REFSET_PERSONS_QUERY, + 'speech_tasks': SPEECH_TASKS_QUERY, +} + + +def download_meemoo_ai_data(url: str, token: str, output_dir: Path, page_size: int): + for view, query in VIEW_TO_QUERY_MAPPER.items(): + variables = {'limit': page_size, 'offset': 0} + + pages_folder = output_dir / view + if pages_folder.exists(): + raise FileExistsError( + 'Remove the outputs folder before running this script.' + ) + pages_folder.mkdir(parents=True) + + for page, offset in yield_results_pages( + url=url, + token=token, + view=view, + query=query, + variables=variables, + page_size=page_size, + ): + id_type = VIEW_TO_ID_TYPE_MAPPER[view] + write_page_data( + id_type=id_type, + folder=pages_folder, + page=page, + offset=offset, + page_size=page_size, + ) + + +if __name__ == '__main__': + # load all environment variables from .env file + load_dotenv() + url = os.getenv('ENDPOINT') + token_url = os.getenv('TOKEN_ENDPOINT') + email = os.getenv('USER_EMAIL') + password = os.getenv('PASSWORD') + expires_in = int(os.getenv('EXPIRES_IN')) + page_size = int(os.getenv('PAGE_SIZE')) + + + # get a token + token = get_bearer_token( + url=token_url, email=email, password=password, expires_in=expires_in + ) + + # download the metadata + download_meemoo_ai_data( + url=url, token=token, output_dir=OUTPUT_DIR, page_size=page_size + ) \ No newline at end of file diff --git a/assets/ai_scripts/download_meemoo_raw_ai_files.py b/assets/ai_scripts/download_meemoo_raw_ai_files.py new file mode 100644 index 00000000..d624fd1b --- /dev/null +++ b/assets/ai_scripts/download_meemoo_raw_ai_files.py @@ -0,0 +1,81 @@ +import json +import os +from pathlib import Path + +import requests +from dotenv import load_dotenv +from tqdm import tqdm +from utils.auth import get_bearer_token +from utils.constants import OUTPUT_DIR +from utils.hasura import get_presigned_urls_by_task_id +from utils.inout import write_task_data + +RAW_FILE_KEY_FILE_NAME_MAPPER = { + 'presigned_json': 'speechmatics_raw.json', + 'presigned_vtt': 'subtitles.vtt', + 'presigned_srt': 'subtitles.srt', + 'presigned_txt': 'transcription.txt', + 'presigned_processed_json': 'processed.json', + 'presigned_textrazor_json': 'textrazor_raw.json', + 'presigned_audio_classification_json': 'audio_classification.json', +} + + +def download_meemoo_raw_files(url: str, token: str, output_dir: Path): + # folders = ['ner_tasks', 'speech_tasks'] + folders = ['speech_tasks'] + for folder in folders: + pages_folder = output_dir / folder + if not pages_folder.exists(): + raise FileNotFoundError( + 'Run the download_meemoo_ai_data script before this one.' + ) + tasks_folder = pages_folder / 'tasks' + if tasks_folder.exists(): + raise FileExistsError( + ( + f'Remove the tasks folder in the {folder} folder' + ' before running this script.' + ) + ) + tasks_folder.mkdir(parents=True) + files = pages_folder.rglob('*.json') + for file in files: + with file.open('r') as fid: + page_proc = json.load(fid) + + for task_id, task in tqdm( + page_proc.items(), desc=f'Processing {file.name}' + ): + presigned_urls = get_presigned_urls_by_task_id( + url=url, token=token, view=folder, task_id=task_id + ) + + # download all files with a proper file name + files = { + RAW_FILE_KEY_FILE_NAME_MAPPER[k]: requests.get(url).content + for k, url in presigned_urls.items() + if url is not None + } + task_folder = tasks_folder / task_id + task_folder.mkdir(parents=True, exist_ok=True) + write_task_data(folder=task_folder, files=files, task=task) + + +if __name__ == '__main__': + # load all environment variables from .env file + load_dotenv() + url = os.getenv('ENDPOINT') + token_url = os.getenv('TOKEN_ENDPOINT') + email = os.getenv('USER_EMAIL') + password = os.getenv('PASSWORD') + expires_in = int(os.getenv('EXPIRES_IN')) + page_size = int(os.getenv('PAGE_SIZE')) + + # get a token + token = get_bearer_token( + url=token_url, email=email, password=password, expires_in=expires_in + ) + + # download the raw files + download_meemoo_raw_files(url=url, token=token, output_dir=OUTPUT_DIR) \ No newline at end of file diff --git a/docs/integratie/ai-metadata-api.md b/docs/integratie/ai-metadata-api.md new file mode 100644 index 00000000..3ab6ec5e --- /dev/null +++ b/docs/integratie/ai-metadata-api.md @@ -0,0 +1,433 @@ +--- +layout: default +title: AI metadata API +parent: Een integratie ontwikkelen +has_children: false +has_toc: true +nav_order: 8 +last_modified_date: 2026-04-21 +--- + +
+ + Inhoudstafel + + {: .text-delta } +1. TOC +{:toc} +
+ +# AI metadata API + +Status: `v1.0.0` +Laatst bijgewerkt: `16/2/26` + +## Inleiding + +De AI metadata API ontsluit alle door meemoo gegenereerde AI-metadata voor +contentpartners. Die metadata wordt opgebouwd tijdens de verwerking van +video- en audiofragmenten door verschillende AI-services. + +De API maakt onder meer volgende gegevens beschikbaar: + +- taakresultaten van AI-verwerkingen op fragmenten +- matches tussen gedetecteerde personen en de referentieset +- metadata van personen in de referentieset +- transcripties en speech-to-textresultaten +- output van Named Entity Recognition (NER) + +De API is bedoeld voor ontwikkelaars die AI-resultaten willen integreren in hun +eigen systemen. + +## API architectuur + +Deze API gebruikt GraphQL. Je stuurt dus een query naar één endpoint en bepaalt +zelf welke velden je terugkrijgt. + +De API is opgebouwd rond verschillende query views. Elke view ontsluit een +specifiek type AI-metadata: + +- `face_(image_)tasks` +- `face_(image_)matches` +- `refset_persons` +- `speech_tasks` +- `ner_tasks` + +## Athenticatie + +De API gebruikt Bearer-tokenauthenticatie. + +Vraag eerst een access token aan via `https://oas.hetarchief.be/token`: + +```bash +curl -X POST "https://oas.hetarchief.be/token" \ + -u ":" \ + -d "grant_type=client_credentials" \ + -d "expires_in=3600" +``` + +Voorbeeldresponse: + +```json +{ + "access_token": "", + "expires_in": 3600, + "token_type": "bearer" +} +``` + +Gebruik het ontvangen token daarna in de `Authorization` header: + +```http +Authorization: Bearer +``` + +## Endpoint + +Alle GraphQL-requests worden gestuurd naar: + +```text +https://services.viaa.be/ai-results/v1/graphql +``` + +## Request naar de API + +Een GraphQL-request is een `POST`-request met een JSON-body. De query staat in +het `query`-veld van die body. + +### Voorbeeld request + +```bash +curl -X POST "https://services.viaa.be/ai-results/v1/graphql" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "query": "query GetSpeechTasks($limit: Int!, $offset: Int!, $status: [String!]) { speech_tasks(limit: $limit, offset: $offset, where: { status: { _in: $status } }) { task_id processed_time status cp title } }", + "variables": { + "limit": 10, + "offset": 0, + "status": ["succeeded"] + } + }' +``` + +### Voorbeeld response + +```json +{ + "data": { + "speech_tasks": [ + { + "task_id": "", + "processed_time": "", + "status": "succeeded", + "cp": "OR-xxxxxxxx", + "title": "Voorbeeld fragment" + } + ] + } +} +``` + +Voor meer achtergrond over de opbouw van GraphQL-queries, zie +[Queries | GraphQL](https://graphql.org/learn/queries/). + +## Views + +### `face_(image_)matches` + +Geeft matches terug tussen gedetecteerde personen en personen in de +referentieset. + +#### Velden + +| Veld | Beschrijving | +| --- | --- | +| `cluster_uuid` | Unieke identifier van de cluster waartoe de match behoort. | +| `cp` | Unieke identifier van de contentpartner. | +| `match_score` | Score van de match. | +| `matched_time` | Tijdstip waarop de match gemaakt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | +| `refset_person_id` | Refset-identifier van de gematchte persoon. | +| `refset_person_name` | Naam van de gematchte persoon. | +| `refset_person_wiki_id` | Wikidata-/Q-identifier van de gematchte persoon. | +| `time_intervals` | Lijst van start- en eindtijden, in seconden, waarin de gematchte persoon voorkomt. | + +### `face_(image_)tasks` + +Geeft resultaten terug van gezichts- en persoonsdetectie op fragmenten. + +#### Velden + +| Veld | Beschrijving | +| --- | --- | +| `cluster_uuids` | Lijst van cluster-UUID's. | +| `cp` | Unieke identifier van de contentpartner. | +| `error` | Foutmelding wanneer de taskstatus `failed` is. | +| `external_id` | Externe identifier van het fragment gelinkt aan de task. | +| `main_local_id` | Interne cp-id indien ingevuld op main-fragmentniveau. Niet beschikbaar voor give-cp's, wel voor shared-AI-cp's. | +| `media_object_id` | Mediaobject-id van het fragment gelinkt aan de task. | +| `n_faces` | Totaal aantal gezichten in de task. | +| `n_faces_per_frame` | Aantal gezichten per frame. | +| `n_persons` | Totaal aantal personen in de task. | +| `n_persons_per_frame` | Aantal personen per frame. | +| `n_scenes` | Totaal aantal scènes in de task. | +| `perc_frames_met_faces` | Percentage frames waarin een gezicht voorkomt. | +| `pid` | PID van het fragment gelinkt aan de task. | +| `processed_time` | Tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | +| `status` | Verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed`. | +| `task_id` | Unieke identifier van de task. | +| `title` | Titel van het fragment. | + +#### Voorbeeld query + +```graphql +query GetFaceTasks($limit: Int!, $offset: Int!, $status: [String!]) { + face_tasks( + limit: $limit + offset: $offset + where: { status: { _in: $status } } + ) { + task_id + pid + title + n_faces + n_persons + n_scenes + processed_time + status + } +} +``` + +### `ner_tasks` + +Geeft NER-resultaten en gerelateerde ruwe output terug. + +#### Velden + +| Veld | Beschrijving | +| --- | --- | +| `cp` | Unieke identifier van de contentpartner. | +| `error` | Foutmelding wanneer de taskstatus `failed` is. | +| `fragment_id` | Unieke identifier van het fragment gelinkt aan de task. | +| `pid` | PID van het fragment gelinkt aan de task. | +| `processed_json` | Ruwe output van de task in JSON-vorm. | +| `processed_time` | Tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | +| `status` | Verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed`. | +| `task_id` | Unieke identifier van de task. | +| `textrazor_json` | Ruwe output van TextRazor. | + +#### Voorbeeld query + +```graphql +query GetNerTasks($limit: Int!, $offset: Int!, $status: [String!]) { + ner_tasks( + limit: $limit + offset: $offset + where: { status: { _in: $status } } + ) { + task_id + pid + cp + status + processed_time + processed_json + textrazor_json + } +} +``` + +### `speech_tasks` + +Geeft speech-to-textresultaten, transcripties en aanverwante metadata terug. + +#### Velden + +| Veld | Beschrijving | +| --- | --- | +| `cp` | Unieke identifier van de contentpartner. | +| `error` | Foutmelding wanneer de taskstatus `failed` is. | +| `external_id` | Externe identifier van het fragment gelinkt aan de task. | +| `fragment_id` | Unieke identifier van het fragment gelinkt aan de task. | +| `main_local_id` | Interne cp-id indien ingevuld op main-fragmentniveau. Niet beschikbaar voor give-cp's, wel voor shared-AI-cp's. | +| `media_object_id` | Mediaobject-id van het fragment gelinkt aan de task. | +| `pid` | PID van het fragment gelinkt aan de task. | +| `processed_time` | Tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | +| `statistics` | Reeks Speechmatics-statistieken. | +| `status` | Verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed`. | +| `task_id` | Unieke identifier van de task. | +| `title` | Titel van het fragment. | +| `transcript_json` | Transcriptie in JSON-formaat. | +| `transcript_srt` | Transcriptie in SRT-formaat. | +| `transcript_txt` | Transcriptie als platte tekst. | +| `transcript_vtt` | Transcriptie in VTT-formaat. | +| `audio_classification_json` | Resultaten van de audioclassificatiepipeline. | + +#### Voorbeeld query + +```graphql +query GetSpeechTasks($limit: Int!, $offset: Int!, $status: [String!]) { + speech_tasks( + limit: $limit + offset: $offset + where: { status: { _in: $status } } + ) { + task_id + processed_time + status + cp + title + transcript_txt + } +} +``` + +#### Voorbeeld query met transcript formats + +```graphql +query GetSpeechTaskTranscripts($limit: Int!, $offset: Int!) { + speech_tasks(limit: $limit, offset: $offset) { + task_id + pid + title + transcript_txt + transcript_srt + transcript_vtt + transcript_json + } +} +``` + +### `refset_persons` + +Geeft metadata terug over personen in de referentieset. + +#### Velden + +| Veld | Beschrijving | +| --- | --- | +| `created_at` | Tijdstip waarop de refset-entry is aangemaakt, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | +| `description` | Omschrijving van de refset-entry. | +| `id` | Unieke identifier van de refset-entry. | +| `label` | Label van de refset-entry, bijvoorbeeld een naam. | +| `modified_at` | Tijdstip waarop de refset-entry het laatst aangepast is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | +| `public_links` | Lijst van publieke links van de refset-entry. | +| `status` | Status van de refset-entry. | + +#### Voorbeeld query + +```graphql +query GetRefsetPersons { + refset_persons { + id + label + description + public_links + status + } +} +``` + +#### Voorbeeld query met timestamps + +```graphql +query GetRefsetPersonsmetTimestamps { + refset_persons { + id + label + created_at + modified_at + status + public_links + } +} +``` + +## Notes + +- Timestamps worden weergegeven in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) waar van toepassing. +- De precieze velden die je opvraagt, bepaal je zelf in je GraphQL-query. +- Ruwe outputvelden zoals `processed_json`, `textrazor_json`, + `transcript_json` en `audio_classification_json` zijn bedoeld voor + integraties die de volledige service-output willen verwerken. + +## Voorbeeldimplementaties +## Over Hasura +Hasura is een open-source engine die automatisch een GraphQL APO genereert bovenop een relationele database, zoals PostgreSQL. +Hierdoor kan je queries uitvoeren zonder zelf complexe backend code te schrijven. + +## Over de repository +Er worden twee voorbeeldscript ter beschikking gesteld om alle data gelinkt aan een contentpartner te downloaden via Hasura en GraphQL queries. + +## Vooraf te doen +- Zorg dat python beschikbaar is op je systeem: + - [Python installatie](https://www.python.org/downloads/) + +- Kopieer het [`.env-template`]({{ site.baseurl }}/assets/ai_scripts/.env-template) en hernoem het naar `.env` +- In het nieuwe `.env` bestand: + - Vul de USER_EMAIL en PASSWORD velden in van een account gelinkt aan jouw organisatie + +- Voer de volgende commando's uit in een terminal om de virtuele omgeving te activeren zodat de scripts kunnen gerund worden: + +Linux: +``` +python3.11 -m venv .venv +source .venv/bin/activate +python -m pip install -U pip wheel +python -m pip install -r requirements.txt +``` + +Windows: +``` +py -3.11 -m venv .venv +.venv\Scripts\activate +python -m pip install -U pip wheel +python -m pip install -r requirements.txt +``` + +## De voorbeeldscripts uitvoeren + +### Metadata downloaden +Gebruik [`download_meemoo_ai_data.py`]({{ site.baseurl }}/assets/ai_scripts/download_meemoo_ai_data.py) om alle beschikbare metadata voor je organisatie op te halen en lokaal als JSON op te slaan. + +Het script maakt in `output/` een submap per view aan: + +- `face_tasks` +- `face_image_tasks` +- `face_matches` +- `face_image_matches` +- `refset_persons` +- `speech_tasks` +- `ner_tasks` + +In elke submap wordt de data paginagewijs opgeslagen. Elk JSON-bestand bevat dus een pagina met resultaten. + +Het script verwacht dat de uitvoermap nog niet bestaat. Wil je de export opnieuw uitvoeren, verwijder dan eerst de map `output/`. + +``` +# vergeet niet eerst je virtuele omgeving te activeren +python download_meemoo_ai_data.py +``` + +### Ruwe AI output downloaden +Gebruik daarna [`download_meemoo_raw_ai_files.py`]({{ site.baseurl }}/assets/ai_scripts/download_meemoo_raw_ai_files.py) om per taak de ruwe bestanden op te halen. + +Voer dit script pas uit nadat `download_meemoo_ai_data.py` succesvol heeft gedraaid. Het script gebruikt namelijk de eerder geëxporteerde metadata in `output/` om te bepalen welke taken moeten worden opgehaald. + +In de huidige versie van het script worden ruwe bestanden voor `speech_tasks` gedownload naar `output/speech_tasks/tasks//`. Per taak kunnen daar onder meer volgende bestanden in terechtkomen: + +- `metadata.json`: metadata van de taak +- `speechmatics_raw.json`: ruwe JSON-respons van Speechmatics +- `subtitles.srt`: transcriptie in SRT-formaat +- `subtitles.vtt`: transcriptie in VTT-formaat +- `transcription.txt`: platte tekstversie van de transcriptie +- `audio_classification.json`: output van de audio-classificatie + +De map `output/speech_tasks/tasks/` mag nog niet bestaan wanneer je het script start. Wil je de ruwe bestanden opnieuw downloaden, verwijder die map dan eerst. + +Afhankelijk van het aantal taken kan dit script enige tijd duren. Tijdens het uitvoeren toont het script een voortgangsbalk. + +``` +# vergeet niet eerst je virtuele omgeving te activeren +python download_meemoo_raw_ai_files.py +``` From 22c12a4871c164dbefcd1f3f3df984e262d1e6c4 Mon Sep 17 00:00:00 2001 From: lennertvandevelde Date: Tue, 21 Apr 2026 11:24:55 +0200 Subject: [PATCH 2/3] Voeg zip file toe --- assets/ai_scripts/.env-template | 12 --- assets/ai_scripts/download_meemoo_ai_data.py | 87 ------------------ .../download_meemoo_raw_ai_files.py | 81 ---------------- assets/ai_scripts/graphql-query-examples.zip | Bin 0 -> 9923 bytes docs/integratie/ai-metadata-api.md | 14 +-- 5 files changed, 5 insertions(+), 189 deletions(-) delete mode 100644 assets/ai_scripts/.env-template delete mode 100644 assets/ai_scripts/download_meemoo_ai_data.py delete mode 100644 assets/ai_scripts/download_meemoo_raw_ai_files.py create mode 100644 assets/ai_scripts/graphql-query-examples.zip diff --git a/assets/ai_scripts/.env-template b/assets/ai_scripts/.env-template deleted file mode 100644 index c8794be8..00000000 --- a/assets/ai_scripts/.env-template +++ /dev/null @@ -1,12 +0,0 @@ -# hasura endpoint url -ENDPOINT=https://services.viaa.be/ai-results/v1/graphql -# bearer token url -TOKEN_ENDPOINT=https://oas.hetarchief.be/token -# token expiration in seconds -EXPIRES_IN=86400 -# number of tasks in one page for a hasura query -PAGE_SIZE=1000 - -# FILL IN THESE VALUES IN THE COPIED .env FILE -USER_EMAIL= -PASSWORD= \ No newline at end of file diff --git a/assets/ai_scripts/download_meemoo_ai_data.py b/assets/ai_scripts/download_meemoo_ai_data.py deleted file mode 100644 index 613770d8..00000000 --- a/assets/ai_scripts/download_meemoo_ai_data.py +++ /dev/null @@ -1,87 +0,0 @@ -import os -from pathlib import Path - -from dotenv import load_dotenv -from utils.auth import get_bearer_token -from utils.constants import OUTPUT_DIR -from utils.hasura import yield_results_pages -from utils.inout import write_page_data -from utils.queries import ( - FACE_IMAGE_MATCHES_QUERY, - FACE_IMAGE_TASKS_QUERY, - FACE_MATCHES_QUERY, - FACE_TASKS_QUERY, - NER_TASKS_QUERY, - REFSET_PERSONS_QUERY, - SPEECH_TASKS_QUERY, -) - -VIEW_TO_ID_TYPE_MAPPER = { - 'face_matches': 'cluster_uuid', - 'face_image_matches': 'cluster_uuid', - 'face_tasks': 'task_id', - 'face_image_tasks': 'task_id', - 'ner_tasks': 'task_id', - 'refset_persons': 'id', - 'speech_tasks': 'task_id', -} -VIEW_TO_QUERY_MAPPER = { - 'face_matches': FACE_MATCHES_QUERY, - 'face_image_matches': FACE_IMAGE_MATCHES_QUERY, - 'face_tasks': FACE_TASKS_QUERY, - 'face_image_tasks': FACE_IMAGE_TASKS_QUERY, - 'ner_tasks': NER_TASKS_QUERY, - 'refset_persons': REFSET_PERSONS_QUERY, - 'speech_tasks': SPEECH_TASKS_QUERY, -} - - -def download_meemoo_ai_data(url: str, token: str, output_dir: Path, page_size: int): - for view, query in VIEW_TO_QUERY_MAPPER.items(): - variables = {'limit': page_size, 'offset': 0} - - pages_folder = output_dir / view - if pages_folder.exists(): - raise FileExistsError( - 'Remove the outputs folder before running this script.' - ) - pages_folder.mkdir(parents=True) - - for page, offset in yield_results_pages( - url=url, - token=token, - view=view, - query=query, - variables=variables, - page_size=page_size, - ): - id_type = VIEW_TO_ID_TYPE_MAPPER[view] - write_page_data( - id_type=id_type, - folder=pages_folder, - page=page, - offset=offset, - page_size=page_size, - ) - - -if __name__ == '__main__': - # load all environment variables from .env file - load_dotenv() - url = os.getenv('ENDPOINT') - token_url = os.getenv('TOKEN_ENDPOINT') - email = os.getenv('USER_EMAIL') - password = os.getenv('PASSWORD') - expires_in = int(os.getenv('EXPIRES_IN')) - page_size = int(os.getenv('PAGE_SIZE')) - - - # get a token - token = get_bearer_token( - url=token_url, email=email, password=password, expires_in=expires_in - ) - - # download the metadata - download_meemoo_ai_data( - url=url, token=token, output_dir=OUTPUT_DIR, page_size=page_size - ) \ No newline at end of file diff --git a/assets/ai_scripts/download_meemoo_raw_ai_files.py b/assets/ai_scripts/download_meemoo_raw_ai_files.py deleted file mode 100644 index d624fd1b..00000000 --- a/assets/ai_scripts/download_meemoo_raw_ai_files.py +++ /dev/null @@ -1,81 +0,0 @@ -import json -import os -from pathlib import Path - -import requests -from dotenv import load_dotenv -from tqdm import tqdm -from utils.auth import get_bearer_token -from utils.constants import OUTPUT_DIR -from utils.hasura import get_presigned_urls_by_task_id -from utils.inout import write_task_data - -RAW_FILE_KEY_FILE_NAME_MAPPER = { - 'presigned_json': 'speechmatics_raw.json', - 'presigned_vtt': 'subtitles.vtt', - 'presigned_srt': 'subtitles.srt', - 'presigned_txt': 'transcription.txt', - 'presigned_processed_json': 'processed.json', - 'presigned_textrazor_json': 'textrazor_raw.json', - 'presigned_audio_classification_json': 'audio_classification.json', -} - - -def download_meemoo_raw_files(url: str, token: str, output_dir: Path): - # folders = ['ner_tasks', 'speech_tasks'] - folders = ['speech_tasks'] - for folder in folders: - pages_folder = output_dir / folder - if not pages_folder.exists(): - raise FileNotFoundError( - 'Run the download_meemoo_ai_data script before this one.' - ) - tasks_folder = pages_folder / 'tasks' - if tasks_folder.exists(): - raise FileExistsError( - ( - f'Remove the tasks folder in the {folder} folder' - ' before running this script.' - ) - ) - tasks_folder.mkdir(parents=True) - files = pages_folder.rglob('*.json') - for file in files: - with file.open('r') as fid: - page_proc = json.load(fid) - - for task_id, task in tqdm( - page_proc.items(), desc=f'Processing {file.name}' - ): - presigned_urls = get_presigned_urls_by_task_id( - url=url, token=token, view=folder, task_id=task_id - ) - - # download all files with a proper file name - files = { - RAW_FILE_KEY_FILE_NAME_MAPPER[k]: requests.get(url).content - for k, url in presigned_urls.items() - if url is not None - } - task_folder = tasks_folder / task_id - task_folder.mkdir(parents=True, exist_ok=True) - write_task_data(folder=task_folder, files=files, task=task) - - -if __name__ == '__main__': - # load all environment variables from .env file - load_dotenv() - url = os.getenv('ENDPOINT') - token_url = os.getenv('TOKEN_ENDPOINT') - email = os.getenv('USER_EMAIL') - password = os.getenv('PASSWORD') - expires_in = int(os.getenv('EXPIRES_IN')) - page_size = int(os.getenv('PAGE_SIZE')) - - # get a token - token = get_bearer_token( - url=token_url, email=email, password=password, expires_in=expires_in - ) - - # download the raw files - download_meemoo_raw_files(url=url, token=token, output_dir=OUTPUT_DIR) \ No newline at end of file diff --git a/assets/ai_scripts/graphql-query-examples.zip b/assets/ai_scripts/graphql-query-examples.zip new file mode 100644 index 0000000000000000000000000000000000000000..bfbdb4007e981aad1e51fc0b665048ec843882e0 GIT binary patch literal 9923 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 literal 0 HcmV?d00001 diff --git a/docs/integratie/ai-metadata-api.md b/docs/integratie/ai-metadata-api.md index 3ab6ec5e..a8ed1e30 100644 --- a/docs/integratie/ai-metadata-api.md +++ b/docs/integratie/ai-metadata-api.md @@ -352,18 +352,14 @@ query GetRefsetPersonsmetTimestamps { integraties die de volledige service-output willen verwerken. ## Voorbeeldimplementaties -## Over Hasura -Hasura is een open-source engine die automatisch een GraphQL APO genereert bovenop een relationele database, zoals PostgreSQL. -Hierdoor kan je queries uitvoeren zonder zelf complexe backend code te schrijven. - -## Over de repository -Er worden twee voorbeeldscript ter beschikking gesteld om alle data gelinkt aan een contentpartner te downloaden via Hasura en GraphQL queries. +Er worden twee voorbeeldscript ter beschikking gesteld om alle data gelinkt aan een contentpartner te downloaden via GraphQL queries. ## Vooraf te doen - Zorg dat python beschikbaar is op je systeem: - [Python installatie](https://www.python.org/downloads/) +- Download het zip-bestand met de scripts [`.env-template`]({{ site.baseurl }}/assets/ai_scripts/graphql-query-examples) -- Kopieer het [`.env-template`]({{ site.baseurl }}/assets/ai_scripts/.env-template) en hernoem het naar `.env` +- Kopieer het `.env-template` en hernoem het naar `.env` - In het nieuwe `.env` bestand: - Vul de USER_EMAIL en PASSWORD velden in van een account gelinkt aan jouw organisatie @@ -388,7 +384,7 @@ python -m pip install -r requirements.txt ## De voorbeeldscripts uitvoeren ### Metadata downloaden -Gebruik [`download_meemoo_ai_data.py`]({{ site.baseurl }}/assets/ai_scripts/download_meemoo_ai_data.py) om alle beschikbare metadata voor je organisatie op te halen en lokaal als JSON op te slaan. +Gebruik `download_meemoo_ai_data.py` om alle beschikbare metadata voor je organisatie op te halen en lokaal als JSON op te slaan. Het script maakt in `output/` een submap per view aan: @@ -410,7 +406,7 @@ python download_meemoo_ai_data.py ``` ### Ruwe AI output downloaden -Gebruik daarna [`download_meemoo_raw_ai_files.py`]({{ site.baseurl }}/assets/ai_scripts/download_meemoo_raw_ai_files.py) om per taak de ruwe bestanden op te halen. +Gebruik daarna `download_meemoo_raw_ai_files.py` om per taak de ruwe bestanden op te halen. Voer dit script pas uit nadat `download_meemoo_ai_data.py` succesvol heeft gedraaid. Het script gebruikt namelijk de eerder geëxporteerde metadata in `output/` om te bepalen welke taken moeten worden opgehaald. From b0f439346e9784d6432d12474f7c4098b95554f2 Mon Sep 17 00:00:00 2001 From: igloosarecool Date: Thu, 28 May 2026 16:30:22 +0200 Subject: [PATCH 3/3] Rewrite ai metadata api docs and remove coupled assets --- .gitignore | 1 + assets/ai_scripts/graphql-query-examples.zip | Bin 9923 -> 0 bytes docs/integratie/ai-metadata-api.md | 520 +++++++++---------- 3 files changed, 242 insertions(+), 279 deletions(-) delete mode 100644 assets/ai_scripts/graphql-query-examples.zip diff --git a/.gitignore b/.gitignore index 5af7728c..5d55bd25 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ vendor .DS_Store .vscode/settings.json **.DS_Store +.fetch diff --git a/assets/ai_scripts/graphql-query-examples.zip b/assets/ai_scripts/graphql-query-examples.zip deleted file mode 100644 index bfbdb4007e981aad1e51fc0b665048ec843882e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9923 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 diff --git a/docs/integratie/ai-metadata-api.md b/docs/integratie/ai-metadata-api.md index a8ed1e30..ab0abf3c 100644 --- a/docs/integratie/ai-metadata-api.md +++ b/docs/integratie/ai-metadata-api.md @@ -17,18 +17,21 @@ last_modified_date: 2026-04-21 {:toc} -# AI metadata API +## AI metadata API -Status: `v1.0.0` -Laatst bijgewerkt: `16/2/26` +Status: `v1.1.0` +Laatst bijgewerkt: `28/05/26` -## Inleiding +## 1. Inleiding -De AI metadata API ontsluit alle door meemoo gegenereerde AI-metadata voor -contentpartners. Die metadata wordt opgebouwd tijdens de verwerking van -video- en audiofragmenten door verschillende AI-services. +Met verschillende AI-technieken zoals spraak- en gezichtsherkenning, wordt door +meemoo voor geselecteerd audiovisueel materiaal specifieke, verrijkende metadata +gegenereerd. Het genereren gebeurt in zogeheten pipelines. Het uitvoeren van een +pipeline op een enkel object is een taak (of *task*), bijvoorbeeld: de +transcriptie aanmaken van een audiobestand. -De API maakt onder meer volgende gegevens beschikbaar: +De AI metadata API maakt de gegenereerde metadata +beschikbaar voor contentpartners, onder meer: - taakresultaten van AI-verwerkingen op fragmenten - matches tussen gedetecteerde personen en de referentieset @@ -36,37 +39,29 @@ De API maakt onder meer volgende gegevens beschikbaar: - transcripties en speech-to-textresultaten - output van Named Entity Recognition (NER) -De API is bedoeld voor ontwikkelaars die AI-resultaten willen integreren in hun -eigen systemen. +De API is bedoeld voor (externe) ontwikkelaars van contentpartners die de +AI-gegenereerde metadata in hun systemen willen integreren. -## API architectuur +## 2. Authenticatie & Autorisatie -Deze API gebruikt GraphQL. Je stuurt dus een query naar één endpoint en bepaalt -zelf welke velden je terugkrijgt. +De API is alleen toegankelijk voor geautoriseerde gebruikers. Autorisatie +verloopt via een OAuth2.0 flow met Bearer Token, aan te vragen via de volgende +URL: . -De API is opgebouwd rond verschillende query views. Elke view ontsluit een -specifiek type AI-metadata: +De authenticatieflow gebruikt `client_credentials` als +`grant_type` met het e-mailadres en het wachtwoord van je meemoo-account als credentials +([Client Credentials - OAuth 2.0 Simplified](https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/)). -- `face_(image_)tasks` -- `face_(image_)matches` -- `refset_persons` -- `speech_tasks` -- `ner_tasks` - -## Athenticatie - -De API gebruikt Bearer-tokenauthenticatie. - -Vraag eerst een access token aan via `https://oas.hetarchief.be/token`: +### REQUEST -```bash +```shell curl -X POST "https://oas.hetarchief.be/token" \ - -u ":" \ - -d "grant_type=client_credentials" \ - -d "expires_in=3600" +–u ":" \ +-d "grant_type=client_credentials" \ +-d "expires_in=3600 ``` -Voorbeeldresponse: +### RESPONSE ```json { @@ -76,315 +71,272 @@ Voorbeeldresponse: } ``` -Gebruik het ontvangen token daarna in de `Authorization` header: +## 3. API architectuur -```http -Authorization: Bearer -``` +Deze API is een GraphQL endpoint waarnaar je een query stuurt +waarin je zelf bepaalt voor welke velden je data wil krijgen. -## Endpoint +De API biedt een *view* per metadatatype als resultaat van een +pipeline. Elke view bevat op taakniveau het resultaat van de verwerking +uitgevoerd op een mediafragment of een match met een referentieset. -Alle GraphQL-requests worden gestuurd naar: +De beschikbare views en de metadatabeschrijving zijn: -```text -https://services.viaa.be/ai-results/v1/graphql -``` +- `face_tasks:` detectie van gezichten/personen op videofragmenten +- `image_tasks:` detectie van gezichten/personen op foto +- `face_matches:` matches tussen gedetecteerde personen en de referentieset voor video +- `image_matches:` matches tussen gedetecteerde personen en de referentieset voor foto +- `refset_persons`: metadata van personen in de referentieset +- `speech_tasks`: speech-to-text metadata en transcripties +- `ner_tasks`: NER en textrazor metadata -## Request naar de API +## 4. Endpoints -Een GraphQL-request is een `POST`-request met een JSON-body. De query staat in -het `query`-veld van die body. +De API wordt aangeboden via: +. De endpoint is beveiligd en +kan alleen bevraagd worden door een Bearer token mee te geven (zie boven: 2. +Authenticatie & Autorisatie). Met typische GraphQL queries kan flexibel alle of +een deel van de (meta)data van een of meer taken uit een pipeline opgevraagd +worden. -### Voorbeeld request +Het is mogelijk het aantal resultaten van de query te beperken met een `limit` +en door een `offset` mee te geven om bijvoorbeeld de resultaten te pagineren. +Je kan de resultaten ook filteren door een `where` clause mee te geven in de +query. De velden waarop gefiltered kan worden kunnen met een standaard +introspect query opgevraagd worden of worden ingevuld door een query builder te +gebruiken. -```bash -curl -X POST "https://services.viaa.be/ai-results/v1/graphql" \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - -d '{ - "query": "query GetSpeechTasks($limit: Int!, $offset: Int!, $status: [String!]) { speech_tasks(limit: $limit, offset: $offset, where: { status: { _in: $status } }) { task_id processed_time status cp title } }", - "variables": { - "limit": 10, - "offset": 0, - "status": ["succeeded"] +Bijvoorbeeld voor face_tasks: + +- cluster_uuid +- cp +- match_score +- matched_time +- refset_person_id +- refset_person_name +- refset_person_wiki_id +- time_intervals + +Voor meer informatie over GraphQL queries, zie [Queries | GraphQL](https://graphql.org/learn/queries/). + +Het onderstaande voorbeeld van een typische query vraagt de `face_tasks` view op +via het GraphQL endpoint, waarbij `<...>` de in de response gewenste datavelden +van de view zijn. Zie verder bij hoofdstuk '5. Data views' voor een volledig +overzicht van de beschikbare velden per view. + +## GRAPHQL QUERY + +```graphql +query GetFaceTasks($limit: Int!, $offset: Int!, $status: [String!]) { + face_tasks( + limit: $limit + offset: $offset + where: { status: { _in: $status } } + ) { + <...> + } +} +``` + +## cURL REQUEST + +```shell +echo '{ + "query": "query GetFaceTasks($limit: Int!, $offset: Int!, $status: [String!]) { + face_tasks( + limit: $limit + offset: $offset + where: { + status: { + _in: $status + } + } + ) + { + task_id + processed_time + status + cp + title } - }' + }", + "variables": { + "limit": 1, + "offset": 1, + "status": "succeeded" + } +}' | tr -d '\n' | curl --silent \ + -X POST "https://services.viaa.be/ai-results/v1/graphql" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d @- ``` -### Voorbeeld response +## RESPONSE ```json { "data": { - "speech_tasks": [ + "face_tasks": [ { "task_id": "", "processed_time": "", "status": "succeeded", "cp": "OR-xxxxxxxx", - "title": "Voorbeeld fragment" + "title": "Example fragment" } ] } } ``` -Voor meer achtergrond over de opbouw van GraphQL-queries, zie -[Queries | GraphQL](https://graphql.org/learn/queries/). +## 5. Data views -## Views +- Timestamps worden weergegeven in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) waar van toepassing. +- De precieze velden die je opvraagt, bepaal je zelf in je GraphQL-query. +- Ruwe outputvelden zoals `processed_json`, `textrazor_json`, + `transcript_json` en `audio_classification_json` zijn bedoeld voor + integraties die de volledige service-output willen verwerken. -### `face_(image_)matches` +### 5.1 face_matches | image_matches Geeft matches terug tussen gedetecteerde personen en personen in de referentieset. #### Velden -| Veld | Beschrijving | -| --- | --- | -| `cluster_uuid` | Unieke identifier van de cluster waartoe de match behoort. | -| `cp` | Unieke identifier van de contentpartner. | -| `match_score` | Score van de match. | -| `matched_time` | Tijdstip waarop de match gemaakt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | -| `refset_person_id` | Refset-identifier van de gematchte persoon. | -| `refset_person_name` | Naam van de gematchte persoon. | -| `refset_person_wiki_id` | Wikidata-/Q-identifier van de gematchte persoon. | -| `time_intervals` | Lijst van start- en eindtijden, in seconden, waarin de gematchte persoon voorkomt. | +| **Veld** | **Beschrijving** | +| :---------------------- | :----------------------------------------------------------- | +| `cluster_uuid` | een unieke identifier voor de cluster waartoe de match behoort | +| `cp` | de unieke identifier van de content partner | +| `match_score` | de score van de match | +| `matched_time` | het moment waarop de match gemaakt is in in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601)| +| `refset_person_id` | de refset identifier van de gematchte persoon | +| `refset_person_name` | de naam van de gematchte persoon | +| `refset_person_wiki_id` | de wiki/Q-identifier van de gematchte persoon | +| `time_intervals` | een lijst van start- en eindtijden (in seconden) waarin de gematchte persoon voorkomt | -### `face_(image_)tasks` +### 5.2 face_tasks | image_tasks Geeft resultaten terug van gezichts- en persoonsdetectie op fragmenten. -#### Velden - -| Veld | Beschrijving | -| --- | --- | -| `cluster_uuids` | Lijst van cluster-UUID's. | -| `cp` | Unieke identifier van de contentpartner. | -| `error` | Foutmelding wanneer de taskstatus `failed` is. | -| `external_id` | Externe identifier van het fragment gelinkt aan de task. | -| `main_local_id` | Interne cp-id indien ingevuld op main-fragmentniveau. Niet beschikbaar voor give-cp's, wel voor shared-AI-cp's. | -| `media_object_id` | Mediaobject-id van het fragment gelinkt aan de task. | -| `n_faces` | Totaal aantal gezichten in de task. | -| `n_faces_per_frame` | Aantal gezichten per frame. | -| `n_persons` | Totaal aantal personen in de task. | -| `n_persons_per_frame` | Aantal personen per frame. | -| `n_scenes` | Totaal aantal scènes in de task. | -| `perc_frames_met_faces` | Percentage frames waarin een gezicht voorkomt. | -| `pid` | PID van het fragment gelinkt aan de task. | -| `processed_time` | Tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | -| `status` | Verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed`. | -| `task_id` | Unieke identifier van de task. | -| `title` | Titel van het fragment. | - -#### Voorbeeld query - -```graphql -query GetFaceTasks($limit: Int!, $offset: Int!, $status: [String!]) { - face_tasks( - limit: $limit - offset: $offset - where: { status: { _in: $status } } - ) { - task_id - pid - title - n_faces - n_persons - n_scenes - processed_time - status - } -} -``` - -### `ner_tasks` +| **Veld** | **Beschrijving** | +| :----------------------- | :----------------------------------------------------------- | +| `cluster_uuids` | een lijst van cluster uuids | +| `cp` | de unieke identifier van de content partner | +| `error` | de foutmelding indien de task status `failed` is | +| `external_id` | de externe identifier van het fragment gelinkt aan de task | +| `main_local_id` | de interne cp-id, indien ingevuld op main-fragmentniveau en alleen voor shared-AI CP's (niet GiVE) | +| `media_object_id` | het mediaobject-id van het fragment gelinkt aan de task | +| `n_faces` | het totaal aantal gezichten in de task | +| `n_faces_per_frame` | het aantal gezichten per frame | +| `n_persons` | het totaal aantal personen in de task | +| `n_persons_per_frame` | het aantal personen per frame | +| `n_scenes` | het totaal aantal scènes in de task | +| `perc_frames_with_faces` | het precentage aan frames met een gezicht | +| `pid` | de pid van het fragment gelinkt aan de task | +| `processed_time` | het tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) | +| `status` | de verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed` | +| `task_id` | een unieke identifier voor de task | +| `title` | de titel van het fragment | + +### 5.3 ner_tasks Geeft NER-resultaten en gerelateerde ruwe output terug. -#### Velden - -| Veld | Beschrijving | -| --- | --- | -| `cp` | Unieke identifier van de contentpartner. | -| `error` | Foutmelding wanneer de taskstatus `failed` is. | -| `fragment_id` | Unieke identifier van het fragment gelinkt aan de task. | -| `pid` | PID van het fragment gelinkt aan de task. | -| `processed_json` | Ruwe output van de task in JSON-vorm. | -| `processed_time` | Tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | -| `status` | Verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed`. | -| `task_id` | Unieke identifier van de task. | -| `textrazor_json` | Ruwe output van TextRazor. | +| **Veld** | **Beschrijving** | +| :--------------- | :----------------------------------------------------- | +| `cp` | de unieke identifier van de content partner | +| `fragment_id` | de unieke identifier van het fragment gelinkt aan de task | +| `error` | de foutmelding indien de task status `failed` is | +| `pid` | de pid van het fragment gelinkt aan de task | +| `processed_json` | de onbewerkte output van de task in JSON-formaat | +| `processed_time` | het tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) | +| `status` | de verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed` | +| `task_id` | een unieke identifier voor de task | +| `textrazor_json` | de onbewerkte output van textrazor | -#### Voorbeeld query - -```graphql -query GetNerTasks($limit: Int!, $offset: Int!, $status: [String!]) { - ner_tasks( - limit: $limit - offset: $offset - where: { status: { _in: $status } } - ) { - task_id - pid - cp - status - processed_time - processed_json - textrazor_json - } -} -``` - -### `speech_tasks` +### 5.4 speech_tasks Geeft speech-to-textresultaten, transcripties en aanverwante metadata terug. -#### Velden - -| Veld | Beschrijving | -| --- | --- | -| `cp` | Unieke identifier van de contentpartner. | -| `error` | Foutmelding wanneer de taskstatus `failed` is. | -| `external_id` | Externe identifier van het fragment gelinkt aan de task. | -| `fragment_id` | Unieke identifier van het fragment gelinkt aan de task. | -| `main_local_id` | Interne cp-id indien ingevuld op main-fragmentniveau. Niet beschikbaar voor give-cp's, wel voor shared-AI-cp's. | -| `media_object_id` | Mediaobject-id van het fragment gelinkt aan de task. | -| `pid` | PID van het fragment gelinkt aan de task. | -| `processed_time` | Tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | -| `statistics` | Reeks Speechmatics-statistieken. | -| `status` | Verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed`. | -| `task_id` | Unieke identifier van de task. | -| `title` | Titel van het fragment. | -| `transcript_json` | Transcriptie in JSON-formaat. | -| `transcript_srt` | Transcriptie in SRT-formaat. | -| `transcript_txt` | Transcriptie als platte tekst. | -| `transcript_vtt` | Transcriptie in VTT-formaat. | -| `audio_classification_json` | Resultaten van de audioclassificatiepipeline. | - -#### Voorbeeld query - -```graphql -query GetSpeechTasks($limit: Int!, $offset: Int!, $status: [String!]) { - speech_tasks( - limit: $limit - offset: $offset - where: { status: { _in: $status } } - ) { - task_id - processed_time - status - cp - title - transcript_txt - } -} -``` - -#### Voorbeeld query met transcript formats - -```graphql -query GetSpeechTaskTranscripts($limit: Int!, $offset: Int!) { - speech_tasks(limit: $limit, offset: $offset) { - task_id - pid - title - transcript_txt - transcript_srt - transcript_vtt - transcript_json - } -} -``` - -### `refset_persons` +| **Veld** | **Beschrijving** | +| :-------------------------- | :----------------------------------------------------------- | +| `cp` | de unieke identifier van de content partner | +| `error` | de foutmelding indien de task status `failed` is | +| `external_id` | de externe identifier van het fragment gelinkt aan de task | +| `main_local_id` | de interne cp-id, indien ingevuld op main-fragmentniveau en alleen voor shared-AI CP's (niet GiVE) | +| `fragment_id` | de unieke identifier van het fragment gelinkt aan de task | +| `media_object_id` | het mediaobject-id van het fragment gelinkt aan de task | +| `pid` | de pid van het fragment gelinkt aan de task | +| `processed_time` | het tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) | +| `statistics` | een reeks van speechmatics stastieken | +| `status` | de verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed` | +| `task_id` | een unieke identifier voor de task | +| `title` | de titel van het fragment | +| `transcript_json` | de onbewerkte output van textrazor in JSON-formaat | +| `transcript_srt` | de transcriptie als .srt ondertitels | +| `transcript_txt` | de transcriptie als platte tekst | +| `transcript_vtt` | de transcriptie als .vtt ondertitels | +| `audio_classification_json` | de resultaten van de audioclassificatie pipeline | + +### 5.5 refset_persons Geeft metadata terug over personen in de referentieset. -#### Velden - -| Veld | Beschrijving | -| --- | --- | -| `created_at` | Tijdstip waarop de refset-entry is aangemaakt, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | -| `description` | Omschrijving van de refset-entry. | -| `id` | Unieke identifier van de refset-entry. | -| `label` | Label van de refset-entry, bijvoorbeeld een naam. | -| `modified_at` | Tijdstip waarop de refset-entry het laatst aangepast is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601). | -| `public_links` | Lijst van publieke links van de refset-entry. | -| `status` | Status van de refset-entry. | - -#### Voorbeeld query - -```graphql -query GetRefsetPersons { - refset_persons { - id - label - description - public_links - status - } -} -``` - -#### Voorbeeld query met timestamps +| **Veld** | **Beschrijving** | +| :------------- | :----------------------------------------------------------- | +| `created_at` | het tijdstip waarop de refset-entry is aangemaakt, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) | +| `id` | de unieke identifier van de refset-entry | +| `label` | een label van de refset-entry, bijvoorbeeld een naam | +| `description` | een omschrijving van de refset entry | +| `modified_at` | het tijdstip waarop de refset-entry het laatst aangepast is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) | +| `public_links` | een lijst van publieke links van de refset-entry | +| `status` | de status van de refset-entry | -```graphql -query GetRefsetPersonsmetTimestamps { - refset_persons { - id - label - created_at - modified_at - status - public_links - } -} -``` +## 6. Voorbeelden van gebruik -## Notes +Het gebruik van de API wordt toegelicht met 2 concrete voorbeelden in: +[give-graphql-query-examples](https://github.com/viaacode/give-graphql-query-examples). -- Timestamps worden weergegeven in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) waar van toepassing. -- De precieze velden die je opvraagt, bepaal je zelf in je GraphQL-query. -- Ruwe outputvelden zoals `processed_json`, `textrazor_json`, - `transcript_json` en `audio_classification_json` zijn bedoeld voor - integraties die de volledige service-output willen verwerken. +Deze repository bevat twee use cases die de AI metadata API gebruiken: +- alle beschikbare metadata ophalen +- ruwe data downloaden -## Voorbeeldimplementaties -Er worden twee voorbeeldscript ter beschikking gesteld om alle data gelinkt aan een contentpartner te downloaden via GraphQL queries. +Zie ook de [README.md in de repository](https://github.com/viaacode/give-graphql-query-examples/blob/main/README.md) voor uitleg. -## Vooraf te doen -- Zorg dat python beschikbaar is op je systeem: - - [Python installatie](https://www.python.org/downloads/) -- Download het zip-bestand met de scripts [`.env-template`]({{ site.baseurl }}/assets/ai_scripts/graphql-query-examples) +### 6.1 Voorbereiding +- Zorg dat Python 3.11+ geïnstalleerd is op je systeem: [Python installatie](https://www.python.org/downloads/) +- git clone [de repository](https://github.com/viaacode/give-graphql-query-examples) - Kopieer het `.env-template` en hernoem het naar `.env` -- In het nieuwe `.env` bestand: - - Vul de USER_EMAIL en PASSWORD velden in van een account gelinkt aan jouw organisatie - +- Vul in het `.env` bestand de `USER_EMAIL` en `PASSWORD` velden in met de waarden van een account gelinkt aan jouw organisatie - Voer de volgende commando's uit in een terminal om de virtuele omgeving te activeren zodat de scripts kunnen gerund worden: -Linux: -``` +**Linux/MacOS:** + +```shell python3.11 -m venv .venv source .venv/bin/activate python -m pip install -U pip wheel python -m pip install -r requirements.txt ``` -Windows: -``` +**Windows:** + +```shell py -3.11 -m venv .venv .venv\Scripts\activate python -m pip install -U pip wheel python -m pip install -r requirements.txt ``` -## De voorbeeldscripts uitvoeren +### 6.2 De scripts uitvoeren + +#### Metadata downloaden -### Metadata downloaden -Gebruik `download_meemoo_ai_data.py` om alle beschikbare metadata voor je organisatie op te halen en lokaal als JSON op te slaan. +Gebruik `download_meemoo_ai_data.py` om alle beschikbare metadata voor je +organisatie op te halen en lokaal als JSON op te slaan. Het script maakt in `output/` een submap per view aan: @@ -396,21 +348,29 @@ Het script maakt in `output/` een submap per view aan: - `speech_tasks` - `ner_tasks` -In elke submap wordt de data paginagewijs opgeslagen. Elk JSON-bestand bevat dus een pagina met resultaten. +In elke submap wordt de data gepagineerd opgeslagen. Elk JSON-bestand bevat dus +1 pagina met resultaten. -Het script verwacht dat de uitvoermap nog niet bestaat. Wil je de export opnieuw uitvoeren, verwijder dan eerst de map `output/`. +Het script verwacht dat de uitvoermap nog niet bestaat. Wil je de export opnieuw +uitvoeren, verwijder dan eerst de map `output/`. -``` +```shell-script # vergeet niet eerst je virtuele omgeving te activeren python download_meemoo_ai_data.py ``` ### Ruwe AI output downloaden -Gebruik daarna `download_meemoo_raw_ai_files.py` om per taak de ruwe bestanden op te halen. -Voer dit script pas uit nadat `download_meemoo_ai_data.py` succesvol heeft gedraaid. Het script gebruikt namelijk de eerder geëxporteerde metadata in `output/` om te bepalen welke taken moeten worden opgehaald. +Gebruik daarna `download_meemoo_raw_ai_files.py` om per taak de ruwe bestanden +op te halen. -In de huidige versie van het script worden ruwe bestanden voor `speech_tasks` gedownload naar `output/speech_tasks/tasks//`. Per taak kunnen daar onder meer volgende bestanden in terechtkomen: +Voer dit script pas uit nadat `download_meemoo_ai_data.py` succesvol heeft +gedraaid. Het script gebruikt namelijk de eerder geëxporteerde metadata in +`output/` om te bepalen welke taken moeten worden opgehaald. + +In de huidige versie van het script worden ruwe bestanden voor `speech_tasks` +gedownload naar `output/speech_tasks/tasks//`. Per taak kunnen daar +onder meer volgende bestanden in terechtkomen: - `metadata.json`: metadata van de taak - `speechmatics_raw.json`: ruwe JSON-respons van Speechmatics @@ -419,11 +379,13 @@ In de huidige versie van het script worden ruwe bestanden voor `speech_tasks` ge - `transcription.txt`: platte tekstversie van de transcriptie - `audio_classification.json`: output van de audio-classificatie -De map `output/speech_tasks/tasks/` mag nog niet bestaan wanneer je het script start. Wil je de ruwe bestanden opnieuw downloaden, verwijder die map dan eerst. +De map `output/speech_tasks/tasks/` mag nog niet bestaan wanneer je het script +start. Wil je de ruwe bestanden opnieuw downloaden, verwijder die map dan eerst. -Afhankelijk van het aantal taken kan dit script enige tijd duren. Tijdens het uitvoeren toont het script een voortgangsbalk. +Afhankelijk van het aantal taken kan dit script enige tijd duren. Tijdens het +uitvoeren toont het script een voortgangsbalk. -``` +```shell-script # vergeet niet eerst je virtuele omgeving te activeren python download_meemoo_raw_ai_files.py ```