Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alpha -> Dev #85

Merged
merged 10 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions .github/workflows/deploy_containers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,13 @@ on:
branches:
- dev
- main
pull_request:
branches:
- dev
- alpha
workflow_dispatch:
inputs:
version:
description: 'Images tag'
required: true
default: 'alpha'
# images:
# description: 'Include Images (klatchat_observer|chat_client|chat_server) space-separated'
# required: false
# default: klatchat_observer chat_client chat_server

permissions:
contents: write
Expand Down Expand Up @@ -59,17 +53,10 @@ jobs:
if: github.event_name == 'workflow_dispatch'
run: |
echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
# echo ${{ github.event.inputs.images }} >> $IMAGES
- name: Apply Pull Request Environments
if: github.event_name == 'pull_request'
run: |
echo "VERSION=alpha" >> $GITHUB_ENV
# echo klatchat_observer chat_client chat_server >> $IMAGES
- name: Apply Push Environments
if: github.event_name == 'push'
run: |
echo "VERSION=$(echo ${{ github.ref_name }} | tr / -)" >> $GITHUB_ENV
# echo klatchat_observer chat_client chat_server >> $IMAGES
- name: Clean Up Version
run: |
echo "VERSION=${VERSION//['/']/-}" >> $GITHUB_ENV
Expand Down
17 changes: 9 additions & 8 deletions chat_client/static/js/chat_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ async function buildConversation(conversationData={}, skin = CONVERSATION_SKINS.
const newConversationHTML = await buildConversationHTML(conversationData, skin);
const conversationsBody = document.getElementById(conversationParentID);
conversationsBody.insertAdjacentHTML('afterbegin', newConversationHTML);
initMessages(conversationData, skin);
await initMessages(conversationData, skin);

const messageListContainer = getMessageListContainer(cid);
const currentConversation = document.getElementById(cid);
Expand Down Expand Up @@ -363,18 +363,18 @@ async function buildConversation(conversationData={}, skin = CONVERSATION_SKINS.
/**
* Gets conversation data based on input string
* @param input: input string text
* @param firstMessageID: id of the the most recent message
* @param oldestMessageTS: creation timestamp of the oldest displayed message
* @param skin: resolves by server for which data to return
* @param maxResults: max number of messages to fetch
* @param alertParent: parent of error alert (optional)
* @returns {Promise<{}>} promise resolving conversation data returned
*/
async function getConversationDataByInput(input="", skin=CONVERSATION_SKINS.BASE, firstMessageID=null, maxResults=20, alertParent=null){
async function getConversationDataByInput(input="", skin=CONVERSATION_SKINS.BASE, oldestMessageTS=null, maxResults=20, alertParent=null){
let conversationData = {};
if(input && typeof input === "string"){
let query_url = `chat_api/search/${input}?limit_chat_history=${maxResults}&skin=${skin}`;
if(firstMessageID){
query_url += `&first_message_id=${firstMessageID}`;
if(input){
let query_url = `chat_api/search/${input.toString()}?limit_chat_history=${maxResults}&skin=${skin}`;
if(oldestMessageTS){
query_url += `&creation_time_from=${oldestMessageTS}`;
}
await fetchServer(query_url)
.then(response => {
Expand Down Expand Up @@ -443,7 +443,8 @@ async function addNewCID(cid, skin){
* @param cid: conversation id to remove
*/
async function removeConversation(cid){
return await getChatAlignmentTable().where({cid: cid}).delete();
return await Promise.all([DBGateway.getInstance(DB_TABLES.CHAT_ALIGNMENT).deleteItem(cid),
DBGateway.getInstance(DB_TABLES.CHAT_MESSAGES_PAGINATION).deleteItem(cid)]);
}

/**
Expand Down
52 changes: 48 additions & 4 deletions chat_client/static/js/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ const DATABASES = {
}
const DB_TABLES = {
CHAT_ALIGNMENT: 'chat_alignment',
MINIFY_SETTINGS: 'minify_settings'
MINIFY_SETTINGS: 'minify_settings',
CHAT_MESSAGES_PAGINATION: 'chat_messages_pagination'
}
const __db_instances = {}
const __db_definitions = {
"chats": {
"chat_alignment": `cid, added_on, skin`
[DATABASES.CHATS]: {
[DB_TABLES.CHAT_ALIGNMENT]: `cid, added_on, skin`,
[DB_TABLES.CHAT_MESSAGES_PAGINATION]: `cid, oldest_created_on`
}
}

Expand All @@ -30,4 +32,46 @@ const getDb = (db, table) => {
_instance = __db_instances[db];
}
return _instance[table];
}
}


class DBGateway {
constructor(db, table) {
this.db = db;
this.table = table;

this._db_instance = getDb(this.db, this.table);
this._db_columns_definitions = __db_definitions[this.db][this.table]
this._db_key = this._db_columns_definitions.split(',')[0]
}

async getItem(key = "") {
return await this._db_instance.where( {[this._db_key]: key} ).first();
}

async listItems(orderBy="") {
let expression = this._db_instance;
if (orderBy !== ""){
expression = expression.orderBy(orderBy)
}
return await expression.toArray();
}

async putItem(data = {}){
return await this._db_instance.put(data, [data[this._db_key]])
}

updateItem(data = {}) {
const key = data[this._db_key]
delete data[this._db_key]
return this._db_instance.update(key, data);
}

async deleteItem(key = "") {
return await this._db_instance.where({[this._db_key]: key}).delete();
}

static getInstance(table){
return new DBGateway(DATABASES.CHATS, table);
}
}
33 changes: 25 additions & 8 deletions chat_client/static/js/message_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,10 @@ async function addOldMessages(cid, skin=CONVERSATION_SKINS.BASE) {
if (messageContainer.children.length > 0) {
for (let i = 0; i < messageContainer.children.length; i++) {
const firstMessageItem = messageContainer.children[i];
const firstMessageID = getFirstMessageFromCID( firstMessageItem );
if (firstMessageID) {
const oldestMessageTS = await DBGateway.getInstance(DB_TABLES.CHAT_MESSAGES_PAGINATION).getItem(cid).then(res=> res?.oldest_created_on || null);
if (oldestMessageTS) {
const numMessages = await getCurrentSkin(cid) === CONVERSATION_SKINS.PROMPTS? 50: 20;
await getConversationDataByInput( cid, skin, firstMessageID, numMessages, null ).then( async conversationData => {
await getConversationDataByInput( cid, skin, oldestMessageTS, numMessages, null ).then( async conversationData => {
if (messageContainer) {
const userMessageList = getUserMessages( conversationData, null );
userMessageList.sort( (a, b) => {
Expand All @@ -183,7 +183,7 @@ async function addOldMessages(cid, skin=CONVERSATION_SKINS.BASE) {
console.debug( `!!message_id=${message["message_id"]} is already displayed` )
}
}
initMessages( conversationData, skin );
await initMessages( conversationData, skin );
}
} ).then( _ => {
firstMessageItem.scrollIntoView( {behavior: "smooth"} );
Expand Down Expand Up @@ -293,7 +293,7 @@ function addProfileDisplay(cid, messageId, messageType='plain'){

/**
* Inits addProfileDisplay() on each message of provided conversation
* @param conversationData: target conversation data
* @param conversationData - target conversation data
*/
function initProfileDisplay(conversationData){
getUserMessages(conversationData, null).forEach(message => {
Expand All @@ -302,9 +302,25 @@ function initProfileDisplay(conversationData){
}


/**
* Inits pagination based on the oldest message creation timestamp
* @param conversationData - target conversation data
*/
async function initPagination(conversationData) {
const userMessages = getUserMessages(conversationData, null);
if (userMessages.length > 0){
const oldestMessage = Math.min(...userMessages.map(msg => parseInt(msg.created_on)));
await DBGateway
.getInstance(DB_TABLES.CHAT_MESSAGES_PAGINATION)
.putItem({cid: conversationData['_id'],
oldest_created_on: oldestMessage})
}
}


/**
* Initializes messages based on provided conversation aata
* @param conversationData: JS Object containing conversation data of type:
* @param conversationData - JS Object containing conversation data of type:
* {
* '_id': 'id of conversation',
* 'conversation_name': 'title of the conversation',
Expand All @@ -318,14 +334,15 @@ function initProfileDisplay(conversationData){
* 'created_on': 'creation time of the message'
* }, ... (num of user messages returned)]
* }
* @param skin: target conversation skin to consider
* @param skin - target conversation skin to consider
*/
function initMessages(conversationData, skin = CONVERSATION_SKINS.BASE){
async function initMessages(conversationData, skin = CONVERSATION_SKINS.BASE){
initProfileDisplay(conversationData);
attachReplies(conversationData);
addAttachments(conversationData);
addCommunicationChannelTransformCallback(conversationData);
initLoadOldMessages(conversationData, skin);
await initPagination(conversationData);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion chat_server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def create_app(
:param testing_mode: to run application in testing mode (defaults to False)
:param sio_server: socket io server instance (optional)
"""
app_version = get_version("chat_server/version.py")
app_version = get_version("version.py")
chat_app = FastAPI(title="Klatchat Server API", version=app_version)

_init_middleware(app=chat_app)
Expand Down
2 changes: 1 addition & 1 deletion chat_server/blueprints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Import blueprint here so it will be included
# Import blueprint here to include it to Web App
from . import (
admin as admin_blueprint,
auth as auth_blueprint,
Expand Down
53 changes: 26 additions & 27 deletions chat_server/blueprints/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,18 @@
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import warnings
from typing import Optional

from time import time
from fastapi import APIRouter, Request, Form
from fastapi import APIRouter, Request, Form, Depends
from fastapi.responses import JSONResponse

from chat_server.constants.conversations import ConversationSkins
from chat_server.server_utils.auth import login_required
from chat_server.server_utils.conversation_utils import build_message_json
from chat_server.server_utils.dependencies import CurrentUserDependency
from chat_server.server_utils.models.chats import GetConversationModel
from chat_server.services.popularity_counter import PopularityCounter
from utils.common import generate_uuid
from utils.database_utils.mongo_utils import MongoFilter, MongoLogicalOperators
from utils.database_utils.mongo_utils.queries.mongo_queries import fetch_message_data
from utils.database_utils.mongo_utils.queries.wrapper import MongoDocumentsAPI
from utils.http_utils import respond
Expand Down Expand Up @@ -86,53 +87,51 @@ async def new_conversation(
"created_on": int(time()),
}
MongoDocumentsAPI.CHATS.add_item(data=request_data_dict)
PopularityCounter.add_new_chat(cid=cid, name=conversation_name)
PopularityCounter.add_new_chat(cid=cid)
return JSONResponse(content=request_data_dict)


@router.get("/search/{search_str}")
# @login_required
async def get_matching_conversation(
request: Request,
search_str: str,
chat_history_from: int = 0,
first_message_id: Optional[str] = None,
limit_chat_history: int = 100,
skin: str = ConversationSkins.BASE,
current_user: CurrentUserDependency, model: GetConversationModel = Depends()
):
"""
Gets conversation data matching search string

:param request: Starlette Request object
:param search_str: provided search string
:param chat_history_from: upper time bound for messages
:param first_message_id: id of the first message to start from
:param limit_chat_history: lower time bound for messages
:param skin: conversation skin type from ConversationSkins
:param current_user: current user data
:param model: request data model described in GetConversationModel

:returns conversation data if found, 401 error code otherwise
"""
conversation_data = MongoDocumentsAPI.CHATS.get_conversation_data(
search_str=search_str
search_str=model.search_str, requested_user_id=current_user.user_id
)

if not conversation_data:
return respond(f'No conversation matching = "{search_str}"', 404)
return respond(f'No conversation matching = "{model.search_str}"', 404)

if model.creation_time_from:
query_filter = MongoFilter(
key="created_on",
logical_operator=MongoLogicalOperators.LT,
value=int(model.creation_time_from),
)
else:
query_filter = None

message_data = (
fetch_message_data(
skin=skin,
skin=model.skin,
conversation_data=conversation_data,
start_idx=chat_history_from,
limit=limit_chat_history,
start_message_id=first_message_id,
limit=model.limit_chat_history,
creation_time_filter=query_filter,
)
or []
)
conversation_data["chat_flow"] = []
for i in range(len(message_data)):
message_record = build_message_json(raw_message=message_data[i], skin=skin)
conversation_data["chat_flow"].append(message_record)
conversation_data["chat_flow"] = [
build_message_json(raw_message=message_data[i], skin=model.skin)
for i in range(len(message_data))
]

return conversation_data

Expand Down
16 changes: 5 additions & 11 deletions chat_server/blueprints/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
)
from chat_server.server_utils.http_utils import save_file
from utils.common import get_hash
from utils.database_utils.mongo_utils import MongoFilter
from utils.database_utils.mongo_utils.queries.wrapper import MongoDocumentsAPI
from utils.http_utils import respond
from utils.logging_utils import LOG
Expand Down Expand Up @@ -169,17 +170,10 @@ async def update_profile(
if avatar:
update_dict["avatar"] = await save_file(location_prefix="avatars", file=avatar)
try:
filter_expression = {"_id": user["_id"]}
update_expression = {"$set": {k: v for k, v in update_dict.items() if v}}
db_controller.exec_query(
query={
"document": "users",
"command": "update",
"data": (
filter_expression,
update_expression,
),
}
filter_expression = MongoFilter(key="_id", value=user_id)
update_dict = {k: v for k, v in update_dict.items() if v}
MongoDocumentsAPI.USERS.update_item(
filters=(filter_expression,), data=update_dict
)
return respond(msg="OK")
except Exception as ex:
Expand Down
Loading
Loading