chore: update CLAUDE.md and enhance project documentation
- Revised the CLAUDE.md file for clarity and improved structure, including a more concise project overview and a formatted quick orientation section. - Added a new function `resolve_create_project_id` to handle project ID resolution for meeting creation, enhancing the project management logic. - Updated the `MeetingMixin` to utilize the new project ID resolution function, improving the handling of project IDs during meeting creation. - Enhanced logging in the streaming mixins to provide better insights during stream initialization and transcription processes. - Updated various linting and configuration files for improved diagnostics and code quality.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
|
||||
{
|
||||
"version": "1.36.1",
|
||||
"time": "1767753071383",
|
||||
"time": "1767755561086",
|
||||
"generalDiagnostics": [],
|
||||
"summary": {
|
||||
"filesAnalyzed": 700,
|
||||
"errorCount": 0,
|
||||
"warningCount": 0,
|
||||
"informationCount": 0,
|
||||
"timeInSec": 12.389
|
||||
"timeInSec": 11.725
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"summary":{"changed":0,"unchanged":396,"matches":0,"duration":{"secs":0,"nanos":115511739},"scannerDuration":{"secs":0,"nanos":2646535},"errors":0,"warnings":0,"infos":0,"skipped":0,"suggestedFixesSkipped":0,"diagnosticsNotPrinted":0},"diagnostics":[],"command":"lint"}
|
||||
{"summary":{"changed":0,"unchanged":396,"matches":0,"duration":{"secs":0,"nanos":94347688},"scannerDuration":{"secs":0,"nanos":3009402},"errors":0,"warnings":0,"infos":0,"skipped":0,"suggestedFixesSkipped":0,"diagnosticsNotPrinted":0},"diagnostics":[],"command":"lint"}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
2
client
2
client
Submodule client updated: c7a152a3fe...24832b691d
@@ -7,6 +7,7 @@ from uuid import UUID
|
||||
|
||||
from noteflow.config.constants import ERROR_INVALID_PROJECT_ID_PREFIX
|
||||
from noteflow.domain.constants.fields import PROJECT_ID
|
||||
from noteflow.domain.identity import OperationContext
|
||||
from noteflow.infrastructure.logging import get_logger, get_workspace_id
|
||||
|
||||
from ...proto import noteflow_pb2
|
||||
@@ -129,3 +130,50 @@ async def resolve_active_project_id(
|
||||
repo, workspace_uuid
|
||||
)
|
||||
return active_project.id if active_project else None
|
||||
|
||||
|
||||
async def resolve_create_project_id(
|
||||
host: ServicerHost,
|
||||
repo: MeetingRepositoryProvider,
|
||||
op_context: OperationContext,
|
||||
project_id: UUID | None,
|
||||
) -> UUID | None:
|
||||
"""Validate project_id for CreateMeeting and fall back to active/default.
|
||||
|
||||
Returns a resolved project_id or None if no valid project is available.
|
||||
"""
|
||||
if project_id is None:
|
||||
return await resolve_active_project_id(host, repo)
|
||||
|
||||
if not repo.supports_projects:
|
||||
logger.debug(
|
||||
"CreateMeeting: project_id ignored (projects not supported)",
|
||||
project_id=str(project_id),
|
||||
)
|
||||
return None
|
||||
|
||||
project = await repo.projects.get(project_id)
|
||||
if project is None:
|
||||
logger.warning(
|
||||
"CreateMeeting: project not found, falling back to default",
|
||||
project_id=str(project_id),
|
||||
)
|
||||
return await resolve_active_project_id(host, repo)
|
||||
|
||||
if project.is_archived:
|
||||
logger.warning(
|
||||
"CreateMeeting: project archived, falling back to default",
|
||||
project_id=str(project_id),
|
||||
)
|
||||
return await resolve_active_project_id(host, repo)
|
||||
|
||||
if project.workspace_id != op_context.workspace_id:
|
||||
logger.warning(
|
||||
"CreateMeeting: project workspace mismatch, falling back",
|
||||
project_id=str(project_id),
|
||||
project_workspace_id=str(project.workspace_id),
|
||||
workspace_id=str(op_context.workspace_id),
|
||||
)
|
||||
return await resolve_active_project_id(host, repo)
|
||||
|
||||
return project_id
|
||||
|
||||
@@ -21,6 +21,7 @@ from ._project_scope import (
|
||||
parse_project_id_or_abort,
|
||||
parse_project_ids_or_abort,
|
||||
resolve_active_project_id,
|
||||
resolve_create_project_id,
|
||||
)
|
||||
from ._stop_ops import (
|
||||
cleanup_audio_writer,
|
||||
@@ -72,8 +73,7 @@ class MeetingMixin:
|
||||
op_context = self.get_operation_context(context)
|
||||
|
||||
async with cast(MeetingRepositoryProvider, self.create_repository_provider()) as repo:
|
||||
if project_id is None:
|
||||
project_id = await resolve_active_project_id(self, repo)
|
||||
project_id = await resolve_create_project_id(self, repo, op_context, project_id)
|
||||
|
||||
meeting = Meeting.create(
|
||||
title=request.title,
|
||||
|
||||
@@ -89,7 +89,9 @@ class StreamingMixin:
|
||||
persist segments, and yield transcript updates.
|
||||
Works with both database and memory backends via RepositoryProvider.
|
||||
"""
|
||||
logger.info("StreamTranscription opened")
|
||||
if self.asr_engine is None or not self.asr_engine.is_loaded:
|
||||
logger.warning("StreamTranscription rejected: ASR engine not loaded")
|
||||
await abort_failed_precondition(context, "ASR engine not loaded")
|
||||
|
||||
stream_state = _StreamState()
|
||||
@@ -188,6 +190,12 @@ class StreamingMixin:
|
||||
if current_meeting_id is None:
|
||||
# Track meeting_id BEFORE init to guarantee cleanup on any exception
|
||||
initialized_meeting_id = meeting_id
|
||||
logger.info(
|
||||
"StreamTranscription initializing meeting %s (sample_rate=%s channels=%s)",
|
||||
meeting_id,
|
||||
chunk.sample_rate,
|
||||
chunk.channels,
|
||||
)
|
||||
init_result = await self.init_stream_for_meeting(meeting_id, context)
|
||||
return None if init_result is None else (meeting_id, initialized_meeting_id)
|
||||
if meeting_id != current_meeting_id:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import Protocol as TypingProtocol
|
||||
@@ -167,15 +168,33 @@ class StreamSessionManager:
|
||||
Returns:
|
||||
Initialization result, or None if error was sent.
|
||||
"""
|
||||
init_started = time.monotonic()
|
||||
logger.info("Stream init requested for meeting %s", meeting_id)
|
||||
if not await StreamSessionManager._reserve_stream_slot(host, meeting_id, context):
|
||||
return None
|
||||
|
||||
init_result = await StreamSessionManager._init_stream_session(host, meeting_id)
|
||||
success = init_result.success
|
||||
error_code = init_result.error_code
|
||||
error_message = init_result.error_message or ""
|
||||
|
||||
if not init_result.success:
|
||||
if not success:
|
||||
host.active_streams.discard(meeting_id)
|
||||
error_code = init_result.error_code if init_result.error_code is not None else grpc.StatusCode.INTERNAL
|
||||
await context.abort(error_code, init_result.error_message or "")
|
||||
status = error_code if error_code is not None else grpc.StatusCode.INTERNAL
|
||||
logger.warning(
|
||||
"Stream init failed for meeting %s (%s): %s",
|
||||
meeting_id,
|
||||
status,
|
||||
error_message,
|
||||
)
|
||||
await context.abort(status, error_message)
|
||||
else:
|
||||
elapsed_ms = (time.monotonic() - init_started) * 1000.0
|
||||
logger.info(
|
||||
"Stream init completed for meeting %s in %.1fms",
|
||||
meeting_id,
|
||||
elapsed_ms,
|
||||
)
|
||||
|
||||
return init_result
|
||||
|
||||
|
||||
Reference in New Issue
Block a user