Skip to content

Commit 794b7da

Browse files
authored
Merge pull request #23 from baloise/main
PR for release build
2 parents 38e1067 + a0a4201 commit 794b7da

23 files changed

+374
-244
lines changed

.dockerignore

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,14 @@
11
poetry.lock
2-
.install.stamp
2+
.install.stamp
3+
.venv
4+
dist
5+
.vscode
6+
.github
7+
.git
8+
.gitignore
9+
tests
10+
.env
11+
mypi.ini
12+
README.md
13+
sample_text.txt
14+
yoyonmaskr.ipynb

Dockerfile

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ LABEL maintainer="culmat, trichie, robbizbal" \
55
org.opencontainers.image.description="Yo-Yo-Maskr application Docker image" \
66
version="0.1.0"
77

8+
# expose port
9+
EXPOSE 8000
10+
811
# set poetry environment variables
912
ARG POETRY_FLAGS="--only main"
13+
ARG LOAD_NER_MODELS="False"
1014

1115
# set default environment variables
1216
ENV OLLAMA_BASE_URL=http://localhost:11434 \
1317
OLLAMA_MODEL=llama3.2:latest \
18+
DEBIAN_FRONTEND=noninteractive \
1419
HTTPX_CLIENT_VERIFY=
1520

1621
# add app src
@@ -20,7 +25,7 @@ COPY . /app/
2025
WORKDIR /app
2126

2227
# set script permissions
23-
RUN chmod +x entrypoint.sh setup.sh
28+
RUN chmod +x entrypoint.sh docker_setup.sh
2429

2530
RUN apt -y update \
2631
&& apt install -y make \
@@ -37,16 +42,16 @@ RUN chgrp -R 0 /app && chmod -R g+rwX /app
3742
# switch to user
3843
USER anon
3944

45+
# set workdir
46+
WORKDIR /app
47+
4048
RUN python3 -m pip install --upgrade pip \
4149
&& python3 -m pip install pipx \
4250
&& python3 -m pipx ensurepath \
4351
&& python3 -m pipx completions
4452

4553
# run app setup script
46-
RUN "./setup.sh"
47-
48-
# expose port
49-
EXPOSE 8000
54+
RUN "./docker_setup.sh"
5055

5156
# run app
5257
ENTRYPOINT ["/app/entrypoint.sh"]

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ INSTALL_STAMP := .install.stamp
66
.DEFAULT_GOAL := help
77

88
# Declare phony targets
9-
.PHONY: help install clean lint format test cleaner run dev
9+
.PHONY: help install clean lint format test cleaner run dev loadModels
1010

1111
# Help target to display available commands
1212
help:
1313
@echo "Please use 'make <target>' where <target> is one of:"
1414
@echo ""
1515
@echo " install - Install packages and prepare environment"
16+
@echo " loadModels- load spacy models"
1617
@echo " clean - Remove all temporary files"
1718
@echo " cleaner - Remove all temporary files and the .venv folder"
1819
@echo " lint - Run the code linters"
@@ -63,4 +64,6 @@ run: $(INSTALL_STAMP)
6364
# $(POETRY) run gunicorn src.app:app --workers 4 --worker-class uvicorn.workers.UvicornWorker
6465
$(POETRY) run uvicorn src.app:app --host 0.0.0.0 --port 8000
6566

67+
loadModels: $(INSTALL_STAMP)
68+
$(POETRY) run python src/utils/ano_spacy.py loadModels
6669

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ A reversible anonymisation service for us all
77
## Setup development environment
88

99
```
10-
./setup.sh
10+
python3 -m pip install pipx
11+
pipx install poetry
12+
pipx ensurepath
13+
make install
1114
```
1215
## Run
1316

docker_setup.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
export PATH="$HOME/.local/bin:$PATH"
3+
pipx install poetry
4+
pipx ensurepath
5+
. ~/.bashrc
6+
make install
7+
if [ "$LOAD_NER_MODELS" == "True" ]; then
8+
echo "Loading NER models"
9+
make loadModels
10+
fi

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ tqdm = "^4.66.6"
2828
dill = "^0.3.9"
2929
spacy ="^3.8"
3030
presidio_analyzer="^2.2"
31+
pydantic = "^2.9.2"
3132

3233
[tool.poetry.group.dev.dependencies]
3334
pytest = "^6.0"
@@ -52,5 +53,6 @@ testpaths = [
5253
filterwarnings = [
5354
"error",
5455
'ignore:ast.* is deprecated:DeprecationWarning',
56+
'ignore:PluggyTeardownRaisedWarning',
5557
]
5658

sample_text.txt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
Es war ein kühler Herbstmorgen, als Marie Müller mit ihrem Bruder Thomas in Hamburg auf den Zug nach Berlin wartete. Dort wollten sie ihre Freunde Anna Schmidt und Lukas Hoffmann treffen, die gerade aus München zurückgekehrt waren. Während der Reise erzählte Marie von ihrem letzten Urlaub in Italien, wo sie in Rom einen alten Schulfreund namens Peter Lehmann getroffen hatte. Peter wohnte mittlerweile in der Nähe von Mailand und arbeitete für eine Firma in Venedig. Während der Fahrt diskutierten sie lange über Gott und die Welt, ob Berliner jetzt Krapfen oder Pfannkuchen heissen, ob Wilhelm Buschs Max und Moritz auch heute noch aktuelle Werte vermittelt und ob Peters Firma nur in Italien tätig ist.
1+
Es war ein kühler Herbstmorgen, als Marie Müller mit ihrem Bruder Thomas in Hamburg auf den Zug nach Berlin wartete. Dort wollten sie ihre Freunde Anna Schmidt und Lukas Hoffmann treffen, die gerade aus München zurückgekehrt waren. Während der Reise erzählte Marie von ihrem letzten Urlaub in Italien, wo sie in Rom einen alten Schulfreund namens Peter Lehmann getroffen hatte. Peter wohnte mittlerweile in der Nähe von Mailand und arbeitete für eine Firma in Venedig. Während der Fahrt diskutierten sie lange über Gott und die Welt, ob Berliner jetzt Krapfen oder Pfannkuchen heißen, ob Wilhelm Buschs Max und Moritz auch heute noch aktuelle Werte vermittelt und ob Peters Firma nur in Italien tätig ist. Peters Geschäftsadresse lautet Via Roma 10, 20121 Mailand, Italien, und seine geschäftliche E-Mail ist peter.lehmann@firma.it.
22

3-
In Berlin angekommen, holte sie ihr Onkel Karl Weber vom Bahnhof ab. Gemeinsam fuhren sie zu seiner Wohnung in der Friedrichstraße 15, wo sie später an einem Abendessen bei Familie Becker in Charlottenburg teilnehmen wollten. Dort kamen auch Karla Fischer, eine ehemalige Klassenkameradin, und Paul König, ein alter Freund aus der Schulzeit, hinzu.
3+
In Berlin angekommen, holte ihr Onkel Karl Weber vom Bahnhof ab. Gemeinsam fuhren sie zu seiner Wohnung in der Friedrichstraße 15, wo sie später an einem Abendessen bei Familie Becker in der Charlottenburger Straße 32 teilnehmen wollten. Dort kamen auch Karla Fischer, eine ehemalige Klassenkameradin, und Paul König, ein alter Freund aus der Schulzeit, hinzu. Karl hatte eine Telefonnummer, unter der er erreichbar war: +49 30 1234567.
44

5-
Am nächsten Tag machten sich Marie und Thomas auf den Weg nach Potsdam, um dort den berühmten Park Sanssouci zu besuchen. Unterwegs trafen sie auf einen Reiseleiter namens Andreas Schneider, der ihnen alles über die Geschichte der Stadt und den Park erzählte. Später besuchten sie noch den Kurfürstendamm in Berlin, wo sie zufällig auf Julia Wagner und ihren Bruder Frank trafen, die gerade von einem Ausflug nach Dresden zurückkehrten.
5+
Am nächsten Tag machten sich Marie und Thomas auf den Weg nach Potsdam, um dort den berühmten Park Sanssouci zu besuchen. Unterwegs trafen sie auf einen Reiseleiter namens Andreas Schneider, der ihnen alles über die Geschichte der Stadt und den Park erzählte. Andreas hatte eine Visitenkarte mit seiner E-Mail-Adresse andreas.schneider@reiseleiter.de und seiner Telefonnummer +49 30 7654321. Später besuchten sie noch den Kurfürstendamm in Berlin, wo sie zufällig auf Julia Wagner und ihren Bruder Frank trafen, die gerade von einem Ausflug nach Dresden zurückkehrten.
66

7-
Nach einer Woche voller Abenteuer kehrten sie zurück nach Hamburg, wo sie von ihrer Tante Sabine Schmidt und deren Nachbarn Klaus Neumann herzlich begrüßt wurden.
7+
Nach einer Woche voller Abenteuer kehrten sie zurück nach Hamburg, wo sie von ihrer Tante Sabine Schmidt und deren Nachbarn Klaus Neumann herzlich begrüßt wurden. Sabine lebte in der Seestraße 5 und hatte ein kleines Café namens „Kaffeekultur“ eröffnet. Ihre Kontaktdaten waren sabine.schmidt@kaffeekultur.de und +49 40 12345678.
8+
9+
Matthias Cullmann und Roberto Galvagno machen ein Projekt mit Thomas Reichert. Matthias und Roberto können gut coden, bei Thomas geht es so la la. Matthias hatte seine Kreditkarte bei der Volksbank: 1234 5678 9012 3456, und er hatte 1500 CHF in seinem Konto.
10+
11+
If Spike, Tom, and Jerry are going to New York, they will visit the Fifth Avenue and the Broadway. Jerry will visit Macy's and the Apple Store. Jerry hatte auch eine Notiz mit seiner E-Mail-Adresse jerry.mouse@example.com und seiner Telefonnummer +1 212 555 1234.
12+
13+
Bei der Baloise gibt es Versicherungen für alle Fälle. Der Kontakt ist info@baloise.ch oder +41-58-2858585. Sie können auch direkt Clemens Markstein kontaktieren. Die E-Mail-Adresse von Clemens ist clemens@baloise.ch oder ceo@baloise.com, und seine Natelnummer ist 076 123 4567.
14+
15+
Wenn jemand als Schneider arbeitet, sollte dies nicht getaggt werden. Bei Frau Müller hingegen ist es ein Name und sollte getaggt werden, genauso wie ihre belgische Sozialversicherungsnummer 831205-123-45. Außerdem hat Marie eine Kreditkarte mit der Nummer 4111 1111 1111 1111 und einen Kontostand von 2.500 EUR.

setup.sh

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/api/mask.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,37 @@
11
import fastapi
22
from fastapi.responses import JSONResponse
3-
from fastapi import Request, routing
3+
from fastapi import Request
4+
from enum import Enum
45
from pydantic import BaseModel
5-
from src.utils.llm import llm_find_entities
6-
from src.utils.replacer import replace_values
6+
from src.utils.ano_llm import find_entities as llm_find_entities
7+
from src.utils.ano_spacy import Anon_Spacy
8+
from src.utils.ano_regex import find_entities as reg_find_entities
79

810
router = fastapi.APIRouter()
911

12+
class BackendType(Enum):
13+
LLM = "LLM"
14+
NER = "NER"
15+
REG = "REG"
16+
1017
class MaskRequest(BaseModel):
1118
text: str
19+
backendType: BackendType
20+
21+
ano = Anon_Spacy()
1222

1323
@router.post("/mask", response_class=JSONResponse, include_in_schema=True)
1424
async def mask(request: MaskRequest):
15-
entities = llm_find_entities(request.text)
16-
anontext = replace_values(request.text, entities)
17-
return {"original_text": request.text, "llm_entities": entities, "anonymized_text": anontext}
25+
26+
match request.backendType:
27+
case BackendType.LLM:
28+
llm_entities = llm_find_entities(request.text)
29+
return {"original_text": request.text, "entities": llm_entities['replace_dict'], "anonymized_text": llm_entities['text']}
30+
case BackendType.NER:
31+
spacy_entities = ano.find_entities(request.text)
32+
return {"original_text": request.text, "entities": spacy_entities['replace_dict'], "anonymized_text": spacy_entities['text']}
33+
case BackendType.REG:
34+
regex_entities = reg_find_entities(request.text)
35+
return {"original_text": request.text, "entities": regex_entities['replace_dict'], "anonymized_text": regex_entities['text']}
36+
case _:
37+
return {"original_text": "Invalid backend type"}

src/static/scripts/demask.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ document.getElementById('inputForm').addEventListener('submit', function(event)
2424
.then(text => {
2525
// Display the response in the textarea
2626
document.getElementById('responseFieldText').value = inputData; // Format the JSON response
27-
document.getElementById('responseFieldDeanonText').value = text.deanonymized_text; // Format the string response
27+
document.getElementById('responseFieldDeanonText').value = JSON.stringify(text.deanonymized_text, null, 2); // Format the JSON response
28+
2829
})
2930
.catch((error) => {
3031
console.error('Error:', error); // Handle any errors

src/static/scripts/mask.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ document.getElementById('inputForm').addEventListener('submit', function(event)
22
event.preventDefault(); // Prevent the default form submission
33

44
const inputData = document.getElementById('inputData').value;
5+
const backendType = document.getElementById('backendType').value;
56

67
// Use a relative URL for the API endpoint
78
const apiEndpoint = '/api/mask'; // Relative URL
@@ -12,7 +13,7 @@ document.getElementById('inputForm').addEventListener('submit', function(event)
1213
headers: {
1314
'Content-Type': 'application/json',
1415
},
15-
body: JSON.stringify({ text: inputData }), // Send the input text as JSON
16+
body: JSON.stringify({ text: inputData, "backendType": backendType }), // Send the input text as JSON
1617
})
1718
.then(response => {
1819
if (!response.ok) {
@@ -23,12 +24,12 @@ document.getElementById('inputForm').addEventListener('submit', function(event)
2324
.then(text => {
2425
// Display the response in the textarea
2526
document.getElementById('responseFieldText').value = JSON.stringify(text.original_text, null, 2); // Format the JSON response
26-
document.getElementById('responseFieldEntities').value = JSON.stringify(text.llm_entities, null, 2); // Format the JSON response
27-
document.getElementById('responseFieldAnonText').value = text.anonymized_text; // Format the string response
27+
document.getElementById('responseFieldEntities').value = JSON.stringify(text.entities, null, 2); // Format the JSON response
28+
document.getElementById('responseFieldAnonText').value = JSON.stringify(text.anonymized_text, null, 2); // Format the string response
2829
})
2930
.catch((error) => {
3031
console.error('Error:', error); // Handle any errors
3132
// Optionally display the error in the textarea
32-
document.getElementById('responseFieldText').value = 'Error: ' + error.message;
33+
document.getElementById('responseFieldText').value = 'Error: ' + error.message + '\nText: ' + inputData;
3334
});
3435
});

src/templates/html/landing.html

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ <h1>YoYo MaskЯ</h1>
2323
<button class="square-button"onclick="window.location.href='/mask'">Mask</button>
2424
<button class="square-button" onclick="window.location.href='/demask'">DeMask</button>
2525
</div>
26+
<br/>
2627
</main>
2728

2829
<footer>
@@ -33,9 +34,5 @@ <h1>YoYo MaskЯ</h1>
3334
</div>
3435
</footer>
3536

36-
<!-- Link to the external JavaScript file -->
37-
<script src="/static/scripts/mask.js"></script>
38-
<script src="/static/scripts/fileLoader.js"></script>
39-
<script src="/static/scripts/mask_downloader.js"></script>
4037
</body>
4138
</html>

src/templates/html/mask.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,18 @@ <h3>Input</h3>
2727
</div>
2828
<div class="flex-item">
2929
<form id="inputForm">
30-
<textarea type="text" id="inputData" placeholder="Enter text to anonymize or load text from a file" required></textarea>
30+
<textarea type="text" id="inputData" placeholder="Enter text to anonymize or load text from a file" required>Hallo Velo und Roberto in Basel. Nice email roberto@roberto.ch</textarea>
3131
<div class="flex-container">
3232
<div class="flex-item">
3333
<input type="submit" value="Submit">
3434
</div>
35+
<div class="flex-item">
36+
<select id="backendType" name="backendType" required>
37+
<option value="REG">REG</option>
38+
<option value="LLM">LLM</option>
39+
<option value="NER">NER</option>
40+
</select>
41+
</div>
3542
</div>
3643
</form>
3744
</div>

0 commit comments

Comments
 (0)