Vesion Fonctionnelle
This commit is contained in:
167
check_video_authenticity.py
Normal file
167
check_video_authenticity.py
Normal file
@@ -0,0 +1,167 @@
|
||||
import os
|
||||
import sys
|
||||
import requests
|
||||
import json
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog
|
||||
from rich.console import Console
|
||||
from rich.progress import Progress, SpinnerColumn, TextColumn
|
||||
from rich.panel import Panel
|
||||
from rich.table import Table
|
||||
from rich import print
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
# TODO: Replace with your actual Sightengine API credentials
|
||||
API_USER = "1020608869"
|
||||
API_SECRET = "M7WF4mAXwSs2gs869LC9PecvYCBQyBSz"
|
||||
|
||||
API_ENDPOINT = "https://api.sightengine.com/1.0/video/check-sync.json"
|
||||
|
||||
console = Console()
|
||||
|
||||
def select_video_file():
|
||||
"""Opens a file dialog to select a video file using Tkinter."""
|
||||
root = tk.Tk()
|
||||
root.withdraw() # Hide the main window
|
||||
|
||||
file_path = filedialog.askopenfilename(
|
||||
title="Select a video file to analyze",
|
||||
filetypes=[
|
||||
("Video Files", "*.mp4 *.mov *.avi *.mkv *.webm *.flv *.wmv"),
|
||||
("All Files", "*.*")
|
||||
]
|
||||
)
|
||||
return file_path
|
||||
|
||||
def check_video(file_path):
|
||||
"""Checks the video using Sightengine API."""
|
||||
if not os.path.exists(file_path):
|
||||
console.print(f"[bold red]Error:[/bold red] File not found: {file_path}")
|
||||
return
|
||||
|
||||
params = {
|
||||
'models': 'genai',
|
||||
'api_user': API_USER,
|
||||
'api_secret': API_SECRET
|
||||
}
|
||||
|
||||
files = {
|
||||
'media': open(file_path, 'rb')
|
||||
}
|
||||
|
||||
try:
|
||||
with Progress(
|
||||
SpinnerColumn(),
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
transient=True
|
||||
) as progress:
|
||||
progress.add_task(description="Uploading and analyzing video...", total=None)
|
||||
response = requests.post(API_ENDPOINT, files=files, data=params)
|
||||
|
||||
response_data = json.loads(response.text)
|
||||
|
||||
if response_data['status'] == 'success':
|
||||
display_results(file_path, response_data)
|
||||
else:
|
||||
error_msg = response_data.get('error', {}).get('message', 'Unknown error')
|
||||
console.print(f"[bold red]API Error:[/bold red] {error_msg}")
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]System Error:[/bold red] {e}")
|
||||
finally:
|
||||
files['media'].close()
|
||||
|
||||
def display_results(file_path, data):
|
||||
"""Displays the analysis results using Rich."""
|
||||
|
||||
# Calculate aggregate score (average of all frames for simplicity in this demo)
|
||||
frames = data.get('data', {}).get('frames', [])
|
||||
if not frames:
|
||||
console.print("[yellow]No frames analyzed.[/yellow]")
|
||||
return
|
||||
|
||||
total_ai_score = 0
|
||||
count = 0
|
||||
|
||||
# Create detailed table for frames (showing first few or high scores)
|
||||
table = Table(title="Frame Analysis (Sample)")
|
||||
table.add_column("Time (s)", justify="right", style="cyan", no_wrap=True)
|
||||
table.add_column("AI Probability", justify="right", style="magenta")
|
||||
table.add_column("Verdict", justify="center")
|
||||
|
||||
max_ai_score = 0
|
||||
|
||||
for frame in frames:
|
||||
ai_score = frame.get('type', {}).get('ai_generated', 0)
|
||||
total_ai_score += ai_score
|
||||
count += 1
|
||||
if ai_score > max_ai_score:
|
||||
max_ai_score = ai_score
|
||||
|
||||
# Add to table if it's a significant score or just to show some data
|
||||
# Showing only frames with > 0.1 score or every 10th frame to keep it clean if many frames
|
||||
if ai_score > 0.5 or count % 10 == 1:
|
||||
verdict = "[red]FAKE[/red]" if ai_score > 0.8 else ("[yellow]SUSPICIOUS[/yellow]" if ai_score > 0.4 else "[green]REAL[/green]")
|
||||
# Assuming 1 frame per second roughly? API documentation says 'position' is likely offset
|
||||
position = frame.get('info', {}).get('position', 0)
|
||||
# Provide string formatting for score
|
||||
table.add_row(str(position), f"{ai_score:.2%}", verdict)
|
||||
|
||||
avg_ai_score = total_ai_score / count if count else 0
|
||||
|
||||
# Final Verdict Panel
|
||||
final_verdict = "UNCERTAIN"
|
||||
color = "yellow"
|
||||
if max_ai_score > 0.85:
|
||||
final_verdict = "AI GENERATED"
|
||||
color = "red"
|
||||
elif max_ai_score < 0.2:
|
||||
final_verdict = "AUTHENTIC"
|
||||
color = "green"
|
||||
|
||||
request_info = data.get('request', {})
|
||||
req_id = request_info.get('id', 'N/A')
|
||||
ops = request_info.get('operations', 0)
|
||||
|
||||
panel_content = f"""
|
||||
[bold]File:[/bold] {os.path.basename(file_path)}
|
||||
[bold]Request ID:[/bold] {req_id}
|
||||
[bold]Operations Cost:[/bold] {ops}
|
||||
|
||||
[bold]Max AI Score:[/bold] {max_ai_score:.2%}
|
||||
[bold]Average AI Score:[/bold] {avg_ai_score:.2%}
|
||||
|
||||
[bold size=20 style={color}]VERDICT: {final_verdict}[/bold size=20 style={color}]
|
||||
"""
|
||||
|
||||
console.print(Panel(panel_content, title="Analysis Result", expand=False))
|
||||
console.print(table)
|
||||
|
||||
def main():
|
||||
if API_USER == "CHANGE_ME" or API_SECRET == "CHANGE_ME":
|
||||
console.print("[bold red]Configuration Error:[/bold red] Please set API_USER and API_SECRET in the script.")
|
||||
return
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
video_path = sys.argv[1]
|
||||
else:
|
||||
console.print(Panel(
|
||||
"[bold green]AI Video Authenticity Check[/bold green]\n\n"
|
||||
"This script analyzes a video to detect AI-generated content using Sightengine.\n"
|
||||
"Please select a video file in the window that opens...",
|
||||
title="Welcome",
|
||||
border_style="green"
|
||||
))
|
||||
video_path = select_video_file()
|
||||
if not video_path:
|
||||
console.print("[yellow]No file selected. Exiting.[/yellow]")
|
||||
return
|
||||
|
||||
console.print(f"[blue]Analyzing:[/blue] {video_path}")
|
||||
check_video(video_path)
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
finally:
|
||||
input("Press Enter to continue...")
|
||||
Reference in New Issue
Block a user