DEV Community

Cover image for Building an Attendance System Powered by Face Recognition Using React and FACEIO
Ekemini Samuel
Ekemini Samuel

Posted on

Building an Attendance System Powered by Face Recognition Using React and FACEIO

Quer você esteja gerenciando uma equipe remotamente ou ensinando um grupo de alunos, ter um sistema de controle de presença pode simplificar o processo de rastrear quem está ativo e quem não está. Um sistema eficiente de controle de presença não só melhora o registro de dados, mas também motiva os membros da equipe ou alunos a registrar sua presença de forma consistente.

Para ir além, você pode tornar o processo mais seguro ao substituir métodos tradicionais de autenticação, como senhas ou códigos QR, por Autenticação Facial. Isso garante que o registro de presença seja rápido e à prova de fraudes.

Neste artigo, construiremos um Sistema de Controle de Presença usando React e o FACEIO para autenticação facial.

Este é o sistema web de controle de presença que vamos construir:

Attendance system

Parece interessante? Vamos começar!


Pré-requisitos

Antes de começarmos, certifique-se de ter o seguinte pronto:

  • Conhecimento básico de JavaScript e React.js.
  • Uma conta no FACEIO.
  • Node.js e npm instalados localmente para gerenciar dependências.
  • O Pacote NPM do FACEIO instalado.
  • Um editor de texto ou IDE, como o VS Code.

O que é o FACEIO?

O FACEIO é um framework de autenticação facial que pode ser implementado em qualquer site usando JavaScript, permitindo autenticar usuários facilmente por reconhecimento facial em vez de login/senha ou código OTP.

Here is the translation of the provided text to Brazilian Portuguese:

Construindo o Sistema de Presença

Nesta seção, vamos passar pelo processo de configuração de um projeto React e integrar a biblioteca FaceIO para o rastreamento de presença baseado em reconhecimento facial.

Configurando o Projeto React
Para começar, abra o terminal e crie um novo aplicativo React usando o seguinte comando:

npx create-react-app sistema-de-presenca
Enter fullscreen mode Exit fullscreen mode

Isso criará um novo projeto React em um diretório nomeado sistema-de-presenca. Navegue até este diretório para começar a configurar o projeto.

cd sistema-de-presenca
Enter fullscreen mode Exit fullscreen mode

Em seguida, instale o SDK do FACEIO:

npm install faceio
Enter fullscreen mode Exit fullscreen mode

Isso instalará a biblioteca FaceIO e suas dependências, permitindo que você use suas funcionalidades de reconhecimento facial no sistema de presença.

Para usar o SDK do FaceIO, você precisa instalá-lo separadamente. Você pode fazer isso executando o seguinte comando:

npm install @faceio/fiojs
Enter fullscreen mode Exit fullscreen mode

Você também pode instalar o SDK do FaceIO usando o seguinte comando:

npm install @faceio/fiojs@latest
Enter fullscreen mode Exit fullscreen mode

Para a interface do usuário da aplicação web, estamos usando Shadcn UI, então para instalar as dependências necessárias, execute o seguinte comando:

npm install react shadcn react-dom react-router-dom react-hook-form @hookform/resolvers yup
Enter fullscreen mode Exit fullscreen mode

Agora podemos criar funções de Matrícula e Login para nosso sistema, mas antes disso, vamos inicializar o FaceIO em nossa página usando um hook useEffect.

useEffect(() => {
    const initializeFaceIO = () => {
      try {
        const faceioInstance = new faceIO("My Public_ID");
        setFaceio(faceioInstance);
      } catch (err: any) {
        setError("Failed to initialize FaceIO: " + err.message);
      }
    };
    initializeFaceIO();
  }, []);
Enter fullscreen mode Exit fullscreen mode

Here is the translation of the provided text to Brazilian Portuguese, focusing on the key components and functionalities of the attendance system using React, FaceIO, and Yup for validation.

Componente de Autenticação

Aqui, configuramos a chave pública do FACEIO no construtor faceIO. Este componente fornece reconhecimento facial para autenticação e matrícula de usuários usando o SDK do FaceIO. Os usuários podem registrar seus dados faciais e autenticar-se de forma segura usando o FaceIO.

No diretório src/pages, crie um arquivo Auth.tsx e insira o código completo deste repositório do GitHub.

Alguns trechos do código aqui mostram como definimos o esquema de validação para integrar o FACEIO usando yup na constante SignupSchema:

// Defina o esquema de validação usando yup
const SignupSchema = yup.object().shape({
  name: yup.string().required("Nome é obrigatório"),
  email: yup
    .string()
    .email("Endereço de email inválido")
    .required("Email é obrigatório"),
});

// Defina as interfaces
interface FaceIODetails {
  gender: string;
  age: number;
}

interface FaceIOEnrollResponse {
  facialId: string;
  timestamp: string;
  details: FaceIODetails;
}

interface FaceIOAuthenticateResponse {
  facialId: string;
  payload: Record<string, any>;
}

interface FaceIO {
  enroll(options: {
    locale: string;
    payload: { name: string; email: string };
  }): Promise<FaceIOEnrollResponse>;

  authenticate(options: { locale: string }): Promise<FaceIOAuthenticateResponse>;
}

// Declare o construtor faceIO globalmente
declare const faceIO: new (publicId: string) => FaceIO;

type Iuser = {
  name: string;
  email: string;
};

const Auth: React.FC = () => {
  const [faceio, setFaceio] = useState<FaceIO | null>(null);
  const [error, setError] = useState<string | null>(null);
  const navigate = useNavigate();

  // Inicialize a instância do FaceIO
  useEffect(() => {
    const initializeFaceIO = () => {
      try {
        const faceioInstance = new faceIO("fioac691");
        setFaceio(faceioInstance);
      } catch (err: any) {
        setError("Falha ao inicializar o FaceIO: " + err.message);
      }
    };
    initializeFaceIO();
  }, []);
Enter fullscreen mode Exit fullscreen mode

Funcionalidades Chave

  • Usa React com react-hook-form para manipulação de formulários e yup para validação de esquemas.
  • Integra o SDK do FaceIO para matrícula e autenticação.
  • Tratamento de erros para diferentes códigos de erro específicos do FaceIO.
  • Redireciona os usuários para o painel após autenticação ou matrícula bem-sucedida.

Componente de Check-In e Check-Out

Este componente fornece funcionalidades para rastrear a presença, incluindo os horários de check-in e check-out.

No diretório src/pages, criamos esta funcionalidade em um arquivo CheckInOut.tsx com o código como abaixo:

type AttendanceLogEntry = {
  type: "Check-In" | "Check-Out";
  time: string;
};

export default function CheckInOut() {
  const [lastCheckIn, setLastCheckIn] = useState<string>("--:-- --");
  const [lastCheckOut, setLastCheckOut] = useState<string>("--:-- --");
  const [attendanceLog, setAttendanceLog] = useState<AttendanceLogEntry[]>([]);
  const [isCheckedIn, setIsCheckedIn] = useState<boolean>(false);

  const getCurrentTime = (): string => {
    return new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: true });
  };

  const handleCheckIn = (): void => {
    const currentTime = getCurrentTime();
    setLastCheckIn(currentTime);
    setIsCheckedIn(true);
    setAttendanceLog((prevLog) => [...prevLog, { type: "Check-In", time: currentTime }]);
  };

  const handleCheckOut = (): void => {
    const currentTime = getCurrentTime();
    setLastCheckOut(currentTime);
    setIsCheckedIn(false);
    setAttendanceLog((prevLog) => [...prevLog, { type: "Check-Out", time: currentTime }]);
  };
Enter fullscreen mode Exit fullscreen mode

Obtenha o código completo neste repositório.

Componente de Painel

Com opções de navegação, este exibe informações específicas do usuário, como o horário atual, data e ID do funcionário.

Para o painel, insira este código em src/pages/Dashboard.tsx

import { Button } from "../Components/ui/button";
import { Layout } from "../Components/Layout";
import { Card, CardContent, CardHeader, CardTitle } from "../Components/ui/card";
import { Clock, Calendar, User } from "lucide-react";
import { useNavigate } from "react-router-dom";

export default function Dashboard() {
  const navigate = useNavigate();

  return (
    <Layout title="">
      <div className="min-h-screen bg-gray-100 py-8 px-4 lg:px-2">
        <h1 className="text-3xl font-bold mb-8">Bem-vindo, John Doe</h1>
        <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
          <Card>
            <CardHeader>
              <CardTitle className="flex items-center">
                <Calendar className="mr-2" /> Data
              </CardTitle>
            </CardHeader>
            <CardContent>
              <p className="text-2xl font-semibold">
                {new Date().toLocaleDateString()}
              </p>
            </CardContent>
          </Card>
          <Card>
            <CardHeader>
              <CardTitle className="flex items-center">
                <Clock className="mr-2" /> Horário
              </CardTitle>
            </CardHeader>
            <CardContent>
              <p className="text-2xl font-semibold">
                {new Date().toLocaleTimeString([], {
                  hour: "2-digit",
                  minute: "2-digit",
                  hour12: true,
                })}
              </p>
            </CardContent>
          </Card>
          <Card>
            <CardHeader>
              <CardTitle className="flex items-center">
                <User className="mr-2" /> ID do Funcionário
              </CardTitle>
            </CardHeader>
            <CardContent>
              <p className="text-2xl font-semibold">EMP1001</p>
            </CardContent>
          </Card>
        </div>
        <div className="mt-8 flex justify-center">
          <Button size="lg" className="mr-4" onClick={() => navigate("/checkinout")}>
            Check-In/Check-Out
          </Button>
          {/* <Button size="lg" variant="outline" onClick={() => navigate("/attendanceLog")}>
            Ver Registro de Presença
          </Button> */}
        </div>
      </div>
    </Layout>
  );
}
Enter fullscreen mode Exit fullscreen mode

Funções de Matrícula e Login

Aqui, lidamos com as funções de matrícula e login.

// A função de matrícula
const handleEnroll = async (user: Iuser) => {
    if (!faceio) {
      setError("Instância do FaceIO não foi inicializada.");
      return;
    }
    try {
      const response = await faceio.enroll({
        locale: "auto",
        payload: {
          name: user.name,
          email: user.email,
        },
      });
      alert(
        `ID Facial Único: ${response.facialId}\n` +
          `Data de Matrícula: ${response.timestamp}\n` +
          `Gênero: ${response.details.gender}\n` +
          `Aproximação de Idade: ${response.details.age}`
      );
      navigate("/dashboard");
    } catch (err: any) {
      handleError(err.message || "Erro desconhecido");
    }
  };

// A função de autenticação
const handleAuthenticate = async () => {
    if (!faceio) {
      setError("Instância do FaceIO não foi inicializada.");
      return;
    }
    try {
      const response = await faceio.authenticate({
        locale: "auto",
      });
      console.log(
        `ID Facial Único: ${response.facialId}\nPayload: ${JSON.stringify(
          response.payload
        )}`
      );
      navigate("/dashboard");
    } catch (err: any) {
      handleError(err.message || "Erro desconhecido");
    }
  };
Enter fullscreen mode Exit fullscreen mode

Para aumentar a robustez da nossa integração com o FACEIO, podemos implementar uma função centralizada de tratamento de erros. Abaixo está um exemplo de tal função, nomeada handleError, que mapeia códigos de erro específicos para mensagens amigáveis ao usuário.

const handleError = (errCode: string) => {
    const errorMessages: Record<string, string> = {
      PERMISSION_REFUSED: "Acesso à stream da câmera foi negado pelo usuário final.",
      NO_FACES_DETECTED: "Nenhuma face foi detectada durante o processo de matrícula ou autenticação.",
      UNRECOGNIZED_FACE: "Face não reconhecida no Índice Facial desta aplicação.",
      MANY_FACES: "Duas ou mais faces foram detectadas durante o processo de digitalização.",
      FACE_DUPLICATION: "Usuário já matriculado anteriormente. Não pode se matricular novamente.",
      MINORS_NOT_ALLOWED: "Menores de idade não são permitidos se matricular nesta aplicação.",
      PAD_ATTACK: "Ataque de apresentação (spoof) detectado durante o processo de digitalização.",
      FACE_MISMATCH: "Vetores faciais não correspondem.",
      WRONG_PIN_CODE: "Código PIN incorreto fornecido durante a autenticação.",
      PROCESSING_ERR: "Erro no lado do servidor.",
      UNAUTHORIZED: "Sua aplicação não está autorizada. Verifique sua ID pública.",
      TERMS_NOT_ACCEPTED: "Termos e Condições não foram aceitos.",
      UI_NOT_READY: "O widget do FaceIO não pôde ser injetado no DOM.",
      SESSION_EXPIRED: "Sessão do cliente expirou. Reinicie o processo.",
      TIMEOUT: "Operação expirou.",
      TOO_MANY_REQUESTS: "Muitas requisições. Atualize sua aplicação para mais capacidade.",
      EMPTY_ORIGIN: "O cabeçalho HTTP de origem ou referer está vazio ou ausente.",
      FORBIDDDEN_ORIGIN: "A origem do domínio é proibida de usar o FaceIO.",
      FORBIDDDEN_COUNTRY: "O país é proibido de usar o FaceIO.",
      SESSION_IN_PROGRESS: "Outra sessão já está em andamento.",
      NETWORK_IO: "Erro de conexão de rede com o FaceIO.",
    };

    const message = errorMessages[errCode] || "Um erro desconhecido ocorreu.";
    setError(message);
    console.error("Erro do FaceIO:", message);
};
Enter fullscreen mode Exit fullscreen mode

Em seguida, para integrar o FACEIO na interface do usuário, projetamos um formulário simples de Check-In com campos para Nome e Email e botões para Registrar e Login. Aqui está o código JSX para o formulário:

<div className="max-w-md overflow-hidden md:mx-auto mx-4 bg-white shadow-md rounded-lg">  
<div className="p-6">
    <h1 className="text-2xl text-center font-bold">Check-In</h1>

    <form className="space-y-6 mt-6" onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label
          htmlFor="name"
          className="text-sm font-bold text-gray-600 block"
        >
          Nome
        </label>
        <input
          type="text"
          placeholder="Nome"
          {...register("name")}
          className="w-full p-2 border border-blue-900 rounded mt-1"
        />
        {errors.name && (
          <p className="text-red-900">{errors.name.message}</p>
        )}
      </div>
      <div>
        <label
          htmlFor="email"
          className="text-sm font-bold text-gray-600 block"
        >
          Email
        </label>
        <input
          type="email"
          placeholder="email@mail.com"
          {...register("email")}
          className="w-full p-2 border border-blue-900 rounded mt-1"
        />
        {errors.email && (
          <p className="text-red-900">{errors.email.message}</p>
        )}
      </div>
      <div>
        <Button type="submit" variant="secondary" className="w-full">
          Registrar
        </Button>
      </div>
    </form>

    <div className="flex flex-wrap justify-center gap-4 py-10">
      <Button
        onClick={handleAuthenticate}
        variant="default"
        className="w-1/2"
      >
        Login
      </Button>
    </div>
  </div>
</div>
{error && <div className="text-red-600">{error}</div>}
Enter fullscreen mode Exit fullscreen mode

Conectando Tudo

Para conectar todas as funcionalidades, insira este código no arquivo App.tsx no diretório src.

import Auth from './pages/Auth';
import CheckInOut from './pages/CheckInOut';
import Dashboard from './pages/Dashboard';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Auth />} />
        <Route path="/dashboard" element={<Dashboard/>}/>
        <Route path="/checkinout" element={<CheckInOut/>}/>
      </Routes>
    </Router>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Here is the translation of the provided text to Brazilian Portuguese:

Configurando o FACEIO

Registre-se para uma conta no FACEIO e faça login no console. Para integrar o FACEIO à aplicação que você está construindo, você deve criar uma aplicação e, em seguida, obter detalhes como o ID da aplicação e a chave API, que estarão no seu arquivo env e se conectar ao FACEIO quando a aplicação estiver em execução.

Siga estes passos para começar.

No console do FACEIO, clique em Dashboard no menu lateral esquerdo e, em seguida, clique no botão NOVA APLICAÇÃO FACEIO.

Criar nova aplicação FACEIO

Isso abrirá o Assistente de Aplicação FACEIO, onde você inserirá os detalhes da nova aplicação, como:

  • Alias da Aplicação: Este é o nome da aplicação (algo que você possa lembrar facilmente) e é um passo obrigatório para prosseguir.
  • URL da Política de Privacidade da Aplicação: Este é recomendado se você tiver um disponível.
  • URL dos Termos de Serviço da Aplicação: Este é opcional.

Depois de inserir o nome, clique no botão PRÓXIMO como mostrado abaixo.

Nomear a aplicação

O próximo passo é selecionar um Motor de Reconhecimento Facial para a aplicação que você deseja integrar com o FACEIO.

O motor de reconhecimento facial é o componente crítico responsável por mapear cada usuário matriculado em tempo real em um vetor de recursos matemáticos, melhor conhecido como um hash biométrico, que é armazenado em um índice binário isolado.

Para este caso de uso, vamos usar o PixLab, então selecione-o clicando no modal.

Motor

Em seguida, role para baixo e selecione uma região de armazenamento em nuvem para o índice facial e metadados da aplicação e clique no botão PRÓXIMO para prosseguir.

Selecionar região

Avançando, o próximo passo é revisar as configurações de segurança padrão recomendadas para a maioria das aplicações. Você pode referir-se ao Guia de Melhores Práticas de Segurança do FACEIO para uma visão geral das práticas e recomendações de segurança.

Depois de revisar as configurações de segurança, clique no botão PRÓXIMO para prosseguir.

Revisar configurações

Além disso, via console do FACEIO, no gerenciador de aplicações, você pode ativar a opção para evitar que o mesmo usuário se matricule mais de uma vez quando estiver usando sua aplicação.

O próximo passo após isso (não se preocupe, quase lá) é personalizar o widget do FACEIO. Você pode selecionar um tema para combinar com o padrão de design do seu site e também adicionar um link para o logotipo da imagem do seu site ou aplicação -- ****isso será exibido no canto superior esquerdo do widget quando sua aplicação estiver em execução e um usuário quiser iniciar o processo de autenticação facial.

aplicação

Em seguida, revise as informações que você inseriu antes de submeter e criar uma nova aplicação FACEIO e selecione um plano adequado para esta aplicação com base no seu orçamento.

Selecionar plano

Próximo, concorde com os termos de serviço e clique no botão CRIAR APLICAÇÃO FACEIO.

Criar nova aplicação

Em seguida, você verá a modal de sucesso para a nova aplicação FACEIO criada.

Nova aplicação FACEIO criada

Então, um painel para esta nova aplicação carrega com informações como o ID Público da aplicação, Chave API, guias de integração e outras informações necessárias.

construir aplicação

Uma vez que sua aplicação for criada, simplesmente implemente fio.js no seu site ou aplicação web para implementar a autenticação facial para seus usuários.

Copie o ID Público da aplicação e insira-o no arquivo env no diretório raiz do projeto.

Public_Id = "seu-ID-da-aplicação"
Enter fullscreen mode Exit fullscreen mode

Executando a Aplicação

Para executar a aplicação web, digite npm run dev no terminal, então abra esta URL no seu navegador: http://localhost:5173/

Em seguida, o Sistema de Presença carrega como mostrado abaixo:

presença

Insira seu nome e email, então clique em Registrar, o que iniciará o processo de autenticação facial com o FACEIO antes de acessar outros sistemas de presença e registrar sua presença.

aplicação web

Você também será solicitado a definir um PIN para a aplicação.

configuração

Após a autenticação bem-sucedida com o FACEIO, ele registra e exibe o ID facial único, data de matrícula, gênero e idade aproximada dos usuários da aplicação.

login

Isso adiciona uma camada adicional de segurança à aplicação e impede que um usuário registre múltiplos registros de presença.

Em seguida, você pode visualizar o painel e clicar no botão Check In/Out para registrar sua presença.

O sistema de presença registra a data, horário e ID do funcionário para o check-in.

log

Agora clique no botão Check In para check-in.

construir aplicação

Depois disso, você pode visualizar o registro de presença como mostrado abaixo.

web

Você também pode check-out clicando no botão Check Out.

aplicação web app

E pronto, construímos um Sistema de Presença com Autenticação Facial para melhor segurança.

Com esta aplicação, você pode aprimorá-la ainda mais para rastrear a presença dos funcionários na organização, como no caso de uso para a aplicação.

Faça um clone do repositório

git clone https://github.com/Tabintel/Attendance_system.git
Enter fullscreen mode Exit fullscreen mode

Instale as dependências

npm install
Enter fullscreen mode Exit fullscreen mode

Em seguida, execute a aplicação e abra a URL no seu navegador.
http://localhost:5173/

npm run dev
Enter fullscreen mode Exit fullscreen mode

Você também pode testar a aplicação usando o link ao vivo aqui.

Conclusão

Neste artigo, construímos um simples sistema de presença para autenticação facial usando React e FACEIO. Ao aproveitar as funcionalidades de segurança avançadas do FACEIO, criamos uma solução segura e à prova de fraude que pode ser estendida para uso em ambientes de trabalho, escolas ou qualquer ambiente onde o rastreamento de presença seja necessário.

Além disso, visite o Fórum do FACEIO para suporte da comunidade e discussões.

Boa codificação

Top comments (0)