hello
Browse files- .github/workflows/build-push.yml +25 -0
- .gitignore +1 -0
- .vscode/settings.json +3 -0
- App/Analytics/AnalyticsRoutes.py +7 -0
- App/Analytics/Model.py +23 -0
- App/Analytics/Schemas.py +13 -0
- App/Authentication.py +4 -0
- App/Settings.py +3 -0
- App/Transcription/Model.py +21 -0
- App/Transcription/Schemas.py +8 -0
- App/Transcription/TranscriptionRoutes.py +38 -0
- App/Transcription/Utils/audio_transcription.py +42 -0
- App/Users/Model.py +28 -0
- App/Users/Schemas.py +15 -0
- App/Users/UserRoutes.py +28 -0
- App/Worker.py +13 -0
- App/__init__.py +0 -0
- App/app.py +30 -0
- App/celery_config.py +21 -0
- App/modelInit.py +22 -0
- App/utils.py +17 -0
- Dockerfile +20 -0
- README.md +1 -11
- data.txt +1 -0
- okteto-stack.yaml +16 -0
- requirements.txt +26 -0
- stress_test.py +30 -0
.github/workflows/build-push.yml
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Build and Push Docker Image
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches: [main]
|
6 |
+
|
7 |
+
env:
|
8 |
+
IMAGE_NAME: mbonea/trannybrickleberry
|
9 |
+
|
10 |
+
jobs:
|
11 |
+
build-and-push:
|
12 |
+
runs-on: ubuntu-latest
|
13 |
+
steps:
|
14 |
+
- uses: actions/checkout@v2
|
15 |
+
- name: Login to Docker Hub
|
16 |
+
uses: docker/login-action@v1
|
17 |
+
with:
|
18 |
+
username: ${{ secrets.DOCKER_USERNAME }}
|
19 |
+
password: ${{ secrets.DOCKER_PASSWORD }}
|
20 |
+
- name: Build and Push
|
21 |
+
uses: docker/build-push-action@v2
|
22 |
+
with:
|
23 |
+
context: .
|
24 |
+
push: true
|
25 |
+
tags: ${{ env.IMAGE_NAME }}:latest
|
.gitignore
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
*.pyc
|
.vscode/settings.json
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cSpell.words": ["websockets"]
|
3 |
+
}
|
App/Analytics/AnalyticsRoutes.py
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import APIRouter, status
|
2 |
+
from .Schemas import BaseRequest, editRequest
|
3 |
+
from .Model import Comments
|
4 |
+
from App.Users.Model import User
|
5 |
+
from App.Post.Model import Post
|
6 |
+
|
7 |
+
analytics_router = APIRouter(tags=["Analytics"])
|
App/Analytics/Model.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import orm
|
3 |
+
import psycopg2
|
4 |
+
import datetime
|
5 |
+
import pydantic
|
6 |
+
from App.modelInit import database, models
|
7 |
+
from App.Users.Model import User
|
8 |
+
|
9 |
+
|
10 |
+
class Analytics(orm.Model):
|
11 |
+
tablename = "Analytics"
|
12 |
+
registry = models
|
13 |
+
fields = {
|
14 |
+
"id": orm.Integer(primary_key=True),
|
15 |
+
"user": orm.ForeignKey(
|
16 |
+
User, on_delete=orm.CASCADE, allow_null=True
|
17 |
+
), # Optional for unknown users.
|
18 |
+
"post": orm.ForeignKey(User, on_delete=orm.CASCADE),
|
19 |
+
"ip": orm.String(max_length=100),
|
20 |
+
"device": orm.String(max_length=100),
|
21 |
+
"country": orm.String(max_length=100),
|
22 |
+
"createdAt": orm.DateTime(index=True, default=datetime.datetime.now),
|
23 |
+
}
|
App/Analytics/Schemas.py
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import List, Optional
|
2 |
+
from pydantic import EmailStr, BaseModel
|
3 |
+
from datetime import date, datetime, time, timedelta
|
4 |
+
|
5 |
+
|
6 |
+
class BaseRequest(BaseModel):
|
7 |
+
user: Optional[int]
|
8 |
+
id: Optional[int]
|
9 |
+
content: Optional[str]
|
10 |
+
|
11 |
+
|
12 |
+
class editRequest(BaseRequest):
|
13 |
+
updatedAt: datetime = datetime.now()
|
App/Authentication.py
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import APIRouter, status
|
2 |
+
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
3 |
+
|
4 |
+
oauth_scheme = OAuth2PasswordBearer(tokenUrl="/user/login")
|
App/Settings.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
class Settings:
|
2 |
+
ALGORITHM = "HS256"
|
3 |
+
HASH = "86c5ceb27e1bf441130299c0209e5f35b88089f62c06b2b09d65772274f12057"
|
App/Transcription/Model.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import orm
|
3 |
+
import psycopg2
|
4 |
+
import datetime
|
5 |
+
import ujson
|
6 |
+
import pydantic
|
7 |
+
from passlib.context import CryptContext
|
8 |
+
from App.modelInit import database, models
|
9 |
+
|
10 |
+
|
11 |
+
class Transcriptions(orm.Model):
|
12 |
+
tablename = "transcriptions"
|
13 |
+
registry = models
|
14 |
+
fields = {
|
15 |
+
"id": orm.Integer(primary_key=True),
|
16 |
+
"tl_file_id": orm.String(max_length=100, index=True, default=""),
|
17 |
+
"user": orm.ForeignKey(User, on_delete=orm.CASCADE),
|
18 |
+
"createdAt": orm.DateTime(index=True, default=datetime.datetime.now),
|
19 |
+
"content": orm.JSON(default={}),
|
20 |
+
"transcription_state": orm.String(max_length=100, index=True, default="qued"),
|
21 |
+
}
|
App/Transcription/Schemas.py
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import List, Optional
|
2 |
+
from pydantic import EmailStr, BaseModel
|
3 |
+
from passlib.context import CryptContext
|
4 |
+
from fastapi import UploadFile
|
5 |
+
|
6 |
+
|
7 |
+
class UserDetails(BaseModel):
|
8 |
+
userId: str
|
App/Transcription/TranscriptionRoutes.py
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import APIRouter, status, Form, UploadFile, File
|
2 |
+
from typing_extensions import Annotated
|
3 |
+
from .Schemas import UserDetails
|
4 |
+
import aiofiles
|
5 |
+
from celery.result import AsyncResult
|
6 |
+
from App.Worker import transcription_task
|
7 |
+
|
8 |
+
# from .Model import User
|
9 |
+
# from sqlalchemy import and_
|
10 |
+
|
11 |
+
|
12 |
+
transcription_router = APIRouter(tags=["User"])
|
13 |
+
|
14 |
+
|
15 |
+
@transcription_router.post("/uploadfile/")
|
16 |
+
async def create_file(file: UploadFile, userId: int = 1):
|
17 |
+
# Read the file contents
|
18 |
+
contents = await file.read()
|
19 |
+
|
20 |
+
# Write the file to disk asynchronously
|
21 |
+
async with aiofiles.open(file.filename, "wb") as f:
|
22 |
+
await f.write(contents)
|
23 |
+
|
24 |
+
# celery task
|
25 |
+
task = transcription_task.delay(file.filename)
|
26 |
+
|
27 |
+
return {"file_size": file.size, "file_name": file.filename, "task_id": task.id}
|
28 |
+
|
29 |
+
|
30 |
+
@transcription_router.get("/tasks/{task_id}")
|
31 |
+
async def get_status(task_id):
|
32 |
+
task_result = AsyncResult(task_id)
|
33 |
+
result = {
|
34 |
+
"task_id": task_id,
|
35 |
+
"task_status": task_result.status,
|
36 |
+
"task_result": task_result.result,
|
37 |
+
}
|
38 |
+
return result
|
App/Transcription/Utils/audio_transcription.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from faster_whisper import WhisperModel
|
2 |
+
from tqdm import tqdm
|
3 |
+
import os
|
4 |
+
|
5 |
+
model_size = "tiny"
|
6 |
+
|
7 |
+
|
8 |
+
def transcribe_file(state, file_path, model_size="tiny"):
|
9 |
+
result = {}
|
10 |
+
model = WhisperModel(model_size, device="cpu", compute_type="int8")
|
11 |
+
segments, info = model.transcribe(file_path, beam_size=5)
|
12 |
+
|
13 |
+
total_duration = round(info.duration, 2)
|
14 |
+
state.update_state(
|
15 |
+
state="PROGRESS",
|
16 |
+
meta={
|
17 |
+
"logs": "Detected language '%s' with probability %f"
|
18 |
+
% (info.language, info.language_probability),
|
19 |
+
},
|
20 |
+
)
|
21 |
+
|
22 |
+
|
23 |
+
with tqdm(total=total_duration, unit=" seconds") as pbar:
|
24 |
+
for segment in segments:
|
25 |
+
segment_duration = segment.end - segment.start
|
26 |
+
time_stamp = "[%.2fs -> %.2fs]" % (segment.start, segment.end)
|
27 |
+
result[time_stamp] = segment.text
|
28 |
+
state.update_state(
|
29 |
+
state="PROGRESS",
|
30 |
+
meta={
|
31 |
+
"done": segment.end,
|
32 |
+
"total": total_duration,
|
33 |
+
"percentage": f"{((segment.end / total_duration)*100)}",
|
34 |
+
},
|
35 |
+
)
|
36 |
+
pbar.update(segment_duration)
|
37 |
+
|
38 |
+
#delete file
|
39 |
+
os.remove(file_path)
|
40 |
+
|
41 |
+
|
42 |
+
return result
|
App/Users/Model.py
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import orm
|
3 |
+
import psycopg2
|
4 |
+
import datetime
|
5 |
+
import pydantic
|
6 |
+
from passlib.context import CryptContext
|
7 |
+
from App.modelInit import database, models
|
8 |
+
|
9 |
+
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
10 |
+
|
11 |
+
|
12 |
+
class User(orm.Model):
|
13 |
+
tablename = "users"
|
14 |
+
registry = models
|
15 |
+
fields = {
|
16 |
+
"id": orm.Integer(primary_key=True),
|
17 |
+
"name": orm.String(max_length=100, index=True),
|
18 |
+
"email": orm.String(max_length=100, index=True, unique=True),
|
19 |
+
"password": orm.String(max_length=100, index=True),
|
20 |
+
"phoneNumber": orm.String(max_length=100, index=True, allow_null=True),
|
21 |
+
"account_type": orm.Integer(index=True, default=1),
|
22 |
+
"createdAt": orm.DateTime(index=True, default=datetime.datetime.now),
|
23 |
+
"updatedAt": orm.DateTime(index=True, default=datetime.datetime.now),
|
24 |
+
"lastLogin": orm.DateTime(index=True, default=datetime.datetime.now),
|
25 |
+
}
|
26 |
+
|
27 |
+
def verify_password(self, plain_password):
|
28 |
+
return pwd_context.verify(plain_password, self.password)
|
App/Users/Schemas.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import List, Optional
|
2 |
+
from pydantic import EmailStr, BaseModel
|
3 |
+
from passlib.context import CryptContext
|
4 |
+
|
5 |
+
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
6 |
+
|
7 |
+
|
8 |
+
class BaseRequest(BaseModel):
|
9 |
+
email: EmailStr
|
10 |
+
name: str
|
11 |
+
password: str
|
12 |
+
phoneNumber: Optional[str]
|
13 |
+
|
14 |
+
def hash_password(self):
|
15 |
+
self.password = pwd_context.hash(self.password)
|
App/Users/UserRoutes.py
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import APIRouter, status
|
2 |
+
from .Schemas import BaseRequest
|
3 |
+
from .Model import User
|
4 |
+
from sqlalchemy import and_
|
5 |
+
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
6 |
+
|
7 |
+
|
8 |
+
user_router = APIRouter(tags=["User"])
|
9 |
+
|
10 |
+
|
11 |
+
@user_router.post("/user/register")
|
12 |
+
async def register_user(user: BaseRequest):
|
13 |
+
data = await User.objects.filter(email=user.email).first()
|
14 |
+
if data != None:
|
15 |
+
return {"code": 400, "message": "user exists", "payload": None}
|
16 |
+
else:
|
17 |
+
user.hash_password()
|
18 |
+
sample = await User.objects.create(**user.dict())
|
19 |
+
return {"code": 200, "message": "success", "payload": None}
|
20 |
+
|
21 |
+
|
22 |
+
@user_router.post("/user/login")
|
23 |
+
async def register_user(user: BaseRequest):
|
24 |
+
db_user = await User.objects.filter(email=user.email).first()
|
25 |
+
if db_user:
|
26 |
+
if db_user.verify_password(user.password):
|
27 |
+
return {"code": 200, "message": "success", "payload": db_user.__dict__}
|
28 |
+
return {"code": 401, "message": "Invalid Credentials", "payload": None}
|
App/Worker.py
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from celery import Celery
|
2 |
+
import os
|
3 |
+
import time
|
4 |
+
from App import celery_config
|
5 |
+
from App.Transcription.Utils.audio_transcription import transcribe_file
|
6 |
+
|
7 |
+
celery = Celery()
|
8 |
+
celery.config_from_object(celery_config)
|
9 |
+
|
10 |
+
|
11 |
+
@celery.task(name="create_task", bind=True)
|
12 |
+
def transcription_task(self, file_path):
|
13 |
+
return transcribe_file(state=self, file_path=file_path, model_size="tiny")
|
App/__init__.py
ADDED
File without changes
|
App/app.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI
|
2 |
+
from .Users.UserRoutes import user_router
|
3 |
+
from .modelInit import models, database
|
4 |
+
from .Transcription.TranscriptionRoutes import transcription_router
|
5 |
+
|
6 |
+
app = FastAPI()
|
7 |
+
|
8 |
+
|
9 |
+
@app.on_event("startup")
|
10 |
+
async def startup_event():
|
11 |
+
await models.create_all()
|
12 |
+
if not database.is_connected:
|
13 |
+
await database.connect()
|
14 |
+
print("connected!")
|
15 |
+
|
16 |
+
|
17 |
+
@app.on_event("shutdown")
|
18 |
+
async def shutdown_event():
|
19 |
+
if not database.is_connected:
|
20 |
+
await database.disconnect()
|
21 |
+
print("shutting down!")
|
22 |
+
|
23 |
+
|
24 |
+
@app.get("/")
|
25 |
+
async def landing_page():
|
26 |
+
return {"code": 200, "message": "still running"}
|
27 |
+
|
28 |
+
|
29 |
+
app.include_router(user_router)
|
30 |
+
app.include_router(transcription_router)
|
App/celery_config.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from os import environ
|
2 |
+
import ssl
|
3 |
+
|
4 |
+
task_serializer = "json"
|
5 |
+
result_serializer = "json"
|
6 |
+
accept_content = ["json"]
|
7 |
+
timezone = "Europe/Oslo"
|
8 |
+
enable_utc = True
|
9 |
+
|
10 |
+
broker_url = f"rediss://default:59c9ffda43f61cc18b44a3407a2a7793@master.transcription--legal-stuff--a96n-7tyr.addon.code.run:6379?ssl_cert_reqs=none"
|
11 |
+
|
12 |
+
|
13 |
+
result_backend = f"rediss://default:59c9ffda43f61cc18b44a3407a2a7793@master.transcription--legal-stuff--a96n-7tyr.addon.code.run:6379?ssl_cert_reqs=none"
|
14 |
+
|
15 |
+
# SSL/TLS and SNI configuration
|
16 |
+
broker_use_ssl = {
|
17 |
+
"ssl_cert_reqs": ssl.CERT_NONE,
|
18 |
+
"ssl_match_hostname": False,
|
19 |
+
"ssl_check_hostname": False,
|
20 |
+
"ssl_sni": "master.transcription--legal-stuff--a96n-7tyr.addon.code.run",
|
21 |
+
}
|
App/modelInit.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import databases
|
2 |
+
import orm
|
3 |
+
import psycopg2
|
4 |
+
|
5 |
+
|
6 |
+
|
7 |
+
|
8 |
+
#deployment
|
9 |
+
database = databases.Database(
|
10 |
+
"postgresql+asyncpg://postgres:PkkneZrSFsnJR6B@db.vfhoydxvxuesxhrcdnmx.supabase.co:5432/postgres"
|
11 |
+
)
|
12 |
+
|
13 |
+
|
14 |
+
#development
|
15 |
+
|
16 |
+
# database = databases.Database(
|
17 |
+
# "postgresql+asyncpg://postgres:zJAkapOh3IVt8R0h@db.mygpwobpwxttmilnxrtu.supabase.co:5432/postgres"
|
18 |
+
# )
|
19 |
+
|
20 |
+
|
21 |
+
|
22 |
+
models = orm.ModelRegistry(database=database)
|
App/utils.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from App.Users.Model import User
|
2 |
+
from App.Post.Model import Post
|
3 |
+
import asyncio
|
4 |
+
from fastapi import HTTPException
|
5 |
+
|
6 |
+
|
7 |
+
async def get_user_and_post(content):
|
8 |
+
try:
|
9 |
+
# user = None
|
10 |
+
# post = await Post.objects.get(id=content.postId)
|
11 |
+
# print(post.id)
|
12 |
+
user, post = await asyncio.gather(
|
13 |
+
*[User.objects.get(id=content.userId), Post.objects.get(id=content.postId)]
|
14 |
+
)
|
15 |
+
except:
|
16 |
+
raise HTTPException(status_code=400, detail="Invalid data")
|
17 |
+
return user, post
|
Dockerfile
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Builder stage
|
2 |
+
FROM python:3.9.13-slim as builder
|
3 |
+
|
4 |
+
WORKDIR /srv
|
5 |
+
|
6 |
+
RUN apt-get update && apt-get install -y git ffmpeg aria2 \
|
7 |
+
&& rm -rf /var/lib/apt/lists/*
|
8 |
+
|
9 |
+
COPY requirements.txt .
|
10 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
11 |
+
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
COPY . /srv
|
16 |
+
|
17 |
+
|
18 |
+
|
19 |
+
CMD uvicorn App.app:app --host 0.0.0.0 --port 7860 & celery -A App.Worker.celery worker -c 1 --loglevel=info
|
20 |
+
EXPOSE 7860
|
README.md
CHANGED
@@ -1,11 +1 @@
|
|
1 |
-
|
2 |
-
title: Tranny
|
3 |
-
emoji: 🌖
|
4 |
-
colorFrom: red
|
5 |
-
colorTo: red
|
6 |
-
sdk: docker
|
7 |
-
pinned: false
|
8 |
-
license: creativeml-openrail-m
|
9 |
-
---
|
10 |
-
|
11 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
+
# Trasnscription
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
|
okteto-stack.yaml
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
version: 1
|
2 |
+
services:
|
3 |
+
app:
|
4 |
+
build: .
|
5 |
+
command: uvicorn App.app:app --host 0.0.0.0 --port 8000
|
6 |
+
environment:
|
7 |
+
- DATABASE_URL=postgresql://user:password@db:5432/mydatabase
|
8 |
+
ports:
|
9 |
+
- 8000:8000
|
10 |
+
|
11 |
+
worker:
|
12 |
+
build: .
|
13 |
+
command: celery -A App.Worker.celery worker -c 1 --loglevel=info
|
14 |
+
resources:
|
15 |
+
memory: 3Gi
|
16 |
+
cpu: 1000m
|
requirements.txt
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
asyncpg==0.27.0
|
2 |
+
click==8.1.3
|
3 |
+
databases==0.7.0
|
4 |
+
fastapi==0.92.0
|
5 |
+
Flask==2.2.2
|
6 |
+
greenlet==2.0.2
|
7 |
+
itsdangerous==2.1.2
|
8 |
+
orm==0.3.1
|
9 |
+
faster-whisper
|
10 |
+
aiofiles
|
11 |
+
psycopg2-binary==2.9.5
|
12 |
+
SQLAlchemy==1.4.46
|
13 |
+
starlette==0.25.0
|
14 |
+
typesystem==0.3.1
|
15 |
+
Werkzeug==2.2.2
|
16 |
+
passlib # for password hashing
|
17 |
+
pydantic[email]
|
18 |
+
uvicorn==0.21.1
|
19 |
+
gunicorn
|
20 |
+
ujson
|
21 |
+
orm[mysql]
|
22 |
+
celery
|
23 |
+
python-multipart
|
24 |
+
redis==4.5.5
|
25 |
+
python-multipart
|
26 |
+
asyncmy
|
stress_test.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import aiohttp
|
3 |
+
|
4 |
+
analysis = {"failed": 0, "passed": 0}
|
5 |
+
|
6 |
+
|
7 |
+
async def send_post_request(session, number=0):
|
8 |
+
async with session.post(
|
9 |
+
url="https://app-mbonea-mjema.cloud.okteto.net/post/create",
|
10 |
+
json={"content": {}, "recommendations": {}},
|
11 |
+
) as response:
|
12 |
+
response_text = await response.text()
|
13 |
+
if response.status == 200:
|
14 |
+
analysis["passed"] += 1
|
15 |
+
print(f"Response from {number}: {response_text}")
|
16 |
+
else:
|
17 |
+
analysis["failed"] += 1
|
18 |
+
|
19 |
+
|
20 |
+
async def send_post_requests_async():
|
21 |
+
async with aiohttp.ClientSession() as session:
|
22 |
+
tasks = []
|
23 |
+
for number in range(1_000):
|
24 |
+
tasks.append(asyncio.ensure_future(send_post_request(session, number)))
|
25 |
+
await asyncio.gather(*tasks)
|
26 |
+
|
27 |
+
|
28 |
+
if __name__ == "__main__":
|
29 |
+
asyncio.run(send_post_requests_async())
|
30 |
+
print(analysis)
|