Spaces:
Sleeping
Sleeping
| """ | |
| 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 | |