├── .env ├── Makefile ├── server.js ├── lib ├── store │ ├── history-store.ts │ ├── user-store.ts │ ├── yolo-board-detect.tsx │ └── model-store.ts ├── model-detection │ ├── yolo-test │ │ ├── utils.ts │ │ ├── yoloContext.ts │ │ ├── yoloStrategy.ts │ │ ├── type.ts │ │ ├── yolov5.ts │ │ ├── yolov8.ts │ │ └── label.ts │ ├── coco-ssd │ │ └── utils.ts │ └── mediapipe │ │ └── efficience-utils.ts ├── identity │ ├── middleware.ts │ ├── dal.ts │ ├── definition.ts │ ├── session.ts │ └── session-local.ts ├── utils.ts ├── telegram-bot │ └── action.ts ├── data │ ├── user.ts │ └── local-storage │ │ ├── camera-store.ts │ │ └── model-detection-store.ts ├── yolov8n-seg │ ├── labels.json │ └── renderBox.js ├── cocossd │ └── detect.ts ├── azure-table │ └── action.ts ├── mediapipe-utils │ └── definitions.ts ├── yolov8n │ └── renderBox.ts └── helper-board │ └── helper.ts ├── app ├── icon.png ├── parameter │ ├── page.tsx │ ├── telegram │ │ └── page.tsx │ └── labels-detection │ │ └── page.tsx ├── login │ └── page.tsx ├── register │ └── page.tsx ├── _app.tsx ├── video-inference │ └── page.tsx ├── historique │ └── page.tsx ├── page.tsx ├── layout.tsx ├── globals.css └── api │ └── detection │ └── route.ts ├── public ├── IgnitionAI.png ├── centurion.png └── pretorian.jpeg ├── .eslintrc.json ├── postcss.config.mjs ├── next.config.mjs ├── components ├── ui │ ├── skeleton.tsx │ ├── collapsible.tsx │ ├── text-blur.tsx │ ├── label.tsx │ ├── separator.tsx │ ├── progress.tsx │ ├── toaster.tsx │ ├── input.tsx │ ├── acerternity-button.tsx │ ├── sonner.tsx │ ├── meteors.tsx │ ├── switch.tsx │ ├── badge.tsx │ ├── text-generate-effect.tsx │ ├── popover.tsx │ ├── avatar.tsx │ ├── scroll-area.tsx │ ├── button.tsx │ ├── card.tsx │ ├── input-otp.tsx │ ├── aurora-background.tsx │ ├── background-gradient.tsx │ ├── calendar.tsx │ ├── parallax-scroll.tsx │ ├── breadcrumb.tsx │ ├── table.tsx │ ├── animated-tooltip.tsx │ ├── dialog.tsx │ ├── lamp.tsx │ ├── 3d-card.tsx │ ├── time-range.tsx │ ├── sheet.tsx │ ├── use-toast.ts │ └── form.tsx ├── LogoutButton.tsx ├── theme-provider.tsx ├── LoginButton.tsx ├── layout │ ├── header.tsx │ ├── footer.tsx │ ├── header-client.tsx │ └── header-dropdown.tsx ├── sparckles-component.tsx ├── display-history.tsx ├── video-reader.tsx ├── model-loader.tsx ├── mode-toggle.tsx ├── header-menu-nav.tsx ├── img-display-history.tsx ├── modal-picture-drawing.tsx ├── History.tsx ├── label-detection.tsx ├── PriceCard.tsx ├── video-select.tsx ├── history-select.tsx ├── VideoInference.tsx ├── modal-historique.tsx ├── Board.tsx ├── ParamTelegram.tsx └── model-selection.tsx ├── components.json ├── script.js ├── .gitignore ├── hooks ├── use-tfjs-backend.tsx ├── use-video.tsx ├── use-board-detection.tsx ├── use-interval.tsx ├── use-model.tsx ├── use-cocossd.tsx ├── use-history.tsx ├── use-cameras-config.tsx ├── use-model-detection-storage.tsx ├── use-predict-history.tsx ├── use-mediapipe-detector.tsx └── use-yolo-tfjs.tsx ├── .env.exemple ├── ege.md ├── tsconfig.json ├── models └── model-list.ts ├── publishProfile.xml ├── .github └── workflows │ └── app-service-code.yml ├── package.json └── tailwind.config.ts /.env: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/store/history-store.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/store/user-store.ts: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/model-detection/yolo-test/utils.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salim4n/pro-pretorian-system/HEAD/app/icon.png -------------------------------------------------------------------------------- /public/IgnitionAI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salim4n/pro-pretorian-system/HEAD/public/IgnitionAI.png -------------------------------------------------------------------------------- /public/centurion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salim4n/pro-pretorian-system/HEAD/public/centurion.png -------------------------------------------------------------------------------- /public/pretorian.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salim4n/pro-pretorian-system/HEAD/public/pretorian.jpeg -------------------------------------------------------------------------------- /app/parameter/page.tsx: -------------------------------------------------------------------------------- 1 | export default function ParamaterPage() { 2 | return
Parameter Page
3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next", 3 | "rules": { 4 | "react/no-unescaped-entities": "off", 5 | "@next/next/no-page-custom-font": "off" 6 | } 7 | } -------------------------------------------------------------------------------- /app/login/page.tsx: -------------------------------------------------------------------------------- 1 | import Login from "@/components/Login" 2 | 3 | export default async function Home() { 4 | 5 | return ( 6 | 7 | ) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /app/register/page.tsx: -------------------------------------------------------------------------------- 1 | // pages/register.tsx 2 | import RegisterComponent from "@/components/register-component" 3 | 4 | export default function Register() { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /app/_app.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | import type { AppProps } from 'next/app' 3 | 4 | function MyApp({ Component, pageProps }: AppProps) { 5 | return 6 | } 7 | 8 | export default MyApp -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: "standalone", 4 | images: { 5 | domains: ["propretoriansolution.blob.core.windows.net"], 6 | }, 7 | } 8 | 9 | export default nextConfig 10 | -------------------------------------------------------------------------------- /components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /components/LogoutButton.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { logout } from "@/lib/identity/auth" 4 | import { Button } from "./ui/button" 5 | 6 | export default function LogoutButton() { 7 | return ( 8 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" 2 | 3 | const Collapsible = CollapsiblePrimitive.Root 4 | 5 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger 6 | 7 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent 8 | 9 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } 10 | -------------------------------------------------------------------------------- /components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { ThemeProvider as NextThemesProvider } from "next-themes" 5 | import { type ThemeProviderProps } from "next-themes/dist/types" 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config() 2 | 3 | const accountName = process.env.AUTH_AZURE_ACCOUNT 4 | const accountKey = process.env.AUTH_AZURE_ACCESS_KEY 5 | const containerName = process.env.AZURE_STORAGE_CONTAINER 6 | const connectionString = process.env.AUTH_AZURE_STORAGE_CONNECTION_STRING 7 | const token = process.env.TELEGRAM_BOT_TOKEN 8 | 9 | console.log(accountName, accountKey, containerName, connectionString, token) 10 | -------------------------------------------------------------------------------- /components/LoginButton.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useRouter } from "next/navigation" 4 | import { Button } from "./ui/button" 5 | 6 | 7 | export default function LoginButton(){ 8 | const router = useRouter() 9 | return ( 10 | 17 | ) 18 | } -------------------------------------------------------------------------------- /lib/model-detection/yolo-test/yoloContext.ts: -------------------------------------------------------------------------------- 1 | import { ModelConfig } from "./type" 2 | import { YoloV5 } from "./yolov5" 3 | import { YoloV8 } from "./yolov8" 4 | 5 | const createYoloDataExtractor = (classes: string[], config: ModelConfig) => { 6 | switch (config.yoloVersion) { 7 | case "v5": 8 | return new YoloV5(classes) 9 | case "v8": 10 | return new YoloV8(classes) 11 | } 12 | } 13 | 14 | export default createYoloDataExtractor 15 | -------------------------------------------------------------------------------- /lib/model-detection/yolo-test/yoloStrategy.ts: -------------------------------------------------------------------------------- 1 | import { Rank, Tensor } from "@tensorflow/tfjs" 2 | 3 | export type PredictionData = { 4 | boxes: Tensor 5 | scores: Tensor 6 | classes: Tensor 7 | } 8 | 9 | export abstract class YoloStrategy { 10 | classes: string[] 11 | 12 | constructor(classes: string[]) { 13 | this.classes = classes 14 | } 15 | 16 | abstract getPredictionData(output: Tensor | Tensor[]): PredictionData 17 | } 18 | -------------------------------------------------------------------------------- /lib/store/yolo-board-detect.tsx: -------------------------------------------------------------------------------- 1 | import { create } from "zustand"; 2 | 3 | export type YoloDetected = { 4 | class: string; 5 | score: number; 6 | bbox: [number, number, number, number]; 7 | }; 8 | 9 | type YoloBoardDetectStore = { 10 | yoloDetected: YoloDetected[]; 11 | setYoloDetected: (yoloDetected: YoloDetected[]) => void; 12 | }; 13 | 14 | export const useYoloBoardDetectStore = create((set) => ({ 15 | yoloDetected: [], 16 | setYoloDetected: (yoloDetected) => set({ yoloDetected }), 17 | })); 18 | -------------------------------------------------------------------------------- /components/layout/header.tsx: -------------------------------------------------------------------------------- 1 | import { cookies } from "next/headers" 2 | import HeaderClient from "./header-client" 3 | 4 | export default async function Header() { 5 | const isAuth = 6 | cookies().get("pro-pretorian-session") === undefined ? false : true 7 | 8 | return ( 9 | isAuth && ( 10 |
11 | 12 |
13 | ) 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /lib/store/model-store.ts: -------------------------------------------------------------------------------- 1 | import { ModelComputerVision } from "@/models/model-list" 2 | import { create } from "zustand" 3 | 4 | type ModelStore = { 5 | modelName: ModelComputerVision 6 | setModel: (model: ModelComputerVision) => void 7 | disposeModel: () => void 8 | } 9 | 10 | export const useModelStore = create()(set => ({ 11 | modelName: ModelComputerVision.EMPTY, 12 | setModel: modelName => set({ modelName }), 13 | disposeModel: () => { 14 | set({ modelName: ModelComputerVision.EMPTY }) 15 | }, 16 | })) 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | .env 39 | -------------------------------------------------------------------------------- /app/video-inference/page.tsx: -------------------------------------------------------------------------------- 1 | import { UserView } from "../../lib/identity/definition" 2 | import VideoInference from "@/components/VideoInference" 3 | 4 | export default async function VideoInferencePage() { 5 | //const session = await verifySession() 6 | 7 | // const user: UserView = { 8 | // id: session?.userId as string, 9 | // name: session?.name as string, 10 | // surname: session?.surname as string, 11 | // chatid: session?.chatid as string, 12 | // container: session?.container as string, 13 | // } 14 | 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /hooks/use-tfjs-backend.tsx: -------------------------------------------------------------------------------- 1 | import * as tf from "@tensorflow/tfjs" 2 | 3 | import { useEffect, useState } from "react" 4 | 5 | export type TfBackend = "webgl" | "cpu" | "wasm" 6 | 7 | interface ITfjsBackend { 8 | backend: TfBackend 9 | } 10 | 11 | export const useTfjsBackendWeb = ({ backend }: ITfjsBackend) => { 12 | const [tfReady, setTfReady] = useState(false) 13 | useEffect(() => { 14 | tf.ready().then(() => { 15 | tf.getBackend() !== backend && tf.setBackend(backend); 16 | setTfReady(true); 17 | }); 18 | }, [backend]); 19 | 20 | return tfReady 21 | } 22 | -------------------------------------------------------------------------------- /.env.exemple: -------------------------------------------------------------------------------- 1 | # Environment Azure 2 | AZURE_STORAGE_NAME="---------------------------------" 3 | AZURE_STORAGE_KEY="---------------------------------" 4 | AZURE_STORAGE_CONTAINER="---------------------------------" 5 | CONNECTION_STRING="---------------------------------" 6 | AUTH_AZURE_TABLES_ENDPOINT="---------------------------------" 7 | # Environment Telegram 8 | TELEGRAM_BOT_TOKEN="---------------------------------" 9 | TELEGRAM_CHAT_ID="---------------------------------" 10 | # Environment Auth 11 | AUTH_SECRET="---------------------------------" 12 | AUTH_RESEND_KEY="---------------------------------" -------------------------------------------------------------------------------- /app/historique/page.tsx: -------------------------------------------------------------------------------- 1 | import History from "@/components/History" 2 | import { verifySession } from "../../lib/identity/session-local" 3 | import { UserView } from "../../lib/identity/definition" 4 | 5 | async function PageHistory() { 6 | const session = await verifySession() 7 | 8 | const user: UserView = { 9 | id: session?.userId as string, 10 | name: session?.name as string, 11 | surname: session?.surname as string, 12 | chatid: session?.chatid as string, 13 | container: session?.container as string, 14 | } 15 | 16 | return 17 | } 18 | 19 | export default PageHistory 20 | -------------------------------------------------------------------------------- /ege.md: -------------------------------------------------------------------------------- 1 | # Azure Template 2 | 3 | ```shell 4 | 5 | az appservice plan create \ 6 | --resource-group rg-pro-pretorian \ 7 | --location westeurope \ 8 | --name sp-pro-pretorian-system \ 9 | --is-linux \ 10 | --sku F1 11 | 12 | az webapp create \ 13 | --resource-group rg-pro-pretorian \ 14 | --plan sp-pro-pretorian-system \ 15 | --name pro-pretorian-system \ 16 | --runtime "NODE:20-lts" \ 17 | --startup-file "node server.js" 18 | 19 | 20 | az webapp deployment list-publishing-profiles \ 21 | --resource-group rg-pro-pretorian \ 22 | --name pro-pretorian-system \ 23 | --xml > publishProfile.xml 24 | 25 | ``` 26 | -------------------------------------------------------------------------------- /app/parameter/telegram/page.tsx: -------------------------------------------------------------------------------- 1 | "use server" 2 | 3 | import { UserView } from "@/lib/identity/definition" 4 | import { verifySession } from "@/lib/identity/session-local" 5 | import ParamTelegram from "@/components/ParamTelegram" 6 | 7 | export default async function Page() { 8 | const session = await verifySession() 9 | 10 | const user: UserView = { 11 | id: session?.userId as string, 12 | name: session?.name as string, 13 | surname: session?.surname as string, 14 | chatid: session.chatid && (session?.chatid as string), 15 | container: session?.container as string, 16 | } 17 | 18 | return 19 | } 20 | -------------------------------------------------------------------------------- /components/layout/footer.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image" 2 | 3 | export default function Footer() { 4 | return ( 5 |
6 |
7 |

8 | {new Date().getFullYear()} © Pretorian System 9 |

10 | Presentation 17 |
18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /app/parameter/labels-detection/page.tsx: -------------------------------------------------------------------------------- 1 | "use server" 2 | import LabelDetection from "@/components/label-detection" 3 | import { UserView } from "@/lib/identity/definition" 4 | import { verifySession } from "@/lib/identity/session-local" 5 | 6 | export default async function LabelDetectionPage() { 7 | const session = await verifySession() 8 | 9 | const user: UserView = { 10 | id: session?.userId as string, 11 | name: session?.name as string, 12 | surname: session?.surname as string, 13 | chatid: session.chatid && (session?.chatid as string), 14 | container: session?.container as string, 15 | } 16 | 17 | return 18 | } 19 | -------------------------------------------------------------------------------- /hooks/use-video.tsx: -------------------------------------------------------------------------------- 1 | import { MutableRefObject, useRef, useState } from "react" 2 | 3 | type VideoStore = { 4 | canvasRef: MutableRefObject 5 | videoRef: MutableRefObject 6 | videoSrc: string | null 7 | setVideoSrc: (videoSrc: string | null) => void 8 | } 9 | 10 | export const useVideo = (): VideoStore => { 11 | const canvasRef = useRef(null) 12 | const videoRef = useRef(null) 13 | const [videoSrc, setVideoSrc] = useState("") 14 | 15 | return { 16 | canvasRef, 17 | videoRef, 18 | videoSrc, 19 | setVideoSrc, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /components/ui/text-blur.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion" 2 | import { createElement } from "react" 3 | 4 | interface TextBlurProps { 5 | text: string 6 | balise: string 7 | className?: string 8 | } 9 | export function BlurIn({ text, balise, className }: TextBlurProps) { 10 | const variants1 = { 11 | hidden: { filter: "blur(10px)", opacity: 0 }, 12 | visible: { filter: "blur(0px)", opacity: 1 }, 13 | } 14 | return createElement( 15 | motion[balise], 16 | { 17 | initial: "hidden", 18 | animate: "visible", 19 | transition: { duration: 1 }, 20 | variants: variants1, 21 | className: className, 22 | }, 23 | text 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import Board from "@/components/Board" 2 | import { verifySession } from "../lib/identity/session-local" 3 | import { UserView } from "../lib/identity/definition" 4 | import { redirect } from "next/navigation" 5 | 6 | async function BoardPage() { 7 | const session = await verifySession() 8 | const user: UserView = { 9 | id: session?.userId as string, 10 | name: session?.name as string, 11 | surname: session?.surname as string, 12 | chatid: session?.chatid as string, 13 | container: session?.container as string, 14 | } 15 | 16 | console.log(user) 17 | 18 | if (!user.chatid) { 19 | redirect("/parameter/telegram") 20 | } 21 | 22 | return 23 | } 24 | 25 | export default BoardPage 26 | -------------------------------------------------------------------------------- /components/sparckles-component.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useTheme } from "next-themes" 4 | import { SparklesCore } from "./ui/sparkles" 5 | 6 | interface IProps { 7 | minSize: number 8 | maxSize: number 9 | particleDensity: number 10 | } 11 | 12 | export default function SparklesComponent({ 13 | minSize, 14 | maxSize, 15 | particleDensity, 16 | }: IProps) { 17 | const { theme } = useTheme() 18 | 19 | return ( 20 | 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /hooks/use-board-detection.tsx: -------------------------------------------------------------------------------- 1 | import { ObjectDetection } from "@tensorflow-models/coco-ssd" 2 | import { useEffect } from "react" 3 | 4 | interface IProps { 5 | ready: boolean; 6 | net: ObjectDetection | { net: any; inputShape: number[] }; 7 | runObjectDetection: ( 8 | net: ObjectDetection | { net: any; inputShape: number[] }, 9 | ) => void; 10 | } 11 | 12 | export default function useBoardDetection({ 13 | ready, 14 | net, 15 | runObjectDetection, 16 | }: IProps) { 17 | useEffect(() => { 18 | if (!ready) return; 19 | if (net) { 20 | const detectInterval = setInterval(() => { 21 | runObjectDetection(net); 22 | }, 100); 23 | 24 | return () => { 25 | clearInterval(detectInterval); 26 | }; 27 | } 28 | }, [net, ready]); 29 | } 30 | -------------------------------------------------------------------------------- /components/display-history.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import React from "react" 4 | import { PictureStored } from "@/lib/send-detection/action" 5 | import ImgDisplayHistory from "./img-display-history" 6 | 7 | interface IProps { 8 | pictures: PictureStored[] 9 | } 10 | 11 | export default function DisplayHistory({ pictures }: IProps) { 12 | return ( 13 |
14 |

Picture History

15 |
16 | {pictures?.map((pic, i) => ( 17 |
18 | 19 |
20 | ))} 21 |
22 |
23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /lib/model-detection/yolo-test/type.ts: -------------------------------------------------------------------------------- 1 | import { NamedTensorMap } from "@tensorflow/tfjs" 2 | 3 | export type YoloVersion = "v5" | "v8" 4 | 5 | export interface ModelConfig { 6 | scoreThreshold?: number 7 | iouThreshold?: number 8 | maxOutputSize?: number 9 | onProgress?: (fraction: number) => void 10 | yoloVersion: YoloVersion 11 | } 12 | 13 | export interface PreprocessResult { 14 | input: NamedTensorMap 15 | xRatio: number 16 | yRatio: number 17 | } 18 | 19 | export type PreprocessImage = ( 20 | image: HTMLImageElement | HTMLCanvasElement | HTMLVideoElement 21 | ) => PreprocessResult 22 | 23 | export type PredictionData = { 24 | boxes: Float32Array | Int32Array | Uint8Array 25 | scores: Float32Array | Int32Array | Uint8Array 26 | classes: Float32Array | Int32Array | Uint8Array 27 | ratio: [number, number] 28 | } 29 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /hooks/use-interval.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from "react" 2 | 3 | type Props = { 4 | callback: any 5 | delay: number | null 6 | } 7 | 8 | const useInterval = (props: Props) => { 9 | const savedCallback = useRef() 10 | const intervalRef = useRef(null) 11 | 12 | const stopInterval = () => { 13 | if (intervalRef.current !== null) { 14 | clearInterval(intervalRef.current) 15 | } 16 | } 17 | 18 | useEffect(() => { 19 | savedCallback.current = props.callback 20 | }, [props.callback]) 21 | 22 | useEffect(() => { 23 | const tick = () => { 24 | savedCallback.current() 25 | } 26 | 27 | if (props.delay !== null) { 28 | intervalRef.current = setInterval(tick, props.delay) 29 | return () => stopInterval() 30 | } 31 | }, [props.delay]) 32 | } 33 | 34 | export default useInterval 35 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": false, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": [ 26 | "next-env.d.ts", 27 | "**/*.ts", 28 | "**/*.tsx", 29 | ".next/types/**/*.ts", 30 | "lib/yolov8n/renderBox.js", 31 | "lib/yolov8-seg/renderBox.ts", 32 | "lib/yolov8-seg/detect.ts" 33 | ], 34 | "exclude": ["node_modules"] 35 | } 36 | -------------------------------------------------------------------------------- /lib/model-detection/yolo-test/yolov5.ts: -------------------------------------------------------------------------------- 1 | import { concat, Rank, Tensor, tidy } from "@tensorflow/tfjs" 2 | import { YoloStrategy } from "./yoloStrategy" 3 | 4 | export class YoloV5 extends YoloStrategy { 5 | getPredictionData(output: Tensor | Tensor[]) { 6 | const [boxes, scores, classes] = (output as Tensor[]).slice(0, 3) 7 | 8 | const proceedBoxes = tidy(() => { 9 | const x1 = boxes.slice([0, 0, 0], [-1, -1, 1]).mul(640) 10 | const y1 = boxes.slice([0, 0, 1], [-1, -1, 1]).mul(640) 11 | const x2 = boxes.slice([0, 0, 2], [-1, -1, 1]).mul(640) 12 | const y2 = boxes.slice([0, 0, 3], [-1, -1, 1]).mul(640) 13 | 14 | return concat([x1, y1, x2, y2], 2).squeeze() 15 | }) as Tensor 16 | 17 | return { 18 | boxes: proceedBoxes, 19 | scores: scores.squeeze() as Tensor, 20 | classes, 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as SeparatorPrimitive from "@radix-ui/react-separator" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Separator = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >( 10 | ( 11 | { className, orientation = "horizontal", decorative = true, ...props }, 12 | ref 13 | ) => ( 14 | 25 | ) 26 | ) 27 | Separator.displayName = SeparatorPrimitive.Root.displayName 28 | 29 | export { Separator } 30 | -------------------------------------------------------------------------------- /components/ui/progress.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as ProgressPrimitive from "@radix-ui/react-progress" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Progress = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, value, ...props }, ref) => ( 10 | 18 | 22 | 23 | )) 24 | Progress.displayName = ProgressPrimitive.Root.displayName 25 | 26 | export { Progress } 27 | -------------------------------------------------------------------------------- /components/ui/toaster.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Toast, 3 | ToastClose, 4 | ToastDescription, 5 | ToastProvider, 6 | ToastTitle, 7 | ToastViewport, 8 | } from "@/components/ui/toast" 9 | import { useToast } from "@/components/ui/use-toast" 10 | 11 | export function Toaster() { 12 | const { toasts } = useToast() 13 | 14 | return ( 15 | 16 | {toasts.map(function ({ id, title, description, action, ...props }) { 17 | return ( 18 | 19 |
20 | {title && {title}} 21 | {description && ( 22 | {description} 23 | )} 24 |
25 | {action} 26 | 27 |
28 | ) 29 | })} 30 | 31 |
32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /components/video-reader.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | interface IProps { 4 | videoRef: React.RefObject 5 | canvasRef: React.RefObject 6 | videoSrc: string | null 7 | } 8 | 9 | export default function VideoReader({ videoRef, canvasRef, videoSrc }: IProps) { 10 | return ( 11 | <> 12 |
13 | 21 | 27 |
28 |
29 | 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ) 21 | } 22 | ) 23 | Input.displayName = "Input" 24 | 25 | export { Input } 26 | -------------------------------------------------------------------------------- /components/ui/acerternity-button.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { cn } from "@/lib/utils" 3 | import { IconClipboard } from "@tabler/icons-react" 4 | import React from "react" 5 | 6 | export const ButtonsCard = ({ 7 | children, 8 | className, 9 | onClick, 10 | }: { 11 | children?: React.ReactNode 12 | className?: string 13 | onClick?: () => void 14 | }) => { 15 | return ( 16 |
22 |
23 | 24 |
{children}
25 |
26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /components/model-loader.tsx: -------------------------------------------------------------------------------- 1 | import { Progress } from "./ui/progress" 2 | import { BlurIn } from "./ui/text-blur" 3 | import { Card, CardContent, CardHeader } from "./ui/card" 4 | import { ModelList } from "@/models/model-list" 5 | 6 | interface IProps { 7 | percent?: number 8 | model?: ModelList 9 | } 10 | export default function ModelLoader({ percent, model }: IProps) { 11 | return ( 12 | 13 | 14 |
15 | 16 |
17 |
18 | 19 |
20 | 21 | {percent && } 22 | 23 | 24 |
25 |
26 |
27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useTheme } from "next-themes" 4 | import { Toaster as Sonner } from "sonner" 5 | 6 | type ToasterProps = React.ComponentProps 7 | 8 | const Toaster = ({ ...props }: ToasterProps) => { 9 | const { theme = "system" } = useTheme() 10 | 11 | return ( 12 | 28 | ) 29 | } 30 | 31 | export { Toaster } 32 | -------------------------------------------------------------------------------- /components/mode-toggle.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { Moon, Sun } from "lucide-react" 5 | import { useTheme } from "next-themes" 6 | import { Button } from "./ui/button" 7 | 8 | export function ModeToggle() { 9 | const { setTheme, theme } = useTheme() 10 | 11 | const buttonClassName = `rounded-full ${theme === "light" ? "bg-blue-300" : "bg-blue-900"} cursor-pointer hover:bg-blue-400 dark:bg-blue-900 dark:hover:bg-blue-800 transition-colors p-1 md:p-2 md:rounded-full md:hover:bg-blue-400` 12 | 13 | const toggleTheme = () => { 14 | setTheme(theme === "light" ? "dark" : "light") 15 | } 16 | 17 | return ( 18 | 23 | ) 24 | } -------------------------------------------------------------------------------- /hooks/use-model.tsx: -------------------------------------------------------------------------------- 1 | import { useModelStore } from "@/lib/store/model-store" 2 | import { useEffect, useState } from "react" 3 | import * as tf from "@tensorflow/tfjs" 4 | import { ModelComputerVision, modelList } from "@/models/model-list" 5 | 6 | interface IProps { 7 | ready: boolean 8 | } 9 | 10 | export type ModelGraph = { 11 | net: tf.GraphModel 12 | inputShape: number[] 13 | outputShape?: number[] 14 | } 15 | 16 | export default function useModel({ ready }: IProps) { 17 | const { modelName } = useModelStore() 18 | const [model, setModel] = useState(null) 19 | const [loadModel, setLoadModel] = useState(false) 20 | const [percentLoaded, setPercentLoaded] = useState(0) 21 | 22 | useEffect(() => { 23 | if (!ready) return 24 | 25 | if (modelName === ModelComputerVision.EMPTY) { 26 | if (model && model.net) { 27 | model.net.dispose() 28 | console.log(tf.memory()) 29 | } 30 | setModel(null) 31 | } 32 | }, [modelName, ready]) 33 | 34 | return { model, loadModel, percentLoaded } 35 | } 36 | -------------------------------------------------------------------------------- /lib/model-detection/coco-ssd/utils.ts: -------------------------------------------------------------------------------- 1 | import { ObjectDetection } from "@tensorflow-models/coco-ssd" 2 | 3 | const drawBoundingBoxes = async ( 4 | video: HTMLVideoElement, 5 | context: CanvasRenderingContext2D, 6 | cocoSsd: ObjectDetection 7 | ) => { 8 | if (video.paused || video.ended) { 9 | return 10 | } 11 | if (context) { 12 | context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight) 13 | let predictions = [] 14 | predictions = await cocoSsd.detect(video, undefined, 0.1) 15 | predictions.forEach(prediction => { 16 | const [x, y, width, height] = prediction.bbox 17 | context.strokeStyle = "#00FFFF" 18 | context.lineWidth = 2 19 | context.strokeRect(x, y, width, height) 20 | context.font = "16px sans-serif" 21 | context.fillStyle = "#00FFFF" 22 | context.fillText( 23 | `${prediction.class} (${Math.round(prediction.score * 100)}%)`, 24 | x, 25 | y > 10 ? y - 5 : 10 26 | ) 27 | }) 28 | } 29 | requestAnimationFrame(() => drawBoundingBoxes(video, context, cocoSsd)) 30 | } 31 | 32 | export default drawBoundingBoxes 33 | -------------------------------------------------------------------------------- /components/header-menu-nav.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { usePathname, useRouter } from "next/navigation" 4 | import { Button } from "./ui/button" 5 | 6 | export default function HeaderMenuNav() { 7 | const router = useRouter() 8 | const pathname = usePathname() 9 | 10 | return ( 11 | <> 12 |
13 | 21 | 29 | 37 | 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /models/model-list.ts: -------------------------------------------------------------------------------- 1 | export enum ModelComputerVision { 2 | COCO_SSD = "Detection d'objets ordinaires", 3 | DETECTION = "Yolo detection ordinaires", 4 | EMPTY = "", 5 | } 6 | 7 | export type ModelList = { 8 | title: ModelComputerVision; 9 | url: string; 10 | description: string; 11 | labels?: string; 12 | }; 13 | 14 | export const modelList: ModelList[] = [ 15 | { 16 | title: ModelComputerVision.COCO_SSD, 17 | url: "https://tfhub.dev/tensorflow/tfjs-model/ssd_mobilenet_v2/1/default/1", 18 | description: 19 | "Detection d'objets classiques dans des images. Ce modèle est capable de détecter 80 classes d'objets de la base de données COCO (Common Objects in Context).", 20 | labels: "basic", 21 | }, 22 | { 23 | title: ModelComputerVision.DETECTION, 24 | url: "https://huggingface.co/salim4n/yolov8n_web_model/resolve/main/model.json", 25 | description: 26 | "Detection d'objets classiques dans des images. Ce modèle est capable de détecter 80 classes d'objets de la base de données COCO (Common Objects in Context).", 27 | labels: "basic", 28 | }, 29 | 30 | { 31 | title: ModelComputerVision.EMPTY, 32 | url: "", 33 | description: "", 34 | labels: "", 35 | }, 36 | ]; 37 | -------------------------------------------------------------------------------- /components/ui/meteors.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { cn } from "@/lib/utils" 3 | import React from "react" 4 | 5 | export const Meteors = ({ 6 | number, 7 | className, 8 | }: { 9 | number?: number 10 | className?: string 11 | }) => { 12 | const meteors = new Array(number || 20).fill(true) 13 | return ( 14 | <> 15 | {meteors.map((el, idx) => ( 16 | 29 | ))} 30 | 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /hooks/use-cocossd.tsx: -------------------------------------------------------------------------------- 1 | import { useModelStore } from "@/lib/store/model-store" 2 | import { useEffect, useState } from "react" 3 | import { ObjectDetection, load } from "@tensorflow-models/coco-ssd" 4 | import { ModelComputerVision } from "@/models/model-list" 5 | 6 | interface IProps { 7 | ready: boolean 8 | } 9 | 10 | export default function useCocoSsd({ ready }: IProps) { 11 | const { modelName } = useModelStore() 12 | const [cocoSsd, setCocoSsd] = useState(null) 13 | const [loadCoco, setLoadCoco] = useState(false) 14 | 15 | async function fetchModel() { 16 | modelName === ModelComputerVision.COCO_SSD && 17 | (setLoadCoco(true), 18 | await load() 19 | .then(model => { 20 | setCocoSsd(model) 21 | }) 22 | .catch(error => { 23 | console.error(error) 24 | }) 25 | .finally(() => setLoadCoco(false))) 26 | } 27 | 28 | useEffect(() => { 29 | if (ready) { 30 | fetchModel() 31 | } 32 | 33 | if (modelName === ModelComputerVision.EMPTY) { 34 | setCocoSsd(null) 35 | cocoSsd?.dispose() 36 | } 37 | }, [ready, modelName]) 38 | 39 | return { cocoSsd, loadCoco } 40 | } 41 | -------------------------------------------------------------------------------- /lib/identity/middleware.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from "next/server" 2 | import { cookies } from "next/headers" 3 | import { decrypt } from "./session-local" 4 | 5 | // 1. Specify protected and public routes 6 | const protectedRoutes = ["/board", "/historique", "/profile"] 7 | const publicRoutes = ["/login", "/signup", "/", "/video-inference"] 8 | 9 | export default async function middleware(req: NextRequest) { 10 | // 2. Check if the current route is protected or public 11 | const path = req.nextUrl.pathname 12 | const isProtectedRoute = protectedRoutes.includes(path) 13 | const isPublicRoute = publicRoutes.includes(path) 14 | 15 | // 3. Decrypt the session from the cookie 16 | const cookie = cookies().get("session")?.value 17 | const session = await decrypt(cookie) 18 | 19 | // 4. Redirect 20 | if (isProtectedRoute && !session?.userId) { 21 | return NextResponse.redirect(new URL("/login", req.nextUrl)) 22 | } 23 | 24 | if ( 25 | isPublicRoute && 26 | session?.userId && 27 | !req.nextUrl.pathname.startsWith("/board") 28 | ) { 29 | return NextResponse.redirect(new URL("/board", req.nextUrl)) 30 | } 31 | 32 | return NextResponse.next() 33 | } 34 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { DetectedObject } from "@tensorflow-models/coco-ssd" 2 | import { type ClassValue, clsx } from "clsx" 3 | import { twMerge } from "tailwind-merge" 4 | 5 | export function cn(...inputs: ClassValue[]) { 6 | return twMerge(clsx(inputs)) 7 | } 8 | 9 | export function drawRect( 10 | detections: DetectedObject[], 11 | context: CanvasRenderingContext2D, 12 | ) { 13 | detections.forEach((predication) => { 14 | const [x, y, width, height] = predication.bbox 15 | 16 | const score = (predication.score * 100).toFixed(2) + '%' 17 | const label = predication.class.toUpperCase() + ' - ' + score 18 | 19 | // draw bounding box 20 | context.font = '16px Arial' 21 | context.strokeStyle = getRandomColor() 22 | context.lineWidth = 3 23 | context.strokeRect(x, y, width, height) 24 | 25 | // draw label bg 26 | context.fillStyle = "#000000" 27 | const textW = context.measureText(label).width + 10 28 | context.fillRect(x, y, textW, -16) 29 | 30 | // text on top 31 | context.fillStyle = "#ffffff" 32 | context.fillText(label, x, y) 33 | }) 34 | } 35 | 36 | export const getRandomColor = () :string => 37 | `#${Math.floor(Math.random() * 16777215).toString(16)}` 38 | 39 | -------------------------------------------------------------------------------- /lib/telegram-bot/action.ts: -------------------------------------------------------------------------------- 1 | "use server" 2 | 3 | import * as dotenv from 'dotenv' 4 | 5 | dotenv.config() 6 | 7 | const token = process.env.TELEGRAM_BOT_TOKEN as string 8 | if (!token) throw Error('Telegram Bot token not found') 9 | 10 | export const sendDetection = async (chatId: string, message: string) => { 11 | const url = `https://api.telegram.org/bot${token}/sendMessage` 12 | const response = await fetch(url, { 13 | method: 'POST', 14 | headers: { 15 | 'Content-Type': 'application/json', 16 | }, 17 | body: JSON.stringify({ 18 | chat_id: chatId, 19 | text: message, 20 | }), 21 | }) 22 | return response.json() 23 | } 24 | 25 | export const getChatId = async (text:string) => { 26 | const url = `https://api.telegram.org/bot${token}/getUpdates` 27 | const response = await fetch(url) 28 | let chatId = '' 29 | const data = await response.json() 30 | data.result.forEach((element:any) => { 31 | if (element?.message?.text?.trim()?.toLowerCase() === text?.trim()?.toLowerCase()) { 32 | console.log(element.message.chat.id) 33 | chatId = element.message.chat.id 34 | } 35 | }) 36 | return chatId 37 | } -------------------------------------------------------------------------------- /components/ui/switch.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as SwitchPrimitives from "@radix-ui/react-switch" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Switch = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, ...props }, ref) => ( 10 | 17 | 22 | 23 | )) 24 | Switch.displayName = SwitchPrimitives.Root.displayName 25 | 26 | export { Switch } 27 | -------------------------------------------------------------------------------- /hooks/use-history.tsx: -------------------------------------------------------------------------------- 1 | import { UserView } from "@/lib/identity/definition" 2 | import { PictureStored, getPictures } from "@/lib/send-detection/action" 3 | import { addDays } from "date-fns" 4 | import { useEffect, useState } from "react" 5 | import { DateRange } from "react-day-picker" 6 | 7 | interface IProps { 8 | user: UserView 9 | } 10 | 11 | export default function useHistory({ user }: IProps) { 12 | const actualDate = new Date() 13 | const actualYear = actualDate.getFullYear() 14 | const actualMonth = actualDate.getMonth() 15 | const [date, setDate] = useState({ 16 | from: new Date(actualYear, actualMonth, 1), 17 | to: addDays(new Date(actualYear, actualMonth, 1), 6), 18 | }) 19 | const [blobs, setBlobs] = useState([]) 20 | 21 | const fetchPicturesFromRange = async () => { 22 | if (date && date.from && date.to) { 23 | const fromDateStr = date.from.toISOString() 24 | const toDateStr = date.to.toISOString() 25 | const blobs = await getPictures(fromDateStr, toDateStr, user.container) 26 | setBlobs(blobs) 27 | } 28 | } 29 | 30 | useEffect(() => { 31 | fetchPicturesFromRange() 32 | }, [date]) 33 | 34 | return { blobs, setBlobs, date, setDate } 35 | } 36 | -------------------------------------------------------------------------------- /components/img-display-history.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { PictureStored } from "@/lib/send-detection/action" 4 | import { Badge } from "./ui/badge" 5 | import { useRef } from "react" 6 | 7 | interface IProps { 8 | pic: PictureStored 9 | } 10 | 11 | export default function ImgDisplayHistory({ pic }: IProps) { 12 | const imgRef = useRef(null) 13 | return ( 14 |
15 | img 25 | 26 |
27 | {pic.detected?.map((d, i) => ( 28 | 29 | {d.class} - {Math.round(parseFloat(d?.score?.toString()) * 100)}% 30 | 31 | ))} 32 |

33 | Uploaded on {new Date(pic.created).toDateString()} at {pic.hour} 34 |

35 |
36 |
37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /lib/model-detection/yolo-test/yolov8.ts: -------------------------------------------------------------------------------- 1 | import { 2 | add, 3 | concat, 4 | dispose, 5 | div, 6 | Rank, 7 | sub, 8 | Tensor, 9 | TensorContainer, 10 | tidy, 11 | } from "@tensorflow/tfjs" 12 | import { YoloStrategy } from "./yoloStrategy" 13 | 14 | export class YoloV8 extends YoloStrategy { 15 | getPredictionData(output: Tensor | Tensor[]) { 16 | const prediction = (output as Tensor).transpose([0, 2, 1]) 17 | 18 | const boxes = tidy(() => { 19 | const width = prediction.slice([0, 0, 2], [-1, -1, 1]) 20 | const height = prediction.slice([0, 0, 3], [-1, -1, 1]) 21 | const x1 = sub(prediction.slice([0, 0, 0], [-1, -1, 1]), div(width, 2)) 22 | const y1 = sub(prediction.slice([0, 0, 1], [-1, -1, 1]), div(height, 2)) 23 | const x2 = add(x1, width) 24 | const y2 = add(y1, height) 25 | return concat([x1, y1, x2, y2], 2).squeeze() 26 | }) as Tensor 27 | 28 | const [scores, classes] = tidy(() => { 29 | const scores = prediction 30 | .slice([0, 0, 4], [-1, -1, this.classes.length]) 31 | .squeeze() 32 | return [scores.max(1), scores.argMax(1)] 33 | }) 34 | 35 | dispose([prediction] as TensorContainer) 36 | 37 | return { boxes, scores, classes } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva, type VariantProps } from "class-variance-authority" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const badgeVariants = cva( 7 | "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 8 | { 9 | variants: { 10 | variant: { 11 | default: 12 | "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", 13 | secondary: 14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", 15 | destructive: 16 | "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", 17 | outline: "text-foreground", 18 | }, 19 | }, 20 | defaultVariants: { 21 | variant: "default", 22 | }, 23 | } 24 | ) 25 | 26 | export interface BadgeProps 27 | extends React.HTMLAttributes, 28 | VariantProps {} 29 | 30 | function Badge({ className, variant, ...props }: BadgeProps) { 31 | return ( 32 |
33 | ) 34 | } 35 | 36 | export { Badge, badgeVariants } 37 | -------------------------------------------------------------------------------- /lib/data/user.ts: -------------------------------------------------------------------------------- 1 | import { cache } from "react" 2 | import { verifySession } from "../identity/session-local" 3 | import { TableClient, AzureNamedKeyCredential } from "@azure/data-tables" 4 | 5 | import * as dotenv from "dotenv" 6 | 7 | dotenv.config() 8 | 9 | const connectionString = process.env 10 | .AUTH_AZURE_STORAGE_CONNECTION_STRING as string 11 | const accountName = process.env.AUTH_AZURE_ACCOUNT as string 12 | const accountKey = process.env.AUTH_AZURE_ACCESS_KEY as string 13 | const secretKey = process.env.AUTH_SECRET 14 | 15 | if (!connectionString) throw Error("Azure Storage connectionString not found") 16 | if (!accountName) throw Error("Azure Storage accountName not found") 17 | if (!accountKey) throw Error("Azure Storage accountKey not found") 18 | 19 | const key = new TextEncoder().encode(secretKey) 20 | const credential = new AzureNamedKeyCredential(accountName, accountKey) 21 | const client = new TableClient( 22 | `https://${accountName}.table.core.windows.net`, 23 | "PretorianSystem", 24 | credential 25 | ) 26 | 27 | export const getUser = cache(async () => { 28 | const session = await verifySession() 29 | 30 | if (!session) { 31 | return null 32 | } 33 | 34 | const data = await client.getEntity(session.userId.toString(), "User") 35 | return data 36 | }) 37 | -------------------------------------------------------------------------------- /components/layout/header-client.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { MenuSquareIcon } from "lucide-react" 4 | import HeaderMenuNav from "../header-menu-nav" 5 | import { Button } from "../ui/button" 6 | import { Sheet, SheetContent, SheetTrigger } from "../ui/sheet" 7 | import { ModeToggle } from "../mode-toggle" 8 | import HeaderDropdown from "./header-dropdown" 9 | 10 | export default function HeaderClient() { 11 | return ( 12 | <> 13 |
14 | 17 |
18 | 19 | 20 | 23 | 24 | 25 | 28 | 29 | 30 |
31 | 32 | 33 |
34 | 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /components/ui/text-generate-effect.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { useEffect } from "react" 3 | import { motion, stagger, useAnimate } from "framer-motion" 4 | import { cn } from "@/lib/utils" 5 | 6 | export const TextGenerateEffect = ({ 7 | words, 8 | className, 9 | }: { 10 | words: string 11 | className?: string 12 | }) => { 13 | const [scope, animate] = useAnimate() 14 | let wordsArray = words.split(" ") 15 | useEffect(() => { 16 | animate( 17 | "span", 18 | { 19 | opacity: 1, 20 | }, 21 | { 22 | duration: 2, 23 | delay: stagger(0.2), 24 | } 25 | ) 26 | }, [scope.current]) 27 | 28 | const renderWords = () => { 29 | return ( 30 | 31 | {wordsArray.map((word, idx) => { 32 | return ( 33 | 36 | {word}{" "} 37 | 38 | ) 39 | })} 40 | 41 | ) 42 | } 43 | 44 | return ( 45 |
46 |
47 |
{renderWords()}
48 |
49 |
50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /lib/identity/dal.ts: -------------------------------------------------------------------------------- 1 | import 'server-only' 2 | 3 | import { cache } from 'react' 4 | import { verifySession } from './session-local' 5 | import * as dotenv from 'dotenv' 6 | import { TableClient, AzureNamedKeyCredential } from '@azure/data-tables' 7 | 8 | dotenv.config() 9 | 10 | const connectionString = process.env.AUTH_AZURE_STORAGE_CONNECTION_STRING as string 11 | const accountName = process.env.AUTH_AZURE_ACCOUNT as string 12 | const accountKey = process.env.AUTH_AZURE_ACCESS_KEY as string 13 | 14 | if (!connectionString) throw Error('Azure Storage connectionString not found') 15 | if (!accountName) throw Error('Azure Storage accountName not found') 16 | if (!accountKey) throw Error('Azure Storage accountKey not found') 17 | 18 | const credential = new AzureNamedKeyCredential( 19 | accountName, 20 | accountKey 21 | ) 22 | 23 | const client = new TableClient(`https://${accountName}.table.core.windows.net`, "PretorianSystem", credential) 24 | 25 | export const getUser = cache(async () => { 26 | const session = await verifySession() 27 | if (!session) return null 28 | 29 | try { 30 | const data = await client.getEntity(session.userId.toString(), 'User') 31 | const user = data[0] 32 | return user 33 | } catch (error) { 34 | console.log('Failed to fetch user'); 35 | return null; 36 | } 37 | }); -------------------------------------------------------------------------------- /components/ui/popover.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as PopoverPrimitive from "@radix-ui/react-popover" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const Popover = PopoverPrimitive.Root 7 | 8 | const PopoverTrigger = PopoverPrimitive.Trigger 9 | 10 | const PopoverContent = React.forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 14 | 15 | 25 | 26 | )) 27 | PopoverContent.displayName = PopoverPrimitive.Content.displayName 28 | 29 | export { Popover, PopoverTrigger, PopoverContent } 30 | -------------------------------------------------------------------------------- /lib/yolov8n-seg/labels.json: -------------------------------------------------------------------------------- 1 | [ 2 | "person", 3 | "bicycle", 4 | "car", 5 | "motorcycle", 6 | "airplane", 7 | "bus", 8 | "train", 9 | "truck", 10 | "boat", 11 | "traffic light", 12 | "fire hydrant", 13 | "stop sign", 14 | "parking meter", 15 | "bench", 16 | "bird", 17 | "cat", 18 | "dog", 19 | "horse", 20 | "sheep", 21 | "cow", 22 | "elephant", 23 | "bear", 24 | "zebra", 25 | "giraffe", 26 | "backpack", 27 | "umbrella", 28 | "handbag", 29 | "tie", 30 | "suitcase", 31 | "frisbee", 32 | "skis", 33 | "snowboard", 34 | "sports ball", 35 | "kite", 36 | "baseball bat", 37 | "baseball glove", 38 | "skateboard", 39 | "surfboard", 40 | "tennis racket", 41 | "bottle", 42 | "wine glass", 43 | "cup", 44 | "fork", 45 | "knife", 46 | "spoon", 47 | "bowl", 48 | "banana", 49 | "apple", 50 | "sandwich", 51 | "orange", 52 | "broccoli", 53 | "carrot", 54 | "hot dog", 55 | "pizza", 56 | "donut", 57 | "cake", 58 | "chair", 59 | "couch", 60 | "potted plant", 61 | "bed", 62 | "dining table", 63 | "toilet", 64 | "tv", 65 | "laptop", 66 | "mouse", 67 | "remote", 68 | "keyboard", 69 | "cell phone", 70 | "microwave", 71 | "oven", 72 | "toaster", 73 | "sink", 74 | "refrigerator", 75 | "book", 76 | "clock", 77 | "vase", 78 | "scissors", 79 | "teddy bear", 80 | "hair drier", 81 | "toothbrush" 82 | ] 83 | -------------------------------------------------------------------------------- /lib/model-detection/yolo-test/label.ts: -------------------------------------------------------------------------------- 1 | export const cocoDataSet = [ 2 | "person", 3 | "bicycle", 4 | "car", 5 | "motorcycle", 6 | "airplane", 7 | "bus", 8 | "train", 9 | "truck", 10 | "boat", 11 | "traffic light", 12 | "fire hydrant", 13 | "stop sign", 14 | "parking meter", 15 | "bench", 16 | "bird", 17 | "cat", 18 | "dog", 19 | "horse", 20 | "sheep", 21 | "cow", 22 | "elephant", 23 | "bear", 24 | "zebra", 25 | "giraffe", 26 | "backpack", 27 | "umbrella", 28 | "handbag", 29 | "tie", 30 | "suitcase", 31 | "frisbee", 32 | "skis", 33 | "snowboard", 34 | "sports ball", 35 | "kite", 36 | "baseball bat", 37 | "baseball glove", 38 | "skateboard", 39 | "surfboard", 40 | "tennis racket", 41 | "bottle", 42 | "wine glass", 43 | "cup", 44 | "fork", 45 | "knife", 46 | "spoon", 47 | "bowl", 48 | "banana", 49 | "apple", 50 | "sandwich", 51 | "orange", 52 | "broccoli", 53 | "carrot", 54 | "hot dog", 55 | "pizza", 56 | "donut", 57 | "cake", 58 | "chair", 59 | "couch", 60 | "potted plant", 61 | "bed", 62 | "dining table", 63 | "toilet", 64 | "tv", 65 | "laptop", 66 | "mouse", 67 | "remote", 68 | "keyboard", 69 | "cell phone", 70 | "microwave", 71 | "oven", 72 | "toaster", 73 | "sink", 74 | "refrigerator", 75 | "book", 76 | "clock", 77 | "vase", 78 | "scissors", 79 | "teddy bear", 80 | "hair drier", 81 | "toothbrush", 82 | ] 83 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next" 2 | import { Inter as FontSans } from "next/font/google" 3 | import "./globals.css" 4 | import { cn } from "@/lib/utils" 5 | import { ThemeProvider } from "../components/theme-provider" 6 | import Header from "@/components/layout/header" 7 | import { Toaster } from "@/components/ui/sonner" 8 | import Footer from "@/components/layout/footer" 9 | 10 | const fontSans = FontSans({ 11 | subsets: ["latin"], 12 | variable: "--font-sans", 13 | }) 14 | 15 | export const metadata: Metadata = { 16 | title: "Pro Pretorian - Computer Vision Solutions", 17 | description: 18 | "Pro Pretorian System Solutions is a company that provides Computer Vision solutions for your home and business.", 19 | } 20 | 21 | export default function RootLayout({ 22 | children, 23 | }: Readonly<{ 24 | children: React.ReactNode 25 | }>) { 26 | return ( 27 | 28 | 33 | 38 |
39 |
40 | {children} 41 | 42 |
43 |