# SPDX-FileCopyrightText: Copyright (C) 2026 Omid Jafari <omidjafari.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import codecs
from drf_writable_nested import WritableNestedModelSerializer
from rest_framework import serializers
from nlpmed_portal.nlp.constants import VTE_KEYWORD_EXC_LIST
from nlpmed_portal.nlp.constants import VTE_KEYWORD_INC_LIST
from nlpmed_portal.nlp.constants import VTE_SECTION_EXC_LIST
from nlpmed_portal.nlp.constants import VTE_SECTION_INC_LIST
from nlpmed_portal.nlp.models import DuplicateChecker
from nlpmed_portal.nlp.models import EncodingFixer
from nlpmed_portal.nlp.models import Joiner
from nlpmed_portal.nlp.models import MLInference
from nlpmed_portal.nlp.models import NlpProcessJob
from nlpmed_portal.nlp.models import NLPSetting
from nlpmed_portal.nlp.models import NoteFilter
from nlpmed_portal.nlp.models import PatternReplacer
from nlpmed_portal.nlp.models import SectionFilter
from nlpmed_portal.nlp.models import SectionSplitter
from nlpmed_portal.nlp.models import SentenceExpander
from nlpmed_portal.nlp.models import SentenceFilter
from nlpmed_portal.nlp.models import SentenceSegmenter
from nlpmed_portal.nlp.models import WordMasker
[docs]
class EscapedNewlineCharField(serializers.CharField):
[docs]
def get_initial(self):
value = super().get_initial()
return value.replace("\n", "\\n").replace(r"\s", r"\\s") if value else value
[docs]
def to_internal_value(self, data):
return codecs.decode(data, "unicode-escape")
[docs]
class EncodingFixerSerializer(serializers.ModelSerializer):
[docs]
class PatternReplacerSerializer(serializers.ModelSerializer):
pattern = EscapedNewlineCharField(
initial=r"(?:\s*\n\s*){2,}",
trim_whitespace=False,
)
target = EscapedNewlineCharField(initial="\n\n", trim_whitespace=False)
[docs]
class WordMaskerSerializer(serializers.ModelSerializer):
[docs]
class NoteFilterSerializer(serializers.ModelSerializer):
[docs]
class SectionSplitterSerializer(serializers.ModelSerializer):
delimiter = EscapedNewlineCharField(initial="\n\n", trim_whitespace=False)
[docs]
class SectionFilterSerializer(serializers.ModelSerializer):
[docs]
class SentenceSegmenterSerializer(serializers.ModelSerializer):
[docs]
class DuplicateCheckerSerializer(serializers.ModelSerializer):
[docs]
class SentenceFilterSerializer(serializers.ModelSerializer):
[docs]
class SentenceExpanderSerializer(serializers.ModelSerializer):
[docs]
class JoinerSerializer(serializers.ModelSerializer):
sentence_delimiter = EscapedNewlineCharField(initial="\n", trim_whitespace=False)
section_delimiter = EscapedNewlineCharField(initial="\n\n", trim_whitespace=False)
[docs]
class MLInferenceSerializer(serializers.ModelSerializer):
COMPONENTS = {
"encoding_fixer": EncodingFixer,
"pattern_replacer": PatternReplacer,
"word_masker": WordMasker,
"note_filter": NoteFilter,
"section_splitter": SectionSplitter,
"section_filter": SectionFilter,
"sentence_segmenter": SentenceSegmenter,
"duplicate_checker": DuplicateChecker,
"sentence_filter": SentenceFilter,
"sentence_expander": SentenceExpander,
"joiner": Joiner,
"ml_inference": MLInference,
}
[docs]
class NLPSettingSerializer(WritableNestedModelSerializer):
encoding_fixer = EncodingFixerSerializer(required=False)
pattern_replacer = PatternReplacerSerializer(required=False)
word_masker = WordMaskerSerializer(required=False)
note_filter = NoteFilterSerializer(required=False)
section_splitter = SectionSplitterSerializer(required=False)
section_filter = SectionFilterSerializer(required=False)
sentence_segmenter = SentenceSegmenterSerializer(required=False)
duplicate_checker = DuplicateCheckerSerializer(required=False)
sentence_filter = SentenceFilterSerializer(required=False)
sentence_expander = SentenceExpanderSerializer(required=False)
joiner = JoinerSerializer(required=False)
ml_inference = MLInferenceSerializer(required=False)
[docs]
class NLPSerializer(NLPSettingSerializer):
input_text = serializers.CharField(required=True)
[docs]
def to_internal_value(self, data):
data = super().to_internal_value(data)
if data.get("input_text"):
data["input_text"] = codecs.decode(data["input_text"], "unicode_escape")
return data
[docs]
class NlpProcessJobSerializer(serializers.ModelSerializer):
job_progress = serializers.ReadOnlyField()
username = serializers.CharField(source="user.username", read_only=True)
[docs]
class DemoSerializer(serializers.Serializer):
input_text = serializers.CharField(required=True)
[docs]
def to_internal_value(self, data):
data = super().to_internal_value(data)
if data.get("input_text"):
data["input_text"] = codecs.decode(data["input_text"], "unicode_escape")
return data