Spaces:
Runtime error
Runtime error
Upload 7 files
Browse files- Dockerfile +27 -0
- main.py +52 -0
- requirements.txt +8 -0
- static/index.html +61 -0
- static/script.js +52 -0
- static/style.css +118 -0
Dockerfile
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Use the official Python 3.9 image
|
2 |
+
FROM python:3.9
|
3 |
+
|
4 |
+
# Set the working directory to /code
|
5 |
+
WORKDIR /code
|
6 |
+
|
7 |
+
# Copy the current directory contents into the container at /code
|
8 |
+
COPY ./requirements.txt /code/requirements.txt
|
9 |
+
|
10 |
+
# Install requirements.txt
|
11 |
+
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
12 |
+
|
13 |
+
# Set up a new user named "user" with user ID 1000
|
14 |
+
RUN useradd -m -u 1000 user
|
15 |
+
# Switch to the "user" user
|
16 |
+
USER user
|
17 |
+
# Set home to the user's home directory
|
18 |
+
ENV HOME=/home/user \
|
19 |
+
PATH=/home/user/.local/bin:$PATH
|
20 |
+
|
21 |
+
# Set the working directory to the user's home directory
|
22 |
+
WORKDIR $HOME/app
|
23 |
+
|
24 |
+
# Copy the current directory contents into the container at $HOME/app setting the owner to the user
|
25 |
+
COPY --chown=user . $HOME/app
|
26 |
+
|
27 |
+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
|
main.py
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI
|
2 |
+
from fastapi.staticfiles import StaticFiles
|
3 |
+
from fastapi.responses import FileResponse
|
4 |
+
from transformers import pipeline
|
5 |
+
from pysbd import Segmenter
|
6 |
+
|
7 |
+
app = FastAPI()
|
8 |
+
segmenter = Segmenter(language='en', clean=False)
|
9 |
+
privacy_intent_pipe = pipeline("text-classification",
|
10 |
+
"remzicam/privacy_intent" )
|
11 |
+
|
12 |
+
def doc2sent(text:str)-> dict:
|
13 |
+
"""
|
14 |
+
> It takes a string of text and returns a list of sentences
|
15 |
+
|
16 |
+
Args:
|
17 |
+
text (str): the text to be segmented
|
18 |
+
|
19 |
+
Returns:
|
20 |
+
A list of sentences
|
21 |
+
"""
|
22 |
+
sentences = segmenter.segment(text)
|
23 |
+
return [sentence.replace("\n", "").strip() for sentence in sentences]
|
24 |
+
|
25 |
+
|
26 |
+
def pipe(text:str) -> list[str]:
|
27 |
+
"""
|
28 |
+
It takes a string of text and returns a dictionary of sentences and their corresponding privacy
|
29 |
+
intent labels.
|
30 |
+
|
31 |
+
Args:
|
32 |
+
text (str): the text to be classified
|
33 |
+
|
34 |
+
Returns:
|
35 |
+
A dictionary of sentences and their corresponding labels.
|
36 |
+
"""
|
37 |
+
sentences = doc2sent(text)
|
38 |
+
preds = [privacy_intent_pipe(sent)[0]["label"] for sent in sentences]
|
39 |
+
return dict(zip(sentences, preds))
|
40 |
+
|
41 |
+
|
42 |
+
@app.get("/infer_intents")
|
43 |
+
def t5(input):
|
44 |
+
return {"output": pipe(input)}
|
45 |
+
|
46 |
+
|
47 |
+
app.mount("/", StaticFiles(directory="static", html=True), name="static")
|
48 |
+
|
49 |
+
|
50 |
+
@app.get("/")
|
51 |
+
def index() -> FileResponse:
|
52 |
+
return FileResponse(path="/app/static/index.html", media_type="text/html")
|
requirements.txt
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
fastapi==0.74.*
|
2 |
+
requests==2.27.*
|
3 |
+
pysbd==0.3.4
|
4 |
+
uvicorn[standard]==0.17.*
|
5 |
+
transformers
|
6 |
+
--find-links https://download.pytorch.org/whl/torch_stable.html
|
7 |
+
torch==1.13.1+cpu
|
8 |
+
|
static/index.html
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8" />
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
6 |
+
<title>Privacy Policy Intent Classifier</title>
|
7 |
+
<link rel="stylesheet" href="style.css" />
|
8 |
+
<script type="module" src="script.js"></script>
|
9 |
+
</head>
|
10 |
+
<body>
|
11 |
+
<main>
|
12 |
+
<section id="text-gen">
|
13 |
+
<h1>Privacy Policy Intent Classifier</h1>
|
14 |
+
<!-- Trigger/Open The Modal -->
|
15 |
+
<button id="myBtn">Intent Explanations</button>
|
16 |
+
|
17 |
+
<!-- The Modal -->
|
18 |
+
<div id="myModal" class="modal">
|
19 |
+
|
20 |
+
<!-- Modal content -->
|
21 |
+
<div class="modal-content">
|
22 |
+
<span class="close">×</span>
|
23 |
+
<p> 5 Intents:
|
24 |
+
<br>
|
25 |
+
<br><em>(1) Data Collection/Usage: What, why and how
|
26 |
+
user information is collected;
|
27 |
+
<br>(2) Data Sharing/Disclosure: What, why and how
|
28 |
+
user information is shared with or collected
|
29 |
+
by third parties;
|
30 |
+
<br>(3) Data Storage/Retention: How long and where
|
31 |
+
user information will be stored;
|
32 |
+
<br>(4) Data Security/Protection: Protection measures for user information;
|
33 |
+
<br>(5) Other: Other privacy practices that do not fall
|
34 |
+
into the above four categories.</em>
|
35 |
+
<br>
|
36 |
+
<br>Model is trained on PolicyIE dataset. <a href="https://aclanthology.org/2021.acl-long.340/">For more info</a>
|
37 |
+
</p>
|
38 |
+
</div>
|
39 |
+
|
40 |
+
</div>
|
41 |
+
</script>
|
42 |
+
<form class="text-gen-form">
|
43 |
+
<label for="text-gen-input">Text prompt</label>
|
44 |
+
<input
|
45 |
+
id="text-gen-input"
|
46 |
+
contenteditable="true"
|
47 |
+
overflow-y= "scroll"
|
48 |
+
style="height: 30px; width: 700px;"
|
49 |
+
type="text"
|
50 |
+
value="At any time during your use of the Services, you may decide to share some information or content publicly or privately.
|
51 |
+
If you decide to share your information or content publicly, and if you decide to include Personal Information, you understand that anyone may view this information.
|
52 |
+
If you decide to keep your information private and control the access to it, you understand that only the users that you authorize will view this information.
|
53 |
+
The Company also reserves the right to access this information with your consent, or without your consent only for the purposes of pursuing legitimate interests such as maintaining security on its Services or complying with any legal or regulatory obligations."
|
54 |
+
/>
|
55 |
+
<button id="text-gen-submit">Submit</button>
|
56 |
+
<p class="text-gen-output"></p>
|
57 |
+
</form>
|
58 |
+
</section>
|
59 |
+
</main>
|
60 |
+
</body>
|
61 |
+
</html>
|
static/script.js
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const textGenForm = document.querySelector('.text-gen-form');
|
2 |
+
|
3 |
+
const translateText = async (text) => {
|
4 |
+
const inferResponse = await fetch(`infer_intents?input=${text}`);
|
5 |
+
const inferJson = await inferResponse.json();
|
6 |
+
|
7 |
+
return inferJson.output;
|
8 |
+
};
|
9 |
+
|
10 |
+
|
11 |
+
textGenForm.addEventListener('submit', async (event) => {
|
12 |
+
event.preventDefault();
|
13 |
+
|
14 |
+
const textGenInput = document.getElementById('text-gen-input');
|
15 |
+
const textGenParagraph = document.querySelector('.text-gen-output');
|
16 |
+
textGenParagraph.innerHTML = "";
|
17 |
+
try {
|
18 |
+
var object= await translateText(textGenInput.value);
|
19 |
+
|
20 |
+
for (const [key, value] of Object.entries(object)) {
|
21 |
+
textGenParagraph.innerHTML+=(`<span style='color:#0068C9;'> • ${key}</span> : <span style='color:red;'> ${value}</span><br><br>`);
|
22 |
+
}
|
23 |
+
} catch (err) {
|
24 |
+
console.error(err);
|
25 |
+
}
|
26 |
+
});
|
27 |
+
|
28 |
+
// Get the modal
|
29 |
+
var modal = document.getElementById("myModal");
|
30 |
+
|
31 |
+
// Get the button that opens the modal
|
32 |
+
var btn = document.getElementById("myBtn");
|
33 |
+
|
34 |
+
// Get the <span> element that closes the modal
|
35 |
+
var span = document.getElementsByClassName("close")[0];
|
36 |
+
|
37 |
+
// When the user clicks on the button, open the modal
|
38 |
+
btn.onclick = function() {
|
39 |
+
modal.style.display = "block";
|
40 |
+
}
|
41 |
+
|
42 |
+
// When the user clicks on <span> (x), close the modal
|
43 |
+
span.onclick = function() {
|
44 |
+
modal.style.display = "none";
|
45 |
+
}
|
46 |
+
|
47 |
+
// When the user clicks anywhere outside of the modal, close it
|
48 |
+
window.onclick = function(event) {
|
49 |
+
if (event.target == modal) {
|
50 |
+
modal.style.display = "none";
|
51 |
+
}
|
52 |
+
}
|
static/style.css
ADDED
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
--text: hsl(0 0% 15%);
|
3 |
+
padding: 2.5rem;
|
4 |
+
font-family: sans-serif;
|
5 |
+
color: var(--text);
|
6 |
+
}
|
7 |
+
|
8 |
+
body.dark-theme {
|
9 |
+
--text: hsl(0 0% 90%);
|
10 |
+
background-color: hsl(223 39% 7%);
|
11 |
+
}
|
12 |
+
|
13 |
+
main {
|
14 |
+
max-width: 80rem;
|
15 |
+
text-align: left;
|
16 |
+
}
|
17 |
+
|
18 |
+
section {
|
19 |
+
display: flex;
|
20 |
+
flex-direction: column;
|
21 |
+
align-items: center;
|
22 |
+
}
|
23 |
+
|
24 |
+
a {
|
25 |
+
color: var(--text);
|
26 |
+
}
|
27 |
+
|
28 |
+
form {
|
29 |
+
width: 700px;
|
30 |
+
margin: 0 auto;
|
31 |
+
}
|
32 |
+
|
33 |
+
|
34 |
+
button {
|
35 |
+
cursor: pointer;
|
36 |
+
align-items: center;
|
37 |
+
}
|
38 |
+
|
39 |
+
/* */
|
40 |
+
/* Popup container */
|
41 |
+
.popup {
|
42 |
+
position: relative;
|
43 |
+
display: inline-block;
|
44 |
+
cursor: pointer;
|
45 |
+
}
|
46 |
+
|
47 |
+
/* The actual popup (appears on top) */
|
48 |
+
.popup .popuptext {
|
49 |
+
visibility: hidden;
|
50 |
+
width: 160px;
|
51 |
+
background-color: #555;
|
52 |
+
color: #fff;
|
53 |
+
text-align: center;
|
54 |
+
border-radius: 6px;
|
55 |
+
padding: 8px 0;
|
56 |
+
position: absolute;
|
57 |
+
z-index: 1;
|
58 |
+
bottom: 125%;
|
59 |
+
left: 50%;
|
60 |
+
margin-left: -80px;
|
61 |
+
}
|
62 |
+
|
63 |
+
/* Popup arrow */
|
64 |
+
.popup .popuptext::after {
|
65 |
+
content: "";
|
66 |
+
position: absolute;
|
67 |
+
top: 100%;
|
68 |
+
left: 50%;
|
69 |
+
margin-left: -5px;
|
70 |
+
border-width: 5px;
|
71 |
+
border-style: solid;
|
72 |
+
border-color: #555 transparent transparent transparent;
|
73 |
+
}
|
74 |
+
|
75 |
+
/* Toggle this class when clicking on the popup container (hide and show the popup) */
|
76 |
+
.popup .show {
|
77 |
+
visibility: visible;
|
78 |
+
-webkit-animation: fadeIn 1s;
|
79 |
+
animation: fadeIn 1s
|
80 |
+
}
|
81 |
+
|
82 |
+
/* The Modal (background) */
|
83 |
+
.modal {
|
84 |
+
display: none; /* Hidden by default */
|
85 |
+
position: fixed; /* Stay in place */
|
86 |
+
z-index: 1; /* Sit on top */
|
87 |
+
left: 0;
|
88 |
+
top: 0;
|
89 |
+
width: 100%; /* Full width */
|
90 |
+
height: 100%; /* Full height */
|
91 |
+
overflow: auto; /* Enable scroll if needed */
|
92 |
+
background-color: rgb(0,0,0); /* Fallback color */
|
93 |
+
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
94 |
+
}
|
95 |
+
|
96 |
+
/* Modal Content/Box */
|
97 |
+
.modal-content {
|
98 |
+
background-color: #fefefe;
|
99 |
+
margin: 15% auto; /* 15% from the top and centered */
|
100 |
+
padding: 20px;
|
101 |
+
border: 1px solid #888;
|
102 |
+
width: 80%; /* Could be more or less, depending on screen size */
|
103 |
+
}
|
104 |
+
|
105 |
+
/* The Close Button */
|
106 |
+
.close {
|
107 |
+
color: #aaa;
|
108 |
+
float: right;
|
109 |
+
font-size: 28px;
|
110 |
+
font-weight: bold;
|
111 |
+
}
|
112 |
+
|
113 |
+
.close:hover,
|
114 |
+
.close:focus {
|
115 |
+
color: black;
|
116 |
+
text-decoration: none;
|
117 |
+
cursor: pointer;
|
118 |
+
}
|