Skip to content
Open
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
1 change: 1 addition & 0 deletions backend/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

36 changes: 23 additions & 13 deletions backend/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
factory is the only public API main.py should use.
"""

import asyncio
import logging

from ollama import AsyncClient
from pydantic import BaseModel

import config as cfg
try:
from . import config as cfg
except ImportError:
import config as cfg # type: ignore

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -72,14 +76,17 @@ async def correct(
self._history = self._history[-cfg.LLM_HISTORY_MAX:]

try:
response = await self._client.chat(
model=cfg.LLM_MODEL,
messages=[
{"role": "system", "content": _SYSTEM_PROMPT},
*self._history,
],
format=_Schema.model_json_schema(),
options={"think": False},
response = await asyncio.wait_for(
self._client.chat(
model=cfg.LLM_MODEL,
messages=[
{"role": "system", "content": _SYSTEM_PROMPT},
*self._history,
],
format=_Schema.model_json_schema(),
options={"think": False},
),
timeout=60.0,
)

try:
Expand All @@ -95,12 +102,15 @@ async def correct(
text += "."
return text

except asyncio.TimeoutError:
logger.warning("LLM timed out after 60 s; falling back to raw transcript")
except Exception:
logger.exception("LLM correction failed; falling back to raw transcript")
fallback = transcript.strip().capitalize()
if fallback and fallback[-1] not in ".?!":
fallback += "."
return fallback

fallback = (transcript or "").strip().capitalize()
if fallback and fallback[-1] not in ".?!":
fallback += "."
return fallback


def make_corrector() -> LLMCorrector:
Expand Down
23 changes: 13 additions & 10 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,24 @@
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

import config as cfg
import vsr
import llm

# Gesture recogniser — lazy import so the VSR backend works even if
# the gesture module's mediapipe install is separate.
try:
import sys as _sys
_sys.path.insert(0, str(__import__("pathlib").Path(__file__).parent.parent))
from . import config as cfg
from . import vsr
from . import llm
except ImportError:
import config as cfg # type: ignore
import vsr # type: ignore
import llm # type: ignore

# Gesture recogniser — lazy import (mediapipe may be in a separate env)
import sys as _sys, pathlib as _pl
_sys.path.insert(0, str(_pl.Path(__file__).parent.parent))
try:
Comment on lines +54 to +57
from gesture.recognizer import GestureRecognizer as _GestureRecognizer
_gesture_available = True
except Exception as _ge:
_gesture_available = False
logger_tmp = __import__("logging").getLogger("silent-speech")
logger_tmp.warning("Gesture module unavailable: %s", _ge)
__import__("logging").getLogger("silent-speech").warning("Gesture module unavailable: %s", _ge)

# ── logging ───────────────────────────────────────────────────────────────────
logging.basicConfig(
Expand Down
5 changes: 4 additions & 1 deletion backend/vsr.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
import numpy as np
import torch

import config as cfg
try:
from . import config as cfg
except ImportError:
import config as cfg # type: ignore

logger = logging.getLogger(__name__)

Expand Down
37 changes: 37 additions & 0 deletions frontend/src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use client';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
import Dashboard from '@/components/dashboard/Dashboard';

export default function DashboardPage() {
const { data: session, status } = useSession();
const router = useRouter();

useEffect(() => {
if (status === 'unauthenticated') router.replace('/login');
}, [status, router]);

if (status === 'loading' || !session) {
return (
<div style={{
minHeight: '100vh', background: 'var(--bg-0)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.18em', color: 'var(--fg-3)',
}}>
LOADING…
</div>
);
}

const u = session.user;
return (
<Dashboard
user={{
name: u?.name ?? null,
email: u?.email ?? null,
image: u?.image ?? null,
}}
/>
);
}
4 changes: 2 additions & 2 deletions frontend/src/components/AuthFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ export default function AuthFlow({ initialMode = 'login' }: { initialMode?: 'log

useEffect(() => {
if (session) {
router.push('/');
router.push('/dashboard');
}
}, [session, router]);

const handleGoogleSignIn = () => {
signIn('google', { callbackUrl: '/' });
signIn('google', { callbackUrl: '/dashboard' });
};

const isFlipped = mode === 'signup';
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/GestureCapture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ export default function GestureCapture() {
</div>

{/* Back link */}
<a href="/" style={{
<a href="/dashboard" style={{
fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.1em',
color: 'var(--fg-3)', textDecoration: 'none', padding: '8px 20px',
border: '1px solid var(--fg-4)', borderRadius: 99,
Expand All @@ -324,7 +324,7 @@ export default function GestureCapture() {
onMouseEnter={e => { (e.currentTarget as HTMLAnchorElement).style.color = 'var(--fg-0)'; (e.currentTarget as HTMLAnchorElement).style.borderColor = 'var(--fg-2)'; }}
onMouseLeave={e => { (e.currentTarget as HTMLAnchorElement).style.color = 'var(--fg-3)'; (e.currentTarget as HTMLAnchorElement).style.borderColor = 'var(--fg-4)'; }}
>
← Back to home
← Back to dashboard
</a>

<style>{`
Expand Down
6 changes: 0 additions & 6 deletions frontend/src/components/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,6 @@ export default function Hero() {
<path d="M3 7h8m0 0L7 3m4 4l-4 4" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</a>
<a href="/gesture" className="btn btn-ghost" style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
<path d="M18 11V7a2 2 0 00-4 0v5M10 11V5a2 2 0 00-4 0v6M6 11a2 2 0 00-4 0v4a8 8 0 008 8h4a8 8 0 008-8v-5a2 2 0 00-4 0" />
</svg>
<span>Gesture recognition</span>
</a>
<a href="#vision" className="btn btn-ghost">
<span>Read the vision</span>
</a>
Expand Down
Loading