chore: update development documentation and dependencies

- Added important notes regarding Docker operations to prevent disruption of the hot-reload server.
- Introduced a section outlining forbidden Docker commands without explicit user permission.
- Refactored `pyproject.toml` to categorize audio-related dependencies under an optional section.
- Updated dependencies for `weasyprint` and `spacy` to their latest versions.
- Adjusted the server Dockerfile to ensure the hot-reload server starts correctly.

All quality checks pass.
This commit is contained in:
2025-12-31 05:29:33 -05:00
parent 246837ea35
commit e23c0555e2
4 changed files with 65 additions and 16 deletions

View File

@@ -61,6 +61,8 @@ python scripts/dev_watch_server.py # Auto-reload server (watches src/)
## Docker Development
**IMPORTANT: The server runs with hot-reload enabled.** Assume Docker services are always running. Never restart, rebuild, or stop containers without explicit user permission—doing so disrupts the development workflow.
```bash
# Start PostgreSQL (with pgvector)
docker compose up -d postgres
@@ -75,6 +77,14 @@ python scripts/dev_watch_server.py # Uses watchfiles, monitors src/ and alembic
Dev container features: dbus-x11, GTK-3, libgl1 for system tray and hotkey support.
### Forbidden Docker Operations (without explicit permission)
- `docker compose build` — rebuilds images, disrupts running containers
- `docker compose up` / `down` / `restart` — starts/stops services
- `docker stop` / `docker kill` — kills running containers
- Any command that would interrupt the hot-reload server
Code changes are automatically picked up by the watchfiles-based hot-reload. If you need to suggest a Docker operation, ask the user first.
## Architecture
```

View File

@@ -61,6 +61,8 @@ RUN --mount=type=cache,target=/root/.cache/uv \
EXPOSE 50051
CMD ["uv", "run", "python", "scripts/dev_watch_server.py"]
# -----------------------------------------------------------------------------
# NER stage: Add spaCy model for named entity recognition
# -----------------------------------------------------------------------------

View File

@@ -7,9 +7,6 @@ requires-python = ">=3.12"
dependencies = [
# Core
"pydantic>=2.0",
# Audio
"sounddevice>=0.4.6",
"numpy>=1.26",
# Spike 3: ASR
"faster-whisper>=1.0",
# Spike 4: Encryption
@@ -27,17 +24,18 @@ dependencies = [
# Settings
"pydantic-settings>=2.0",
"psutil>=7.1.3",
"diart>=0.9.2",
# HTTP client for webhooks and integrations
"httpx>=0.27",
"weasyprint>=67.0",
"authlib>=1.6.6",
"spacy>=3.8.11",
"rich>=14.2.0",
"types-psutil>=7.2.0.20251228",
]
[project.optional-dependencies]
audio = [
"sounddevice>=0.4.6",
"numpy>=1.26",
]
dev = [
"pytest>=8.0",
"pytest-cov>=4.0",
@@ -61,10 +59,10 @@ diarization = [
"torch>=2.0",
]
pdf = [
"weasyprint>=62.0",
"weasyprint>=67.0",
]
ner = [
"spacy>=3.7",
"spacy>=3.8.11",
]
calendar = [
"google-api-python-client>=2.100",
@@ -77,8 +75,36 @@ observability = [
"opentelemetry-instrumentation-grpc>=0.49b",
"opentelemetry-exporter-otlp>=1.28",
]
optional = [
# Audio
"sounddevice>=0.4.6",
"numpy>=1.26",
# Triggers
"pywinctl>=0.3",
# Summarization
"ollama>=0.6.1",
"openai>=2.13.0",
"anthropic>=0.75.0",
# Diarization
"pyannote.audio>=3.3",
"diart>=0.9.2",
"torch>=2.0",
# PDF export
"weasyprint>=67.0",
# NER
"spacy>=3.8.11",
# Calendar
"google-api-python-client>=2.100",
"google-auth>=2.23",
"google-auth-oauthlib>=1.1",
# Observability
"opentelemetry-api>=1.28",
"opentelemetry-sdk>=1.28",
"opentelemetry-instrumentation-grpc>=0.49b",
"opentelemetry-exporter-otlp>=1.28",
]
all = [
"noteflow[dev,triggers,summarization,diarization,pdf,ner,calendar,observability]",
"noteflow[audio,dev,triggers,summarization,diarization,pdf,ner,calendar,observability]",
]
[build-system]
@@ -184,7 +210,15 @@ reportUnknownVariableType = false
reportArgumentType = false # proto enums accept ints at runtime
reportIncompatibleVariableOverride = false # SQLAlchemy __table_args__
reportAttributeAccessIssue = false # SQLAlchemy mapped column assignments
reportMissingImports = "warning" # Optional deps like opentelemetry may not be installed
reportMissingImports = "warning" # Optional deps (audio, summarization, triggers, etc.) may not be installed
exclude = ["**/proto/*_pb2*.py", "**/proto/*_pb2*.pyi", ".venv"]
venvPath = "."
venv = ".venv"
[tool.pyrefly]
pythonVersion = "3.12"
python-interpreter-path = "/home/vasceannie/repos/noteflow/.venv/bin/python"
site-package-path = ["/home/vasceannie/repos/noteflow/.venv/lib/python3.12/site-packages"]
exclude = ["**/proto/*_pb2*.py", "**/proto/*_pb2*.pyi", ".venv"]
[tool.pytest.ini_options]

View File

@@ -128,7 +128,7 @@ class SoundDeviceCapture:
self._callback(audio_data, timestamp)
try:
self._stream = sd.InputStream(
stream = sd.InputStream(
device=device_id,
channels=channels,
samplerate=sample_rate,
@@ -136,7 +136,8 @@ class SoundDeviceCapture:
dtype=np.float32,
callback=_stream_callback,
)
self._stream.start()
stream.start()
self._stream = stream
logger.info(
"Started audio capture: device=%s, rate=%d, channels=%d, blocksize=%d",
device_id,
@@ -154,10 +155,11 @@ class SoundDeviceCapture:
Safe to call even if not capturing.
"""
if self._stream is not None:
stream = self._stream
if stream is not None:
try:
self._stream.stop()
self._stream.close()
stream.stop()
stream.close()
except sd.PortAudioError as e:
logger.warning("Error stopping audio stream: %s", e)
finally:
@@ -171,7 +173,8 @@ class SoundDeviceCapture:
Returns:
True if capture is active.
"""
return self._stream is not None and self._stream.active
stream = self._stream
return stream is not None and stream.active
@property
def current_device_id(self) -> int | None: