Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
jonra1993 committed Feb 24, 2024
2 parents a5064b3 + 3622202 commit 2f0a9ac
Show file tree
Hide file tree
Showing 21 changed files with 118 additions and 65 deletions.
3 changes: 0 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,6 @@ run-pgadmin:
echo "$$SERVERS_JSON" > ./pgadmin/servers.json && \
docker volume create pgadmin_data && \
docker compose -f pgadmin.yml up --force-recreate

load-server-pgadmin:
docker exec -it pgadmin python /pgadmin4/setup.py --load-servers servers.json

clean-pgadmin:
docker volume rm pgadmin_data
Expand Down
78 changes: 69 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Developing web applications can be a challenging process, especially when dealin
- Development Best Practices: We apply code formatting, type checking, and static analysis tools to ensure that the code is readable, robust, and reliable.

## Table of Contents
1. [Set environment variables](#set-environment-variables)
1. [Prerequisites](#prerequisites)
2. [Run the project using Docker containers and forcing build containers](#run-the-project-using-docker-containers-and-forcing-build-containers)
3. [Run project using Docker containers](#run-project-using-docker-containers)
4. [Setup database with initial data](#setup-database-with-initial-data)
Expand All @@ -36,10 +36,72 @@ Developing web applications can be a challenging process, especially when dealin
20. [TODO List](#todo-list)
21. [License](#license)

# Prerequisites

## Set environment variables

Create an **.env** file on root folder and copy the content from **.env.example**. Feel free to change it according to your own configuration.

## Docker engine
This project utilizes Docker and Docker Compose, so please ensure that you have installed the latest version compatible with your operating system. If you haven't already installed Docker, you can find detailed instructions on how to do so [here](https://docs.docker.com/engine/install/). Docker desktop can be good for a dev computer.

You can check if it is installed with this command
```
docker --version
```

## Make
"Make" is a build automation tool that is primarily used to manage the compilation and building of software projects. It reads a file called a "Makefile" which specifies a set of rules and dependencies for building a project, and then executes the necessary commands to build the project according to those rules. Depending of your OS you will requiere to install it in different ways.

Mac
```
xcode-select --install
```

Ubuntu
```
sudo apt-get install build-essential
sudo apt-get -y install make
```

You can check if it is installed with this command
```
make --version
```

## Python ">3.9,<3.12"
If you haven't already installed Python. You can download and install python from [here](https://www.python.org/downloads/).

You can check yu python version:
```
python --version
```

## Poetry

Python Poetry is a tool for dependency management and packaging in Python. It provides a modern and efficient approach to managing Python projects' dependencies, virtual environments, and packaging. You can find detailed instructions on how install it [here](https://python-poetry.org/docs/#installing-with-the-official-installer). Poetry manages packages in **pyproject.toml** file; In this project you can find it in the folder backend/app.

You can check if it is installed with this command
```
poetry --version
```

### Dev tip to activate virtual environment
When you are opening python files do this cna help you to vscode detect installed packages.

```
cd backend/app/
poetry shell
```

After that you can show the interpreted path. You can copy that path and set as the default for the project in vscode. Press on **Enter interpreter path ..** and past path.

<p align="center">
<img src="static/python_int.png" align="center"/>
</p>



## Run the project using Docker containers and forcing build containers

*Using docker compose command*
Expand Down Expand Up @@ -92,12 +154,7 @@ You can connect to the Database using pgAdmin4 and use the credentials from .env
make run-pgadmin
```

*Load server configuration (It is required just the first time)*
```sh
make load-server-pgadmin
```

This starts pgamin in [http://localhost:15432](http://localhost:15432).
This starts pgamin in [http://localhost:15432](http://localhost:15432). When connecting to db server introduce the password by default it is **postgres** if you didn't change it in .env file.

<p align="center">
<img src="static/tables.png" align="center"/>
Expand Down Expand Up @@ -298,13 +355,13 @@ make mypy
```

## Basic chatbot example with Langchain and OpenAI
In addition to its core features, this project template demonstrates how to integrate an basic chatbot powered by Langchain and OpenAI through websockets.
In addition to its core features, this project template demonstrates how to integrate an basic chatbot powered by Langchain and OpenAI through websockets. You can use [PieSocket Websocket Tester](https://chromewebstore.google.com/detail/oilioclnckkoijghdniegedkbocfpnip) to test websockets.

To begin experimenting with the basic chatbot, follow these steps:

1. **Obtain an OpenAI API Key**: You'll need to set the `OPENAI_API_KEY` environment variable, which you can obtain from [OpenAI's platform](https://platform.openai.com/).

2. **Test Websocket Connection**: You can test the websocket connection by using the following URL: [ws://fastapi.localhost/chat/\<USER_ID\>](ws://fastapi.localhost/chat/<USER_ID>). Replace `<USER_ID>` with a user identifier of your choice.
2. **Test Websocket Connection**: You can test the websocket connection by using the following URL: [ws://fastapi.localhost/chat/\<USER_ID\>](ws://fastapi.localhost/chat/<USER_ID>). Replace `<USER_ID>` with a user identifier of your choice. It should be the ID of your user.

3. **Sending and Receiving Messages**: You should be able to send messages to the chatbot using the provided websocket connection. To do this, use the following message structure:

Expand All @@ -313,6 +370,9 @@ To begin experimenting with the basic chatbot, follow these steps:
```
Once you send a message, the chatbot will respond with generated responses based on the content of your input.

<p align="center">
<img src="static/ws.png" align="center"/>
</p>

## Inspiration and References

Expand Down
2 changes: 1 addition & 1 deletion backend/app/app/api/v1/endpoints/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ async def get_new_access_token(
status_code=status.HTTP_403_FORBIDDEN,
detail="Error when decoding the token. Please check your request.",
)
except MissingRequiredClaimError as e:
except MissingRequiredClaimError:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="There is no required field in your token. Please contact the administrator.",
Expand Down
2 changes: 1 addition & 1 deletion backend/app/app/crud/base_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async def get_multi_paginated(
db_session = db_session or self.db.session
if query is None:
query = select(self.model)

output = await paginate(db_session, query, params)
return output

Expand Down
4 changes: 2 additions & 2 deletions backend/app/app/db/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
str(settings.ASYNC_CELERY_BEAT_DATABASE_URI),
# echo=True,
future=True,
#pool_size=POOL_SIZE,
#max_overflow=64,
# pool_size=POOL_SIZE,
# max_overflow=64,
)

SessionLocalCelery = sessionmaker(
Expand Down
7 changes: 3 additions & 4 deletions backend/app/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from fastapi_cache.backends.redis import RedisBackend
from fastapi_limiter import FastAPILimiter
from fastapi_limiter.depends import WebSocketRateLimiter
from fastapi_pagination import add_pagination
from jwt import DecodeError, ExpiredSignatureError, MissingRequiredClaimError
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage
Expand Down Expand Up @@ -189,7 +188,7 @@ async def websocket_endpoint(websocket: WebSocket, user_id: UUID):
# Receive and send back the client message
data = await websocket.receive_json()
await ws_ratelimit(websocket)
user_message = IUserMessage.parse_obj(data)
user_message = IUserMessage.model_validate(data)
user_message.user_id = user_id

resp = IChatResponse(
Expand Down Expand Up @@ -227,7 +226,7 @@ async def websocket_endpoint(websocket: WebSocket, user_id: UUID):
message_id="",
id="",
sender="bot",
message="Sorry, something went wrong. Your user limit of api usages has been reached.",
message="Sorry, something went wrong. Your user limit of api usages has been reached or check your API key.",
type="error",
)
await websocket.send_json(resp.dict())
Expand All @@ -237,4 +236,4 @@ async def websocket_endpoint(websocket: WebSocket, user_id: UUID):


# Add Routers
app.include_router(api_router_v1, prefix=settings.API_V1_STR)
app.include_router(api_router_v1, prefix=settings.API_V1_STR)
1 change: 1 addition & 0 deletions backend/app/app/models/base_uuid_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from sqlalchemy.orm import declared_attr
from datetime import datetime


# id: implements proposal uuid7 draft4
class SQLModel(_SQLModel):
@declared_attr # type: ignore
Expand Down
1 change: 0 additions & 1 deletion backend/app/app/models/team_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from uuid import UUID



class TeamBase(SQLModel):
name: str = Field(index=True)
headquarters: str
Expand Down
4 changes: 3 additions & 1 deletion backend/app/app/models/user_follow_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ class UserFollowBase(SQLModel):


class UserFollow(BaseUUIDModel, UserFollowBase, table=True):
is_mutual: bool | None = Field(default=None, sa_column=Column(Boolean(), server_default="0"))
is_mutual: bool | None = Field(
default=None, sa_column=Column(Boolean(), server_default="0")
)
2 changes: 1 addition & 1 deletion backend/app/app/schemas/common_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class TokenType(str, Enum):
class IUserMessage(BaseModel):
"""User message schema."""

user_id: UUID | None
user_id: UUID | None = None
message: str


Expand Down
2 changes: 1 addition & 1 deletion backend/app/app/schemas/hero_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


class IHeroCreate(HeroBase):
@field_validator('age')
@field_validator("age")
def check_age(cls, value):
if value < 0:
raise ValueError("Invalid age")
Expand Down
6 changes: 3 additions & 3 deletions backend/app/app/schemas/image_media_schema.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from app.models.image_media_model import ImageMedia, ImageMediaBase
from app.models.media_model import Media
from pydantic import model_validator, root_validator
from pydantic import model_validator
from .media_schema import IMediaRead
from app.utils.partial import optional

Expand All @@ -20,11 +20,11 @@ class IImageMediaRead(ImageMediaBase):
media: IMediaRead | None


#Todo make it compatible with pydantic v2
# Todo make it compatible with pydantic v2
class IImageMediaReadCombined(ImageMediaBase):
link: str | None

@model_validator(mode='before')
@model_validator(mode="before")
def combine_attributes(cls, values):
link_fields = {"link": values.get("link", None)}
if "media" in values:
Expand Down
1 change: 0 additions & 1 deletion backend/app/app/schemas/team_schema.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from typing import Any
from app.models.hero_model import HeroBase
from app.models.team_model import TeamBase
from .user_schema import IUserBasicInfo
Expand Down
2 changes: 1 addition & 1 deletion backend/app/app/schemas/user_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pydantic import BaseModel
from uuid import UUID
from enum import Enum
from .image_media_schema import IImageMediaReadCombined, IImageMediaRead
from .image_media_schema import IImageMediaRead
from .role_schema import IRoleRead


Expand Down
1 change: 0 additions & 1 deletion backend/app/app/utils/partial.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# https://github.com/pydantic/pydantic/pull/3179
# https://github.com/pydantic/pydantic/issues/1673

from pydantic import BaseModel
from copy import deepcopy
from typing import Any, Callable, Optional, Type, TypeVar
from pydantic import BaseModel, create_model
Expand Down
12 changes: 6 additions & 6 deletions docker-compose-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,22 @@ services:
- caddy_reverse_proxy:storage.localhost

database:
image: bitnami/postgresql:13.3.0
image: bitnami/postgresql
restart: always
container_name: database
env_file: ".env"
user: root
volumes:
- ./db_docker:/bitnami/postgresql
- db_docker:/bitnami/postgresql
- ./create-dbs.sql:/docker-entrypoint-initdb.d/create-dbs.sql
ports:
- 5454:5432 # Remove this on production
expose:
- 5432
environment:
- POSTGRES_USERNAME=${DATABASE_USER}
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
- POSTGRES_DATABASE=${DATABASE_NAME}
- POSTGRES_HOST_AUTH_METHOD= "trust"
- POSTGRESQL_USERNAME=${DATABASE_USER}
- POSTGRESQL_PASSWORD=${DATABASE_PASSWORD}
- POSTGRESQL_DATABASE=${DATABASE_NAME}

redis_server:
image: redis:alpine
Expand Down Expand Up @@ -108,5 +107,6 @@ services:
- caddy_config:/config

volumes:
db_docker:
caddy_data:
caddy_config:
2 changes: 1 addition & 1 deletion docker-compose-sonarqube.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: "3.9"
services:
sonarqube:
container_name: "sonarqube"
image: "sonarqube:9.9.1-community"
image: "sonarqube:9.9.2-community"
volumes:
- ./sonarqube/extensions:/opt/sonarqube/extensions
- ./sonarqube/logs:/opt/sonarqube/logs
Expand Down
17 changes: 7 additions & 10 deletions docker-compose-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,22 @@ services:
- caddy_reverse_proxy:storage.localhost

database:
image: bitnami/postgresql:13.3.0
image: bitnami/postgresql
restart: always
container_name: database
env_file: ".env"
user: root
volumes:
- ./db_docker:/bitnami/postgresql
- db_docker:/bitnami/postgresql
- ./create-dbs.sql:/docker-entrypoint-initdb.d/create-dbs.sql
ports:
- 5454:5432 # Remove this on production
expose:
- 5432
environment:
- POSTGRES_USERNAME=${DATABASE_USER}
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
- POSTGRES_DATABASE=${DATABASE_NAME}
- POSTGRES_HOST_AUTH_METHOD= "trust"
- POSTGRESQL_USERNAME=${DATABASE_USER}
- POSTGRESQL_PASSWORD=${DATABASE_PASSWORD}
- POSTGRESQL_DATABASE=${DATABASE_NAME}

redis_server:
image: redis:alpine
Expand All @@ -52,10 +51,7 @@ services:
container_name: celery_worker
restart: always
# platform: linux/arm64/v8
build:
context: ./backend
args:
INSTALL_DEV: "true"
build: ./backend
command: "watchfiles 'celery -A app.core.celery worker -l info' "
volumes:
- ./backend/app:/code
Expand Down Expand Up @@ -115,5 +111,6 @@ services:
- caddy_config:/config

volumes:
db_docker:
caddy_data:
caddy_config:
Loading

0 comments on commit 2f0a9ac

Please sign in to comment.