{"id":26608074,"url":"https://github.com/thu-keg/omnievent","last_synced_at":"2025-05-15T10:07:14.368Z","repository":{"id":59221854,"uuid":"480721741","full_name":"THU-KEG/OmniEvent","owner":"THU-KEG","description":"A comprehensive, unified and modular event extraction toolkit.","archived":false,"fork":false,"pushed_at":"2024-12-18T02:50:40.000Z","size":18179,"stargazers_count":376,"open_issues_count":12,"forks_count":37,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-05-15T10:06:35.803Z","etag":null,"topics":["big-models","bmtrain","deep-learning","event-detection","event-extraction","huggingface-transformers","information-extration","natural-language-generation","natural-language-processing","pytorch"],"latest_commit_sha":null,"homepage":"https://omnievent.readthedocs.io/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/THU-KEG.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-04-12T08:35:34.000Z","updated_at":"2025-05-14T16:48:31.000Z","dependencies_parsed_at":"2025-04-14T15:58:45.288Z","dependency_job_id":null,"html_url":"https://github.com/THU-KEG/OmniEvent","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/THU-KEG%2FOmniEvent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/THU-KEG%2FOmniEvent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/THU-KEG%2FOmniEvent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/THU-KEG%2FOmniEvent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/THU-KEG","download_url":"https://codeload.github.com/THU-KEG/OmniEvent/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254319720,"owners_count":22051073,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["big-models","bmtrain","deep-learning","event-detection","event-extraction","huggingface-transformers","information-extration","natural-language-generation","natural-language-processing","pytorch"],"created_at":"2025-03-23T23:32:00.624Z","updated_at":"2025-05-15T10:07:09.350Z","avatar_url":"https://github.com/THU-KEG.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align='center'\u003e\n\u003cimg src=\"imgs/Omnievent.png\" style=\"width:350px;\"\u003e\n\n**A comprehensive, unified and modular event extraction toolkit.**\n\n\n------\n\n\u003cp align=\"center\"\u003e  \n    \u003ca href=\"http://103.238.162.34:9621/\"\u003e\n        \u003cimg alt=\"Demo\" src=\"https://img.shields.io/badge/Demo-site-green\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/OmniEvent/\"\u003e\n        \u003cimg alt=\"PyPI\" src=\"https://img.shields.io/badge/Pypi-v.0.1.7-blue\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://omnievent.readthedocs.io/en/latest/\"\u003e\n        \u003cimg alt=\"Documentation\" src=\"https://img.shields.io/badge/Doc-site-red\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/THU-KEG/OmniEvent/blob/main/LICENSE\"\u003e\n        \u003cimg alt=\"License\" src=\"https://img.shields.io/badge/License-MIT-blue\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\u003c/div\u003e\n\n\n# Table of Contents\n\n- [Table of Contents](#table-of-contents)\n- [Overview](#overview)\n  - [Highlights](#highlights)\n- [Installation](#installation)\n  - [With pip](#with-pip)\n  - [From source](#from-source)\n- [Easy Start](#easy-start)\n- [Train your Own Model with OmniEvent](#train-your-own-model-with-omnievent)\n  - [Step 1: Process the dataset into the unified format](#step-1-process-the-dataset-into-the-unified-format)\n  - [Step 2: Set up the customized configurations](#step-2-set-up-the-customized-configurations)\n  - [Step 3: Initialize the model and tokenizer](#step-3-initialize-the-model-and-tokenizer)\n  - [Step 4: Initialize the dataset and evaluation metric](#step-4-initialize-the-dataset-and-evaluation-metric)\n  - [Step 5: Define Trainer and train](#step-5-define-trainer-and-train)\n  - [Step 6: Unified Evaluation](#step-6-unified-evaluation)\n- [Supported Datasets \\\u0026 Models \\\u0026 Contests](#supported-datasets--models--contests)\n  - [Datasets](#datasets)\n  - [Models](#models)\n- [Consistent Evaluation](#consistent-evaluation)\n  - [1. Consistent data preprocessing](#1-consistent-data-preprocessing)\n  - [2. Output Standardization](#2-output-standardization)\n  - [3. Pipeline Evaluation](#3-pipeline-evaluation)\n- [Experiments](#experiments)\n- [Citation](#citation)\n\n# News \u003cspan style=\"color: red;\"\u003e❗\u003c/span\u003e \n[2024.12] In the spring of next year, we will build a new agent system based on LLMs and small models optimized for IE tasks. The system will be more powerful and general than the models in OmniEvent. The OmniEvent repository will only serve as introductory code for EE, and major updates will no longer be made in the future.\n\n[2024.10] We recently released a series of LLMs (**[ADELIE](https://huggingface.co/THU-KEG/ADELIE-SFT-1.5B)**) trained for information extraction, which includes event extraction tasks. Although its performance underperforms specialized small models, such as BERT, its general capabilities and ability to learn from schemas in context are impressive. Welcome to try! Link: https://huggingface.co/THU-KEG/ADELIE-SFT-1.5B. \n\n\n\n# Overview\nOmniEvent is a powerful open-source toolkit for **event extraction**, including **event detection** and **event argument extraction**. We comprehensively cover various paradigms and provide fair and unified evaluations on widely-used **English** and **Chinese** datasets. Modular implementations make OmniEvent highly extensible.\n\n## Highlights\n- **Comprehensive Capability**\n  - Support to do ***Event Extraction*** at once, and also to independently do its two subtasks: ***Event Detection***, ***Event Argument Extraction***.\n  - Cover various paradigms: ***Token Classification***, ***Sequence Labeling***, ***MRC(QA)*** and ***Seq2Seq***.\n  - Implement ***Transformer-based*** ([BERT](https://arxiv.org/pdf/1810.04805.pdf), [T5](https://arxiv.org/pdf/1910.10683.pdf), etc.) and ***classical*** ([DMCNN](https://aclanthology.org/P15-1017.pdf), [CRF](http://www.cs.cmu.edu/afs/cs/Web/People/aladdin/papers/pdfs/y2001/crf.pdf), etc.) models.\n  - Both ***Chinese*** and ***English*** are supported for all event extraction sub-tasks, paradigms and models. \n\n- **Unified Benchmark \u0026 Evaluation** \n  - Various datasets are processed into a [unified format](https://github.com/THU-KEG/OmniEvent/tree/main/scripts/data_processing#unified-omnievent-format).\n  - Predictions of different paradigms are all converted into a [unified candidate set](https://github.com/THU-KEG/OmniEvent/tree/main/OmniEvent/evaluation#convert-the-predictions-of-different-paradigms-to-a-unified-candidate-set) for fair evaluations.\n  - Four [evaluation modes](https://github.com/THU-KEG/OmniEvent/tree/main/OmniEvent/evaluation#provide-four-standard-eae-evaluation-modes) (**gold**, **loose**, **default**, **strict**) well cover different previous evaluation settings.\n\n- **Modular Implementation**\n  - All models are decomposed into four modules:\n    - **Input Engineering**: Prepare inputs and support various input engineering methods like prompting.\n    - **Backbone**: Encode text into hidden states.\n    - **Aggregation**: Fuse hidden states (e.g., select [CLS], pooling, GCN) to the final event representation. \n    - **Output Head**: Map the event representation to the final outputs, such as Linear, CRF, MRC head, etc. \n  - You can combine and reimplement different modules to design and implement your own new model.\n\n- **Big Model Training \u0026 Inference**\n  - Efficient training and inference of big event extraction models are supported with [BMTrain](https://github.com/OpenBMB/BMTrain).\n\n- **Easy to Use \u0026 Highly Extensible**\n  - Open datasets can be downloaded and processed with a single command.\n  - Fully compatible with 🤗 [Transformers](https://github.com/huggingface/transformers) and its [Trainer](https://huggingface.co/docs/transformers/main/en/main_classes/trainer).\n  - Users can easily reproduce existing models and build customized models with OmniEvent.\n\n\n\n# Installation\n\n## With pip\nThis repository is tested on Python 3.9+, Pytorch 1.12.1+. OmniEvent can be installed with pip as follows:\n```shell\npip install OmniEvent\n```\n\n## From source\nIf you want to install the repository from local source, you can install as follows:\n```shell\npip install .\n```\nAnd if you want to edit the repositoy, you can \n```shell\npip install -e .\n```\n\n# Easy Start\nOmniEvent provides several off-the-shelf models for the users. Examples are shown below.\n\n*Make sure you have installed OmniEvent as instructed above. Note that it may take a few minutes to download checkpoint at the first time.*\n```python\n\u003e\u003e\u003e from OmniEvent.infer import infer\n\n\u003e\u003e\u003e # Even Extraction (EE) Task\n\u003e\u003e\u003e text = \"2022年北京市举办了冬奥会\"\n\u003e\u003e\u003e results = infer(text=text, task=\"EE\")\n\u003e\u003e\u003e print(results[0][\"events\"])\n[\n    {\n        \"type\": \"组织行为开幕\", \"trigger\": \"举办\", \"offset\": [8, 10],\n        \"arguments\": [\n            {   \"mention\": \"2022年\", \"offset\": [9, 16], \"role\": \"时间\"},\n            {   \"mention\": \"北京市\", \"offset\": [81, 89], \"role\": \"地点\"},\n            {   \"mention\": \"冬奥会\", \"offset\": [0, 4], \"role\": \"活动名称\"},\n        ]\n    }\n]\n\n\u003e\u003e\u003e text = \"U.S. and British troops were moving on the strategic southern port city of Basra \\ \nSaturday after a massive aerial assault pounded Baghdad at dawn\"\n\n\u003e\u003e\u003e # Event Detection (ED) Task\n\u003e\u003e\u003e results = infer(text=text, task=\"ED\")\n\u003e\u003e\u003e print(results[0][\"events\"])\n[\n    { \"type\": \"attack\", \"trigger\": \"assault\", \"offset\": [113, 120]},\n    { \"type\": \"injure\", \"trigger\": \"pounded\", \"offset\": [121, 128]}\n]\n\n\u003e\u003e\u003e # Event Argument Extraction (EAE) Task\n\u003e\u003e\u003e results = infer(text=text, triggers=[(\"assault\", 113, 120), (\"pounded\", 121, 128)], task=\"EAE\")\n\u003e\u003e\u003e print(results[0][\"events\"])\n[\n    {\n        \"type\": \"attack\", \"trigger\": \"assault\", \"offset\": [113, 120],\n        \"arguments\": [\n            {   \"mention\": \"U.S.\", \"offset\": [0, 4], \"role\": \"attacker\"},\n            {   \"mention\": \"British\", \"offset\": [9, 16], \"role\": \"attacker\"},\n            {   \"mention\": \"Saturday\", \"offset\": [81, 89], \"role\": \"time\"}\n        ]\n    },\n    {\n        \"type\": \"injure\", \"trigger\": \"pounded\", \"offset\": [121, 128],\n        \"arguments\": [\n            {   \"mention\": \"U.S.\", \"offset\": [0, 4], \"role\": \"attacker\"},\n            {   \"mention\": \"Saturday\", \"offset\": [81, 89], \"role\": \"time\"},\n            {   \"mention\": \"British\", \"offset\": [9, 16], \"role\": \"attacker\"}\n        ]\n    }\n]\n```\n\n# Train your Own Model with OmniEvent\nOmniEvent can help users easily train and evaluate their customized models on specific datasets.\n\nWe show a step-by-step example of using OmniEvent to train and evaluate an ***Event Detection*** model on ***ACE-EN*** dataset in the ***Seq2Seq*** paradigm.\nMore examples are shown in [examples](./examples).\n\n## Step 1: Process the dataset into the unified format\nWe provide standard data processing scripts for several commonly-used datasets. Checkout the details in [scripts/data_processing](./scripts/data_processing).\n```shell\ndataset=ace2005-en  # the dataset name\ncd scripts/data_processing/$dataset\nbash run.sh\n```\n\n## Step 2: Set up the customized configurations\nWe keep track of the configurations of dataset, model and training parameters via a single `*.yaml` file. See [./configs](./configs) for details.\n\n```python\n\u003e\u003e\u003e from OmniEvent.arguments import DataArguments, ModelArguments, TrainingArguments, ArgumentParser\n\u003e\u003e\u003e from OmniEvent.input_engineering.seq2seq_processor import type_start, type_end\n\n\u003e\u003e\u003e parser = ArgumentParser((ModelArguments, DataArguments, TrainingArguments))\n\u003e\u003e\u003e model_args, data_args, training_args = parser.parse_yaml_file(yaml_file=\"config/all-datasets/ed/s2s/ace-en.yaml\")\n\n\u003e\u003e\u003e training_args.output_dir = 'output/ACE2005-EN/ED/seq2seq/t5-base/'\n\u003e\u003e\u003e data_args.markers = [\"\u003cevent\u003e\", \"\u003c/event\u003e\", type_start, type_end]\n```\n\n## Step 3: Initialize the model and tokenizer\nOmniEvent supports various backbones. The users can specify the model and tokenizer in the config file and initialize them as follows.\n\n```python\n\u003e\u003e\u003e from OmniEvent.backbone.backbone import get_backbone\n\u003e\u003e\u003e from OmniEvent.model.model import get_model\n\n\u003e\u003e\u003e backbone, tokenizer, config = get_backbone(model_type=model_args.model_type, \n                           \t\t       model_name_or_path=model_args.model_name_or_path, \n                           \t\t       tokenizer_name=model_args.model_name_or_path, \n                           \t\t       markers=data_args.markers,\n                           \t\t       new_tokens=data_args.markers)\n\u003e\u003e\u003e model = get_model(model_args, backbone)\n```\n\n## Step 4: Initialize the dataset and evaluation metric\nOmniEvent prepares the `DataProcessor` and the corresponding evaluation metrics for different task and paradigms.\n\n***Note that** the metrics here are paradigm-dependent and are **not** used for the final unified evaluation.*\n\n```python\n\u003e\u003e\u003e from OmniEvent.input_engineering.seq2seq_processor import EDSeq2SeqProcessor\n\u003e\u003e\u003e from OmniEvent.evaluation.metric import compute_seq_F1\n\n\u003e\u003e\u003e train_dataset = EDSeq2SeqProcessor(data_args, tokenizer, data_args.train_file)\n\u003e\u003e\u003e eval_dataset = EDSeq2SeqProcessor(data_args, tokenizer, data_args.validation_file)\n\u003e\u003e\u003e metric_fn = compute_seq_F1\n```\n\n## Step 5: Define Trainer and train\nOmniEvent adopts [Trainer](https://huggingface.co/docs/transformers/main/en/main_classes/trainer) from 🤗 [Transformers](https://github.com/huggingface/transformers) for training and evaluation.\n\n```python\n\u003e\u003e\u003e from OmniEvent.trainer_seq2seq import Seq2SeqTrainer\n\n\u003e\u003e\u003e trainer = Seq2SeqTrainer(\n        args=training_args,\n        model=model,\n        train_dataset=train_dataset,\n        eval_dataset=eval_dataset,\n        compute_metrics=metric_fn,\n        data_collator=train_dataset.collate_fn,\n        tokenizer=tokenizer,\n    )\n\u003e\u003e\u003e trainer.train()\n```\n\n## Step 6: Unified Evaluation\nSince the metrics in Step 4 depend on the paradigm, it is not fair to directly compare the performance of models in different paradigms. \n\nOmniEvent evaluates models of different paradigms in a unified manner, where the predictions of different models are converted to predictions on the same candidate sets and then evaluated.\n\n```python  \n\u003e\u003e\u003e from OmniEvent.evaluation.utils import predict, get_pred_s2s\n\u003e\u003e\u003e from OmniEvent.evaluation.convert_format import get_trigger_detection_s2s\n\n\u003e\u003e\u003e logits, labels, metrics, test_dataset = predict(trainer=trainer, tokenizer=tokenizer, data_class=EDSeq2SeqProcessor,\n                                                    data_args=data_args, data_file=data_args.test_file,\n                                                    training_args=training_args)\n\u003e\u003e\u003e # paradigm-dependent metrics\n\u003e\u003e\u003e print(\"{} test performance before converting: {}\".formate(test_dataset.dataset_name, metrics[\"test_micro_f1\"]))  \nACE2005-EN test performance before converting: 66.4215686224377\n\n\u003e\u003e\u003e preds = get_pred_s2s(logits, tokenizer)\n\u003e\u003e\u003e # convert to the unified prediction and evaluate\n\u003e\u003e\u003e pred_labels = get_trigger_detection_s2s(preds, labels, data_args.test_file, data_args, None)\nACE2005-EN test performance after converting: 67.41016109045849\n```\n\nFor those datasets whose test set annotations are not public, such as MAVEN and LEVEN, OmniEvent provide scripts to generate submission files. See [dump_result.py](./OmniEvent/evaluation/dump_result.py) for details.\n\n# Supported Datasets \u0026 Models \u0026 Contests\nContinually updated. Welcome to add more!\n\n\n## Datasets\n\u003cdiv align='center'\u003e\n\n\u003ctable\u003e\n    \u003ctr\u003e\n        \u003cth\u003eLanguage\u003c/th\u003e\n        \u003cth\u003eDomain\u003c/th\u003e\n        \u003cth\u003eTask\u003c/th\u003e  \n        \u003cth\u003eDataset\u003c/th\u003e  \n    \u003c/tr \u003e\n    \u003ctr \u003e\n        \u003ctd rowspan=\"4\"\u003eEnglish\u003c/td\u003e\n        \u003ctd\u003eGeneral\u003c/td\u003e\n        \u003ctd\u003eED\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/THU-KEG/MAVEN-dataset\"\u003e MAVEN\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eGeneral\u003c/td\u003e\n        \u003ctd\u003eED EAE\u003c/td\u003e\n        \u003ctd\u003eACE-EN\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eGeneral\u003c/td\u003e\n        \u003ctd\u003eED EAE\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://aclanthology.org/D19-1585.pdf\"\u003eACE-DYGIE\u003c/a\u003e \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eGeneral\u003c/td\u003e\n        \u003ctd\u003eED EAE\u003c/td\u003e\n        \u003ctd\u003eRichERE (KBP+ERE)\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd rowspan=\"4\"\u003eChinese\u003c/td\u003e\n        \u003ctd\u003eLegal\u003c/td\u003e\n        \u003ctd\u003eED\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/thunlp/LEVEN\"\u003e LEVEN \u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eGeneral\u003c/td\u003e\n        \u003ctd\u003eED EAE\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://www.luge.ai/#/luge/dataDetail?id=6\"\u003eDuEE \u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003eGeneral\u003c/td\u003e\n        \u003ctd\u003eED EAE\u003c/td\u003e\n        \u003ctd\u003eACE-ZH\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd \u003eFinancial\u003c/td\u003e\n        \u003ctd\u003eED EAE\u003c/td\u003e\n        \u003ctd\u003e\u003ca href=\"https://github.com/TimeBurningFish/FewFC\"\u003e FewFC\u003c/a\u003e\u003c/td\u003e\n\n\n\u003c/table\u003e\n\u003c/div\u003e\n\n## Models\n\n- Paradigm\n  - Token Classification (TC)\n  - Sequence Labeling (SL)\n  - Sequence to Sequence (Seq2Seq)\n  - Machine Reading Comprehension (MRC)\n- Backbone\n  - CNN / LSTM\n  - Transformers (BERT, T5, etc.)\n- Aggregation\n  - Select [CLS]\n  - Dynamic/Max Pooling\n  - Marker\n  - GCN\n- Head\n  - Linear / CRF / MRC heads\n\n# Consistent Evaluation\nOmniEvent provides corresponding remedies for the three discrepancies in event extraction evaluation, as suggested in our ACL 2023 [paper](https://aclanthology.org/2023.findings-acl.586.pdf). \n## 1. Consistent data preprocessing\nWe provide several preprocessing scripts in `scripts/data_processing`. For ACE 2005, we provide three mainstream scripts: `ace2005-dygie`, `ace2005-oneie`, and `ace2005-en`. Users can easily use the scripts to process the original data into a unified data format. \n## 2. Output Standardization\nWe implement the output standardization in `OmniEvent/evaluation/convert_format.py`. Specifically, users can use corresponding functions to convert the output of different paradigms into the output space of the token classification method.\n## 3. Pipeline Evaluation\nAs suggested in `OmniEvent/evaluation/README.md`, we provide several evaluation modes for evaluating event argument extraction. We recommend the **strict** mode for comparable evaluation. And we provide a unified extracted trigger set for pipeline evaluation of different event argument extraction methods. The triggers are extracted by an advanced ED model: CLEVE. The extracted triggers for different datasets (ACE 2005, RichERE, and TACKBP 2014-2017) are placed in [here](https://cloud.tsinghua.edu.cn/f/799c8c7c44d24c1db2b7/?dl=1).\n\n\n# Experiments\nWe implement and evaluate state-of-the-art methods on some popular benchmarks using OmniEvent, and the results are shown in our ACL 2023 paper \"[The Devil is in the Details: On the Pitfalls of Event Extraction Evaluation](https://aclanthology.org/2023.findings-acl.586.pdf)\". \n\n# Citation\nIf our codes help you, please cite us:\n```\n@inproceedings{peng2023devil,\n  title={The Devil is in the Details: On the Pitfalls of Event Extraction Evaluation},\n  author={Peng, Hao and Wang, Xiaozhi and Yao, Feng and Zeng, Kaisheng and Hou, Lei and Li, Juanzi and Liu, Zhiyuan and Shen, Weixing},\n  booktitle={Findings of ACL 2023},\n  year={2023}\n}\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthu-keg%2Fomnievent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthu-keg%2Fomnievent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthu-keg%2Fomnievent/lists"}