1583 lines
67 KiB
Python
1583 lines
67 KiB
Python
|
|
import os
|
|
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
|
|
import tkinter as tk
|
|
from tkinter import filedialog
|
|
import customtkinter
|
|
import cv2
|
|
from cv2 import dnn
|
|
from pydub import AudioSegment
|
|
from PIL import Image, ImageTk
|
|
import threading
|
|
from glob import glob
|
|
import sounddevice as sd
|
|
import wavio
|
|
import re
|
|
import pygame
|
|
from tkinter import ttk, Canvas
|
|
import whisper
|
|
import webbrowser
|
|
import pyaudio
|
|
import wave
|
|
from moviepy.editor import *
|
|
import librosa
|
|
from librosa import load
|
|
import librosa.display
|
|
from pycallgraph2 import PyCallGraph
|
|
from pycallgraph2.output import GraphvizOutput
|
|
from librosa.feature import mfcc
|
|
from transformers import pipeline
|
|
import IPython.display as ipd
|
|
from collections import defaultdict
|
|
from tkcalendar import DateEntry
|
|
import speech_recognition as sr
|
|
import numpy as np
|
|
import sys
|
|
import shutil
|
|
import geocoder
|
|
import logging
|
|
import time
|
|
from tensorflow.keras.models import load_model
|
|
from tensorflow.image import resize
|
|
from math import ceil
|
|
import subprocess
|
|
import matplotlib.pyplot as plt
|
|
from pyannote.audio import Pipeline
|
|
import matplotlib
|
|
matplotlib.use("Agg")
|
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
|
from reportlab.lib.pagesizes import letter, A4, landscape
|
|
from moviepy.video.fx.all import speedx
|
|
from reportlab.pdfgen import canvas
|
|
from reportlab.lib.colors import red, black, Color
|
|
from PyPDF2 import PdfMerger
|
|
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle,Spacer, PageBreak, Image as ReportImage
|
|
from reportlab.platypus.flowables import PageBreak
|
|
from reportlab.lib import colors
|
|
import pandas as pd
|
|
import tabula
|
|
import PyPDF2
|
|
import torch
|
|
import string
|
|
from pdf2docx import Converter
|
|
import urllib.parse
|
|
from fpdf import FPDF
|
|
import pdfplumber
|
|
from datetime import datetime
|
|
import fitz
|
|
import warnings
|
|
from reportlab.lib.units import inch
|
|
from docx import Document
|
|
from moviepy.config import change_settings
|
|
import joblib
|
|
import spacy
|
|
|
|
change_settings({"IMAGEMAGICK_BINARY": "Dependencias\\ImageMagick-7.1.1-Q16-HDRI\\magick.exe"})
|
|
image_mean = np.array([127, 127, 127])
|
|
image_std = 128.0
|
|
iou_threshold = 0.3
|
|
center_variance = 0.1
|
|
size_variance = 0.2
|
|
min_boxes = [[10.0, 16.0, 24.0], [32.0, 48.0], [64.0, 96.0], [128.0, 192.0, 256.0]]
|
|
strides = [8.0, 16.0, 32.0, 64.0]
|
|
threshold = 0.5
|
|
customtkinter.set_appearance_mode("Dark")
|
|
pdf_path =""
|
|
g = geocoder.ip('me')
|
|
Local="PJM Lisboa"
|
|
City=g.city
|
|
agora = datetime.now()
|
|
Datainterrogatorio = agora
|
|
Datainterrogatorio = agora.strftime("%d/%m/%Y")
|
|
Hour=agora.strftime("%H")
|
|
Minutes=agora.strftime("%M")
|
|
hora = agora.strftime("%H:%M")
|
|
resultados={}
|
|
Nome, nim, posto, DTnasc, cc, ccval, nif, pai, mae, morada, imagem,Interrogador, vetoremocoes,vetoremocoesFER,a, codigo_postal, freguesia, concelho, Nacionalidade, data_atual =[None]*20
|
|
|
|
def preprocess_frase_pt(frase):
|
|
nlp = spacy.load("pt_core_news_sm")
|
|
portuguesstopwords = set(nlp.Defaults.stop_words)
|
|
if not isinstance(frase, str):
|
|
raise ValueError("A entrada deve ser uma string.")
|
|
frase = frase.lower()
|
|
frase = frase.translate(str.maketrans('', '', string.punctuation))
|
|
frase = ''.join([char for char in frase if not char.isdigit()])
|
|
frase = ' '.join(frase.split())
|
|
frase = ' '.join([word for word in frase.split() if word not in portuguesstopwords])
|
|
frase_lemmatizada = ' '.join([token.lemma_ for token in nlp(frase)])
|
|
return frase_lemmatizada
|
|
|
|
def preencheraintestemunha(caminho_docx, dados, caminho_saida):
|
|
doc = Document(caminho_docx)
|
|
for paragrafo in doc.paragraphs:
|
|
for marcador, valor in dados.items():
|
|
if marcador in paragrafo.text:
|
|
for run in paragrafo.runs:
|
|
if marcador in run.text:
|
|
run.text = run.text.replace(marcador, valor)
|
|
for tabela in doc.tables:
|
|
for linha in tabela.rows:
|
|
for celula in linha.cells:
|
|
for marcador, valor in dados.items():
|
|
if marcador in celula.text:
|
|
for paragrafo in celula.paragraphs:
|
|
for run in paragrafo.runs:
|
|
if marcador in run.text:
|
|
run.text = run.text.replace(marcador, valor)
|
|
for section in doc.sections:
|
|
header = section.header
|
|
footer = section.footer
|
|
for paragrafo in header.paragraphs:
|
|
for marcador, valor in dados.items():
|
|
if marcador in paragrafo.text:
|
|
for run in paragrafo.runs:
|
|
if marcador in run.text:
|
|
run.text = run.text.replace(marcador, valor)
|
|
for paragrafo in footer.paragraphs:
|
|
for marcador, valor in dados.items():
|
|
if marcador in paragrafo.text:
|
|
for run in paragrafo.runs:
|
|
if marcador in run.text:
|
|
run.text = run.text.replace(marcador, valor)
|
|
doc.save(caminho_saida)
|
|
print(f"Documento preenchido salvo em: {caminho_saida}")
|
|
|
|
def juntapdfs2():
|
|
pdf1="transcricao_audio.pdf"
|
|
pdf2="Anexo_A.pdf"
|
|
pdf3 = "ANEXO_B_C.pdf"
|
|
outputpdf="TranscriptWithAER&FER.pdf"
|
|
try:
|
|
merger = PdfMerger()
|
|
merger.append(pdf1)
|
|
merger.append(pdf2)
|
|
merger.append(pdf3)
|
|
with open(outputpdf, 'wb') as output_file:
|
|
merger.write(output_file)
|
|
merger.close()
|
|
print(f"PDFs combinados com sucesso em {outputpdf}")
|
|
except Exception as e:
|
|
print(f"Erro ao juntar os PDFs: {e}")
|
|
|
|
def define_img_size(image_size):
|
|
shrinkage_list = []
|
|
feature_map_w_h_list = []
|
|
for size in image_size:
|
|
feature_map = [int(ceil(size / stride)) for stride in strides]
|
|
feature_map_w_h_list.append(feature_map)
|
|
|
|
for i in range(0, len(image_size)):
|
|
shrinkage_list.append(strides)
|
|
priors = generate_priors(
|
|
feature_map_w_h_list, shrinkage_list, image_size, min_boxes
|
|
)
|
|
return priors
|
|
|
|
def generate_priors(feature_map_list, shrinkage_list, image_size, min_boxes):
|
|
priors = []
|
|
for index in range(0, len(feature_map_list[0])):
|
|
scale_w = image_size[0] / shrinkage_list[0][index]
|
|
scale_h = image_size[1] / shrinkage_list[1][index]
|
|
for j in range(0, feature_map_list[1][index]):
|
|
for i in range(0, feature_map_list[0][index]):
|
|
x_center = (i + 0.5) / scale_w
|
|
y_center = (j + 0.5) / scale_h
|
|
|
|
for min_box in min_boxes[index]:
|
|
w = min_box / image_size[0]
|
|
h = min_box / image_size[1]
|
|
priors.append([x_center,y_center,w,h])
|
|
print("priors nums:{}".format(len(priors)))
|
|
return np.clip(priors, 0.0, 1.0)
|
|
|
|
def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200):
|
|
scores = box_scores[:, -1]
|
|
boxes = box_scores[:, :-1]
|
|
picked = []
|
|
indexes = np.argsort(scores)
|
|
indexes = indexes[-candidate_size:]
|
|
while len(indexes) > 0:
|
|
current = indexes[-1]
|
|
picked.append(current)
|
|
if 0 < top_k == len(picked) or len(indexes) == 1:
|
|
break
|
|
current_box = boxes[current, :]
|
|
indexes = indexes[:-1]
|
|
rest_boxes = boxes[indexes, :]
|
|
iou = iou_of(rest_boxes,np.expand_dims(current_box, axis=0),)
|
|
indexes = indexes[iou <= iou_threshold]
|
|
return box_scores[picked, :]
|
|
|
|
def area_of(left_top, right_bottom):
|
|
hw = np.clip(right_bottom - left_top, 0.0, None)
|
|
return hw[..., 0] * hw[..., 1]
|
|
|
|
def iou_of(boxes0, boxes1, eps=1e-5):
|
|
overlap_left_top = np.maximum(boxes0[..., :2], boxes1[..., :2])
|
|
overlap_right_bottom = np.minimum(boxes0[..., 2:], boxes1[..., 2:])
|
|
|
|
overlap_area = area_of(overlap_left_top, overlap_right_bottom)
|
|
area0 = area_of(boxes0[..., :2], boxes0[..., 2:])
|
|
area1 = area_of(boxes1[..., :2], boxes1[..., 2:])
|
|
return overlap_area / (area0 + area1 - overlap_area + eps)
|
|
|
|
def predict(width,height,confidences,boxes, prob_threshold,iou_threshold=0.3,top_k=-1):
|
|
boxes = boxes[0]
|
|
confidences = confidences[0]
|
|
picked_box_probs = []
|
|
picked_labels = []
|
|
for class_index in range(1, confidences.shape[1]):
|
|
probs = confidences[:, class_index]
|
|
mask = probs > prob_threshold
|
|
probs = probs[mask]
|
|
if probs.shape[0] == 0:
|
|
continue
|
|
subset_boxes = boxes[mask, :]
|
|
box_probs = np.concatenate(
|
|
[subset_boxes, probs.reshape(-1, 1)], axis=1)
|
|
box_probs = hard_nms(box_probs,iou_threshold=iou_threshold, top_k=top_k,)
|
|
picked_box_probs.append(box_probs)
|
|
picked_labels.extend([class_index] * box_probs.shape[0])
|
|
if not picked_box_probs:
|
|
return np.array([]), np.array([]), np.array([])
|
|
picked_box_probs = np.concatenate(picked_box_probs)
|
|
picked_box_probs[:, 0] *= width
|
|
picked_box_probs[:, 1] *= height
|
|
picked_box_probs[:, 2] *= width
|
|
picked_box_probs[:, 3] *= height
|
|
return (
|
|
picked_box_probs[:, :4].astype(np.int32),
|
|
np.array(picked_labels),
|
|
picked_box_probs[:, 4]
|
|
)
|
|
|
|
def convert_locations_to_boxes(locations, priors, center_variance,
|
|
size_variance):
|
|
if len(priors.shape) + 1 == len(locations.shape):
|
|
priors = np.expand_dims(priors, 0)
|
|
return np.concatenate([
|
|
locations[..., :2] * center_variance * priors[..., 2:] + priors[..., :2],
|
|
np.exp(locations[..., 2:] * size_variance) * priors[..., 2:]
|
|
], axis=len(locations.shape) - 1)
|
|
|
|
def center_form_to_corner_form(locations):
|
|
return np.concatenate(
|
|
[locations[..., :2] - locations[..., 2:] / 2,
|
|
locations[..., :2] + locations[..., 2:] / 2],
|
|
len(locations.shape) - 1
|
|
)
|
|
|
|
def FER_live_cam():
|
|
emotion_dict = {0: 'neutral', 1: 'happiness', 2: 'surprise', 3: 'sadness',4: 'anger', 5: 'disgust', 6: 'fear'}
|
|
|
|
def modelemotionface(parent_frame,parent_frame2):
|
|
cap = cv2.VideoCapture(1)
|
|
frame_width = int(cap.get(3))
|
|
frame_height = int(cap.get(4))
|
|
size = (frame_width, frame_height)
|
|
result = cv2.VideoWriter('FERVideo.mp4', cv2.VideoWriter_fourcc(*'MJPG'), 10, size)
|
|
emotion_dict = {0: 'neutral', 1: 'happiness', 2: 'surprise', 3: 'sadness', 4: 'anger', 5: 'disgust', 6: 'fear'}
|
|
emotion_colors = {'neutral': (255, 255, 255), 'happiness': (0, 255, 0), 'surprise': (255, 255, 0), 'sadness': (0, 0, 255),
|
|
'anger': (0, 0, 128), 'disgust': (128, 0, 128), 'fear': (255, 0, 0)}
|
|
|
|
model = cv2.dnn.readNetFromONNX('Scripts/Modelos/emotion-ferplus-8.onnx')
|
|
proto_path = 'Scripts/Modelos/RFB-320.prototxt'
|
|
model_path = 'Scripts/Modelos/RFB-320.caffemodel'
|
|
net = cv2.dnn.readNetFromCaffe(proto_path, model_path)
|
|
|
|
emotion_counter = {emotion: 0 for emotion in emotion_dict.values()}
|
|
current_emotion = None
|
|
|
|
audio = pyaudio.PyAudio()
|
|
stream = audio.open(input=True, format=pyaudio.paInt16, channels=2, rate=16000, frames_per_buffer=1024)
|
|
frames_audio = []
|
|
|
|
input_size = [320, 240]
|
|
width, height = input_size
|
|
priors = define_img_size(input_size)
|
|
|
|
while cap.isOpened():
|
|
ret, frame = cap.read()
|
|
if ret:
|
|
img_ori = frame
|
|
rect = cv2.resize(img_ori, (width, height))
|
|
rect = cv2.cvtColor(rect, cv2.COLOR_BGR2RGB)
|
|
net.setInput(cv2.dnn.blobFromImage(rect, 1 / 127.5, (width, height), 127))
|
|
boxes, scores = net.forward(["boxes", "scores"])
|
|
boxes = np.expand_dims(np.reshape(boxes, (-1, 4)), axis=0)
|
|
scores = np.expand_dims(np.reshape(scores, (-1, 2)), axis=0)
|
|
boxes = convert_locations_to_boxes(boxes, priors, 0.1, 0.2)
|
|
boxes = center_form_to_corner_form(boxes)
|
|
boxes, labels, probs = predict(img_ori.shape[1], img_ori.shape[0], scores, boxes, 0.5)
|
|
|
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
|
for (x1, y1, x2, y2) in boxes:
|
|
w, h = x2 - x1, y2 - y1
|
|
cv2.rectangle(frame, (x1, y1), (x2, y2), (255, 0, 0), 2)
|
|
face = cv2.resize(gray[y1:y1 + h, x1:x1 + w], (64, 64)).reshape(1, 1, 64, 64)
|
|
model.setInput(face)
|
|
output = model.forward()
|
|
pred_index = np.argmax(output[0])
|
|
pred_emotion = emotion_dict[pred_index]
|
|
color = emotion_colors[pred_emotion]
|
|
|
|
if pred_emotion != current_emotion:
|
|
current_emotion = pred_emotion
|
|
emotion_counter[pred_emotion] += 1
|
|
|
|
cv2.rectangle(img_ori, (x1, y1), (x2, y2), color, 2, lineType=cv2.LINE_AA)
|
|
cv2.putText(frame, pred_emotion, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2, lineType=cv2.LINE_AA)
|
|
|
|
result.write(frame)
|
|
cv2.imshow('Camera', frame)
|
|
audio_data = stream.read(1024)
|
|
frames_audio.append(audio_data)
|
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
break
|
|
else:
|
|
break
|
|
|
|
cap.release()
|
|
result.release()
|
|
stream.stop_stream()
|
|
stream.close()
|
|
audio.terminate()
|
|
|
|
audiopath = "audio.mp3"
|
|
with wave.open(audiopath, 'wb') as wf:
|
|
wf.setnchannels(2)
|
|
wf.setsampwidth(audio.get_sample_size(pyaudio.paInt16))
|
|
wf.setframerate(16000)
|
|
wf.writeframes(b''.join(frames_audio))
|
|
|
|
atualizar_grafico_emocoes(emotion_counter, parent_frame)
|
|
|
|
print("Emotions detected during the video:")
|
|
for emotion, count in emotion_counter.items():
|
|
print(f"{emotion}: {count}")
|
|
video_path='FERVideo.mp4'
|
|
anexoA(audiopath)
|
|
dividirvideoclips(video_path)
|
|
clipes = dividiraudioclips(audiopath)
|
|
classificar_clipes(clipes,parent_frame2)
|
|
classificar_videoclipes()
|
|
sincronizarvideoaudio()
|
|
criarvetoremocoesFER()
|
|
juntapdfs2()
|
|
copiarficheiro()
|
|
|
|
def modelemotionface_video(video_path,parent_frame):
|
|
|
|
cap = cv2.VideoCapture(video_path)
|
|
frame_width = int(cap.get(3))
|
|
frame_height = int(cap.get(4))
|
|
size = (frame_width, frame_height)
|
|
|
|
result = cv2.VideoWriter('Video.avi', cv2.VideoWriter_fourcc(*'MJPG'), 10, size)
|
|
|
|
emotion_dict = {0: 'neutral', 1: 'happiness', 2: 'surprise', 3: 'sadness', 4: 'anger', 5: 'disgust', 6: 'fear'}
|
|
emotion_colors = {'neutral': (255, 255, 255), 'happiness': (0, 255, 0), 'surprise': (255, 255, 0),'sadness': (0, 0, 255), 'anger': (0, 0, 128), 'disgust': (128, 0, 128), 'fear': (255, 0, 0)}
|
|
|
|
proto_path = 'Scripts/Modelos/RFB-320.prototxt'
|
|
model_path = 'Scripts/Modelos/RFB-320.caffemodel'
|
|
emotion_model = cv2.dnn.readNetFromONNX('Scripts/Modelos/emotion-ferplus-8.onnx')
|
|
net = cv2.dnn.readNetFromCaffe(proto_path, model_path)
|
|
|
|
input_size = [320, 240]
|
|
width, height = input_size
|
|
priors = define_img_size(input_size)
|
|
|
|
emotion_counter = {emotion: 0 for emotion in emotion_dict.values()}
|
|
current_emotion = None
|
|
|
|
while cap.isOpened():
|
|
ret, frame = cap.read()
|
|
if not ret:
|
|
break
|
|
|
|
rect = cv2.resize(frame, (width, height))
|
|
rect_rgb = cv2.cvtColor(rect, cv2.COLOR_BGR2RGB)
|
|
net.setInput(cv2.dnn.blobFromImage(rect_rgb, 1 / 127.5, (width, height), 127))
|
|
|
|
boxes, scores = net.forward(["boxes", "scores"])
|
|
boxes = np.expand_dims(np.reshape(boxes, (-1, 4)), axis=0)
|
|
scores = np.expand_dims(np.reshape(scores, (-1, 2)), axis=0)
|
|
boxes = convert_locations_to_boxes(boxes, priors, 0.1, 0.2)
|
|
boxes = center_form_to_corner_form(boxes)
|
|
boxes, labels, probs = predict(frame.shape[1], frame.shape[0], scores, boxes, 0.5)
|
|
|
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
|
|
|
for (x1, y1, x2, y2) in boxes:
|
|
w, h = x2 - x1, y2 - y1
|
|
cv2.rectangle(frame, (x1, y1), (x2, y2), (255, 0, 0), 2)
|
|
|
|
face_region = cv2.resize(gray[y1:y1 + h, x1:x1 + w], (64, 64)).reshape(1, 1, 64, 64)
|
|
emotion_model.setInput(face_region)
|
|
output = emotion_model.forward()
|
|
pred_index = np.argmax(output[0])
|
|
pred_emotion = emotion_dict[pred_index]
|
|
color = emotion_colors[pred_emotion]
|
|
|
|
if pred_emotion != current_emotion:
|
|
current_emotion = pred_emotion
|
|
emotion_counter[pred_emotion] += 1
|
|
|
|
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2, lineType=cv2.LINE_AA)
|
|
cv2.putText(frame, pred_emotion, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2, lineType=cv2.LINE_AA)
|
|
|
|
result.write(frame)
|
|
cv2.imshow('Video FER', frame)
|
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
break
|
|
|
|
cap.release()
|
|
result.release()
|
|
atualizar_grafico_emocoes(emotion_counter, parent_frame)
|
|
video_clip = VideoFileClip('Video.avi')
|
|
video_clip.write_videofile("FERVideo.mp4", codec="libx264", audio_codec="aac")
|
|
|
|
print("Contagem de emoções detectadas durante o vídeo:")
|
|
for emotion, count in emotion_counter.items():
|
|
print(f"{emotion}: {count}")
|
|
|
|
if __name__ == "__main__":
|
|
FER_live_cam()
|
|
|
|
def wrap_text(text, max_length=400):
|
|
words = text.split()
|
|
lines = []
|
|
current_line = []
|
|
for word in words:
|
|
if len(" ".join(current_line + [word])) <= max_length:
|
|
current_line.append(word)
|
|
else:
|
|
lines.append(" ".join(current_line))
|
|
current_line = [word]
|
|
if current_line:
|
|
lines.append(" ".join(current_line))
|
|
return "\n".join(lines)
|
|
|
|
def mostrar_dados(parent_frame):
|
|
dados = Nome, nim, posto, DTnasc, cc, ccval, nif, pai, mae, morada, imagem, codigo_postal, freguesia, concelho, Morada, Nacionalidade
|
|
dados_para_preencher = {
|
|
"NUIPC1": "1234",
|
|
"Equipa1": "Equipe A",
|
|
"NomeIC": "João Silva",
|
|
"DTD": str(Datainterrogatorio),
|
|
"Hora1": str(hora),
|
|
"LOCAL1": str(Local),
|
|
"Name1": f"{Nome.title()}",
|
|
"Posto1": str(posto),
|
|
"NIM1": str(nim),
|
|
"Filiacao1": f"{pai.title()} e de {mae.title()}",
|
|
"Morada1": str(morada),
|
|
"CP1": str(codigo_postal),
|
|
"Freguesia1": str(freguesia),
|
|
"Conc1": f"{concelho.title()}",
|
|
"DN": str(DTnasc),
|
|
"NCC": str(cc),
|
|
"CCVal": str(ccval),
|
|
"NIF1": str(nif),
|
|
"Nacionalidade1":str(Nacionalidade)
|
|
}
|
|
caminho_saida = "Dataset/6_ainqtestemunha_Final.docx"
|
|
preencheraintestemunha("Dataset/6_ainqtestemunha.docx", dados_para_preencher,caminho_saida)
|
|
caminho_saida2 = "Dataset/3_aintarg_Final.docx"
|
|
preencheraintestemunha("Dataset/3_aintarg.docx", dados_para_preencher, caminho_saida2)
|
|
caminho_saida3 = "Dataset/2_auto_de_denuncia_Final.docx"
|
|
preencheraintestemunha("Dataset/2_auto_de_denuncia.docx", dados_para_preencher, caminho_saida3)
|
|
|
|
|
|
for widget in parent_frame.winfo_children():
|
|
widget.destroy()
|
|
canvas = Canvas(parent_frame, width=600, height=400, bg="#2B2B2B", highlightthickness=0)
|
|
canvas.grid(row=0, column=0, sticky="nsew")
|
|
Postonimnome=posto+" "+nim+ " " +Nome
|
|
cceval=cc+" válido até "+ccval
|
|
|
|
labels = [("Nome", Postonimnome),("Data de Nascimento", DTnasc),("Cartão de Cidadão", cceval),("NIF", nif),("Pai", pai),("Mãe", mae),("Morada", Morada)]
|
|
y_position=10
|
|
for label_text, value in labels:
|
|
label = f"{label_text}: {value}"
|
|
wrapped_label = wrap_text(label, max_length=80)
|
|
canvas.create_text(10, y_position, anchor="nw", text=wrapped_label, font=("Arial", 10), fill="white")
|
|
y_position += 40
|
|
try:
|
|
if imagem:
|
|
img = Image.open(imagem)
|
|
img = img.resize((150, 150))
|
|
img_tk = ImageTk.PhotoImage(img)
|
|
canvas.create_image(550, 10, anchor="ne", image=img_tk)
|
|
canvas.image = img_tk
|
|
except Exception as e:
|
|
print(f"Erro ao carregar a imagem: {e}")
|
|
|
|
def graficos(emotion_counter, parent_frame):
|
|
emotions=list(emotion_counter.keys())
|
|
counts=list(emotion_counter.values())
|
|
|
|
fig, ax = plt.subplots(figsize=(5, 3))
|
|
fig.patch.set_facecolor('#2B2B2B')
|
|
ax.set_facecolor('#2B2B2B')
|
|
bars= ax.bar(emotions, counts, color=['White', 'green', 'yellow', 'blue', 'darkred', 'purple', 'red'])
|
|
for bar in bars:
|
|
yval = bar.get_height()
|
|
ax.text(bar.get_x() + bar.get_width() / 2, yval, int(yval), ha='center', va='bottom', color='white')
|
|
ax.set_xlabel('Emoções', color='white')
|
|
ax.set_ylabel('Contagem', color='white')
|
|
ax.set_title('FER', color='white')
|
|
ax.tick_params(colors='white')
|
|
ax.spines['top'].set_visible(False)
|
|
ax.spines['right'].set_visible(False)
|
|
ax.spines['left'].set_color('white')
|
|
ax.spines['bottom'].set_color('white')
|
|
plt.xticks(rotation=45, color='white')
|
|
plt.xticks(color='white')
|
|
plt.tight_layout()
|
|
parent_frame.grid_rowconfigure(0, weight=1)
|
|
parent_frame.grid_columnconfigure(0, weight=1)
|
|
canvas = FigureCanvasTkAgg(fig, master=parent_frame)
|
|
canvas.draw()
|
|
canvas.get_tk_widget().grid(row=0, column=0, padx=10, pady=10)
|
|
|
|
def graficosAER(emotion_counter, parent_frame):
|
|
emotions=list(emotion_counter.keys())
|
|
counts=list(emotion_counter.values())
|
|
|
|
fig, ax = plt.subplots(figsize=(5, 3))
|
|
fig.patch.set_facecolor('#2B2B2B')
|
|
ax.set_facecolor('#2B2B2B')
|
|
bars= ax.bar(emotions, counts, color=['White', 'green', 'yellow', 'blue', 'darkred', 'purple', 'red'])
|
|
for bar in bars:
|
|
yval = bar.get_height()
|
|
ax.text(bar.get_x() + bar.get_width() / 2, yval, int(yval), ha='center', va='bottom', color='white')
|
|
ax.set_xlabel('Emoções', color='white')
|
|
ax.set_ylabel('Contagem', color='white')
|
|
ax.set_title('AER', color='white')
|
|
ax.tick_params(colors='white')
|
|
ax.spines['top'].set_visible(False)
|
|
ax.spines['right'].set_visible(False)
|
|
ax.spines['left'].set_color('white')
|
|
ax.spines['bottom'].set_color('white')
|
|
plt.xticks(rotation=45, color='white')
|
|
plt.xticks(color='white')
|
|
plt.tight_layout()
|
|
parent_frame.grid_rowconfigure(0, weight=1)
|
|
parent_frame.grid_columnconfigure(0, weight=1)
|
|
canvas = FigureCanvasTkAgg(fig, master=parent_frame)
|
|
canvas.draw()
|
|
canvas.get_tk_widget().grid(row=0, column=0, padx=10, pady=10)
|
|
|
|
def atualizar_grafico_emocoes(emotion_counter, parent_frame):
|
|
for widget in parent_frame.winfo_children():
|
|
widget.destroy()
|
|
graficos(emotion_counter, parent_frame)
|
|
|
|
def atualizar_graficosAER(emotion_counter, parent_frame):
|
|
for widget in parent_frame.winfo_children():
|
|
widget.destroy()
|
|
graficosAER(emotion_counter, parent_frame)
|
|
|
|
def extrairinfo(pdf_path, keyword):
|
|
with pdfplumber.open(pdf_path) as pdf:
|
|
for page in pdf.pages:
|
|
text = page.extract_text()
|
|
for line in text.split('\n'):
|
|
if keyword in line:
|
|
extracted_text = line.split(keyword, 1)[1].strip()
|
|
if "AUTENTICAÇÃO" in extracted_text:
|
|
extracted_text = extracted_text.split("AUTENTICAÇÃO", 1)[0].strip()
|
|
return extracted_text
|
|
return None
|
|
|
|
def extrairinfomaisdificil(pdf_path, keyword):
|
|
resultados = []
|
|
with pdfplumber.open(pdf_path) as pdf:
|
|
for page in pdf.pages:
|
|
text = page.extract_text()
|
|
for line in text.split('\n'):
|
|
if keyword in line:
|
|
extracted_text = line.split(keyword, 1)[1].strip()
|
|
if "AUTENTICAÇÃO" in extracted_text:
|
|
extracted_text = extracted_text.split("AUTENTICAÇÃO", 1)[0].strip()
|
|
resultados.append(extracted_text)
|
|
|
|
return resultados
|
|
|
|
def extrairinfoabaixo(pdf_path, keyword):
|
|
resultados = []
|
|
with pdfplumber.open(pdf_path) as pdf:
|
|
for page in pdf.pages:
|
|
text = page.extract_text()
|
|
lines = text.split('\n')
|
|
for i, line in enumerate(lines):
|
|
if keyword in line:
|
|
if i + 1 < len(lines):
|
|
extracted_text = lines[i + 1].strip()
|
|
resultados.append(extracted_text)
|
|
|
|
return resultados
|
|
|
|
def extrairinfoabaixo3(pdf_path, keyword):
|
|
resultados = []
|
|
with pdfplumber.open(pdf_path) as pdf:
|
|
for page in pdf.pages:
|
|
text = page.extract_text()
|
|
lines = text.split('\n')
|
|
for i, line in enumerate(lines):
|
|
if keyword in line:
|
|
for j in range(1, 4):
|
|
if i + j < len(lines):
|
|
extracted_text = lines[i + j].strip()
|
|
resultados.append(extracted_text)
|
|
|
|
return resultados
|
|
|
|
def Login():
|
|
janela = customtkinter.CTk()
|
|
janela.title("Login")
|
|
janela.geometry("400x250")
|
|
janela.resizable(False, False)
|
|
texto = customtkinter.CTkLabel(janela, text="Login")
|
|
texto.pack(padx=10, pady=10)
|
|
user = customtkinter.CTkEntry(janela, placeholder_text="User")
|
|
user.pack (padx=10, pady=10)
|
|
password = customtkinter.CTkEntry(janela, placeholder_text="Password", show='*')
|
|
password.pack (padx=10, pady=10)
|
|
botao = customtkinter.CTkButton(janela, text="Login", command=lambda: validar_login(user, password, janela))
|
|
botao.pack(padx=10, pady=10)
|
|
janela.mainloop()
|
|
|
|
def validar_login(user, password, janela):
|
|
userverifica = user.get()
|
|
passwordverifica = password.get()
|
|
if userverifica == "kl3z" and passwordverifica == "12345":
|
|
janela.destroy()
|
|
janelaprincipal()
|
|
else:
|
|
show_messagebox("Erro", "User ou password incorretos!")
|
|
|
|
def extrairimagemdopdfFM(pdf_path, page_number=0):
|
|
pdf_path = os.path.normpath(pdf_path)
|
|
doc = fitz.open(pdf_path)
|
|
pagina = doc[page_number]
|
|
imagem_extraida = False
|
|
print("Extrair imagens do PDF")
|
|
for img_index, img in enumerate(pagina.get_images(full=True)):
|
|
try:
|
|
xref = img[0]
|
|
base_image = doc.extract_image(xref)
|
|
image_bytes = base_image["image"]
|
|
image_ext = base_image["ext"]
|
|
image_filename = f"imagem_extraida_{img_index}.{image_ext}"
|
|
with open(image_filename, "wb") as img_file:
|
|
img_file.write(image_bytes)
|
|
imagem = Image.open(image_filename)
|
|
imagem.save(f"Imagens\\imagem_corrigida_{img_index}.jpeg")
|
|
imagem_extraida = True
|
|
print(f"Imagem {img_index} extraída e corrigida: {image_filename}")
|
|
except Exception as e:
|
|
print(f"Erro ao extrair a imagem {img_index}: {e}")
|
|
continue
|
|
if not imagem_extraida:
|
|
print("Nenhuma imagem foi extraída.")
|
|
doc.close()
|
|
|
|
def extrair_imagem_do_pdf(pdf_path):
|
|
doc = fitz.open(pdf_path)
|
|
for page_num in range(len(doc)):
|
|
pagina = doc[page_num]
|
|
for img_index, img in enumerate(pagina.get_images(full=True)):
|
|
xref = img[0]
|
|
base_image = doc.extract_image(xref)
|
|
image_bytes = base_image["image"]
|
|
image_ext = base_image["ext"]
|
|
image_filename = f"Imagens\\imagem_extraida_{page_num + 1}_{img_index + 1}.{image_ext}"
|
|
with open(image_filename, "wb") as img_file:
|
|
img_file.write(image_bytes)
|
|
print(f"Imagem extraída e salva como: {image_filename}")
|
|
imagem=image_filename
|
|
doc.close()
|
|
return imagem
|
|
|
|
def carregar_ficheiro(user,parent_frame):
|
|
pdf_path = filedialog.askopenfilename(filetypes=[("PDF files", "*.pdf")])
|
|
if pdf_path:
|
|
user.configure(fg_color="green", text="File Loaded")
|
|
retirarinfodafolha(pdf_path)
|
|
mostrar_dados(parent_frame)
|
|
|
|
def retirarinfodafolha(pdf_path):
|
|
global Nome, nim, posto, DTnasc, cc, ccval, nif, pai, mae, morada, imagem, a, codigo_postal, freguesia, concelho, Morada
|
|
valor100=extrairinfo(pdf_path, "MINISTÉRIO DA DEFESA NACIONAL")
|
|
if valor100 is not None:
|
|
pai = extrairinfo(pdf_path, "Pai:") or ""
|
|
mae = extrairinfo(pdf_path, "Mãe:") or ""
|
|
posto = extrairinfo(pdf_path, "Posto:") or ""
|
|
nim = extrairinfo(pdf_path, "NIM:") or ""
|
|
Nome = extrairinfo(pdf_path, "Nome:") or ""
|
|
valor5 = extrairinfo(pdf_path, "Data de Nascimento:") or ""
|
|
DTnasc = re.search(r"\d{2}-\d{2}-\d{4}", valor5).group() if valor5 else ""
|
|
Freg = extrairinfo(pdf_path, "Freguesia:") or ""
|
|
valor7 = extrairinfo(pdf_path, "Concelho:") or ""
|
|
valor7= re.split(r"\s+Distrito", valor7)[0].strip() if valor7 else ""
|
|
valor8 = extrairinfo(pdf_path, "Distrito:") or ""
|
|
valor9 = extrairinfo(pdf_path, "País:")or ""
|
|
valor9= re.split(r"\s+Posto", valor9)[0].strip() if valor9 else ""
|
|
valor10 = extrairinfo(pdf_path, "Endereço:") or ""
|
|
valor11 = extrairinfo(pdf_path, "Código Postal:") or ""
|
|
valor12 = re.split(r"\s+Localidade:", valor11)[1].strip() if "Localidade:" in valor11 else ""
|
|
valor11 = re.split(r"\s+Localidade:", valor11)[0].strip() if "Localidade:" in valor11 else ""
|
|
valor13 = extrairinfo(pdf_path, "Cartão do Cidadão") or ""
|
|
ccval = re.search(r"\d{2}-\d{2}-\d{4}", valor13).group() if valor13 else ""
|
|
cc = valor13.replace(ccval, "").strip() if valor13 else ""
|
|
nif = extrairinfo(pdf_path, "Número de Identificação Fiscal") or ""
|
|
valor16 = extrairinfo(pdf_path, "Cartão da Segurança Social") or ""
|
|
valor17 = extrairinfo(pdf_path, "Telemóvel:") or ""
|
|
valor17 = re.split(r"\s+email:", valor17)[0].strip() if "email:" in valor17 else ""
|
|
valor18 = extrairinfo(pdf_path, "email:") or ""
|
|
valor19 = extrairinfomaisdificil(pdf_path, "Freguesia:")[1] if extrairinfomaisdificil(pdf_path, "Freguesia:") else ""
|
|
valor20 = extrairinfomaisdificil(pdf_path, "Concelho:")[1] if extrairinfomaisdificil(pdf_path, "Concelho:") else ""
|
|
valor21 = extrairinfomaisdificil(pdf_path, "Distrito:")[1] if extrairinfomaisdificil(pdf_path, "Distrito:") else ""
|
|
valor22 = extrairinfomaisdificil(pdf_path, "País:")[1] if extrairinfomaisdificil(pdf_path, "País:") else ""
|
|
valor22 = re.split(r"\s+Posto", valor22)[0].strip() if valor22 else ""
|
|
Morada = valor10 +","+ " "+ valor11 +","+ " "+ valor12+","+ " "+ valor19 +","+ " "+ valor20
|
|
extrairimagemdopdfFM(pdf_path, page_number=0)
|
|
imagem= "Imagens\\imagem_corrigida_1.jpeg"
|
|
a = pdf_path
|
|
partes = Morada.split(",")
|
|
morada = partes[0].strip().title() if len(partes) > 0 else ""
|
|
codigo_postal = f"{partes[1].strip()}, {partes[2].strip()}" if len(partes) > 2 else ""
|
|
freguesia = partes[3].strip().title() if len(partes) > 3 else ""
|
|
concelho = partes[4].strip().title() if len(partes) > 4 else ""
|
|
Nacionalidade = extrairinfo(pdf_path, "País:") or ""
|
|
Nacionalidade = re.sub(r"Posto Consular:\S*.+", "", Nacionalidade).strip()
|
|
Nacionalidade = " ".join(Nacionalidade.split()[:-2]) if Nacionalidade else ""
|
|
else:
|
|
valor1 = extrairinfoabaixo(pdf_path, "Apelido(s)") or ""
|
|
valor2 = extrairinfoabaixo(pdf_path, "Nome(s)") or ""
|
|
valor3 = valor2+valor1
|
|
valor3 = " ".join(valor3)
|
|
Nome=valor3
|
|
nim = ""
|
|
posto = ""
|
|
valor4 = extrairinfoabaixo(pdf_path, "Nascimento") or ""
|
|
valor4 = re.search(r"\d{2}-\d{2}-\d{4}", "".join(valor4)).group() if valor4 else ""
|
|
DTnasc = valor4
|
|
valor5 = extrairinfoabaixo(pdf_path, "Nº cartão") or ""
|
|
valor5 = "".join(valor5) or ""
|
|
valor6 = re.search(r"\d{2}-\d{2}-\d{4}", valor5).group() if valor5 else ""
|
|
valor7 = valor5.replace(valor6, "").strip() if valor5 else ""
|
|
valor8 = extrairinfoabaixo3(pdf_path, "Morada")[:2] if extrairinfoabaixo3(pdf_path, "Morada") else ["", ""]
|
|
Morada = " ".join(valor8).strip()
|
|
valor10 = extrairinfoabaixo3(pdf_path, "Filiação")[2] if len(extrairinfoabaixo3(pdf_path, "Filiação")) > 2 else ""
|
|
mae = valor10
|
|
valor11 = extrairinfoabaixo3(pdf_path, "Filiação")[1] if len(extrairinfoabaixo3(pdf_path, "Filiação")) > 1 else ""
|
|
valor12 = re.findall(r"\d+", valor11) if valor11 else []
|
|
valor13 = valor12[0] if len(valor12) > 0 else ""
|
|
cc = valor7
|
|
ccval = valor6
|
|
nif = valor13
|
|
valor14 = valor12[1] if len(valor12) > 1 else ""
|
|
valor15 = valor12[2] if len(valor12) > 2 else ""
|
|
valor11 = re.findall(r"[A-Za-zçÇáÁéÉíÍóÓúÚâÂêÊîÎôÔûÛãÃõÕàÀèÈìÌòÒùÙäÄëËïÏöÖüÜñÑ]+", valor11) if valor11 else []
|
|
valor11 = " ".join(valor11)
|
|
pai = valor11
|
|
extrair_imagem_do_pdf(pdf_path)
|
|
imagem = "Imagens\\imagem_extraida_1_2.jpeg"
|
|
a = pdf_path
|
|
codigo_postal = re.search(r'\b\d{4}-\d{3}\b', Morada).group() if Morada else ""
|
|
freguesia = re.search(r'\b([A-Za-zçãáéíóúâêô]*)\b(?=\s\d{4}-\d{3})', Morada).group() if Morada else ""
|
|
concelho = re.search(r'\b[A-Z]{2,}\b$', Morada).group() if Morada else ""
|
|
morada = re.search(r'^(.*?)(?=\s\d{4}-\d{3})', Morada).group() if Morada else ""
|
|
Nacionalidade = extrairinfoabaixo(pdf_path, "Nascimento")
|
|
Nacionalidade = "".join(Nacionalidade)
|
|
Nacionalidade = Nacionalidade.split()[2]
|
|
return Nome, nim, posto, DTnasc, cc, ccval, nif, pai, mae, morada, imagem, a, codigo_postal, freguesia, concelho, Morada, Nacionalidade
|
|
|
|
def resumir_texto(texto, max_length=320, min_length=30):
|
|
tamanhodotexto = len(texto.split())
|
|
max_length=min(max_length, tamanhodotexto)
|
|
max_length=int(max_length)
|
|
min_length=min(min_length, tamanhodotexto/4)
|
|
min_length=int(min_length)
|
|
summarizer = pipeline("summarization", model="rhaymison/flan-t5-portuguese-small-summarization", tokenizer="rhaymison/flan-t5-portuguese-small-summarization", device=0)
|
|
resumo = summarizer(texto, max_length=max_length, min_length=min_length, do_sample=False)
|
|
return resumo[0]['summary_text']
|
|
|
|
def anexoA(audio_path):
|
|
model=whisper.load_model("large")
|
|
result = model.transcribe(audio_path, language='pt')
|
|
textoarranjado = result['text']
|
|
|
|
textoformatado=''
|
|
for char in textoarranjado:
|
|
if char.isupper() and textoformatado:
|
|
textoformatado += '\n'
|
|
textoformatado += char
|
|
texto_resumido = resumir_texto(textoarranjado)
|
|
|
|
dados_para_preencher = {"ATT": textoarranjado}
|
|
caminho_saida = "Dataset/6_ainqtestemunha_Final.docx"
|
|
preencheraintestemunha("Dataset/6_ainqtestemunha_Final.docx", dados_para_preencher,caminho_saida)
|
|
caminho_saida2 = "Dataset/3_aintarg_Final.docx"
|
|
preencheraintestemunha("Dataset/3_aintarg_Final.docx", dados_para_preencher, caminho_saida2)
|
|
caminho_saida3 = "Dataset/2_auto_de_denuncia_Final.docx"
|
|
preencheraintestemunha("Dataset/2_auto_de_denuncia_Final.docx", dados_para_preencher, caminho_saida3)
|
|
|
|
transcrever_audio(audio_path,texto_resumido)
|
|
caminho_pdf = 'Anexo_A.pdf'
|
|
c = canvas.Canvas(caminho_pdf, pagesize=letter)
|
|
largura, altura = letter
|
|
caminho_imagem = 'Icons/logo_presidencia_republica.jpg'
|
|
cabecalho = [("RESERVADO",red),('MINISTÉRIO DA DEFESA NACIONAL', black),('EXÉRCITO PORTUGUÊS',black),('ESTADO-MAIOR GENERAL DAS FORÇAS ARMADAS',black), ('RELATÓRIO DE ENTERVISTA - PJM',black), ('ANEXO A - TRANSCRIÇÃO DO INTERREGOTÓRIO', black)]
|
|
y_position = altura - 72
|
|
|
|
def check_y_position():
|
|
nonlocal y_position
|
|
if y_position < 40:
|
|
c.showPage()
|
|
y_position = altura - 72
|
|
adicionar_cabecalho()
|
|
|
|
def adicionar_cabecalho():
|
|
nonlocal y_position
|
|
c.setFont("Helvetica-Bold", 12)
|
|
c.setFillColor(black)
|
|
y_position = altura - 72
|
|
c.setFillColor(cabecalho[0][1])
|
|
c.setFont("Helvetica-Bold", 14)
|
|
text_width = c.stringWidth(cabecalho[0][0], "Helvetica", 12)
|
|
c.drawString((largura - text_width) / 2, y_position, cabecalho[0][0])
|
|
y_position -= 30
|
|
|
|
c.drawImage(caminho_imagem, (largura - 50) / 2, y_position - 20, width=40, height=40)
|
|
y_position -= 50
|
|
|
|
for line, color in cabecalho[1:]:
|
|
check_y_position()
|
|
c.setFillColor(color)
|
|
text_width = c.stringWidth(line, "Helvetica-Bold", 14)
|
|
c.drawString((largura - text_width) / 2, y_position, line)
|
|
y_position -= 20
|
|
|
|
adicionar_cabecalho()
|
|
for line in textoarranjado.strip().split('\n'):
|
|
y_position -= 40
|
|
words = line.split(' ')
|
|
current_line = ""
|
|
|
|
for word in words:
|
|
test_line = current_line + word + " "
|
|
test_line_width = c.stringWidth(test_line, "Helvetica", 12)
|
|
|
|
if test_line_width <= largura - 160:
|
|
current_line = test_line
|
|
else:
|
|
check_y_position()
|
|
c.drawString(36, y_position, current_line.strip())
|
|
y_position -= 15
|
|
current_line = word + " "
|
|
|
|
if current_line.strip():
|
|
check_y_position()
|
|
c.drawString(36, y_position, current_line.strip())
|
|
y_position -= 15
|
|
c.save()
|
|
print("anexo criado")
|
|
|
|
def transcrever_audio(audio_path,texto_resumido):
|
|
caminho_pdf = 'transcricao_audio.pdf'
|
|
c = canvas.Canvas(caminho_pdf, pagesize=letter)
|
|
largura, altura = letter
|
|
caminho_imagem = 'Icons/logo_presidencia_republica.jpg'
|
|
cabecalho = [("RESERVADO",red),('MINISTÉRIO DA DEFESA NACIONAL', black),('FORÇAS ARMADAS',black),('ESTADO-MAIOR DAS FORÇAS ARMADAS',black), ('RELATÓRIO DE ENTERVISTA - PJM',black)]
|
|
y_position = altura - 72
|
|
def check_y_position():
|
|
nonlocal y_position
|
|
if y_position < 40:
|
|
c.showPage()
|
|
y_position = altura - 72
|
|
adicionar_cabecalho()
|
|
|
|
def adicionar_cabecalho():
|
|
nonlocal y_position
|
|
c.setFont("Helvetica-Bold", 12)
|
|
c.setFillColor(black)
|
|
y_position = altura - 72
|
|
c.setFillColor(cabecalho[0][1])
|
|
c.setFont("Helvetica-Bold", 14)
|
|
text_width = c.stringWidth(cabecalho[0][0], "Helvetica", 12)
|
|
c.drawString((largura - text_width) / 2, y_position, cabecalho[0][0])
|
|
y_position -= 30
|
|
|
|
c.drawImage(caminho_imagem, (largura - 50) / 2, y_position - 20, width=40, height=40)
|
|
y_position -= 50
|
|
|
|
for line, color in cabecalho[1:]:
|
|
check_y_position()
|
|
c.setFillColor(color)
|
|
text_width = c.stringWidth(line, "Helvetica-Bold", 14)
|
|
c.drawString((largura - text_width) / 2, y_position, line)
|
|
y_position -= 20
|
|
adicionar_cabecalho()
|
|
|
|
c.setFillColor(black)
|
|
c.setFont("Helvetica-Bold", 12)
|
|
horamins = (Hour if Hour else "00") + ":" + (Minutes if Minutes else "00")
|
|
informacoes_texto = f"""
|
|
DADOS DO INTERROGADO
|
|
|
|
Posto: {posto} NIM: {nim} Nome: {Nome}
|
|
Data de Nascimento: {DTnasc}
|
|
Cartão de Cidadão: {cc} Validade: {ccval}
|
|
NIF: {nif}
|
|
|
|
|
|
DADOS DO INTERROGADOR
|
|
|
|
Interrogador: {Interrogador}
|
|
Data do Interrogatório: {Datainterrogatorio}, Horas: {horamins}
|
|
Local: {Local} , Cidade: {City}
|
|
"""
|
|
for linha in informacoes_texto.strip().split('\n'):
|
|
y_position -= 20
|
|
c.drawString(36, y_position, linha.strip())
|
|
|
|
paibem=pai.title()
|
|
maebem=mae.title()
|
|
Moradabem=Morada.title()
|
|
idade = datetime.strptime(DTnasc, "%d-%m-%Y")
|
|
dataatual = datetime.now()
|
|
idadeanos = dataatual.year - idade.year - ((dataatual.month, dataatual.day) < (idade.month, idade.day))
|
|
|
|
introducao= f"""
|
|
Aos {Datainterrogatorio}, no {Local} em {City} compareceu perante mim, {Interrogador}, o {posto} {nim} {Nome} portador do Cartão de Cidadão n.º {cc}, válido até {ccval}. Declarou ser filho de {paibem} e de {maebem}, ter {idadeanos} anos de idade, residir na {Moradabem}.--/
|
|
RESUMO DA ENTREVISTA
|
|
{texto_resumido}
|
|
"""
|
|
|
|
for line in introducao.strip().split('\n'):
|
|
y_position -= 40
|
|
words = line.split(' ')
|
|
current_line = ""
|
|
|
|
for word in words:
|
|
test_line = current_line + word + " "
|
|
test_line_width = c.stringWidth(test_line, "Helvetica", 12)
|
|
|
|
if test_line_width <= largura - 140:
|
|
current_line = test_line
|
|
else:
|
|
check_y_position()
|
|
c.drawString(36, y_position, current_line.strip())
|
|
y_position -= 15
|
|
current_line = word + " "
|
|
|
|
if current_line.strip():
|
|
check_y_position()
|
|
c.drawString(36, y_position, current_line.strip())
|
|
y_position -= 15
|
|
|
|
c.save()
|
|
|
|
print("PDF criado com sucesso!")
|
|
|
|
def show_messagebox(title, message, box_type="Erro"):
|
|
Janela_erro = customtkinter.CTkToplevel()
|
|
Janela_erro.title(title)
|
|
Janela_erro.geometry("300x150+500+300")
|
|
label_title = customtkinter.CTkLabel(Janela_erro, text=title, font=('Arial', 16, 'bold'))
|
|
label_title.pack(pady=10)
|
|
label_message = customtkinter.CTkLabel(Janela_erro, text=message)
|
|
label_message.pack(pady=10)
|
|
close_button = customtkinter.CTkButton(Janela_erro, text="OK", command=Janela_erro.destroy)
|
|
close_button.pack(pady=10)
|
|
|
|
def update_frame(video_clip):
|
|
for frame in video_clip.iter_frames(fps=24, dtype='uint8'):
|
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
img = Image.fromarray(frame)
|
|
img = img.resize((600, 400))
|
|
imgTk = ImageTk.PhotoImage(image=img)
|
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
break
|
|
cv2.destroyAllWindows()
|
|
|
|
def play_video(video_path,parent_frame,parent_frame2):
|
|
audiopath='audio.mp3'
|
|
video_clip = VideoFileClip(video_path)
|
|
video_clip.audio.write_audiofile(audiopath)
|
|
print('audio gravado')
|
|
update_frame(video_clip)
|
|
modelemotionface_video(video_path,parent_frame)
|
|
anexoA(audiopath)
|
|
dividirvideoclips(video_path)
|
|
clipes = dividiraudioclips(audiopath)
|
|
classificar_clipes(clipes,parent_frame2)
|
|
classificar_videoclipes()
|
|
sincronizarvideoaudio()
|
|
criarvetoremocoesFER()
|
|
juntapdfs2()
|
|
copiarficheiro()
|
|
|
|
def criarvetoremocoesFER():
|
|
video_clips = "video_clips"
|
|
audio_clips = "clips"
|
|
vetoremocoesFER = []
|
|
vetoremocoesAER = []
|
|
vetor_sentimentos = []
|
|
|
|
try:
|
|
video_clips = sorted([f for f in os.listdir(video_clips) if f.endswith('.mp4')])
|
|
audio_clips = sorted([f for f in os.listdir(audio_clips) if f.endswith('.mp3')])
|
|
for video_clip in video_clips:
|
|
parts = os.path.basename(video_clip).replace('.mp4', '').split('_')
|
|
if len(parts) >= 4:
|
|
intervalo = f"{parts[1]}-{parts[2]}"
|
|
emocao = parts[3]
|
|
vetoremocoesFER.append([f"({intervalo})", emocao])
|
|
|
|
print("Vetor de emoções (FER):", vetoremocoesFER)
|
|
|
|
for audio_clip in audio_clips:
|
|
parts = os.path.basename(audio_clip).replace('.mp3', '').split('_')
|
|
if len(parts) >= 5:
|
|
intervalo = f"{parts[1]}-{parts[2]}"
|
|
emocao = parts[3]
|
|
sentimento = parts[4]
|
|
vetoremocoesAER.append([f"({intervalo})", emocao, sentimento])
|
|
vetor_sentimentos.append(sentimento)
|
|
|
|
print("Vetor de emoções e sentimentos (AER):", vetoremocoesAER)
|
|
print("Vetor de sentimentos:", vetor_sentimentos)
|
|
|
|
except Exception as e:
|
|
print(f"Erro ao criar os vetores de emoções: {e}")
|
|
|
|
criarpdfemocoes(vetoremocoesAER, vetoremocoesFER, vetor_sentimentos)
|
|
|
|
return vetoremocoesFER, vetoremocoesAER, vetor_sentimentos
|
|
|
|
def sincronizarvideoaudio():
|
|
video_path = "FERVideo.mp4"
|
|
audio_path = "audio.mp3"
|
|
outputpath = "VideoFINAL.mp4"
|
|
|
|
audio_clips = sorted([
|
|
os.path.join("clips", f)
|
|
for f in os.listdir("clips")
|
|
if f.endswith('.mp3')
|
|
])
|
|
video_clips = sorted([
|
|
os.path.join("video_clips", f)
|
|
for f in os.listdir("video_clips")
|
|
if f.endswith('.mp4')
|
|
])
|
|
|
|
emotion_colors = {
|
|
'neutral': 'white', 'happiness': 'green', 'surprise': 'yellow',
|
|
'sadness': 'lightblue', 'anger': 'red', 'disgust': 'purple', 'fear': 'red'
|
|
}
|
|
|
|
try:
|
|
video_clip = VideoFileClip(video_path)
|
|
audio_clip = AudioFileClip(audio_path)
|
|
|
|
video_duration = video_clip.duration
|
|
audio_duration = audio_clip.duration
|
|
|
|
speed_factor = video_duration / audio_duration
|
|
video_clip = speedx(video_clip, factor=speed_factor).set_audio(audio_clip)
|
|
|
|
annotated_clips = []
|
|
clip_duration = 10
|
|
|
|
for i, (audio_clip_path, video_clip_path) in enumerate(zip(audio_clips, video_clips)):
|
|
aer_label_match = re.search(r'_([^_]+)_([^_]+)\.mp3$', audio_clip_path)
|
|
fer_label_match = re.search(r'_([^_]+)\.mp4$', video_clip_path)
|
|
|
|
aer_label = aer_label_match.group(1) if aer_label_match else 'neutral'
|
|
sentiment_label = aer_label_match.group(2) if aer_label_match else 'neutral'
|
|
fer_label = fer_label_match.group(1) if fer_label_match else 'neutral'
|
|
|
|
aer_color = emotion_colors.get(aer_label, 'white')
|
|
fer_color = emotion_colors.get(fer_label, 'white')
|
|
sentiment_color = 'orange'
|
|
|
|
aer_text = TextClip(f"AER: {aer_label}", fontsize=24, color=aer_color, bg_color="black")
|
|
fer_text = TextClip(f"FER: {fer_label}", fontsize=24, color=fer_color, bg_color="black")
|
|
sentiment_text = TextClip(f"Sentiment: {sentiment_label}", fontsize=24, color=sentiment_color, bg_color="black")
|
|
|
|
video_height = video_clip.h
|
|
|
|
aer_text = aer_text.set_position(("left", video_height - 90)).set_duration(clip_duration)
|
|
fer_text = fer_text.set_position(("left", video_height - 60)).set_duration(clip_duration)
|
|
sentiment_text = sentiment_text.set_position(("left", video_height - 30)).set_duration(clip_duration)
|
|
|
|
start_time = i * clip_duration
|
|
end_time = min((i + 1) * clip_duration, video_clip.duration)
|
|
|
|
video_segment = video_clip.subclip(start_time, end_time)
|
|
annotated_segment = CompositeVideoClip([video_segment, aer_text, fer_text, sentiment_text])
|
|
annotated_clips.append(annotated_segment)
|
|
|
|
final_video = concatenate_videoclips(annotated_clips, method="compose")
|
|
final_video.write_videofile(outputpath, codec="libx264", audio_codec="aac")
|
|
|
|
print(f"Vídeo com áudio sincronizado salvo em: {outputpath}")
|
|
|
|
except Exception as e:
|
|
print(f"Erro ao sincronizar vídeo e áudio: {e}")
|
|
|
|
def carregar_video(parent_frame,parent_frame2):
|
|
video_path = filedialog.askopenfilename(filetypes=[("Carregar Vídeo", "*.mp4;*.avi;*.mov")])
|
|
if video_path:
|
|
video_path = os.path.normpath(video_path)
|
|
threading.Thread(target=play_video, args=(video_path,parent_frame,parent_frame2)).start()
|
|
|
|
def criarpdfemocoes(vetoremocoesAER, vetoremocoesFER, vetor_sentimentos):
|
|
output_pdf_path = "ANEXO_B_C.pdf"
|
|
try:
|
|
def cabecalho(canvas, doc):
|
|
canvas.saveState()
|
|
largura, altura = A4
|
|
caminho_imagem = 'Icons/logo_presidencia_republica.jpg'
|
|
|
|
canvas.setFillColor(colors.red)
|
|
canvas.setFont("Helvetica-Bold", 16)
|
|
text_width = canvas.stringWidth("RESERVADO", "Helvetica-Bold", 16)
|
|
canvas.drawString((largura - text_width) / 2, altura - 40, "RESERVADO")
|
|
|
|
canvas.drawImage(caminho_imagem, largura / 2 - 20, altura - 100, width=40, height=40)
|
|
|
|
cabecalho_texto = [
|
|
"MINISTÉRIO DA DEFESA NACIONAL",
|
|
"EXÉRCITO PORTUGUÊS",
|
|
"ESTADO-MAIOR GENERAL DAS FORÇAS ARMADAS",
|
|
"RELATÓRIO DE ENTREVISTA - PJM",
|
|
"ANEXOS B, C e D - SUMMARY AER, FER e Sentiment Analysis",
|
|
]
|
|
y_position = altura - 120
|
|
for linha in cabecalho_texto:
|
|
canvas.setFillColor(colors.black)
|
|
canvas.setFont("Helvetica-Bold", 12)
|
|
text_width = canvas.stringWidth(linha, "Helvetica-Bold", 12)
|
|
canvas.drawString((largura - text_width) / 2, y_position, linha)
|
|
y_position -= 15
|
|
|
|
canvas.restoreState()
|
|
|
|
tabela_cabecalho = ['Tempo (SER)', 'SER', 'FER', 'Sentiment Analysis']
|
|
|
|
dados_combinados = [
|
|
[aer[0], aer[1], fer[1], sentimento]
|
|
for aer, fer, sentimento in zip(vetoremocoesAER, vetoremocoesFER, vetor_sentimentos)
|
|
]
|
|
|
|
dados_tabela = [tabela_cabecalho] + dados_combinados
|
|
largura_tabela = A4[0] - inch
|
|
col_widths = [largura_tabela / 4] * 4
|
|
tabela_combinada = Table(dados_tabela, colWidths=col_widths)
|
|
|
|
tabela_combinada.setStyle(TableStyle([
|
|
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
|
|
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
|
|
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
|
|
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
|
|
('FONTSIZE', (0, 0), (-1, -1), 10),
|
|
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
|
|
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
|
]))
|
|
|
|
doc = SimpleDocTemplate(output_pdf_path, pagesize=A4)
|
|
elementos = [Spacer(1, 120)]
|
|
elementos.append(tabela_combinada)
|
|
|
|
doc.build(
|
|
elementos,
|
|
onFirstPage=cabecalho,
|
|
onLaterPages=cabecalho
|
|
)
|
|
|
|
print(f"PDF gerado com sucesso em: {output_pdf_path}")
|
|
|
|
except Exception as e:
|
|
print(f"Erro ao criar o PDF: {e}")
|
|
|
|
def carregar_audio(parent_frame):
|
|
audio_path1 = filedialog.askopenfilename(filetypes=[("Carregar Áudio", "*.mp3;*.wav;*.ogg")])
|
|
if audio_path1:
|
|
audio_path = os.path.normpath(audio_path1)
|
|
anexoA(audio_path1)
|
|
clipes = dividiraudioclips(audio_path)
|
|
classificar_clipes(clipes,parent_frame)
|
|
criarvetoremocoesFER()
|
|
juntapdfs2()
|
|
copiarficheiro()
|
|
|
|
def dividiraudioclips(audio_path, duracaoclipe=10, outputdir="clips"):
|
|
audio = AudioSegment.from_file(audio_path)
|
|
duracao_total = len(audio)
|
|
clipescriados = []
|
|
os.makedirs(outputdir, exist_ok=True)
|
|
|
|
for i in range(0, duracao_total, duracaoclipe * 1000):
|
|
clipe = audio[i:i + duracaoclipe * 1000]
|
|
clipe_path = os.path.join(outputdir, f"clipe_{i // 1000}s_{(i + duracaoclipe * 1000) // 1000}s.mp3")
|
|
clipe.export(clipe_path, format="mp3")
|
|
clipescriados.append(clipe_path)
|
|
|
|
return clipescriados
|
|
|
|
def dividirvideoclips(video_path, duracaoclipe=10, outputdir="video_clips"):
|
|
video = VideoFileClip(video_path)
|
|
duracao_total = video.duration
|
|
clipes_criados = []
|
|
os.makedirs(outputdir, exist_ok=True)
|
|
for i in range(0, int(duracao_total), duracaoclipe):
|
|
start_time = i
|
|
end_time = min(i + duracaoclipe, duracao_total)
|
|
clipe = video.subclip(start_time, end_time)
|
|
clipe_path = os.path.join(outputdir, f"clipe_{start_time}s_{end_time}s.mp4")
|
|
clipe.write_videofile(clipe_path, codec="libx264", audio_codec="aac")
|
|
clipes_criados.append(clipe_path)
|
|
video.close()
|
|
return clipes_criados
|
|
|
|
def preprocessar_video(video_path, frame_size=(64, 64)):
|
|
cap = cv2.VideoCapture(video_path)
|
|
frames = []
|
|
while cap.isOpened():
|
|
ret, frame = cap.read()
|
|
if not ret:
|
|
break
|
|
resized_frame = cv2.resize(frame, frame_size)
|
|
gray_frame = cv2.cvtColor(resized_frame, cv2.COLOR_BGR2GRAY)
|
|
gray_frame = gray_frame.astype(np.uint8)
|
|
frames.append(gray_frame)
|
|
cap.release()
|
|
return frames
|
|
|
|
def classificar_videoclipes():
|
|
|
|
modelo = cv2.dnn.readNetFromONNX('Scripts/Modelos/emotion-ferplus-8.onnx')
|
|
clipes = sorted([os.path.join("video_clips", f) for f in os.listdir("video_clips") if f.endswith('.mp4')])
|
|
emotion_labels= {0: 'neutral', 1: 'happiness', 2: 'surprise', 3: 'sadness', 4: 'anger', 5: 'disgust', 6: 'fear'}
|
|
resultados = {}
|
|
emotion_counter = {label: 0 for label in emotion_labels.values()}
|
|
for clipe in clipes:
|
|
try:
|
|
frames = preprocessar_video(clipe, frame_size=(64, 64))
|
|
predicoes = []
|
|
for frame in frames:
|
|
var= cv2.dnn.blobFromImage(frame, scalefactor=1.0, size=(64, 64), mean=(0, 0, 0), swapRB=False, crop=False)
|
|
modelo.setInput(var)
|
|
output = modelo.forward()
|
|
predicoes.append(output)
|
|
predicao_media = np.mean(predicoes, axis=0)
|
|
classe = np.argmax(predicao_media)
|
|
rotulo = emotion_labels.get(classe, "Unknown")
|
|
resultados[clipe] = rotulo
|
|
if rotulo in emotion_counter:
|
|
emotion_counter[rotulo] += 1
|
|
pasta, nome_original = os.path.split(clipe)
|
|
nome, extensao = os.path.splitext(nome_original)
|
|
novo_nome = f"{nome}_{rotulo}{extensao}"
|
|
novo_caminho = os.path.join(pasta, novo_nome)
|
|
os.rename(clipe, novo_caminho)
|
|
print(f"Clipe {clipe} classificado como: {rotulo} e renomeado para {novo_caminho}")
|
|
except Exception as e:
|
|
print(f"Erro ao classificar o clipe {clipe}: {e}")
|
|
resultados[clipe] = None
|
|
|
|
return resultados, emotion_counter
|
|
|
|
def preprocessar_audio(caminho_audio, target_shape=(400, 480)):
|
|
y, sr = librosa.load(caminho_audio, sr=16000)
|
|
mfcc_features = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=40)
|
|
resized_features = resize(np.expand_dims(mfcc_features, axis=-1),target_shape).numpy()
|
|
|
|
return np.expand_dims(resized_features, axis=0)
|
|
|
|
def classificar_clipes(clipes, parent_frame):
|
|
modelocaminho = "Scripts\\Modelos\\model.h5"
|
|
modelo_emocao = load_model(modelocaminho)
|
|
vectorizer_path = "Scripts\\Modelos\\vectorizer2.joblib"
|
|
modelo_sentiment_path = "Scripts\\Modelos\\logistic_regression_model2.joblib"
|
|
vectorizer = joblib.load(vectorizer_path)
|
|
modelo_sentiment = joblib.load(modelo_sentiment_path)
|
|
emotion_labels = {1: 'Neutral',2: 'Neutral',3: 'happiness',4: 'sadness',5: 'anger',6: 'fear',7: 'Disgust',8: 'surprise'}
|
|
sentiment_labels = {0: "Sadness", 1: "Happiness", 2: "Disgust", 3: "Anger", 4: "Fear", 5: "Surprise"}
|
|
resultados = {}
|
|
emotion_counter = {label: 0 for label in emotion_labels.values()}
|
|
sentiment_counter = {label: 0 for label in sentiment_labels.values()}
|
|
for clipe in clipes:
|
|
try:
|
|
features = preprocessar_audio(clipe)
|
|
predicao_emocao = modelo_emocao.predict(features)
|
|
classe_emocao = np.argmax(predicao_emocao) + 1
|
|
if classe_emocao in emotion_labels:
|
|
rotulo_emocao = emotion_labels[classe_emocao]
|
|
else:
|
|
rotulo_emocao = "Unknown"
|
|
if rotulo_emocao in emotion_counter:
|
|
emotion_counter[rotulo_emocao] += 1
|
|
texto_audio = transcrever_audio_para_texto(clipe)
|
|
texto_processado = preprocess_frase_pt(texto_audio)
|
|
texto_vetorizado = vectorizer.transform([texto_processado])
|
|
predicao_sentiment = modelo_sentiment.predict(texto_vetorizado)
|
|
classe_sentiment = predicao_sentiment[0]
|
|
rotulo_sentiment = sentiment_labels.get(classe_sentiment, "Unknown")
|
|
if rotulo_sentiment in sentiment_counter:
|
|
sentiment_counter[rotulo_sentiment] += 1
|
|
pasta, nome_original = os.path.split(clipe)
|
|
nome, extensao = os.path.splitext(nome_original)
|
|
novo_nome = f"{nome}_{rotulo_emocao}_{rotulo_sentiment}{extensao}"
|
|
novo_caminho = os.path.join(pasta, novo_nome)
|
|
os.rename(clipe, novo_caminho)
|
|
resultados[clipe] = {"Emotion": rotulo_emocao, "Sentiment": rotulo_sentiment}
|
|
print(f"Clipe {clipe} classificado como: {rotulo_emocao} (Emoção) e {rotulo_sentiment} (Sentimento)")
|
|
print(f"Arquivo renomeado para: {novo_caminho}")
|
|
except Exception as e:
|
|
print(f"Erro ao classificar o clipe {clipe}: {e}")
|
|
resultados[clipe] = None
|
|
atualizar_graficosAER(emotion_counter, parent_frame)
|
|
return resultados, emotion_counter, sentiment_counter
|
|
|
|
def transcrever_audio_para_texto(audio_path):
|
|
try:
|
|
model = whisper.load_model("large")
|
|
result = model.transcribe(audio_path, language='pt')
|
|
return result['text'].encode('utf-8', errors='ignore').decode('utf-8')
|
|
except Exception as e:
|
|
print(f"Erro na transcrição do áudio {audio_path}: {e}")
|
|
return ""
|
|
|
|
def atribuivalores(user2, local, city, data_entry, horas, minutos):
|
|
global Datainterrogatorio, Hour, Minutes, Local, City, Interrogador
|
|
Datainterrogatorio = data_entry.get_date() if data_entry.get_date() else None
|
|
Hour = horas.get()
|
|
Minutes = minutos.get()
|
|
Local = local.get()
|
|
City = city.get()
|
|
Interrogador = user2.get()
|
|
return Datainterrogatorio, Hour, Minutes, Local, City, Interrogador
|
|
|
|
def abrir_email_com_anexos():
|
|
global data_atual, cc
|
|
assunto = "Relatório PJM"
|
|
corpo = f"Segue em anexo o relatório gerado pelo programa PJM em {data_atual}. Por favor, anexe o arquivo localizado no caminho abaixo:\n\n"
|
|
nome_pasta = f"{cc}_{data_atual}"
|
|
destino_base = "Corpus"
|
|
ficheiro1 = "TranscriptWithAER&FER.pdf"
|
|
caminho_destino = os.path.join(destino_base, nome_pasta, ficheiro1)
|
|
corpo += f"{caminho_destino}\n\nAtenciosamente,"
|
|
mailto_link = f"mailto:?subject={urllib.parse.quote(assunto)}&body={urllib.parse.quote(corpo)}"
|
|
webbrowser.open(mailto_link)
|
|
|
|
def abrir_site_PJM():
|
|
url = "https://www.defesa.gov.pt/pt/defesa/organizacao/sc/pjm"
|
|
webbrowser.open(url)
|
|
|
|
def abrir_pdf_final():
|
|
pdf_path = "TranscriptWithAER&FER.pdf"
|
|
try:
|
|
os.startfile(pdf_path)
|
|
except Exception as e:
|
|
print(f"Erro ao abrir o PDF: {e}")
|
|
|
|
def abrir_CR():
|
|
word_path = "Dataset\\2_auto_de_denuncia_Final.docx"
|
|
try:
|
|
os.startfile(word_path)
|
|
except Exception as e:
|
|
print(f"Erro ao abrir o PDF: {e}")
|
|
|
|
def abrir_WER():
|
|
word_path = "Dataset\\6_ainqtestemunha_Final.docx"
|
|
try:
|
|
os.startfile(word_path)
|
|
except Exception as e:
|
|
print(f"Erro ao abrir o PDF: {e}")
|
|
|
|
def abrir_IRD():
|
|
word_path = "Dataset\\3_aintarg_Final.docx"
|
|
try:
|
|
os.startfile(word_path)
|
|
except Exception as e:
|
|
print(f"Erro ao abrir o PDF: {e}")
|
|
|
|
def copiarficheiro():
|
|
global data_atual, cc
|
|
ficheiros_origem = [
|
|
"VideoFINAL.mp4",
|
|
"TranscriptWithAER&FER.pdf",
|
|
"Dataset\\6_ainqtestemunha_Final.docx",
|
|
"Dataset\\3_aintarg_Final.docx",
|
|
"Dataset\\2_auto_de_denuncia_Final.docx"
|
|
]
|
|
destino_base = "Corpus"
|
|
data_atual = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
|
nome_pasta = f"{cc}_{data_atual}"
|
|
caminho_destino = os.path.join(destino_base, nome_pasta)
|
|
|
|
if not os.path.exists(caminho_destino):
|
|
os.makedirs(caminho_destino)
|
|
|
|
for ficheiro_origem in ficheiros_origem:
|
|
try:
|
|
nome_original = os.path.basename(ficheiro_origem)
|
|
nome, extensao = os.path.splitext(nome_original)
|
|
novo_nome = f"{nome}_{cc}{extensao}"
|
|
caminho_novo = os.path.join(caminho_destino, novo_nome)
|
|
shutil.copy(ficheiro_origem, caminho_novo)
|
|
print(f"Arquivo {nome_original} copiado e renomeado para {novo_nome}.")
|
|
except Exception as e:
|
|
print(f"Erro ao copiar e renomear {ficheiro_origem}: {e}")
|
|
print(f"Arquivos copiados com sucesso para {caminho_destino}")
|
|
|
|
def excluir_arquivos(pasta):
|
|
for nome_arquivo in os.listdir(pasta):
|
|
caminho_arquivo = os.path.join(pasta, nome_arquivo)
|
|
try:
|
|
if os.path.isfile(caminho_arquivo):
|
|
os.remove(caminho_arquivo)
|
|
print(f"Arquivo {caminho_arquivo} apagado com sucesso.")
|
|
except Exception as e:
|
|
print(f"Erro ao tentar deletar {caminho_arquivo}: {e}")
|
|
pastaclips = "clips"
|
|
pastavideo = "video_clips"
|
|
pastaImagens = "Imagens"
|
|
excluir_arquivos(pastaclips)
|
|
excluir_arquivos(pastavideo)
|
|
excluir_arquivos(pastaImagens)
|
|
arquivos_para_apagar = [
|
|
"audio.mp3",
|
|
"ANEXO_B_C.pdf",
|
|
"Anexo_A.pdf",
|
|
"transcricao_audio.pdf",
|
|
"VideoFINAL.mp4",
|
|
"Video.avi",
|
|
"imagem_extraida_0.jpeg",
|
|
"imagem_extraida_1.jpeg",
|
|
"FERVideo.mp4"
|
|
]
|
|
for arquivo in arquivos_para_apagar:
|
|
try:
|
|
if os.path.exists(arquivo):
|
|
os.remove(arquivo)
|
|
print(f"Arquivo {arquivo} apagado com sucesso.")
|
|
else:
|
|
print(f"Arquivo {arquivo} não encontrado.")
|
|
except Exception as e:
|
|
print(f"Erro ao tentar deletar o arquivo {arquivo}: {e}")
|
|
return data_atual
|
|
|
|
def janelaprincipal():
|
|
janela_principal = customtkinter.CTk()
|
|
janela_principal.geometry("1200x800")
|
|
janela_principal.title("PJM IA")
|
|
janela_principal.resizable(False, False)
|
|
janela_principal.grid_columnconfigure(0, weight=0)
|
|
janela_principal.grid_columnconfigure(1, weight=0)
|
|
janela_principal.grid_rowconfigure(0, weight=0)
|
|
janela_principal.grid_rowconfigure(1, weight=0)
|
|
customtkinter.set_appearance_mode("Dark")
|
|
lado_esquerdo1 = customtkinter.CTkFrame(janela_principal, width=600, height=400)
|
|
lado_esquerdo1.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
|
|
lado_direito1 = customtkinter.CTkFrame(janela_principal, width=600, height=400)
|
|
lado_direito1.grid(row=0, column=1, padx=10, pady=10, sticky="nsew")
|
|
lado_esquerdo2 = customtkinter.CTkFrame(janela_principal, width=600, height=400)
|
|
lado_esquerdo2.grid(row=1, column=1, padx=10, pady=10, sticky="nsew")
|
|
lado_direito2 = customtkinter.CTkFrame(janela_principal, width=600, height=400)
|
|
lado_direito2.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
|
|
janela_principal.grid_columnconfigure((0,1), weight=1)
|
|
janela_principal.grid_rowconfigure((0,1), weight=1)
|
|
barradetarefas=tk.Menu(janela_principal)
|
|
Carregar=tk.Menu(barradetarefas, tearoff=0)
|
|
Carregar.add_command(label='Carregar Video', command=lambda:carregar_video(lado_direito2,lado_esquerdo2))
|
|
Carregar.add_command(label='Carregar gravação som',command=lambda:carregar_audio(lado_esquerdo2))
|
|
Carregar.add_command(label='Usar a Camera', command=lambda:modelemotionface(lado_direito2,lado_esquerdo2))
|
|
Carregar.add_separator()
|
|
Carregar.add_command(label="Sair", command=janela_principal.destroy)
|
|
barradetarefas.add_cascade(label="Ficheiros", menu=Carregar)
|
|
janela_principal.config(menu=barradetarefas)
|
|
pdfimage = Image.open("Icons\\pdf.png").resize((50,50), Image.Resampling.LANCZOS)
|
|
pdficon=ImageTk.PhotoImage(pdfimage)
|
|
pdfspeachFER = tk.Button(lado_direito1, image=pdficon, borderwidth=0, highlightthickness=0, bg="#2B2B2B",command=abrir_pdf_final)
|
|
pdfspeachFER.grid(row=0, column=3, padx=6)
|
|
labelpdfspeachFER = tk.Label(lado_direito1, text="Emotions\n Analysis", fg="white", bg="#2B2B2B")
|
|
labelpdfspeachFER.grid(row=1, column=3, pady=(0, 5))
|
|
wordimage = Image.open("Icons\\word.png").resize((50,50), Image.Resampling.LANCZOS)
|
|
wordicon=ImageTk.PhotoImage(wordimage)
|
|
aintargaicon = tk.Button(lado_direito1, image=wordicon, borderwidth=0, highlightthickness=0, bg="#2B2B2B", command=abrir_CR)
|
|
aintargaicon.grid(row=0, column=0, padx=10)
|
|
aintarg = tk.Label(lado_direito1, text="Complaint\nReport", fg="white", bg="#2B2B2B")
|
|
aintarg.grid(row=1, column=0, pady=(5, 10))
|
|
PJMimage = Image.open("Icons\\PJM.png").resize((60,80), Image.Resampling.LANCZOS)
|
|
PJMicon=ImageTk.PhotoImage(PJMimage)
|
|
PJMiconb = tk.Button(lado_direito1, image=PJMicon, borderwidth=0, highlightthickness=0, bg="#2B2B2B",command=abrir_site_PJM)
|
|
PJMiconb.grid(row=8, column=0, padx=10)
|
|
mailimage = Image.open("Icons\\mail.png").resize((50,50), Image.Resampling.LANCZOS)
|
|
mailicon=ImageTk.PhotoImage(mailimage)
|
|
mailiconb = tk.Button(lado_direito1, image=mailicon, borderwidth=0, highlightthickness=0, bg="#2B2B2B",command=abrir_email_com_anexos)
|
|
mailiconb.grid(row=8, column=1, padx=10)
|
|
ainttesticon = tk.Button(lado_direito1, image=wordicon, borderwidth=0, highlightthickness=0, bg="#2B2B2B", command=abrir_WER)
|
|
ainttesticon.grid(row=0, column=1, padx=10)
|
|
ainttest = tk.Label(lado_direito1, text="Witness examination\nreport", fg="white", bg="#2B2B2B")
|
|
ainttest.grid(row=1, column=1, pady=(5, 10))
|
|
adenicon = tk.Button(lado_direito1, image=wordicon, borderwidth=0, highlightthickness=0, bg="#2B2B2B", command=abrir_IRD)
|
|
adenicon.grid(row=0, column=2, padx=10)
|
|
aden = tk.Label(lado_direito1, text="Interrogation report\nof defendant", fg="white", bg="#2B2B2B")
|
|
aden.grid(row=1, column=2, pady=(5, 10))
|
|
user = customtkinter.CTkButton(lado_direito1,text="Carregar Ficheiro PDF",command=lambda:carregar_ficheiro(user,lado_esquerdo1),fg_color="gray")
|
|
user.grid(row=4, column=0, padx=10)
|
|
userlabel = tk.Label(lado_direito1, text="FM/CC", fg="white", bg="#2B2B2B")
|
|
userlabel.grid(row=5, column=0, pady=(5, 10))
|
|
opcoes = ["OF3 12345678 Tomás", "OF2 17645234 Doe", "OF4 12827412 Smith", "OF3 13235467 Johnson", "OF2 12314558 Wilson"]
|
|
user2 = customtkinter.CTkOptionMenu(lado_direito1, values=opcoes,fg_color="#2B2B2B")
|
|
user2.grid(row=4, column=1, padx=10)
|
|
userlabel2 = tk.Label(lado_direito1, text="NIM/NIF", fg="white", bg="#2B2B2B")
|
|
userlabel2.grid(row=5, column=1, pady=(5, 10))
|
|
data_entry = DateEntry(lado_direito1, width=15, background="#2B2B2B", foreground="white", borderwidth=2, date_pattern='dd/mm/yyyy')
|
|
data_entry.grid(row=4, column=2, padx=(0, 10), pady=(5, 10))
|
|
datalabel = tk.Label(lado_direito1, text="Date\n(dd/mm/yyyy)", fg="white", bg="#2B2B2B")
|
|
datalabel.grid(row=5, column=2, pady=(5, 10))
|
|
horas= ttk.Combobox(lado_direito1, width=3, values=[f"{i:02d}" for i in range(24)])
|
|
horas.grid(row=4, column=3, sticky="w", padx=(10))
|
|
horas.set("HH")
|
|
minutos = ttk.Combobox(lado_direito1, width=3, values=[f"{i:02d}" for i in range(60)])
|
|
minutos.grid(row=4, column=3, padx=(55))
|
|
minutos.set("MM")
|
|
timelabel = tk.Label(lado_direito1, text="Hour", fg="white", bg="#2B2B2B")
|
|
timelabel.grid(row=5, column=3, sticky="w", padx=35)
|
|
local = customtkinter.CTkEntry(lado_direito1, placeholder_text="Local")
|
|
local.grid(row=6, column=0, padx=10)
|
|
locallabel = tk.Label(lado_direito1, text="Local", fg="white", bg="#2B2B2B")
|
|
locallabel.grid(row=7, column=0, pady=(5, 10))
|
|
city = customtkinter.CTkEntry(lado_direito1, placeholder_text="City")
|
|
city.grid(row=6, column=1, padx=10)
|
|
citylabel = tk.Label(lado_direito1, text="City", fg="white", bg="#2B2B2B")
|
|
citylabel.grid(row=7, column=1, pady=(5, 10))
|
|
validar = customtkinter.CTkButton(lado_direito1, text="Need Validation", fg_color="gray")
|
|
validar.grid(row=6, column=2)
|
|
def verificarcampospreenchidos():
|
|
fm_cc_valor = user2.get()
|
|
local_valor = local.get()
|
|
city_valor = city.get()
|
|
data_valor = data_entry.get_date() if data_entry.get_date() else None
|
|
hora_valor = horas.get()
|
|
minuto_valor = minutos.get()
|
|
if all([fm_cc_valor, local_valor, city_valor, data_valor, hora_valor, minuto_valor]):
|
|
validar.configure(fg_color="green", text="Validated", command=lambda: atribuivalores(user2, local, city, data_entry, horas, minutos))
|
|
else:
|
|
validar.configure(fg_color="gray", text="Need Validation")
|
|
for campo in [user2,data_entry,horas,minutos,local,city]:
|
|
campo.bind("<FocusOut>", lambda event: verificarcampospreenchidos())
|
|
|
|
janela_principal.mainloop()
|
|
|
|
Login() |