Skip to content

Commit 36737fc

Browse files
Feat/swipe anomaly 3 (#310)
* Enhance model management and transcription provider setup - Added `add_or_update_model` method in `ConfigManager` to facilitate adding or updating models in the configuration. - Updated `ChronicleSetup` to support a new OpenAI-Compatible transcription provider, allowing users to configure custom endpoints and API keys. - Enhanced user prompts for API base URL and model name during setup, improving the configuration experience. - Introduced unit tests for the new model management functionality and transcription provider setup, ensuring robust validation of the changes. - Improved Docker configurations for ASR services, including support for customizable CUDA versions and DNS settings. * Remove outdated unit tests for LLM custom provider and transcription URL configuration * Enhance Docker Compose and service management for LangFuse integration - Updated `services.py` to include new options for service management, allowing for forced recreation of containers during startup. - Added LangFuse configuration options in the setup wizard, improving user experience for observability setup. - Introduced new API endpoints for retrieving observability configuration, enhancing integration with the frontend. - Enhanced error handling and logging for service startup processes, ensuring better visibility of configuration issues. - Updated documentation to reflect changes in service management and LangFuse integration. * Enhance README and add new ASR service configurations - Updated README.md to include a new section for the Desktop Menu Bar Client with an accompanying screenshot. - Added configuration options for the new `galileo` ASR provider in `pyproject.toml` and `uv.lock`, enhancing support for additional audio processing capabilities. - Modified Dockerfile to include `galileo` as an extra dependency for both main and test environments, improving service management. - Enhanced job handling in `queue_controller.py` to track batch progress for transcription jobs, providing better user feedback during processing. - Updated Queue.tsx to display batch progress for audio transcription jobs, improving user experience in the web interface. - Refactored System.tsx to allow for restarting both workers and backend services, enhancing service management capabilities. * Refactor pre-commit configuration and enhance development scripts (#309) * Refactor pre-commit configuration and enhance development scripts - Removed local hooks for Robot Framework tests and cleanup from `.pre-commit-config.yaml`, streamlining the pre-commit setup. - Updated `Makefile` to install pre-commit using the `uv` tool, improving dependency management. - Enhanced `restart.sh`, `start.sh`, `status.sh`, and `stop.sh` scripts to source a new `check_uv.sh` script for better environment validation. - Added new environment variables for Galileo observability in `.env.template`, improving observability setup. - Introduced OpenTelemetry initialization in `app_factory.py` for enhanced observability during application runtime. * Update button event handling and plugin architecture - Changed button state terminology from `SINGLE_TAP` and `DOUBLE_TAP` to `SINGLE_PRESS` and `DOUBLE_PRESS` across various files, including documentation and code implementations. - Enhanced the `send_button_event` method to reflect the updated button state values, ensuring consistency in event handling. - Introduced new methods for managing button events in the plugin architecture, improving the overall interaction with device buttons. - Updated tests to align with the new button state definitions, ensuring robust coverage for the updated functionality. * Add unit tests for Qwen3-ASR output parsing and repetition detection - Introduced a new test file `test_qwen3_asr_parsing.py` to validate the functionality of the `_parse_qwen3_output` and `detect_and_fix_repetitions` methods. - Implemented various test cases covering standard and edge cases for ASR output parsing, including language detection, handling of empty inputs, and unexpected text. - Added tests for repetition detection to ensure proper functionality based on specified thresholds. - Enhanced the `Makefile` to include a new target for running specific tests by name, tag, or file, improving test execution flexibility. - Created a shared prerequisite check script `check_uv.sh` to ensure the `uv` package manager is installed before running scripts, enhancing setup reliability. * Add unit tests for Qwen3-ASR output parsing and repetition detection - Introduced a new test file `test_qwen3_asr_parsing.py` to validate the functionality of the `_parse_qwen3_output` and `detect_and_fix_repetitions` methods. - Implemented various test cases covering standard and edge cases for ASR output parsing, including language detection, handling of empty inputs, and unexpected text. - Added tests for repetition detection to ensure proper functionality based on specified thresholds. * Refactor Redis session handling and enhance error management - Updated session retrieval logic in `queue_routes.py` to ensure proper closure of Redis connections using `await redis_client.aclose()`, improving resource management. - Enhanced error handling during session data retrieval, providing clearer logging for issues encountered while fetching session information. - Streamlined the session key scanning process, maintaining existing functionality while improving code readability and maintainability. - Added optional parameters to the `transcribe` method in `mock_provider.py` for better flexibility in handling context information and progress callbacks during transcription tasks. * Refactor test workflows to utilize Makefile targets and enhance documentation - Replaced the `run-no-api-tests.sh` script with a Makefile target `make test-no-api` for executing tests without API keys, streamlining the testing process. - Updated GitHub Actions workflows and README documentation to reflect the new Makefile usage, improving clarity for contributors. - Removed the deprecated `run-no-api-tests.sh` script to reduce redundancy and simplify the codebase. * Update user loop with keyboard shortcuts - Added new service configuration for LangFuse in `services.py`, including path, compose file, description, and ports. - Refactored the backend initialization process to improve observability and prompt management with LangFuse. - Updated the `load_config_yml` function to ensure proper loading of LangFuse settings. - Enhanced error handling and logging during service startup to provide better visibility into configuration issues. * Feat/asr progress (#308) * Enhance Docker Compose and service management for LangFuse integration - Updated `services.py` to include new options for service management, allowing for forced recreation of containers during startup. - Added LangFuse configuration options in the setup wizard, improving user experience for observability setup. - Introduced new API endpoints for retrieving observability configuration, enhancing integration with the frontend. - Enhanced error handling and logging for service startup processes, ensuring better visibility of configuration issues. - Updated documentation to reflect changes in service management and LangFuse integration. * Enhance README and add new ASR service configurations - Updated README.md to include a new section for the Desktop Menu Bar Client with an accompanying screenshot. - Added configuration options for the new `galileo` ASR provider in `pyproject.toml` and `uv.lock`, enhancing support for additional audio processing capabilities. - Modified Dockerfile to include `galileo` as an extra dependency for both main and test environments, improving service management. - Enhanced job handling in `queue_controller.py` to track batch progress for transcription jobs, providing better user feedback during processing. - Updated Queue.tsx to display batch progress for audio transcription jobs, improving user experience in the web interface. - Refactored System.tsx to allow for restarting both workers and backend services, enhancing service management capabilities. * Refactor pre-commit configuration and enhance development scripts (#309) * Refactor pre-commit configuration and enhance development scripts - Removed local hooks for Robot Framework tests and cleanup from `.pre-commit-config.yaml`, streamlining the pre-commit setup. - Updated `Makefile` to install pre-commit using the `uv` tool, improving dependency management. - Enhanced `restart.sh`, `start.sh`, `status.sh`, and `stop.sh` scripts to source a new `check_uv.sh` script for better environment validation. - Added new environment variables for Galileo observability in `.env.template`, improving observability setup. - Introduced OpenTelemetry initialization in `app_factory.py` for enhanced observability during application runtime. * Update button event handling and plugin architecture - Changed button state terminology from `SINGLE_TAP` and `DOUBLE_TAP` to `SINGLE_PRESS` and `DOUBLE_PRESS` across various files, including documentation and code implementations. - Enhanced the `send_button_event` method to reflect the updated button state values, ensuring consistency in event handling. - Introduced new methods for managing button events in the plugin architecture, improving the overall interaction with device buttons. - Updated tests to align with the new button state definitions, ensuring robust coverage for the updated functionality. * Add unit tests for Qwen3-ASR output parsing and repetition detection - Introduced a new test file `test_qwen3_asr_parsing.py` to validate the functionality of the `_parse_qwen3_output` and `detect_and_fix_repetitions` methods. - Implemented various test cases covering standard and edge cases for ASR output parsing, including language detection, handling of empty inputs, and unexpected text. - Added tests for repetition detection to ensure proper functionality based on specified thresholds. - Enhanced the `Makefile` to include a new target for running specific tests by name, tag, or file, improving test execution flexibility. - Created a shared prerequisite check script `check_uv.sh` to ensure the `uv` package manager is installed before running scripts, enhancing setup reliability. * Add unit tests for Qwen3-ASR output parsing and repetition detection - Introduced a new test file `test_qwen3_asr_parsing.py` to validate the functionality of the `_parse_qwen3_output` and `detect_and_fix_repetitions` methods. - Implemented various test cases covering standard and edge cases for ASR output parsing, including language detection, handling of empty inputs, and unexpected text. - Added tests for repetition detection to ensure proper functionality based on specified thresholds. * Refactor Redis session handling and enhance error management - Updated session retrieval logic in `queue_routes.py` to ensure proper closure of Redis connections using `await redis_client.aclose()`, improving resource management. - Enhanced error handling during session data retrieval, providing clearer logging for issues encountered while fetching session information. - Streamlined the session key scanning process, maintaining existing functionality while improving code readability and maintainability. - Added optional parameters to the `transcribe` method in `mock_provider.py` for better flexibility in handling context information and progress callbacks during transcription tasks. * Refactor test workflows to utilize Makefile targets and enhance documentation - Replaced the `run-no-api-tests.sh` script with a Makefile target `make test-no-api` for executing tests without API keys, streamlining the testing process. - Updated GitHub Actions workflows and README documentation to reflect the new Makefile usage, improving clarity for contributors. - Removed the deprecated `run-no-api-tests.sh` script to reduce redundancy and simplify the codebase. * Enhance Docker Compose and service management for LangFuse integration - Updated `services.py` to include new options for service management, allowing for forced recreation of containers during startup. - Added LangFuse configuration options in the setup wizard, improving user experience for observability setup. - Introduced new API endpoints for retrieving observability configuration, enhancing integration with the frontend. - Enhanced error handling and logging for service startup processes, ensuring better visibility of configuration issues. - Updated documentation to reflect changes in service management and LangFuse integration. * Refactor pre-commit configuration and enhance development scripts (#309) * Refactor pre-commit configuration and enhance development scripts - Removed local hooks for Robot Framework tests and cleanup from `.pre-commit-config.yaml`, streamlining the pre-commit setup. - Updated `Makefile` to install pre-commit using the `uv` tool, improving dependency management. - Enhanced `restart.sh`, `start.sh`, `status.sh`, and `stop.sh` scripts to source a new `check_uv.sh` script for better environment validation. - Added new environment variables for Galileo observability in `.env.template`, improving observability setup. - Introduced OpenTelemetry initialization in `app_factory.py` for enhanced observability during application runtime. * Update button event handling and plugin architecture - Changed button state terminology from `SINGLE_TAP` and `DOUBLE_TAP` to `SINGLE_PRESS` and `DOUBLE_PRESS` across various files, including documentation and code implementations. - Enhanced the `send_button_event` method to reflect the updated button state values, ensuring consistency in event handling. - Introduced new methods for managing button events in the plugin architecture, improving the overall interaction with device buttons. - Updated tests to align with the new button state definitions, ensuring robust coverage for the updated functionality. * Add unit tests for Qwen3-ASR output parsing and repetition detection - Introduced a new test file `test_qwen3_asr_parsing.py` to validate the functionality of the `_parse_qwen3_output` and `detect_and_fix_repetitions` methods. - Implemented various test cases covering standard and edge cases for ASR output parsing, including language detection, handling of empty inputs, and unexpected text. - Added tests for repetition detection to ensure proper functionality based on specified thresholds. - Enhanced the `Makefile` to include a new target for running specific tests by name, tag, or file, improving test execution flexibility. - Created a shared prerequisite check script `check_uv.sh` to ensure the `uv` package manager is installed before running scripts, enhancing setup reliability. * Add unit tests for Qwen3-ASR output parsing and repetition detection - Introduced a new test file `test_qwen3_asr_parsing.py` to validate the functionality of the `_parse_qwen3_output` and `detect_and_fix_repetitions` methods. - Implemented various test cases covering standard and edge cases for ASR output parsing, including language detection, handling of empty inputs, and unexpected text. - Added tests for repetition detection to ensure proper functionality based on specified thresholds. * Refactor Redis session handling and enhance error management - Updated session retrieval logic in `queue_routes.py` to ensure proper closure of Redis connections using `await redis_client.aclose()`, improving resource management. - Enhanced error handling during session data retrieval, providing clearer logging for issues encountered while fetching session information. - Streamlined the session key scanning process, maintaining existing functionality while improving code readability and maintainability. - Added optional parameters to the `transcribe` method in `mock_provider.py` for better flexibility in handling context information and progress callbacks during transcription tasks. * lint --------- Co-authored-by: 0xrushi <6279035+0xrushi@users.noreply.github.com>
1 parent 430027d commit 36737fc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+5548
-1334
lines changed

backends/advanced/init.py

Lines changed: 644 additions & 248 deletions
Large diffs are not rendered by default.

backends/advanced/src/advanced_omi_backend/app_factory.py

Lines changed: 218 additions & 155 deletions
Large diffs are not rendered by default.

backends/advanced/src/advanced_omi_backend/controllers/conversation_controller.py

Lines changed: 65 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,25 @@
4646
audio_logger = logging.getLogger("audio_processing")
4747

4848

49+
async def _get_conversation_or_error(conversation_id: str, user: User):
50+
"""Fetch a conversation and validate user access.
51+
52+
Returns (conversation, None) on success, or (None, error_response) on failure.
53+
"""
54+
conversation = await Conversation.find_one(
55+
Conversation.conversation_id == conversation_id
56+
)
57+
if not conversation:
58+
return None, JSONResponse(
59+
status_code=404, content={"error": "Conversation not found"}
60+
)
61+
if not user.is_superuser and conversation.user_id != str(user.user_id):
62+
return None, JSONResponse(
63+
status_code=403, content={"error": "Access forbidden"}
64+
)
65+
return conversation, None
66+
67+
4968
async def close_current_conversation(client_id: str, user: User):
5069
"""Close the current conversation for a specific client.
5170
@@ -112,18 +131,9 @@ async def close_current_conversation(client_id: str, user: User):
112131
async def get_conversation(conversation_id: str, user: User):
113132
"""Get a single conversation with full transcript details."""
114133
try:
115-
# Find the conversation using Beanie
116-
conversation = await Conversation.find_one(
117-
Conversation.conversation_id == conversation_id
118-
)
119-
if not conversation:
120-
return JSONResponse(
121-
status_code=404, content={"error": "Conversation not found"}
122-
)
123-
124-
# Check ownership for non-admin users
125-
if not user.is_superuser and conversation.user_id != str(user.user_id):
126-
return JSONResponse(status_code=403, content={"error": "Access forbidden"})
134+
conversation, error = await _get_conversation_or_error(conversation_id, user)
135+
if error:
136+
return error
127137

128138
# Build response with explicit curated fields
129139
response = {
@@ -184,16 +194,9 @@ async def get_conversation(conversation_id: str, user: User):
184194
async def get_conversation_memories(conversation_id: str, user: User, limit: int = 100):
185195
"""Get memories extracted from a specific conversation."""
186196
try:
187-
conversation = await Conversation.find_one(
188-
Conversation.conversation_id == conversation_id
189-
)
190-
if not conversation:
191-
return JSONResponse(
192-
status_code=404, content={"error": "Conversation not found"}
193-
)
194-
195-
if not user.is_superuser and conversation.user_id != str(user.user_id):
196-
return JSONResponse(status_code=403, content={"error": "Access forbidden"})
197+
conversation, error = await _get_conversation_or_error(conversation_id, user)
198+
if error:
199+
return error
197200

198201
memory_service = get_memory_service()
199202
memories = await memory_service.get_memories_by_source(
@@ -671,29 +674,13 @@ async def delete_conversation(
671674
f"Attempting to {'permanently ' if permanent else ''}delete conversation: {masked_id}"
672675
)
673676

674-
# Find the conversation using Beanie
675-
conversation = await Conversation.find_one(
676-
Conversation.conversation_id == conversation_id
677-
)
678-
679-
if not conversation:
680-
return JSONResponse(
681-
status_code=404,
682-
content={"error": f"Conversation '{conversation_id}' not found"},
683-
)
684-
685-
# Check ownership for non-admin users
686-
if not user.is_superuser and conversation.user_id != str(user.user_id):
687-
logger.warning(
688-
f"User {user.user_id} attempted to delete conversation {conversation_id} without permission"
689-
)
690-
return JSONResponse(
691-
status_code=403,
692-
content={
693-
"error": "Access forbidden. You can only delete your own conversations.",
694-
"details": f"Conversation '{conversation_id}' does not belong to your account.",
695-
},
696-
)
677+
conversation, error = await _get_conversation_or_error(conversation_id, user)
678+
if error:
679+
if error.status_code == 403:
680+
logger.warning(
681+
f"User {user.user_id} attempted to delete conversation {conversation_id} without permission"
682+
)
683+
return error
697684

698685
# Hard delete (admin only, permanent flag)
699686
if permanent and user.is_superuser:
@@ -719,18 +706,9 @@ async def restore_conversation(conversation_id: str, user: User) -> JSONResponse
719706
user: Requesting user
720707
"""
721708
try:
722-
conversation = await Conversation.find_one(
723-
Conversation.conversation_id == conversation_id
724-
)
725-
726-
if not conversation:
727-
return JSONResponse(
728-
status_code=404, content={"error": "Conversation not found"}
729-
)
730-
731-
# Permission check
732-
if not user.is_superuser and conversation.user_id != str(user.user_id):
733-
return JSONResponse(status_code=403, content={"error": "Access denied"})
709+
conversation, error = await _get_conversation_or_error(conversation_id, user)
710+
if error:
711+
return error
734712

735713
if not conversation.deleted:
736714
return JSONResponse(
@@ -933,16 +911,9 @@ def _enqueue_speaker_reprocessing_chain(
933911
async def toggle_star(conversation_id: str, user: User):
934912
"""Toggle the starred/favorite status of a conversation."""
935913
try:
936-
conversation = await Conversation.find_one(
937-
Conversation.conversation_id == conversation_id
938-
)
939-
if not conversation:
940-
return JSONResponse(
941-
status_code=404, content={"error": "Conversation not found"}
942-
)
943-
944-
if not user.is_superuser and conversation.user_id != str(user.user_id):
945-
return JSONResponse(status_code=403, content={"error": "Access forbidden"})
914+
conversation, error = await _get_conversation_or_error(conversation_id, user)
915+
if error:
916+
return error
946917

947918
# Toggle
948919
conversation.starred = not conversation.starred
@@ -993,17 +964,9 @@ async def toggle_star(conversation_id: str, user: User):
993964
async def reprocess_orphan(conversation_id: str, user: User):
994965
"""Reprocess an orphan audio session - restore if deleted and enqueue full processing chain."""
995966
try:
996-
conversation = await Conversation.find_one(
997-
Conversation.conversation_id == conversation_id
998-
)
999-
if not conversation:
1000-
return JSONResponse(
1001-
status_code=404, content={"error": "Conversation not found"}
1002-
)
1003-
1004-
# Check ownership
1005-
if not user.is_superuser and conversation.user_id != str(user.user_id):
1006-
return JSONResponse(status_code=403, content={"error": "Access forbidden"})
967+
conversation, error = await _get_conversation_or_error(conversation_id, user)
968+
if error:
969+
return error
1007970

1008971
# Verify audio chunks exist (check both deleted and non-deleted)
1009972
total_chunks = await AudioChunkDocument.find(
@@ -1068,23 +1031,11 @@ async def reprocess_orphan(conversation_id: str, user: User):
10681031
async def reprocess_transcript(conversation_id: str, user: User):
10691032
"""Reprocess transcript for a conversation. Users can only reprocess their own conversations."""
10701033
try:
1071-
# Find the conversation using Beanie
1072-
conversation_model = await Conversation.find_one(
1073-
Conversation.conversation_id == conversation_id
1034+
conversation_model, error = await _get_conversation_or_error(
1035+
conversation_id, user
10741036
)
1075-
if not conversation_model:
1076-
return JSONResponse(
1077-
status_code=404, content={"error": "Conversation not found"}
1078-
)
1079-
1080-
# Check ownership for non-admin users
1081-
if not user.is_superuser and conversation_model.user_id != str(user.user_id):
1082-
return JSONResponse(
1083-
status_code=403,
1084-
content={
1085-
"error": "Access forbidden. You can only reprocess your own conversations."
1086-
},
1087-
)
1037+
if error:
1038+
return error
10881039

10891040
# Get audio_uuid from conversation
10901041
# Validate audio chunks exist in MongoDB
@@ -1137,24 +1088,11 @@ async def reprocess_memory(
11371088
):
11381089
"""Reprocess memory extraction for a specific transcript version. Users can only reprocess their own conversations."""
11391090
try:
1140-
# Find the conversation using Beanie
1141-
conversation_model = await Conversation.find_one(
1142-
Conversation.conversation_id == conversation_id
1091+
conversation_model, error = await _get_conversation_or_error(
1092+
conversation_id, user
11431093
)
1144-
if not conversation_model:
1145-
return JSONResponse(
1146-
status_code=404, content={"error": "Conversation not found"}
1147-
)
1148-
1149-
# Check ownership for non-admin users
1150-
if not user.is_superuser and conversation_model.user_id != str(user.user_id):
1151-
return JSONResponse(
1152-
status_code=403,
1153-
content={
1154-
"error": "Access forbidden. You can only reprocess your own conversations."
1155-
},
1156-
)
1157-
1094+
if error:
1095+
return error
11581096
# Resolve transcript version ID (handle "active" special case)
11591097
error, transcript_version_id, transcript_version = _resolve_transcript_version(
11601098
conversation_model, transcript_version_id
@@ -1205,23 +1143,11 @@ async def reprocess_speakers(
12051143
"""
12061144
try:
12071145
# 1. Find conversation and validate ownership
1208-
conversation_model = await Conversation.find_one(
1209-
Conversation.conversation_id == conversation_id
1146+
conversation_model, error = await _get_conversation_or_error(
1147+
conversation_id, user
12101148
)
1211-
if not conversation_model:
1212-
return JSONResponse(
1213-
status_code=404, content={"error": "Conversation not found"}
1214-
)
1215-
1216-
# Check ownership for non-admin users
1217-
if not user.is_superuser and conversation_model.user_id != str(user.user_id):
1218-
return JSONResponse(
1219-
status_code=403,
1220-
content={
1221-
"error": "Access forbidden. You can only reprocess your own conversations."
1222-
},
1223-
)
1224-
1149+
if error:
1150+
return error
12251151
# 2-3. Resolve source transcript version ID and find version object
12261152
error, source_version_id, source_version = _resolve_transcript_version(
12271153
conversation_model, transcript_version_id
@@ -1349,23 +1275,11 @@ async def activate_transcript_version(
13491275
):
13501276
"""Activate a specific transcript version. Users can only modify their own conversations."""
13511277
try:
1352-
# Find the conversation using Beanie
1353-
conversation_model = await Conversation.find_one(
1354-
Conversation.conversation_id == conversation_id
1278+
conversation_model, error = await _get_conversation_or_error(
1279+
conversation_id, user
13551280
)
1356-
if not conversation_model:
1357-
return JSONResponse(
1358-
status_code=404, content={"error": "Conversation not found"}
1359-
)
1360-
1361-
# Check ownership for non-admin users
1362-
if not user.is_superuser and conversation_model.user_id != str(user.user_id):
1363-
return JSONResponse(
1364-
status_code=403,
1365-
content={
1366-
"error": "Access forbidden. You can only modify your own conversations."
1367-
},
1368-
)
1281+
if error:
1282+
return error
13691283

13701284
# Activate the transcript version using Beanie model method
13711285
success = conversation_model.set_active_transcript_version(version_id)
@@ -1401,23 +1315,11 @@ async def activate_transcript_version(
14011315
async def activate_memory_version(conversation_id: str, version_id: str, user: User):
14021316
"""Activate a specific memory version. Users can only modify their own conversations."""
14031317
try:
1404-
# Find the conversation using Beanie
1405-
conversation_model = await Conversation.find_one(
1406-
Conversation.conversation_id == conversation_id
1318+
conversation_model, error = await _get_conversation_or_error(
1319+
conversation_id, user
14071320
)
1408-
if not conversation_model:
1409-
return JSONResponse(
1410-
status_code=404, content={"error": "Conversation not found"}
1411-
)
1412-
1413-
# Check ownership for non-admin users
1414-
if not user.is_superuser and conversation_model.user_id != str(user.user_id):
1415-
return JSONResponse(
1416-
status_code=403,
1417-
content={
1418-
"error": "Access forbidden. You can only modify your own conversations."
1419-
},
1420-
)
1321+
if error:
1322+
return error
14211323

14221324
# Activate the memory version using Beanie model method
14231325
success = conversation_model.set_active_memory_version(version_id)
@@ -1449,23 +1351,11 @@ async def activate_memory_version(conversation_id: str, version_id: str, user: U
14491351
async def get_conversation_version_history(conversation_id: str, user: User):
14501352
"""Get version history for a conversation. Users can only access their own conversations."""
14511353
try:
1452-
# Find the conversation using Beanie to check ownership
1453-
conversation_model = await Conversation.find_one(
1454-
Conversation.conversation_id == conversation_id
1354+
conversation_model, error = await _get_conversation_or_error(
1355+
conversation_id, user
14551356
)
1456-
if not conversation_model:
1457-
return JSONResponse(
1458-
status_code=404, content={"error": "Conversation not found"}
1459-
)
1460-
1461-
# Check ownership for non-admin users
1462-
if not user.is_superuser and conversation_model.user_id != str(user.user_id):
1463-
return JSONResponse(
1464-
status_code=403,
1465-
content={
1466-
"error": "Access forbidden. You can only access your own conversations."
1467-
},
1468-
)
1357+
if error:
1358+
return error
14691359

14701360
# Get version history from model
14711361
# Convert datetime objects to ISO strings for JSON serialization

0 commit comments

Comments
 (0)