Skip to content

Commit ed01483

Browse files
authored
Implement Pydantic models for SIO events (#9)
* WIP implementation of neon-data-models SIO communication models * Run pre-commit formatting * WIP troubleshooting * Confirmed functional CCAI performance with some bugs, likely related to client handling * Clean up `sid` (shout_id)/`message_id` handling * Remove extra log * Remove unused import * Update neon-data-models dependency spec * Clean up temporary exception handling * Clean up changes in `prompt.py` * Clean up changes in `stt` * Clean up changes in `tts` * Clean up changes in `user_message` * Update neon-data-models dependency spec
1 parent 81431e7 commit ed01483

8 files changed

Lines changed: 201 additions & 279 deletions

File tree

Dockerfile

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@ COPY . /app/
1313
WORKDIR /app
1414

1515
RUN apt-get update \
16-
&& apt-get install -y \
17-
&& apt install build-essential -y \
18-
&& pip install --upgrade pip \
19-
&& pip install wheel
16+
&& apt-get install build-essential git -y \
17+
&& pip install --no-cache-dir --upgrade pip wheel
2018

21-
RUN pip install /app
19+
RUN pip install --no-cache-dir /app
2220

2321

2422
CMD ["pyklatchat-server"]

chat_server/blueprints/users.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,16 @@ async def get_user(
6767
session_token = ""
6868
if user_id:
6969
user = MongoDocumentsAPI.USERS.get_user(user_id=user_id)
70-
user.pop("password", None)
71-
user.pop("date_created", None)
72-
user.pop("tokens", None)
73-
if session_data.user.user_id != user_id:
74-
user.pop("roles", None)
75-
user.pop("preferences", None)
76-
LOG.info(f"Fetched user data (id={user_id}): {user}")
70+
try:
71+
user.pop("password", None)
72+
user.pop("date_created", None)
73+
user.pop("tokens", None)
74+
if session_data.user.user_id != user_id:
75+
user.pop("roles", None)
76+
user.pop("preferences", None)
77+
LOG.info(f"Fetched user data (id={user_id}): {user}")
78+
except Exception as e:
79+
raise RuntimeError(f"Failed to get user for user_id={user_id}") from e
7780
else:
7881
user = session_data.user
7982
session_token = session_data.session

chat_server/sio/handlers/prompt.py

Lines changed: 46 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,17 @@
2626
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2727
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828

29-
from time import time
30-
3129
from klatchat_utils.database_utils.mongo_utils.queries import mongo_queries
32-
from klatchat_utils.database_utils.mongo_utils.queries.wrapper import MongoDocumentsAPI
30+
from klatchat_utils.database_utils.mongo_utils.queries.wrapper import (
31+
MongoDocumentsAPI,
32+
)
3333
from neon_utils.logger import LOG
34+
from neon_data_models.models.api.klat.socketio import (
35+
NewCcaiPrompt,
36+
CcaiPromptCompleted,
37+
GetPromptData,
38+
PromptData,
39+
)
3440
from chat_server.sio.server import sio
3541

3642

@@ -40,33 +46,17 @@ async def new_prompt(sid, data):
4046
SIO event fired on new prompt data saving request
4147
:param sid: client session id
4248
:param data: user message data
43-
Example:
44-
```
45-
data = {'cid':'conversation id',
46-
'promptID': 'id of related prompt',
47-
'context': 'message context (optional)',
48-
'timeCreated': 'timestamp on which message was created'
49-
}
50-
```
5149
"""
52-
prompt_id = data["prompt_id"]
53-
cid = data["cid"]
54-
prompt_text = data["prompt_text"]
55-
created_on = int(data.get("created_on") or time())
56-
context = data.get("context") or {}
50+
prompt = NewCcaiPrompt(**data)
51+
LOG.debug(f"Creating new prompt: {prompt.prompt_text}")
5752
try:
58-
formatted_data = {
59-
"_id": prompt_id,
60-
"cid": cid,
61-
"is_completed": "0",
62-
"data": {"prompt_text": prompt_text},
63-
"context": context,
64-
"created_on": created_on,
65-
}
53+
formatted_data = prompt.to_db_query()
6654
MongoDocumentsAPI.PROMPTS.add_item(data=formatted_data)
6755
await sio.emit("new_prompt_created", data=formatted_data)
6856
except Exception as ex:
69-
LOG.error(f'Prompt "{prompt_id}" was not created due to exception - {ex}')
57+
LOG.error(
58+
f'Prompt "{prompt.prompt_id}" was not created due to exception - {ex}'
59+
)
7060

7161

7262
@sio.event
@@ -76,17 +66,13 @@ async def prompt_completed(sid, data):
7666
:param sid: client session id
7767
:param data: user message data
7868
"""
79-
prompt_id = data["context"]["prompt"]["prompt_id"]
80-
81-
LOG.info(f"setting {prompt_id = } as completed")
82-
MongoDocumentsAPI.PROMPTS.set_completed(
83-
prompt_id=prompt_id, prompt_context=data["context"]
69+
prompt = CcaiPromptCompleted(**data)
70+
LOG.info(
71+
f"setting prompt_id={prompt.prompt_id} as completed with: " f"{prompt.winner}"
8472
)
85-
formatted_data = {
86-
"winner": data["context"].get("winner", ""),
87-
"prompt_id": prompt_id,
88-
}
89-
await sio.emit("set_prompt_completed", data=formatted_data)
73+
MongoDocumentsAPI.PROMPTS.set_completed(**prompt.to_db_query())
74+
75+
await sio.emit("set_prompt_completed", data=prompt.model_dump())
9076

9177

9278
@sio.event
@@ -95,41 +81,29 @@ async def get_prompt_data(sid, data):
9581
SIO event fired getting prompt data request
9682
:param sid: client session id
9783
:param data: user message data
98-
Example:
99-
```
100-
data = {'userID': 'emitted user id',
101-
'cid':'conversation id',
102-
'promptID': 'id of related prompt'}
103-
```
10484
"""
105-
prompt_id = data.get("prompt_id")
106-
_prompt_data = mongo_queries.fetch_prompt_data(
107-
cid=data["cid"],
108-
limit=data.get("limit", 5),
109-
prompt_ids=[prompt_id],
110-
fetch_user_data=True,
111-
)
112-
if prompt_id:
113-
prompt_data = {
114-
"_id": _prompt_data[0]["_id"],
115-
"is_completed": _prompt_data[0].get("is_completed", "1"),
116-
**_prompt_data[0].get("data", {}),
117-
}
118-
else:
119-
prompt_data = []
120-
for item in _prompt_data:
121-
prompt_data.append(
122-
{
123-
"_id": item["_id"],
124-
"created_on": item["created_on"],
125-
"is_completed": item.get("is_completed", "1"),
126-
**item["data"],
127-
}
128-
)
129-
result = dict(
130-
data=prompt_data,
131-
receiver=data["nick"],
132-
cid=data["cid"],
133-
request_id=data["request_id"],
134-
)
135-
await sio.emit("prompt_data", data=result)
85+
try:
86+
requested_prompt_data = GetPromptData(**data)
87+
_prompt_data = PromptData(
88+
**mongo_queries.fetch_prompt_data(**requested_prompt_data.to_db_query())
89+
)
90+
if requested_prompt_data.prompt_id:
91+
if isinstance(_prompt_data.data, list):
92+
prompt_data = _prompt_data.data[0].model_dump()
93+
else:
94+
prompt_data = _prompt_data.data.model_dump()
95+
else:
96+
prompt_data = []
97+
if isinstance(_prompt_data.data, list):
98+
for item in _prompt_data:
99+
prompt_data.append(item.model_dump())
100+
result = dict(
101+
data=prompt_data,
102+
receiver=requested_prompt_data.nick,
103+
cid=requested_prompt_data.cid,
104+
request_id=requested_prompt_data.request_id,
105+
)
106+
LOG.info(f"Emitting prompt_data: {result}")
107+
await sio.emit("prompt_data", data=result)
108+
except Exception as ex:
109+
LOG.error(f"Failed to get prompt data due to exception - {ex}")

chat_server/sio/handlers/stt.py

Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -28,35 +28,34 @@
2828

2929
from klatchat_utils.database_utils.mongo_utils.queries.wrapper import MongoDocumentsAPI
3030
from neon_utils.logger import LOG
31+
from pydantic import ValidationError
3132
from chat_server.sio.server import sio
3233
from chat_server.sio.utils import emit_error
33-
from chat_server.utils.languages import LanguageSettings
34+
35+
from neon_data_models.models.api.klat.socketio import GetSttResponse, GetSttRequest
3436

3537

3638
@sio.event
3739
async def stt_response(sid, data):
3840
"""Handle STT Response from Observer"""
39-
mq_context = data.get("context", {})
40-
message_id = mq_context.get("message_id")
41-
matching_shout = MongoDocumentsAPI.SHOUTS.get_item(item_id=message_id)
41+
response = GetSttResponse(**data)
42+
matching_shout = MongoDocumentsAPI.SHOUTS.get_item(item_id=response.sid)
4243
if not matching_shout:
4344
LOG.warning(
44-
f"Skipping STT Response for message_id={message_id} - matching shout does not exist"
45+
f"Skipping STT Response for sid={response.sid} - matching shout does not exist"
4546
)
4647
else:
4748
try:
48-
message_text = data.get("transcript")
49-
lang = LanguageSettings.to_system_lang(data["lang"])
5049
MongoDocumentsAPI.SHOUTS.save_stt_response(
51-
shout_id=message_id, message_text=message_text, lang=lang
50+
shout_id=response.sid,
51+
message_text=response.transcript,
52+
lang=response.lang,
5253
)
53-
sid = mq_context.get("sid")
54-
cid = mq_context.get("cid")
5554
response_data = {
56-
"cid": cid,
57-
"message_id": message_id,
58-
"lang": lang,
59-
"message_text": message_text,
55+
"cid": response.cid,
56+
"message_id": response.sid,
57+
"lang": response.lang,
58+
"message_text": response.transcript,
6059
}
6160
await sio.emit("incoming_stt", data=response_data, to=sid)
6261
except Exception as ex:
@@ -70,32 +69,18 @@ async def request_stt(sid, data):
7069
7170
:param sid: client session id
7271
:param data: received tts request data
73-
Example of tts request data:
74-
```
75-
data = {
76-
'cid': (target conversation id)
77-
'message_id': (target message id),
78-
'audio_data':(target audio data base64 encoded),
79-
(optional) 'lang': (target message lang)
80-
}
81-
```
8272
"""
83-
required_keys = ("message_id",)
84-
if not all(key in list(data) for key in required_keys):
85-
LOG.error(f"Missing one of the required keys - {required_keys}")
86-
else:
87-
cid = data.get("cid", "")
88-
message_id = data.get("message_id", "")
89-
# TODO: process received language
90-
lang = "en"
91-
# lang = data.get('lang', 'en')
92-
if shout_data := MongoDocumentsAPI.SHOUTS.get_item(item_id=message_id):
93-
message_transcript = shout_data.get("transcripts", {}).get(lang)
73+
try:
74+
request = GetSttRequest(sid=sid, **data)
75+
# TODO: Identify reason for this language patch
76+
request.lang = "en"
77+
if shout_data := MongoDocumentsAPI.SHOUTS.get_item(item_id=request.sid):
78+
message_transcript = shout_data.get("transcripts", {}).get(request.lang)
9479
if message_transcript:
9580
response_data = {
96-
"cid": cid,
97-
"message_id": message_id,
98-
"lang": lang,
81+
"cid": request.cid,
82+
"message_id": request.sid,
83+
"lang": request.lang,
9984
"message_text": message_transcript,
10085
}
10186
return await sio.emit("incoming_stt", data=response_data, to=sid)
@@ -105,16 +90,10 @@ async def request_stt(sid, data):
10590
return await emit_error(message=err_msg, sids=[sid])
10691
audio_data = data.get(
10792
"audio_data"
108-
) or MongoDocumentsAPI.SHOUTS.fetch_audio_data(message_id=message_id)
93+
) or MongoDocumentsAPI.SHOUTS.fetch_audio_data(sid=request.sid)
10994
if not audio_data:
11095
LOG.error("Failed to fetch audio data")
11196
else:
112-
lang = LanguageSettings.to_neon_lang(lang)
113-
formatted_data = {
114-
"cid": cid,
115-
"sid": sid,
116-
"message_id": message_id,
117-
"audio_data": audio_data,
118-
"lang": lang,
119-
}
120-
await sio.emit("get_stt", data=formatted_data)
97+
await sio.emit("get_stt", data=request.model_dump())
98+
except ValidationError:
99+
LOG.exception(f"Invalid STT request data - {data}")

chat_server/sio/handlers/translation.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
from chat_server.sio.server import sio
3636
from chat_server.utils.cache_utils import CacheFactory
3737

38+
# TODO: The backend service supporting these endpoints is no longer functional.
39+
# These need to be updated to implement appropriate data models once the
40+
# backend service is re-implemented.
41+
3842

3943
@sio.event
4044
async def request_translate(sid, data):

0 commit comments

Comments
 (0)