feat: analiz zincirini atlayıp ham segmenti doğrudan Telegram'a gönderme modu

Yeni "Ham Kayıt Modu" ayarı (send_raw_segments_to_telegram, varsayılan
kapalı): açıksa her ham segment tamamlanır tamamlanmaz sinyal analizi/
STT/9:16 render zincirine hiç girmeden doğrudan Telegram'a gönderiliyor
ve sunucudan siliniyor. Kullanıcı transkript/9:16 istemediğinde ("sen
bana direk videoyu gönder") tüm analiz pipeline'ını atlayıp sadece
kayıt+gönder+sil yapan basit bir mod.

- RawSegmentStatus'a SENT_TO_TELEGRAM eklendi, RawSegment.filePath
  nullable yapıldı (aynı ShortVideo.filePath deseni — gönderim sonrası
  null, dosya diskten silinmiş demek).
- api-daemon/src/telegram.ts'e sendTelegramVideo eklendi (native fetch+
  FormData+Blob ile multipart upload, ~50MB bot-limiti önceden kontrol
  ediliyor) — worker/telegram.py'deki aynı fonksiyonun Node karşılığı.
- streamIngest.ts: segment tamamlanınca, mod açıksa signal-detection
  kuyruğuna hiç eklemeden doğrudan gönderiyor (kuyruğa eklemek, aşağıda
  dosyayı silmenin sinyal analizini bozmasına sebep olurdu).
- Panel: segment listelerinde filePath=null durumunda video/indir yerine
  "Telegram'a gönderildi" notu (segments, channels/[id]).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 19:57:14 +03:00
co-authored by Claude Sonnet 5
parent 9aed4e891e
commit 11e98b300e
10 changed files with 193 additions and 52 deletions
+35 -21
View File
@@ -30,6 +30,7 @@ const STATUS_BADGE: Record<string, VariantProps<typeof badgeVariants>["variant"]
PENDING: "muted",
PROCESSED: "ok",
DISCARDED: "err",
SENT_TO_TELEGRAM: "ok",
PENDING_STT: "warn",
TRANSCRIBED: "ok",
RENDERING: "warn",
@@ -225,30 +226,43 @@ export default async function ChannelDetailPage({ params }: { params: Promise<{
</span>
<Badge variant={STATUS_BADGE[segment.status] ?? "muted"}>{segment.status}</Badge>
</div>
<span className="font-mono-num text-[0.7rem] text-muted-foreground">{segment.filePath}</span>
<video controls preload="metadata" className="mt-2 w-full max-w-md rounded-md border border-border">
<source src={`/api/segments/${segment.id}/video`} type="video/mp4" />
</video>
<div className="mt-2 flex items-center gap-2">
<Button asChild variant="outline" size="sm">
<a href={`/api/segments/${segment.id}/video?download=1`}>İndir</a>
</Button>
<form action={deleteRawSegment.bind(null, segment.id)}>
<ConfirmButton
confirmText="Bu segmenti ve içindeki tüm aday klipleri silmek istediğine emin misin? Geri alınamaz."
label="Sil"
/>
</form>
</div>
{segment.candidates.length === 0 && segment.status !== "PENDING" && (
<p className="mt-3 text-xs text-muted-foreground">
Bu segmentte aday klip bulunamadı (sinyal analizi ilginç bir an tespit etmedi).
{segment.filePath ? (
<>
<span className="font-mono-num text-[0.7rem] text-muted-foreground">{segment.filePath}</span>
<video controls preload="metadata" className="mt-2 w-full max-w-md rounded-md border border-border">
<source src={`/api/segments/${segment.id}/video`} type="video/mp4" />
</video>
<div className="mt-2 flex items-center gap-2">
<Button asChild variant="outline" size="sm">
<a href={`/api/segments/${segment.id}/video?download=1`}>İndir</a>
</Button>
<form action={deleteRawSegment.bind(null, segment.id)}>
<ConfirmButton
confirmText="Bu segmenti ve içindeki tüm aday klipleri silmek istediğine emin misin? Geri alınamaz."
label="Sil"
/>
</form>
</div>
</>
) : (
<p className="mt-1 text-xs text-muted-foreground">
Telegram&apos;a gönderildi, sunucuda saklanmıyor.
</p>
)}
{segment.status === "SENT_TO_TELEGRAM" ? (
<p className="mt-3 text-xs text-muted-foreground">
Analiz edilmeden (transkript/9:16 atlanarak) doğrudan gönderildi.
</p>
) : (
segment.candidates.length === 0 &&
segment.status !== "PENDING" && (
<p className="mt-3 text-xs text-muted-foreground">
Bu segmentte aday klip bulunamadı (sinyal analizi ilginç bir an tespit etmedi).
</p>
)
)}
{segment.candidates.length > 0 && (
<div className="mt-3 flex flex-col gap-2">
{segment.candidates.map((c) => (