File size: 3,397 Bytes
343eed9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
"""
Analyseur de Structure Intelligent pour DarkMedia-X Studio.
Sépare visuels et narrations par analyse de contenu plutôt que par Regex complexes.
"""
import re
from pathlib import Path

def is_visual(line):
    """Détermine si une ligne décrit une image."""
    l = line.lower()
    keywords = [
        'plan ', 'vue ', 'image', 'camera', 'visual', 'prompt', 'visuel', 
        '--ar', 'style', 'cinématique', 'gros plan', 'trajectoire', 
        'fond noir', 'ambiance', 'texture', 'éclairage'
    ]
    # Si la ligne commence par un label de prompt ou contient un mot technique
    return any(x in l for x in keywords) or l.startswith('- visual')

def is_narration(line):
    """Détermine si une ligne est destinée à être lue."""
    l = line.lower()
    # Si la ligne est entre guillemets ou commence par un label de parole
    if re.match(r'^[«"„“].*[»"”]$', line.strip()): return True
    labels = ['narration', "l'histoire", 'paroles', 'audio', 'texte']
    return any(l.startswith(x) for x in labels)

def clean_content(text):
    """Nettoie le bruit Markdown et les labels."""
    if not text: return ""
    # Supprimer les labels au début (ex: "Narration :")
    text = re.sub(r'^(.*?)\s*[:\-]\s*', '', text).strip()
    # Supprimer les astérisques et guillemets
    text = text.replace('**', '').replace('"', '').replace('«', '').replace('»', '')
    return text.strip()

def normalize_content(content):
    # Nettoyage global préliminaire
    content = re.sub(r"Gemini said.*?\n", "", content, flags=re.DOTALL)
    content = re.sub(r"\(\d+-\d+s\)", "", content)
    
    # Découpage par scènes (##)
    parts = re.split(r"(?:\n|^)##\s*", content)
    intro = parts[0].strip()
    new_content = intro + "\n\n" if intro else ""
    
    for p in parts[1:]:
        if not p.strip(): continue
        
        lines = p.split('\n')
        header = lines[0].strip()
        body_lines = lines[1:]
        
        visual_pool = []
        narration_pool = []
        
        for line in body_lines:
            line = line.strip()
            if not line or line.startswith('##'): continue
            
            if is_visual(line):
                visual_pool.append(clean_content(line))
            elif is_narration(line):
                narration_pool.append(clean_content(line))
            else:
                # Heuristique finale : si c'est court et sans ponctuation finale, 
                # c'est probablement du visuel, sinon de la narration.
                if len(line) < 50 and not any(line.endswith(x) for x in ['.', '!', '?', '"']):
                    visual_pool.append(clean_content(line))
                else:
                    narration_pool.append(clean_content(line))

        # Re-synthèse propre
        visual_text = " ".join(visual_pool)
        narration_text = " ".join(narration_pool)

        new_content += f"## {header}\n"
        new_content += f"**Visual Prompt :** {visual_text}\n"
        new_content += f"**Narration :** \"{narration_text}\"\n\n"
        
    return new_content.strip()

def normalize_file(file_path):
    path = Path(file_path)
    if not path.exists(): return False
    content = path.read_text(encoding="utf-8")
    normalized = normalize_content(content)
    if normalized.strip() != content.strip():
        path.write_text(normalized, encoding="utf-8")
        return True
    return False