kavlab commited on
Commit ·
1e7f40c
1
Parent(s): dc4c135
merged with github repo
Browse files- README.md +8 -4
- kuznetsov_av/test_api.py +1 -1
- mulyavin_aa/{PostmanLangDetect.png → screens/PostmanLangDetect.png} +0 -0
- mulyavin_aa/{PostmanTranslate.png → screens/PostmanTranslate.png} +0 -0
- mulyavin_aa/{audio_gen_image.png → screens/audio_gen_image.png} +0 -0
- requirements.txt +2 -1
- api.py → run_api.py +4 -4
- test/test_api.py +151 -0
- zvereva_ev/get_description_image.py +5 -5
README.md
CHANGED
|
@@ -9,7 +9,9 @@ app_file: run.py
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
| 13 |
|
| 14 |
Приложение разработано с использованием фреймворка [Streamlit](https://streamlit.io/).
|
| 15 |
Состоит из двух страниц и Главной страницы:
|
|
@@ -48,7 +50,7 @@ streamlit run run.py
|
|
| 48 |
### Генератор аудио
|
| 49 |
Необходимо ввести текст в текстовое поле и нажать кнопку "Генерировать!!!". В результате появится аудио запись на английском языке с описанием введенного текста.
|
| 50 |
|
| 51 |
-

|
| 52 |

|
| 53 |
|
| 54 |
### Описание изображения
|
|
@@ -65,7 +67,7 @@ streamlit run run.py
|
|
| 65 |
#### Пример вызова сервиса Определение языка текста
|
| 66 |
Вызвать url сервиса ```<host>/langdetector/detect``` методом POST
|
| 67 |
|
| 68 |
-

|
| 69 |
|
| 70 |
Передаваемые параметры:
|
| 71 |
```
|
|
@@ -89,7 +91,7 @@ streamlit run run.py
|
|
| 89 |
#### Пример вызова сервиса Перевод текста с языка Ru на En
|
| 90 |
Вызвать url сервиса ```<host>/translator/translate``` методом POST
|
| 91 |
|
| 92 |
-

|
| 93 |
|
| 94 |
Передаваемые параметры:
|
| 95 |
```
|
|
@@ -137,3 +139,5 @@ streamlit run run.py
|
|
| 137 |
"url": "https://fikiwiki.com/uploads/posts/2022-02/1645000127_53-fikiwiki-com-p-kartinki-krasivie-babochki-narisovannie-55.png"
|
| 138 |
}
|
| 139 |
```
|
|
|
|
|
|
|
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
+
[](https://github.com/kavlab/urfu_iml_2023_1_3_hw2/actions/workflows/python-app.yml)
|
| 13 |
+
|
| 14 |
+
# Программная инженерия. Практические задания №2, №3, №4 и №5
|
| 15 |
|
| 16 |
Приложение разработано с использованием фреймворка [Streamlit](https://streamlit.io/).
|
| 17 |
Состоит из двух страниц и Главной страницы:
|
|
|
|
| 50 |
### Генератор аудио
|
| 51 |
Необходимо ввести текст в текстовое поле и нажать кнопку "Генерировать!!!". В результате появится аудио запись на английском языке с описанием введенного текста.
|
| 52 |
|
| 53 |
+

|
| 54 |

|
| 55 |
|
| 56 |
### Описание изображения
|
|
|
|
| 67 |
#### Пример вызова сервиса Определение языка текста
|
| 68 |
Вызвать url сервиса ```<host>/langdetector/detect``` методом POST
|
| 69 |
|
| 70 |
+

|
| 71 |
|
| 72 |
Передаваемые параметры:
|
| 73 |
```
|
|
|
|
| 91 |
#### Пример вызова сервиса Перевод текста с языка Ru на En
|
| 92 |
Вызвать url сервиса ```<host>/translator/translate``` методом POST
|
| 93 |
|
| 94 |
+

|
| 95 |
|
| 96 |
Передаваемые параметры:
|
| 97 |
```
|
|
|
|
| 139 |
"url": "https://fikiwiki.com/uploads/posts/2022-02/1645000127_53-fikiwiki-com-p-kartinki-krasivie-babochki-narisovannie-55.png"
|
| 140 |
}
|
| 141 |
```
|
| 142 |
+
|
| 143 |
+
Тестирует GitHub Actions
|
kuznetsov_av/test_api.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
from fastapi.testclient import TestClient
|
| 2 |
-
from kuznetsov_av.api import Request,
|
| 3 |
|
| 4 |
client = TestClient(app)
|
| 5 |
|
|
|
|
| 1 |
from fastapi.testclient import TestClient
|
| 2 |
+
from kuznetsov_av.api import Request, app
|
| 3 |
|
| 4 |
client = TestClient(app)
|
| 5 |
|
mulyavin_aa/{PostmanLangDetect.png → screens/PostmanLangDetect.png}
RENAMED
|
File without changes
|
mulyavin_aa/{PostmanTranslate.png → screens/PostmanTranslate.png}
RENAMED
|
File without changes
|
mulyavin_aa/{audio_gen_image.png → screens/audio_gen_image.png}
RENAMED
|
File without changes
|
requirements.txt
CHANGED
|
@@ -10,4 +10,5 @@ fastapi==0.104.1
|
|
| 10 |
uvicorn==0.24.0
|
| 11 |
httpx==0.25.2
|
| 12 |
pillow~=10.1.0
|
| 13 |
-
pydantic~=2.5.2
|
|
|
|
|
|
| 10 |
uvicorn==0.24.0
|
| 11 |
httpx==0.25.2
|
| 12 |
pillow~=10.1.0
|
| 13 |
+
pydantic~=2.5.2
|
| 14 |
+
requests~=2.31.0
|
api.py → run_api.py
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
import uvicorn
|
| 2 |
from fastapi import FastAPI
|
| 3 |
|
|
@@ -37,7 +38,7 @@ async def root():
|
|
| 37 |
},
|
| 38 |
{
|
| 39 |
"descr": "API для описания загруженного изображения",
|
| 40 |
-
"base_url": "/get_description_image"
|
| 41 |
}
|
| 42 |
]}
|
| 43 |
|
|
@@ -75,12 +76,11 @@ async def text_to_speech(entity: Request) -> Response:
|
|
| 75 |
@app.post("/get_description_image/predict/")
|
| 76 |
async def get_description_image_predict(item: develop_api_app.Url):
|
| 77 |
"""
|
| 78 |
-
Получение ссылки на изображение. Запись изображения в ди
|
| 79 |
-
под названием 'image.png для получения его описания
|
| 80 |
"""
|
| 81 |
response = requests.get(item.url, stream=True)
|
| 82 |
# сохранение изображения для дальнейшей передачи в модель
|
| 83 |
-
with open("
|
| 84 |
f.write(response.content)
|
| 85 |
|
| 86 |
return get_description_image.get_description_image()
|
|
|
|
| 1 |
+
import os
|
| 2 |
import uvicorn
|
| 3 |
from fastapi import FastAPI
|
| 4 |
|
|
|
|
| 38 |
},
|
| 39 |
{
|
| 40 |
"descr": "API для описания загруженного изображения",
|
| 41 |
+
"base_url": "/get_description_image/predict/"
|
| 42 |
}
|
| 43 |
]}
|
| 44 |
|
|
|
|
| 76 |
@app.post("/get_description_image/predict/")
|
| 77 |
async def get_description_image_predict(item: develop_api_app.Url):
|
| 78 |
"""
|
| 79 |
+
Получение ссылки на изображение. Запись изображения под названием 'image_predict_test_image.png для получения его описания
|
|
|
|
| 80 |
"""
|
| 81 |
response = requests.get(item.url, stream=True)
|
| 82 |
# сохранение изображения для дальнейшей передачи в модель
|
| 83 |
+
with open(f"{os.path.dirname(__file__)}/zvereva_ev/image_predict_tmp.png", "wb") as f:
|
| 84 |
f.write(response.content)
|
| 85 |
|
| 86 |
return get_description_image.get_description_image()
|
test/test_api.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import kuznetsov_av
|
| 2 |
+
from fastapi.testclient import TestClient
|
| 3 |
+
from run_api import app
|
| 4 |
+
|
| 5 |
+
client = TestClient(app)
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def test_get_description_image_predict() -> None:
|
| 9 |
+
"""
|
| 10 |
+
Тест API Описание загруженного изображения
|
| 11 |
+
"""
|
| 12 |
+
from zvereva_ev.develop_api_app import Url
|
| 13 |
+
|
| 14 |
+
response = client.post(
|
| 15 |
+
url="/get_description_image/predict/",
|
| 16 |
+
json=Url(url="https://fikiwiki.com/uploads/posts/2022-02/1645000127_53-"
|
| 17 |
+
"fikiwiki-com-p-kartinki-krasivie-babochki"
|
| 18 |
+
"-narisovannie-55.png"
|
| 19 |
+
).model_dump())
|
| 20 |
+
|
| 21 |
+
assert response.status_code == 200
|
| 22 |
+
assert response.text == '"Фото бабочки с оранжевыми крыльями и белыми точками"'
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def test_langdetector_api_ru() -> None:
|
| 26 |
+
"""
|
| 27 |
+
Тест API определения языка текста RU (mulyavin_aa)
|
| 28 |
+
"""
|
| 29 |
+
import mulyavin_aa.model.langdetector
|
| 30 |
+
|
| 31 |
+
api_resp = client.post(
|
| 32 |
+
url="/langdetector/detect",
|
| 33 |
+
json=mulyavin_aa.model.langdetector.Request(
|
| 34 |
+
text='Доброго дня всем котам!').model_dump())
|
| 35 |
+
|
| 36 |
+
response = mulyavin_aa.model.langdetector.Response.model_validate_json(api_resp.text)
|
| 37 |
+
|
| 38 |
+
assert api_resp.status_code == 200
|
| 39 |
+
assert len(response.langs) > 0
|
| 40 |
+
assert response.langs[0].label == 'ru'
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def test_langdetector_api_en() -> None:
|
| 44 |
+
"""
|
| 45 |
+
Тест API определения языка текста EN (mulyavin_aa)
|
| 46 |
+
"""
|
| 47 |
+
import mulyavin_aa.model.langdetector
|
| 48 |
+
|
| 49 |
+
api_resp = client.post(
|
| 50 |
+
url="/langdetector/detect",
|
| 51 |
+
json=mulyavin_aa.model.langdetector.Request(
|
| 52 |
+
text='So I checked functions in the class model').model_dump())
|
| 53 |
+
|
| 54 |
+
response = mulyavin_aa.model.langdetector.Response.model_validate_json(api_resp.text)
|
| 55 |
+
|
| 56 |
+
assert api_resp.status_code == 200
|
| 57 |
+
assert len(response.langs) > 0
|
| 58 |
+
assert response.langs[0].label == 'en'
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def test_langdetector_api_err() -> None:
|
| 62 |
+
"""
|
| 63 |
+
Тест API определения языка текста не Ru и En (mulyavin_aa)
|
| 64 |
+
Модель не ограничена только Ru и En
|
| 65 |
+
"""
|
| 66 |
+
import mulyavin_aa.model.langdetector
|
| 67 |
+
|
| 68 |
+
api_resp = client.post(
|
| 69 |
+
url="/langdetector/detect",
|
| 70 |
+
json=mulyavin_aa.model.langdetector.Request(
|
| 71 |
+
text='').model_dump())
|
| 72 |
+
|
| 73 |
+
response = mulyavin_aa.model.langdetector.Response.model_validate_json(api_resp.text)
|
| 74 |
+
|
| 75 |
+
assert api_resp.status_code == 200
|
| 76 |
+
assert len(response.langs) > 0
|
| 77 |
+
assert response.langs[0].label != 'en'
|
| 78 |
+
assert response.langs[0].label != 'ru'
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def test_translator_ru_to_en() -> None:
|
| 82 |
+
"""
|
| 83 |
+
Тест API Перевод текста с языка Ru на En (mulyavin_aa)
|
| 84 |
+
"""
|
| 85 |
+
import mulyavin_aa.model.translator
|
| 86 |
+
|
| 87 |
+
api_resp = client.post(
|
| 88 |
+
url="/translator/translate",
|
| 89 |
+
json=mulyavin_aa.model.translator.Request(
|
| 90 |
+
text='Доброго деня всем котам!').model_dump())
|
| 91 |
+
|
| 92 |
+
response = mulyavin_aa.model.translator.Response.model_validate_json(api_resp.text)
|
| 93 |
+
|
| 94 |
+
assert api_resp.status_code == 200
|
| 95 |
+
assert len(response.text) > 0
|
| 96 |
+
assert response.text == 'Good day to all cats!'
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def test_translator_en_to_en() -> None:
|
| 100 |
+
"""
|
| 101 |
+
Тест API Перевод текста с языка En на En (mulyavin_aa)
|
| 102 |
+
"""
|
| 103 |
+
import mulyavin_aa.model.translator
|
| 104 |
+
|
| 105 |
+
api_resp = client.post(
|
| 106 |
+
url="/translator/translate",
|
| 107 |
+
json=mulyavin_aa.model.translator.Request(
|
| 108 |
+
text='Good day to all cats!').model_dump())
|
| 109 |
+
|
| 110 |
+
response = mulyavin_aa.model.translator.Response.model_validate_json(api_resp.text)
|
| 111 |
+
|
| 112 |
+
assert api_resp.status_code == 200
|
| 113 |
+
assert len(response.text) > 0
|
| 114 |
+
assert response.text == 'Good day to all cats!'
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def test_text_to_speech_ok():
|
| 118 |
+
"""
|
| 119 |
+
Тест API преобразования текста в речь
|
| 120 |
+
"""
|
| 121 |
+
response = client.post(
|
| 122 |
+
url='/text-to-speech/convert/',
|
| 123 |
+
json=kuznetsov_av.api.Request(text='Test').model_dump()
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
assert response.status_code == 200
|
| 127 |
+
assert response.json().get('audio') is not None
|
| 128 |
+
assert type(response.json().get('audio')) == str
|
| 129 |
+
assert len(response.json().get('audio')) > 0
|
| 130 |
+
assert response.json().get('sampling_rate') is not None
|
| 131 |
+
assert type(response.json().get('sampling_rate')) == int
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def test_text_to_speech_error422():
|
| 135 |
+
"""
|
| 136 |
+
Тест API преобразования текста в речь
|
| 137 |
+
"""
|
| 138 |
+
response = client.post(
|
| 139 |
+
url='/text-to-speech/convert/',
|
| 140 |
+
json=''
|
| 141 |
+
)
|
| 142 |
+
|
| 143 |
+
assert response.status_code == 422
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def test_root():
|
| 147 |
+
response = client.get('/')
|
| 148 |
+
|
| 149 |
+
assert response.status_code == 200
|
| 150 |
+
assert response.json().get('message') is not None
|
| 151 |
+
assert len(response.json().get('message')) > 0
|
zvereva_ev/get_description_image.py
CHANGED
|
@@ -20,7 +20,7 @@ def load_image():
|
|
| 20 |
st.image(image_data)
|
| 21 |
image_data_open = Image.open(io.BytesIO(image_data))
|
| 22 |
# Сохранение изображения из буффера
|
| 23 |
-
image_data_open.save("
|
| 24 |
return image_data_open
|
| 25 |
else:
|
| 26 |
return None
|
|
@@ -39,7 +39,7 @@ def get_description_image():
|
|
| 39 |
"""
|
| 40 |
processor, model = load_models()
|
| 41 |
|
| 42 |
-
raw_image = Image.open("
|
| 43 |
|
| 44 |
text = "a photography of"
|
| 45 |
inputs = processor(raw_image, text, return_tensors="pt")
|
|
@@ -53,7 +53,7 @@ def get_description_image():
|
|
| 53 |
|
| 54 |
|
| 55 |
# Получение полного пути к сохраненному изображению из буффера
|
| 56 |
-
file_path = "
|
| 57 |
absolute_path = os.path.abspath(file_path)
|
| 58 |
|
| 59 |
|
|
@@ -71,7 +71,7 @@ def run_():
|
|
| 71 |
st.warning("Загрузите изображение, чтобы получить описание", icon="🚀")
|
| 72 |
else:
|
| 73 |
exit()
|
| 74 |
-
if "
|
| 75 |
-
os.remove("
|
| 76 |
except FileNotFoundError:
|
| 77 |
return "Изображение не загружено"
|
|
|
|
| 20 |
st.image(image_data)
|
| 21 |
image_data_open = Image.open(io.BytesIO(image_data))
|
| 22 |
# Сохранение изображения из буффера
|
| 23 |
+
image_data_open.save(f"{os.path.dirname(__file__)}/image_predict_tmp.png")
|
| 24 |
return image_data_open
|
| 25 |
else:
|
| 26 |
return None
|
|
|
|
| 39 |
"""
|
| 40 |
processor, model = load_models()
|
| 41 |
|
| 42 |
+
raw_image = Image.open(f"{os.path.dirname(__file__)}/image_predict_tmp.png")
|
| 43 |
|
| 44 |
text = "a photography of"
|
| 45 |
inputs = processor(raw_image, text, return_tensors="pt")
|
|
|
|
| 53 |
|
| 54 |
|
| 55 |
# Получение полного пути к сохраненному изображению из буффера
|
| 56 |
+
file_path = f"{os.path.dirname(__file__)}/image_predict_tmp.png"
|
| 57 |
absolute_path = os.path.abspath(file_path)
|
| 58 |
|
| 59 |
|
|
|
|
| 71 |
st.warning("Загрузите изображение, чтобы получить описание", icon="🚀")
|
| 72 |
else:
|
| 73 |
exit()
|
| 74 |
+
if f"{os.path.dirname(__file__)}/image_predict_tmp.png" in absolute_path:
|
| 75 |
+
os.remove(f"{os.path.dirname(__file__)}/image_predict_tmp.png")
|
| 76 |
except FileNotFoundError:
|
| 77 |
return "Изображение не загружено"
|