Spaces:
Sleeping
Sleeping
VERY Important commit
Browse files- .gitignore +1 -3
- app/__init__.py +6 -0
- app/api/message/ai/utils.py +22 -0
- app/api/message/dto.py +1 -1
- app/api/message/schemas.py +14 -1
- app/api/message/views.py +10 -1
- app/core/config.py +4 -3
.gitignore
CHANGED
@@ -8,6 +8,4 @@ venv/
|
|
8 |
pip-wheel-metadata/
|
9 |
.env
|
10 |
.DS_Store
|
11 |
-
|
12 |
-
|
13 |
-
|
|
|
8 |
pip-wheel-metadata/
|
9 |
.env
|
10 |
.DS_Store
|
11 |
+
static/
|
|
|
|
app/__init__.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
from fastapi import FastAPI
|
2 |
from fastapi.middleware.cors import CORSMiddleware
|
3 |
from starlette.exceptions import HTTPException as StarletteHTTPException
|
|
|
4 |
|
5 |
from app.core.wrappers import HectoolResponseWrapper, ErrorHectoolResponse
|
6 |
|
@@ -27,6 +28,11 @@ def create_app() -> FastAPI:
|
|
27 |
allow_headers=["*"],
|
28 |
)
|
29 |
|
|
|
|
|
|
|
|
|
|
|
30 |
@app.exception_handler(StarletteHTTPException)
|
31 |
async def http_exception_handler(_, exc):
|
32 |
return HectoolResponseWrapper(
|
|
|
1 |
from fastapi import FastAPI
|
2 |
from fastapi.middleware.cors import CORSMiddleware
|
3 |
from starlette.exceptions import HTTPException as StarletteHTTPException
|
4 |
+
from starlette.staticfiles import StaticFiles
|
5 |
|
6 |
from app.core.wrappers import HectoolResponseWrapper, ErrorHectoolResponse
|
7 |
|
|
|
28 |
allow_headers=["*"],
|
29 |
)
|
30 |
|
31 |
+
app.mount(
|
32 |
+
'/static',
|
33 |
+
StaticFiles(directory='static'),
|
34 |
+
)
|
35 |
+
|
36 |
@app.exception_handler(StarletteHTTPException)
|
37 |
async def http_exception_handler(_, exc):
|
38 |
return HectoolResponseWrapper(
|
app/api/message/ai/utils.py
CHANGED
@@ -1,5 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
from app.api.message.ai.prompts import Prompts
|
2 |
from app.api.message.model import MessageModel
|
|
|
|
|
3 |
|
4 |
|
5 |
def transform_messages_to_openai(messages: list[MessageModel]) -> list[dict]:
|
@@ -30,3 +38,17 @@ def transform_messages_to_openai(messages: list[MessageModel]) -> list[dict]:
|
|
30 |
return openai_messages
|
31 |
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import base64
|
2 |
+
import os
|
3 |
+
from uuid import uuid4
|
4 |
+
|
5 |
+
from fastapi import HTTPException
|
6 |
+
|
7 |
from app.api.message.ai.prompts import Prompts
|
8 |
from app.api.message.model import MessageModel
|
9 |
+
from app.api.message.schemas import UploadImageRequest
|
10 |
+
from app.core.config import settings
|
11 |
|
12 |
|
13 |
def transform_messages_to_openai(messages: list[MessageModel]) -> list[dict]:
|
|
|
38 |
return openai_messages
|
39 |
|
40 |
|
41 |
+
def save_image(file: UploadImageRequest) -> str:
|
42 |
+
try:
|
43 |
+
image_data = base64.b64decode(file.base64String)
|
44 |
+
except Exception:
|
45 |
+
raise HTTPException(status_code=400, detail="Invalid base64 string")
|
46 |
+
|
47 |
+
file_extension = os.path.splitext(file.name)[1] or ".jpg"
|
48 |
+
unique_filename = f"{uuid4()}{file_extension}"
|
49 |
+
file_path = os.path.join(settings.STATIC_DIR, unique_filename)
|
50 |
+
|
51 |
+
with open(file_path, "wb") as f:
|
52 |
+
f.write(image_data)
|
53 |
+
file_url = f"{settings.Issuer}/static/{unique_filename}"
|
54 |
+
return file_url
|
app/api/message/dto.py
CHANGED
@@ -10,4 +10,4 @@ class Author(Enum):
|
|
10 |
|
11 |
class File(BaseModel):
|
12 |
name: str
|
13 |
-
|
|
|
10 |
|
11 |
class File(BaseModel):
|
12 |
name: str
|
13 |
+
url: str
|
app/api/message/schemas.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
from pydantic import BaseModel
|
2 |
|
3 |
from app.api.common.dto import Paging
|
4 |
-
from app.api.message.dto import
|
5 |
from app.api.message.model import MessageModel
|
6 |
from app.core.wrappers import HectoolResponseWrapper
|
7 |
|
@@ -22,3 +22,16 @@ class AllMessageResponse(BaseModel):
|
|
22 |
|
23 |
class AllMessageWrapper(HectoolResponseWrapper[AllMessageResponse]):
|
24 |
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
from pydantic import BaseModel
|
2 |
|
3 |
from app.api.common.dto import Paging
|
4 |
+
from app.api.message.dto import File
|
5 |
from app.api.message.model import MessageModel
|
6 |
from app.core.wrappers import HectoolResponseWrapper
|
7 |
|
|
|
22 |
|
23 |
class AllMessageWrapper(HectoolResponseWrapper[AllMessageResponse]):
|
24 |
pass
|
25 |
+
|
26 |
+
|
27 |
+
class UploadImageRequest(BaseModel):
|
28 |
+
name: str
|
29 |
+
base64String: str
|
30 |
+
|
31 |
+
|
32 |
+
class UploadImageResponse(BaseModel):
|
33 |
+
url: str
|
34 |
+
|
35 |
+
|
36 |
+
class UploadImageWrapper(HectoolResponseWrapper[UploadImageResponse]):
|
37 |
+
pass
|
app/api/message/views.py
CHANGED
@@ -5,11 +5,20 @@ from app.api.account.model import AccountModel
|
|
5 |
from app.api.common.dto import Paging
|
6 |
from app.api.message import message_router
|
7 |
from app.api.message.ai.openai_request import response_generator
|
|
|
8 |
from app.api.message.db_requests import get_all_chat_messages_obj, create_message_obj, update_chat_with_thread_id
|
9 |
-
from app.api.message.schemas import AllMessageWrapper, AllMessageResponse, CreateMessageRequest
|
|
|
10 |
from app.core.security import PermissionDependency
|
11 |
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
@message_router.get('/{chatId}/all')
|
14 |
async def get_all_chat_messages(
|
15 |
chatId: str, account: AccountModel = Depends(PermissionDependency(is_public=True))
|
|
|
5 |
from app.api.common.dto import Paging
|
6 |
from app.api.message import message_router
|
7 |
from app.api.message.ai.openai_request import response_generator
|
8 |
+
from app.api.message.ai.utils import save_image
|
9 |
from app.api.message.db_requests import get_all_chat_messages_obj, create_message_obj, update_chat_with_thread_id
|
10 |
+
from app.api.message.schemas import AllMessageWrapper, AllMessageResponse, CreateMessageRequest, UploadImageRequest, \
|
11 |
+
UploadImageWrapper, UploadImageResponse
|
12 |
from app.core.security import PermissionDependency
|
13 |
|
14 |
|
15 |
+
@message_router.post('/image')
|
16 |
+
async def create_image_message(
|
17 |
+
file: UploadImageRequest,
|
18 |
+
):
|
19 |
+
url = save_image(file)
|
20 |
+
return UploadImageWrapper(data=UploadImageResponse(url=url))
|
21 |
+
|
22 |
@message_router.get('/{chatId}/all')
|
23 |
async def get_all_chat_messages(
|
24 |
chatId: str, account: AccountModel = Depends(PermissionDependency(is_public=True))
|
app/core/config.py
CHANGED
@@ -9,7 +9,8 @@ from openai import AsyncClient
|
|
9 |
load_dotenv()
|
10 |
|
11 |
class BaseConfig:
|
12 |
-
BASE_DIR: pathlib.Path = pathlib.Path(__file__).parent.parent
|
|
|
13 |
SECRET_KEY = os.getenv('SECRET')
|
14 |
DB_CLIENT = motor.motor_asyncio.AsyncIOMotorClient(os.getenv("MONGO_DB_URL")).hectool
|
15 |
OPENAI_CLIENT = AsyncClient(api_key=os.getenv('OPENAI_API_KEY'))
|
@@ -22,8 +23,8 @@ class DevelopmentConfig(BaseConfig):
|
|
22 |
|
23 |
|
24 |
class ProductionConfig(BaseConfig):
|
25 |
-
Issuer = "https://
|
26 |
-
Audience = "https://
|
27 |
|
28 |
|
29 |
@lru_cache()
|
|
|
9 |
load_dotenv()
|
10 |
|
11 |
class BaseConfig:
|
12 |
+
BASE_DIR: pathlib.Path = pathlib.Path(__file__).parent.parent.parent
|
13 |
+
STATIC_DIR = "static"
|
14 |
SECRET_KEY = os.getenv('SECRET')
|
15 |
DB_CLIENT = motor.motor_asyncio.AsyncIOMotorClient(os.getenv("MONGO_DB_URL")).hectool
|
16 |
OPENAI_CLIENT = AsyncClient(api_key=os.getenv('OPENAI_API_KEY'))
|
|
|
23 |
|
24 |
|
25 |
class ProductionConfig(BaseConfig):
|
26 |
+
Issuer = "https://brestok-hector-demo-backend.hf.space"
|
27 |
+
Audience = "https://brestok-1.github.io/hectool-demo-frontend/"
|
28 |
|
29 |
|
30 |
@lru_cache()
|