Spaces:
Sleeping
Sleeping
Javier Montalvo Claude Sonnet 4.6 (1M context) commited on
Commit ·
015fde7
1
Parent(s): 114ea19
Add demo video link to README; frontend and server updates
Browse filesCo-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- README.md +4 -0
- frontend/dist/assets/index-CiwitQvv.js +0 -0
- frontend/dist/index.html +1 -1
- frontend/src/lib/dashboard.tsx +1 -0
- frontend/src/modules/detector/DetectorPanel.tsx +26 -1
- server.py +8 -0
README.md
CHANGED
|
@@ -23,8 +23,12 @@ The LLM path is intentionally constrained: Replicate, OpenAI, or Claude compile
|
|
| 23 |
natural language into JSON/YAML automation rules. The app validates those rules
|
| 24 |
before evaluating them, and the LLM never emits executable code.
|
| 25 |
|
|
|
|
|
|
|
| 26 |
For a quick operator checklist, see [`DEMO.md`](DEMO.md).
|
| 27 |
|
|
|
|
|
|
|
| 28 |
## Run Locally
|
| 29 |
|
| 30 |
```bash
|
|
|
|
| 23 |
natural language into JSON/YAML automation rules. The app validates those rules
|
| 24 |
before evaluating them, and the LLM never emits executable code.
|
| 25 |
|
| 26 |
+
DEMO video: https://youtu.be/BfXir6fonR0
|
| 27 |
+
|
| 28 |
For a quick operator checklist, see [`DEMO.md`](DEMO.md).
|
| 29 |
|
| 30 |
+
|
| 31 |
+
|
| 32 |
## Run Locally
|
| 33 |
|
| 34 |
```bash
|
frontend/dist/assets/index-CiwitQvv.js
DELETED
|
The diff for this file is too large to render.
See raw diff
|
|
|
frontend/dist/index.html
CHANGED
|
@@ -16,7 +16,7 @@
|
|
| 16 |
href="https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap"
|
| 17 |
rel="stylesheet"
|
| 18 |
/>
|
| 19 |
-
<script type="module" crossorigin src="/assets/index-
|
| 20 |
<link rel="stylesheet" crossorigin href="/assets/index-DbWTYGKW.css">
|
| 21 |
</head>
|
| 22 |
<body>
|
|
|
|
| 16 |
href="https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap"
|
| 17 |
rel="stylesheet"
|
| 18 |
/>
|
| 19 |
+
<script type="module" crossorigin src="/assets/index-xgyljnse.js"></script>
|
| 20 |
<link rel="stylesheet" crossorigin href="/assets/index-DbWTYGKW.css">
|
| 21 |
</head>
|
| 22 |
<body>
|
frontend/src/lib/dashboard.tsx
CHANGED
|
@@ -115,6 +115,7 @@ export function DashboardProvider({ children }: { children: ReactNode }) {
|
|
| 115 |
const previewRef = useRef<string | null>(null)
|
| 116 |
const compileInFlightRef = useRef(false)
|
| 117 |
|
|
|
|
| 118 |
const applyRulesText = useCallback(async (nextRulesText: string) => {
|
| 119 |
setRulesText(nextRulesText)
|
| 120 |
const nextValidation = await api.validateRules(nextRulesText)
|
|
|
|
| 115 |
const previewRef = useRef<string | null>(null)
|
| 116 |
const compileInFlightRef = useRef(false)
|
| 117 |
|
| 118 |
+
|
| 119 |
const applyRulesText = useCallback(async (nextRulesText: string) => {
|
| 120 |
setRulesText(nextRulesText)
|
| 121 |
const nextValidation = await api.validateRules(nextRulesText)
|
frontend/src/modules/detector/DetectorPanel.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
import { useRef, useState } from "react"
|
| 2 |
-
import { ChevronDown, Play, RotateCcw, Upload, Loader2 } from "lucide-react"
|
| 3 |
import { useDashboard } from "@/lib/dashboard"
|
| 4 |
import { Button } from "@/components/ui/button"
|
| 5 |
import { Label } from "@/components/ui/label"
|
|
@@ -58,6 +58,20 @@ export function DetectorPanel() {
|
|
| 58 |
const fileRef = useRef<HTMLInputElement>(null)
|
| 59 |
const [dragging, setDragging] = useState(false)
|
| 60 |
const [advanced, setAdvanced] = useState(false)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
return (
|
| 63 |
<div className="space-y-5">
|
|
@@ -107,6 +121,17 @@ export function DetectorPanel() {
|
|
| 107 |
)}
|
| 108 |
</div>
|
| 109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
<div className="space-y-2">
|
| 111 |
<Label htmlFor="classes">Open-vocabulary classes</Label>
|
| 112 |
<Textarea
|
|
|
|
| 1 |
import { useRef, useState } from "react"
|
| 2 |
+
import { ChevronDown, Play, RotateCcw, Upload, Loader2, Clapperboard } from "lucide-react"
|
| 3 |
import { useDashboard } from "@/lib/dashboard"
|
| 4 |
import { Button } from "@/components/ui/button"
|
| 5 |
import { Label } from "@/components/ui/label"
|
|
|
|
| 58 |
const fileRef = useRef<HTMLInputElement>(null)
|
| 59 |
const [dragging, setDragging] = useState(false)
|
| 60 |
const [advanced, setAdvanced] = useState(false)
|
| 61 |
+
const [loadingDemo, setLoadingDemo] = useState(false)
|
| 62 |
+
|
| 63 |
+
async function loadDemo() {
|
| 64 |
+
setLoadingDemo(true)
|
| 65 |
+
try {
|
| 66 |
+
const r = await fetch("/demo-video")
|
| 67 |
+
const blob = await r.blob()
|
| 68 |
+
setVideo(new File([blob], "tiny-trigger-demo.mp4", { type: "video/mp4" }))
|
| 69 |
+
} catch {
|
| 70 |
+
// silently ignore if demo not available
|
| 71 |
+
} finally {
|
| 72 |
+
setLoadingDemo(false)
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
|
| 76 |
return (
|
| 77 |
<div className="space-y-5">
|
|
|
|
| 121 |
)}
|
| 122 |
</div>
|
| 123 |
|
| 124 |
+
<Button
|
| 125 |
+
variant="outline"
|
| 126 |
+
size="sm"
|
| 127 |
+
className="w-full gap-2 text-muted-foreground"
|
| 128 |
+
onClick={loadDemo}
|
| 129 |
+
disabled={loadingDemo}
|
| 130 |
+
>
|
| 131 |
+
{loadingDemo ? <Loader2 className="size-3.5 animate-spin" /> : <Clapperboard className="size-3.5" />}
|
| 132 |
+
Use demo video
|
| 133 |
+
</Button>
|
| 134 |
+
|
| 135 |
<div className="space-y-2">
|
| 136 |
<Label htmlFor="classes">Open-vocabulary classes</Label>
|
| 137 |
<Textarea
|
server.py
CHANGED
|
@@ -419,6 +419,14 @@ def media(file_path: str) -> Any:
|
|
| 419 |
return FileResponse(target, media_type="video/mp4")
|
| 420 |
|
| 421 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 422 |
if __name__ == "__main__":
|
| 423 |
app.launch(
|
| 424 |
server_name=os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"),
|
|
|
|
| 419 |
return FileResponse(target, media_type="video/mp4")
|
| 420 |
|
| 421 |
|
| 422 |
+
@app.get("/demo-video")
|
| 423 |
+
def demo_video() -> Any:
|
| 424 |
+
path = ROOT / "tiny-trigger-demo.mp4"
|
| 425 |
+
if not path.is_file():
|
| 426 |
+
return JSONResponse({"error": "demo video not found"}, status_code=404)
|
| 427 |
+
return FileResponse(path, media_type="video/mp4")
|
| 428 |
+
|
| 429 |
+
|
| 430 |
if __name__ == "__main__":
|
| 431 |
app.launch(
|
| 432 |
server_name=os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"),
|