← back to dotradepro__Piper-Master-Trainer

Function bodies 178 total

All specs Real LLM only Function bodies
start_training method · python · L83-L114 (32 LOC)
backend/app/utils/piper_bridge.py
    def start_training(
        self,
        config: TrainingConfig,
        on_metrics: Callable[[dict], None] | None = None,
        on_log: Callable[[str], None] | None = None,
    ) -> subprocess.Popen:
        """Запустити тренування як subprocess."""
        cmd = self.build_training_command(config)
        logger.info(f"Starting training: {' '.join(cmd)}")

        env = os.environ.copy()
        env["PYTHONUNBUFFERED"] = "1"

        process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
            bufsize=1,
            env=env,
        )

        # Start monitor thread
        if on_metrics or on_log:
            monitor = threading.Thread(
                target=self._monitor_output,
                args=(process, on_metrics, on_log),
                daemon=True,
            )
            monitor.start()

        return process
_monitor_output method · python · L116-L136 (21 LOC)
backend/app/utils/piper_bridge.py
    def _monitor_output(
        self,
        process: subprocess.Popen,
        on_metrics: Callable[[dict], None] | None,
        on_log: Callable[[str], None] | None,
    ):
        """Моніторинг stdout тренування, парсинг метрик."""
        for line in iter(process.stdout.readline, ""):
            line = line.strip()
            if not line:
                continue

            if on_log:
                on_log(line)

            if on_metrics:
                metrics = self._parse_metrics(line)
                if metrics:
                    on_metrics(metrics)

        process.wait()
_parse_metrics method · python · L138-L165 (28 LOC)
backend/app/utils/piper_bridge.py
    def _parse_metrics(self, line: str) -> dict | None:
        """Парсити метрики з виводу Lightning trainer."""
        # Lightning format: "Epoch X, global step Y: 'val/loss_g': Z, 'val/loss_d': W"
        # Or progress bar: "Epoch 0:  50%|... loss_g=12.34, loss_d=3.21"
        metrics = {}

        # Parse epoch
        epoch_match = re.search(r'[Ee]poch\s+(\d+)', line)
        if epoch_match:
            metrics["epoch"] = int(epoch_match.group(1))

        # Parse step
        step_match = re.search(r'(?:global.step|step)\s*[=:]\s*(\d+)', line, re.IGNORECASE)
        if step_match:
            metrics["step"] = int(step_match.group(1))

        # Parse losses
        for loss_name in ["loss_g", "loss_d", "loss_gen", "loss_disc", "loss"]:
            match = re.search(rf'{loss_name}\s*[=:]\s*([\d.]+)', line, re.IGNORECASE)
            if match:
                metrics[loss_name] = float(match.group(1))

        # Parse learning rate
        lr_match = re.search(r'lr\s*[=:]\s*([\d.
stop_training method · python · L167-L177 (11 LOC)
backend/app/utils/piper_bridge.py
    def stop_training(self, process: subprocess.Popen):
        """Зупинити тренування gracefully."""
        if process.poll() is None:
            logger.info("Stopping training (SIGTERM)...")
            process.send_signal(signal.SIGTERM)
            try:
                process.wait(timeout=30)
            except subprocess.TimeoutExpired:
                logger.warning("Training did not stop, killing...")
                process.kill()
                process.wait()
export_to_onnx method · python · L179-L190 (12 LOC)
backend/app/utils/piper_bridge.py
    def export_to_onnx(self, checkpoint_path: str, output_path: str) -> str:
        """Експортувати checkpoint в ONNX."""
        cmd = [
            "python3", "-m", "piper.train.export_onnx",
            "--checkpoint", checkpoint_path,
            "--output-file", output_path,
        ]
        logger.info(f"Exporting: {' '.join(cmd)}")
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
        if result.returncode != 0:
            raise RuntimeError(f"Export failed: {result.stderr}")
        return output_path
synthesize method · python · L192-L202 (11 LOC)
backend/app/utils/piper_bridge.py
    def synthesize(self, onnx_path: str, config_path: str, text: str) -> bytes:
        """Синтезувати мовлення з ONNX моделі."""
        from piper import PiperVoice
        import io
        import wave

        voice = PiperVoice.load(onnx_path, config_path)
        wav_buffer = io.BytesIO()
        with wave.open(wav_buffer, "wb") as wav:
            voice.synthesize(text, wav)
        return wav_buffer.getvalue()
WebSocketManager class · python · L7-L39 (33 LOC)
backend/app/utils/websocket_manager.py
class WebSocketManager:
    def __init__(self):
        self._connections: dict[str, list[WebSocket]] = {}

    async def connect(self, project_id: str, websocket: WebSocket):
        await websocket.accept()
        if project_id not in self._connections:
            self._connections[project_id] = []
        self._connections[project_id].append(websocket)

    def disconnect(self, project_id: str, websocket: WebSocket):
        if project_id in self._connections:
            self._connections[project_id] = [
                ws for ws in self._connections[project_id] if ws != websocket
            ]
            if not self._connections[project_id]:
                del self._connections[project_id]

    async def send_to_project(self, project_id: str, message: dict[str, Any]):
        if project_id not in self._connections:
            return
        dead = []
        for ws in self._connections[project_id]:
            try:
                await ws.send_text(json.dumps(message))
     
Open data scored by Repobility · https://repobility.com
connect method · python · L11-L15 (5 LOC)
backend/app/utils/websocket_manager.py
    async def connect(self, project_id: str, websocket: WebSocket):
        await websocket.accept()
        if project_id not in self._connections:
            self._connections[project_id] = []
        self._connections[project_id].append(websocket)
disconnect method · python · L17-L23 (7 LOC)
backend/app/utils/websocket_manager.py
    def disconnect(self, project_id: str, websocket: WebSocket):
        if project_id in self._connections:
            self._connections[project_id] = [
                ws for ws in self._connections[project_id] if ws != websocket
            ]
            if not self._connections[project_id]:
                del self._connections[project_id]
send_to_project method · python · L25-L35 (11 LOC)
backend/app/utils/websocket_manager.py
    async def send_to_project(self, project_id: str, message: dict[str, Any]):
        if project_id not in self._connections:
            return
        dead = []
        for ws in self._connections[project_id]:
            try:
                await ws.send_text(json.dumps(message))
            except Exception:
                dead.append(ws)
        for ws in dead:
            self.disconnect(project_id, ws)
broadcast method · python · L37-L39 (3 LOC)
backend/app/utils/websocket_manager.py
    async def broadcast(self, message: dict[str, Any]):
        for project_id in list(self._connections.keys()):
            await self.send_to_project(project_id, message)
getAudioUrl function · typescript · L53-L55 (3 LOC)
frontend/src/api/youtube.ts
export function getAudioUrl(filePath: string): string {
  return `/api/audio/${filePath}`
}
App function · typescript · L11-L27 (17 LOC)
frontend/src/App.tsx
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route element={<AppShell />}>
          <Route path="/" element={<DashboardPage />} />
          <Route path="/project/:projectId/download" element={<DownloadPage />} />
          <Route path="/project/:projectId/transcription" element={<TranscriptionPage />} />
          <Route path="/project/:projectId/dataset" element={<DatasetPage />} />
          <Route path="/project/:projectId/training" element={<TrainingPage />} />
          <Route path="/project/:projectId/export" element={<ExportPage />} />
          <Route path="/project/:projectId/test" element={<TestPage />} />
        </Route>
      </Routes>
    </BrowserRouter>
  )
}
AppShell function · typescript · L4-L18 (15 LOC)
frontend/src/components/layout/AppShell.tsx
export function AppShell() {
  return (
    <div className="min-h-screen bg-[hsl(var(--background))]">
      <Sidebar />
      <main
        className="min-h-screen"
        style={{ marginLeft: 'var(--sidebar-width)' }}
      >
        <div className="p-8 max-w-5xl mx-auto">
          <Outlet />
        </div>
      </main>
    </div>
  )
}
Sidebar function · typescript · L24-L109 (86 LOC)
frontend/src/components/layout/Sidebar.tsx
export function Sidebar() {
  const location = useLocation()
  const { projectId } = useParams()

  return (
    <aside
      className="fixed left-0 top-0 h-full flex flex-col glass border-r border-[hsl(var(--border)/.5)]"
      style={{ width: 'var(--sidebar-width)', zIndex: 50 }}
    >
      {/* Logo */}
      <div className="p-5">
        <Link to="/" className="flex items-center gap-3 no-underline group">
          <div className="w-9 h-9 rounded-xl bg-gradient-to-br from-[hsl(var(--primary))] to-[hsl(160_71%_40%)] flex items-center justify-center shadow-lg shadow-[hsl(var(--primary)/.2)] group-hover:shadow-[hsl(var(--primary)/.4)] transition-smooth">
            <AudioWaveform size={18} className="text-white" />
          </div>
          <div>
            <h1 className="text-sm font-bold text-[hsl(var(--foreground))]">Piper Trainer</h1>
            <p className="text-[10px] text-[hsl(var(--muted-foreground))] tracking-wider uppercase">Master v0.1</p>
          </div>
        </L
Repobility — same analyzer, your code, free for public repos · /scan/
GpuMonitor function · typescript · L4-L88 (85 LOC)
frontend/src/components/training/GpuMonitor.tsx
export function GpuMonitor() {
  const gpu = useGpuStatus()

  if (!gpu) {
    return (
      <div className="rounded-2xl border border-[hsl(var(--border))] glass p-5">
        <div className="flex items-center gap-2 text-[hsl(var(--muted-foreground))]">
          <Cpu size={16} className="animate-pulse" />
          <span className="text-sm">GPU...</span>
        </div>
      </div>
    )
  }

  if (!gpu.available) {
    return (
      <div className="rounded-2xl border border-red-500/20 bg-red-500/5 p-5">
        <div className="flex items-center gap-2 text-red-400">
          <Cpu size={16} />
          <span className="text-sm">{gpu.error}</span>
        </div>
      </div>
    )
  }

  const vramPercent = gpu.vram_total_mb
    ? Math.round((gpu.vram_used_mb! / gpu.vram_total_mb) * 100)
    : 0

  const barColor = vramPercent > 90 ? 'from-red-500 to-red-400' : vramPercent > 70 ? 'from-yellow-500 to-orange-400' : 'from-[hsl(var(--primary))] to-[hsl(160_71%_55%)]'

  return (
    <di
useGpuStatus function · typescript · L5-L29 (25 LOC)
frontend/src/hooks/useGpuStatus.ts
export function useGpuStatus(intervalMs = 5000) {
  const [gpu, setGpu] = useState<GpuStatus | null>(null)

  useEffect(() => {
    let active = true

    const fetch = async () => {
      try {
        const status = await systemApi.gpuStatus()
        if (active) setGpu(status)
      } catch {
        if (active) setGpu({ available: false, error: 'Не вдалося отримати стан GPU' })
      }
    }

    fetch()
    const id = setInterval(fetch, intervalMs)
    return () => {
      active = false
      clearInterval(id)
    }
  }, [intervalMs])

  return gpu
}
cn function · typescript · L4-L6 (3 LOC)
frontend/src/lib/utils.ts
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}
formatDuration function · typescript · L8-L14 (7 LOC)
frontend/src/lib/utils.ts
export function formatDuration(seconds: number): string {
  const h = Math.floor(seconds / 3600)
  const m = Math.floor((seconds % 3600) / 60)
  const s = Math.floor(seconds % 60)
  if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
  return `${m}:${s.toString().padStart(2, '0')}`
}
formatBytes function · typescript · L16-L22 (7 LOC)
frontend/src/lib/utils.ts
export function formatBytes(bytes: number): string {
  if (bytes === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`
}
formatDate function · typescript · L24-L32 (9 LOC)
frontend/src/lib/utils.ts
export function formatDate(date: string): string {
  return new Date(date).toLocaleDateString('uk-UA', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  })
}
DashboardPage function · typescript · L9-L170 (162 LOC)
frontend/src/pages/DashboardPage.tsx
export function DashboardPage() {
  const { projects, loading, error, fetchProjects, createProject, deleteProject } =
    useProjectStore()
  const navigate = useNavigate()
  const [showCreate, setShowCreate] = useState(false)
  const [newName, setNewName] = useState('')
  const [newLang, setNewLang] = useState('uk')
  const [creating, setCreating] = useState(false)

  useEffect(() => {
    fetchProjects()
  }, [fetchProjects])

  const handleCreate = async () => {
    if (!newName.trim()) return
    setCreating(true)
    try {
      const project = await createProject({ name: newName.trim(), language: newLang })
      setNewName('')
      setShowCreate(false)
      navigate(`/project/${project.id}/download`)
    } catch { } finally { setCreating(false) }
  }

  const handleDelete = async (e: React.MouseEvent, id: string, name: string) => {
    e.preventDefault()
    e.stopPropagation()
    if (!confirm(`Видалити проєкт "${name}"? Всі дані буде втрачено.`)) return
    await deleteProje
DatasetPage function · typescript · L8-L227 (220 LOC)
frontend/src/pages/DatasetPage.tsx
export function DatasetPage() {
  const { projectId } = useParams<{ projectId: string }>()
  const [datasets, setDatasets] = useState<DatasetInfo[]>([])
  const [stats, setStats] = useState<DatasetStats | null>(null)
  const [issues, setIssues] = useState<ValidationIssue[]>([])
  const [preview, setPreview] = useState<CsvRow[]>([])
  const [previewTotal, setPreviewTotal] = useState(0)
  const [loading, setLoading] = useState(true)
  const [preparing, setPreparing] = useState(false)
  const [minDur, setMinDur] = useState(1.0)
  const [maxDur, setMaxDur] = useState(15.0)
  const [sampleRate, setSampleRate] = useState(22050)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    if (projectId) loadData()
  }, [projectId])

  const loadData = async () => {
    if (!projectId) return
    try {
      const ds = await datasetsApi.list(projectId)
      setDatasets(ds)
      if (ds.length > 0) {
        await loadDatasetDetails(ds[0].id)
      }
    } catch {
    } f
All rows scored by the Repobility analyzer (https://repobility.com)
DownloadPage function · typescript · L8-L151 (144 LOC)
frontend/src/pages/DownloadPage.tsx
export function DownloadPage() {
  const { projectId } = useParams<{ projectId: string }>()
  const [url, setUrl] = useState('')
  const [downloading, setDownloading] = useState(false)
  const [uploading, setUploading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [files, setFiles] = useState<AudioFile[]>([])
  const [loading, setLoading] = useState(true)
  const [playingId, setPlayingId] = useState<string | null>(null)
  const audioRef = useRef<HTMLAudioElement | null>(null)
  const fileInputRef = useRef<HTMLInputElement | null>(null)

  useEffect(() => { if (projectId) loadFiles() }, [projectId])

  const loadFiles = async () => {
    if (!projectId) return
    try { setFiles(await youtubeApi.listFiles(projectId)) } catch {} finally { setLoading(false) }
  }

  const handleDownload = async () => {
    if (!projectId || !url.trim()) return
    setDownloading(true); setError(null)
    try {
      const file = await youtubeApi.download(projectId, ur
ExportPage function · typescript · L10-L140 (131 LOC)
frontend/src/pages/ExportPage.tsx
export function ExportPage() {
  const { projectId } = useParams<{ projectId: string }>()
  const [checkpoints, setCheckpoints] = useState<CheckpointInfo[]>([])
  const [models, setModels] = useState<ExportedModel[]>([])
  const [selectedCkpt, setSelectedCkpt] = useState('')
  const [exporting, setExporting] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    if (projectId) loadData()
  }, [projectId])

  const loadData = async () => {
    if (!projectId) return
    try {
      const [ckpts, mdls] = await Promise.all([
        trainingApi.checkpoints(projectId),
        modelsApi.list(projectId),
      ])
      setCheckpoints(ckpts)
      setModels(mdls)
      if (ckpts.length > 0) setSelectedCkpt(ckpts[0].path)
    } catch {
    } finally {
      setLoading(false)
    }
  }

  const handleExport = async () => {
    if (!projectId || !selectedCkpt) return
    setExporting(true)
    setError(
TestPage function · typescript · L8-L188 (181 LOC)
frontend/src/pages/TestPage.tsx
export function TestPage() {
  const { projectId } = useParams<{ projectId: string }>()
  const [models, setModels] = useState<ExportedModel[]>([])
  const [selectedModel, setSelectedModel] = useState('')
  const [text, setText] = useState('Привіт, це тестове повідомлення для перевірки якості голосової моделі.')
  const [lengthScale, setLengthScale] = useState(1.0)
  const [noiseScale, setNoiseScale] = useState(0.667)
  const [noiseW, setNoiseW] = useState(0.8)
  const [synthesizing, setSynthesizing] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [audioUrl, setAudioUrl] = useState<string | null>(null)
  const [history, setHistory] = useState<{ text: string; url: string }[]>([])
  const [loading, setLoading] = useState(true)
  const audioRef = useRef<HTMLAudioElement | null>(null)

  useEffect(() => {
    if (projectId) loadData()
    return () => { history.forEach((h) => URL.revokeObjectURL(h.url)) }
  }, [projectId])

  const loadData = async () =>
TrainingPage function · typescript · L12-L330 (319 LOC)
frontend/src/pages/TrainingPage.tsx
export function TrainingPage() {
  const { projectId } = useParams<{ projectId: string }>()
  const [datasets, setDatasets] = useState<DatasetInfo[]>([])
  const [selectedDataset, setSelectedDataset] = useState<string>('')
  const [status, setStatus] = useState<TrainingStatus | null>(null)
  const [checkpoints, setCheckpoints] = useState<CheckpointInfo[]>([])
  const [metricsHistory, setMetricsHistory] = useState<{ epoch: number; loss_g?: number; loss_d?: number }[]>([])
  const [loading, setLoading] = useState(true)
  const [starting, setStarting] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const pollRef = useRef<number | null>(null)
  const logRef = useRef<HTMLDivElement>(null)

  // Config
  const [batchSize, setBatchSize] = useState(4)
  const [maxEpochs, setMaxEpochs] = useState(10000)
  const [precision, setPrecision] = useState('32')
  const [accumGrad, setAccumGrad] = useState(8)
  const [mode, setMode] = useState<'scratch' | 'finetune'>('scrat
TranscriptionPage function · typescript · L21-L361 (341 LOC)
frontend/src/pages/TranscriptionPage.tsx
export function TranscriptionPage() {
  const { projectId } = useParams<{ projectId: string }>()
  const [audioFiles, setAudioFiles] = useState<AudioFile[]>([])
  const [selectedFile, setSelectedFile] = useState<string | null>(null)
  const [segments, setSegments] = useState<Segment[]>([])
  const [loading, setLoading] = useState(true)
  const [transcribing, setTranscribing] = useState(false)
  const [modelSize, setModelSize] = useState('small')
  const [editingId, setEditingId] = useState<string | null>(null)
  const [editText, setEditText] = useState('')
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
  const [playingId, setPlayingId] = useState<string | null>(null)
  const audioRef = useRef<HTMLAudioElement | null>(null)

  useEffect(() => {
    if (projectId) loadData()
  }, [projectId])

  const loadData = async () => {
    if (!projectId) return
    try {
      const [files, segs] = await Promise.all([
        youtubeApi.listFiles(projectId),
        tran
‹ prevpage 4 / 4