asFrants commited on
Commit
d95cbea
1 Parent(s): f2f5171

add new files for docker and fast api

Browse files
Files changed (11) hide show
  1. .vscode/settings.json +16 -0
  2. Dockerfile +38 -0
  3. LICENSE +21 -0
  4. app.py +9 -21
  5. docker-compose.yml +29 -0
  6. main.py +42 -34
  7. run.py +9 -0
  8. static/css/style.css +64 -0
  9. templates/error.html +11 -0
  10. templates/home.html +11 -0
  11. tox.ini +5 -0
.vscode/settings.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "python.linting.pylint" : false,
3
+ "python.linting.flake8" : true,
4
+ "python.linting.enabled" : true,
5
+ "python.formatting.black" : true,
6
+ "editor.formatOnSave": true,
7
+ "python.linting.flake8Args":[
8
+ "--max-line-length=88"
9
+ ],
10
+ "python.testing.unittestEnabled": false,
11
+ "python.testing.pytestEnabled": true,
12
+ "python.testing.autoTestDiscoverOnSaveEnabled": true,
13
+ "python.testing.pytestArgs": [
14
+ "tests"
15
+ ],
16
+ }
Dockerfile ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim as builder
2
+
3
+ # set environment variables
4
+ ENV PYTHONDONTWRITEBYTECODE=1 \
5
+ PYTHONFAULTHANDLER=1 \
6
+ PYTHONUNBUFFERED=1
7
+ ENV POETRY_NO_INTERACTION=1 \
8
+ POETRY_VIRTUALENVS_IN_PROJECT=1 \
9
+ POETRY_VIRTUALENVS_CREATE=1 \
10
+ POETRY_CACHE_DIR=/tmp/poetry_cache
11
+
12
+ RUN mkdir -p /app
13
+ WORKDIR /app
14
+ RUN pip install poetry
15
+ COPY poetry.lock pyproject.toml ./
16
+ RUN --mount=type=cache,target=$POETRY_CACHE_DIR poetry install --no-root
17
+
18
+
19
+ FROM python:3.10-slim as base
20
+
21
+ ENV PYTHONDONTWRITEBYTECODE=1 \
22
+ PYTHONFAULTHANDLER=1 \
23
+ PYTHONUNBUFFERED=1
24
+
25
+ RUN apt-get update && apt-get install -y curl
26
+ WORKDIR /app
27
+ ENV VIRTUAL_ENV=/app/.venv \
28
+ PATH="/app/.venv/bin:$PATH"
29
+
30
+ COPY --from=builder /app/.venv /app/.venv
31
+
32
+ # Necessary Files
33
+ COPY main.py app.py /app/
34
+
35
+ # Expose port
36
+ EXPOSE 8000
37
+
38
+ CMD ["uvicorn","main:app","--proxy-headers","--host","0.0.0.0","--port","8000","--workers","3"]
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Alexander Frantsev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
app.py CHANGED
@@ -75,10 +75,10 @@ class Summarizer():
75
  self.ru_sentiment_pipe = pipeline("sentiment-analysis", model=RU_SENTIMENT_MODEL)
76
  self.en_summary_pipe = sum_pipe
77
  self.en_sentiment_pipe = pipeline("sentiment-analysis", model=EN_SENTIMENT_MODEL)
78
-
79
-
80
- def mT5_summarize(self, text: str) -> str:
81
 
 
 
 
82
  WHITESPACE_HANDLER = lambda k: re.sub('\s+', ' ', re.sub('\n+', ' ', k.strip()))
83
 
84
  input_ids = self.sum_tokenizer(
@@ -111,23 +111,8 @@ class Summarizer():
111
  sentiment = {'en': self.en_sentiment_pipe,
112
  'ru': self.ru_sentiment_pipe,}
113
  return summary[lang], sentiment[lang]
114
-
115
- # def summarize(self, text: str, lang: str = 'en') -> str:
116
- # result = {}
117
- # sum_pipe, sent_pipe = self.get_pipe(lang)
118
-
119
- # response_summary = sum_pipe(text)
120
- # logger.info(response_summary)
121
- # result["summary"] = response_summary[0]["summary_text"]
122
-
123
- # response_sentiment = sent_pipe(text)
124
- # logger.info(response_sentiment)
125
- # result["sentiment_label"] = response_sentiment[0]["label"]
126
- # result["sentiment_score"] = response_sentiment[0]["score"]
127
-
128
- # return f"Summary: {result['summary']}\n Sentiment: {result['sentiment_label']} ({result['sentiment_score']:.3f})"
129
 
130
- def summarize(self, text: Request, lang: str = 'en') -> str:
131
  sum_pipe, sent_pipe = self.get_pipe(lang)
132
  response_summary = sum_pipe(text)
133
  logger.info(response_summary)
@@ -139,6 +124,9 @@ class Summarizer():
139
  sentiment_score=response_sentiment[0]["score"],
140
  )
141
  return result
 
 
 
142
 
143
  if __name__ == "__main__":
144
  pipe = Summarizer()
@@ -161,12 +149,12 @@ if __name__ == "__main__":
161
  ru_inbtn = gr.Button("Запустить")
162
 
163
  en_inbtn.click(
164
- pipe.summarize.to_str(),
165
  [en_inputs, en_lang],
166
  [en_outputs],
167
  )
168
  ru_inbtn.click(
169
- pipe.summarize.to_str(),
170
  [ru_inputs, ru_lang],
171
  [ru_outputs],
172
  )
 
75
  self.ru_sentiment_pipe = pipeline("sentiment-analysis", model=RU_SENTIMENT_MODEL)
76
  self.en_summary_pipe = sum_pipe
77
  self.en_sentiment_pipe = pipeline("sentiment-analysis", model=EN_SENTIMENT_MODEL)
 
 
 
78
 
79
+ def mT5_summarize(self, text: str) -> str:
80
+ '''Handle text with mT5 model without pipeline'''
81
+
82
  WHITESPACE_HANDLER = lambda k: re.sub('\s+', ' ', re.sub('\n+', ' ', k.strip()))
83
 
84
  input_ids = self.sum_tokenizer(
 
111
  sentiment = {'en': self.en_sentiment_pipe,
112
  'ru': self.ru_sentiment_pipe,}
113
  return summary[lang], sentiment[lang]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
+ def summarize(self, text: Request, lang: str = 'en') -> Result:
116
  sum_pipe, sent_pipe = self.get_pipe(lang)
117
  response_summary = sum_pipe(text)
118
  logger.info(response_summary)
 
124
  sentiment_score=response_sentiment[0]["score"],
125
  )
126
  return result
127
+
128
+ def summ(self, text: Request, lang: str = 'en') -> str:
129
+ return self.summarize(text, lang).to_str()
130
 
131
  if __name__ == "__main__":
132
  pipe = Summarizer()
 
149
  ru_inbtn = gr.Button("Запустить")
150
 
151
  en_inbtn.click(
152
+ pipe.summ,
153
  [en_inputs, en_lang],
154
  [en_outputs],
155
  )
156
  ru_inbtn.click(
157
+ pipe.summ,
158
  [ru_inputs, ru_lang],
159
  [ru_outputs],
160
  )
docker-compose.yml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+ services:
3
+ app:
4
+ container_name: summary-app
5
+ restart: unless-stopped
6
+ # env_file:
7
+ # - .env
8
+ # environment:
9
+ # PGHOST: 'db'
10
+ # PGDATABASE: ${DATABASE_NAME}
11
+ # PGUSER: ${DATABASE_USER}
12
+ # PGPASSWORD: ${DATABASE_PASS}
13
+ build:
14
+ context: .
15
+ dockerfile: Dockerfile
16
+ ports:
17
+ - "8000:8000"
18
+ expose:
19
+ - 8000
20
+ healthcheck:
21
+ test: curl --fail -s http://localhost:8000/ || exit 1
22
+ interval: 10s
23
+ timeout: 5s
24
+ retries: 3
25
+ start_period: 10s
26
+ command: ["uvicorn","main:app","--proxy-headers","--host","0.0.0.0","--port","8000","--workers","3"]
27
+
28
+
29
+
main.py CHANGED
@@ -8,40 +8,48 @@ from app import DEFAULT_EN_TEXT, DEFAULT_RU_TEXT
8
  app = FastAPI()
9
  pipe = Summarizer()
10
 
11
-
12
  @app.post("/summ_ru", response_model=Result)
13
  async def ru_summ_api(request: Request):
14
- results = pipe.summarize(request.text)
 
 
 
 
 
 
 
15
  return results
16
-
17
-
18
- if __name__ == "__main__":
19
-
20
- with gr.Blocks() as demo:
21
- with gr.Row():
22
- with gr.Column(scale=2, min_width=600):
23
- en_sum_description=gr.Markdown(value=f"Model for Summary: {EN_SUMMARY_MODEL}")
24
- en_sent_description=gr.Markdown(value=f"Model for Sentiment: {EN_SENTIMENT_MODEL}")
25
- en_inputs=gr.Textbox(label="en_input", lines=5, value=DEFAULT_EN_TEXT, placeholder=DEFAULT_EN_TEXT)
26
- en_lang=gr.Textbox(value='en',visible=False)
27
- en_outputs=gr.Textbox(label="en_output", lines=5, placeholder="Summary and Sentiment would be here...")
28
- en_inbtn = gr.Button("Proceed")
29
- with gr.Column(scale=2, min_width=600):
30
- ru_sum_description=gr.Markdown(value=f"Model for Summary: {RU_SUMMARY_MODEL}")
31
- ru_sent_description=gr.Markdown(value=f"Model for Sentiment: {RU_SENTIMENT_MODEL}")
32
- ru_inputs=gr.Textbox(label="ru_input", lines=5, value=DEFAULT_RU_TEXT, placeholder=DEFAULT_RU_TEXT)
33
- ru_lang=gr.Textbox(value='ru',visible=False)
34
- ru_outputs=gr.Textbox(label="ru_output", lines=5, placeholder="Здесь будет обобщение и эмоциональный окрас текста...")
35
- ru_inbtn = gr.Button("Запустить")
36
-
37
- en_inbtn.click(
38
- pipe.summarize.to_str(),
39
- [en_inputs, en_lang],
40
- [en_outputs],
41
- )
42
- ru_inbtn.click(
43
- pipe.summarize.to_str(),
44
- [ru_inputs, ru_lang],
45
- [ru_outputs],
46
- )
47
- demo.launch(show_api=False)
 
 
 
8
  app = FastAPI()
9
  pipe = Summarizer()
10
 
 
11
  @app.post("/summ_ru", response_model=Result)
12
  async def ru_summ_api(request: Request):
13
+ results = pipe.summarize(request.text, lang='ru')
14
+ return results
15
+
16
+
17
+
18
+ @app.post("/summ_en", response_model=Result)
19
+ async def ru_summ_api(request: Request):
20
+ results = pipe.summarize(request.text, lang='en')
21
  return results
22
+
23
+
24
+ with gr.Blocks() as demo:
25
+ with gr.Row():
26
+ with gr.Column(scale=2, min_width=600):
27
+ en_sum_description=gr.Markdown(value=f"Model for Summary: {EN_SUMMARY_MODEL}")
28
+ en_sent_description=gr.Markdown(value=f"Model for Sentiment: {EN_SENTIMENT_MODEL}")
29
+ en_inputs=gr.Textbox(label="en_input", lines=5, value=DEFAULT_EN_TEXT, placeholder=DEFAULT_EN_TEXT)
30
+ en_lang=gr.Textbox(value='en',visible=False)
31
+ en_outputs=gr.Textbox(label="en_output", lines=5, placeholder="Summary and Sentiment would be here...")
32
+ en_inbtn = gr.Button("Proceed")
33
+ with gr.Column(scale=2, min_width=600):
34
+ ru_sum_description=gr.Markdown(value=f"Model for Summary: {RU_SUMMARY_MODEL}")
35
+ ru_sent_description=gr.Markdown(value=f"Model for Sentiment: {RU_SENTIMENT_MODEL}")
36
+ ru_inputs=gr.Textbox(label="ru_input", lines=5, value=DEFAULT_RU_TEXT, placeholder=DEFAULT_RU_TEXT)
37
+ ru_lang=gr.Textbox(value='ru',visible=False)
38
+ ru_outputs=gr.Textbox(label="ru_output", lines=5, placeholder="Здесь будет обобщение и эмоциональный окрас текста...")
39
+ ru_inbtn = gr.Button("Запустить")
40
+
41
+ en_inbtn.click(
42
+ pipe.summ,
43
+ [en_inputs, en_lang],
44
+ [en_outputs],
45
+ )
46
+ ru_inbtn.click(
47
+ pipe.summ,
48
+ [ru_inputs, ru_lang],
49
+ [ru_outputs],
50
+ )
51
+
52
+ # demo.launch(show_api=False)
53
+
54
+ # mounting at the root path
55
+ app = gr.mount_gradio_app(app, demo, path="/")
run.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import uvicorn
2
+
3
+ if __name__ == "__main__":
4
+ uvicorn.run(
5
+ app="main:app",
6
+ host="localhost",
7
+ port=8000,
8
+ reload=True
9
+ )
static/css/style.css ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ display: flex;
3
+ justify-content: center;
4
+ align-items: center;
5
+ height: 100vh;
6
+ margin: 0;
7
+ background-color: #f0f0f0;
8
+ font-family: Arial, sans-serif;
9
+ }
10
+
11
+ .container {
12
+ height: 50vh;
13
+ width: 25vw;
14
+ display: flex;
15
+ padding-block: 2rem;
16
+ justify-content: space-between;
17
+ flex-direction: column;
18
+ align-items: center;
19
+ border: 1px solid #47616c;
20
+ border-radius: 12px;
21
+ }
22
+
23
+ .header {
24
+ display: flex;
25
+ flex-direction: column;
26
+ align-items: center;
27
+ }
28
+
29
+ .img-box {
30
+ width: 70px;
31
+ height: 70px;
32
+ border-radius: 50%;
33
+ overflow: hidden;
34
+ }
35
+
36
+ .img {
37
+ width: 100%;
38
+ }
39
+
40
+ .google-btn {
41
+ display: flex;
42
+ align-items: center;
43
+ background-color: #47616c;
44
+ color: white;
45
+ width: 200px;
46
+ height: 50px;
47
+ border-radius: 5px;
48
+ box-shadow: 0px 3px 10px -2px rgba(0, 0, 0, 0.15);
49
+ overflow: hidden;
50
+ padding-inline: 8px;
51
+ text-decoration: none;
52
+ }
53
+
54
+ .google-icon {
55
+ background: url("https://upload.wikimedia.org/wikipedia/commons/5/53/Google_%22G%22_Logo.svg") transparent 5px 50% no-repeat;
56
+ display: inline-block;
57
+ vertical-align: middle;
58
+ width: 35px;
59
+ height: 50px;
60
+ }
61
+
62
+ .btn-text {
63
+ margin-left: 10px;
64
+ }
templates/error.html ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
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>Error</title>
7
+ </head>
8
+ <body>
9
+ <h2>{{error}}</h2>
10
+ </body>
11
+ </html>
templates/home.html ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8"/>
5
+ <link rel="stylesheet" href="{{ url_for('static',path='/css/style.css')}}"/>
6
+ <title>Home Page</title>
7
+ </head>
8
+ <body>
9
+ <h1>Welcome!</h1>
10
+ </body>
11
+ </html>
tox.ini ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ [flake8]
2
+ exclude = .git, __pycache__, env, .venv
3
+ max-line-length = 88
4
+ max-complexity = 18
5
+ extend-ignore = E203, E266, E501, W503