Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| USLaP SELF-GROWING FOREST SYSTEM | |
| One file. Six components. Zero manual intervention. | |
| Your 2.6 MB file grows itself. | |
| HOW TO USE: | |
| 1. Save this file as 'uslap_forest.py' in the same folder as your Excel file | |
| 2. Open terminal in that folder | |
| 3. Run: python uslap_forest.py | |
| 4. Watch it grow | |
| The system will: | |
| - Read your entire Excel file | |
| - Find its own gaps and patterns | |
| - Generate new entries automatically | |
| - Validate everything internally | |
| - Write back to the file | |
| - Repeat every time you run it | |
| """ | |
| import openpyxl | |
| from openpyxl import load_workbook | |
| from pathlib import Path | |
| from datetime import datetime | |
| import os | |
| import sys | |
| import re | |
| # ============================================================================ | |
| # COMPONENT 1: SELF-READER ENGINE | |
| # ============================================================================ | |
| class SelfReader: | |
| """Reads the entire Excel file into memory as a living graph""" | |
| def __init__(self, filepath): | |
| self.filepath = Path(filepath) | |
| self.wb = None | |
| self.graph = {} | |
| self.foundation = {} | |
| self.mechanism = {} | |
| self.application = {} | |
| self.sheets_data = {} | |
| self.total_entries = 0 | |
| def read_all(self): | |
| """Read every sheet in the workbook""" | |
| print(f"\nπ Reading {self.filepath.name}...") | |
| if not self.filepath.exists(): | |
| raise FileNotFoundError(f"File not found: {self.filepath}") | |
| self.wb = load_workbook(self.filepath, data_only=True) | |
| # Read all sheets | |
| for sheet_name in self.wb.sheetnames: | |
| sheet = self.wb[sheet_name] | |
| data = [] | |
| headers = [] | |
| # Get headers from first row | |
| for row in sheet.iter_rows(min_row=1, max_row=1, values_only=True): | |
| headers = [str(h) if h else f"COL_{i}" for i, h in enumerate(row)] | |
| # Get data from remaining rows | |
| for row in sheet.iter_rows(min_row=2, values_only=True): | |
| if any(cell for cell in row if cell is not None): | |
| row_dict = {} | |
| for i, value in enumerate(row): | |
| if i < len(headers): | |
| row_dict[headers[i]] = value | |
| if row_dict: | |
| data.append(row_dict) | |
| self.sheets_data[sheet_name] = data | |
| # Categorize by sheet prefix | |
| if sheet_name.startswith('F'): | |
| self.foundation[sheet_name] = data | |
| elif sheet_name.startswith('M'): | |
| self.mechanism[sheet_name] = data | |
| elif sheet_name.startswith('A'): | |
| self.application[sheet_name] = data | |
| print(f" β {sheet_name}: {len(data)} rows") | |
| # Build graph from A1_ENTRIES | |
| self.build_graph() | |
| return self | |
| def build_graph(self): | |
| """Build a connected graph from A1_ENTRIES""" | |
| entries = self.sheets_data.get('A1_ENTRIES', []) | |
| for entry in entries: | |
| entry_id = entry.get('ENTRY_ID') or entry.get('ΠΠΠΠΠ‘Π¬_ID') | |
| if not entry_id: | |
| continue | |
| node = { | |
| 'id': str(entry_id), | |
| 'en_term': entry.get('EN_TERM') or entry.get('Π Π£Π‘_Π’ΠΠ ΠΠΠ', ''), | |
| 'root': entry.get('ROOT_ID', ''), | |
| 'root_letters': entry.get('ROOT_LETTERS') or entry.get('ΠΠΠ ΠΠΠ¬_ID', ''), | |
| 'network': entry.get('NETWORK_ID') or entry.get('Π‘ΠΠ’Π¬_ID', ''), | |
| 'allah_name': entry.get('ALLAH_NAME_ID') or entry.get('ΠΠΠ―_ΠΠΠΠΠ₯Π_ID', ''), | |
| 'phonetic_chain': entry.get('PHONETIC_CHAIN') or entry.get('Π€ΠΠΠΠ’ΠΠ§ΠΠ‘ΠΠΠ―_Π¦ΠΠΠ¬', ''), | |
| 'score': entry.get('SCORE') or entry.get('ΠΠΠΠ', 0), | |
| 'aa_word': entry.get('AR_WORD') or entry.get('ΠΠ _Π‘ΠΠΠΠ', ''), | |
| 'pattern': entry.get('PATTERN') or entry.get('ΠΠΠ’Π’ΠΠ Π', ''), | |
| 'foundation_ref': entry.get('FOUNDATION_REF') or entry.get('ΠΠ‘ΠΠΠΠΠΠΠ', ''), | |
| 'connections': [] | |
| } | |
| self.graph[str(entry_id)] = node | |
| self.total_entries = len(self.graph) | |
| print(f"\nπ Graph built: {self.total_entries} nodes") | |
| return self.graph | |
| # ============================================================================ | |
| # COMPONENT 2: PATTERN DETECTOR | |
| # ============================================================================ | |
| class PatternDetector: | |
| """Finds gaps and opportunities in the existing data""" | |
| def __init__(self, reader): | |
| self.reader = reader | |
| self.graph = reader.graph | |
| self.gaps = [] | |
| self.candidates = [] | |
| self.shifts = self._load_shifts() | |
| self.networks = self._load_networks() | |
| self.roots = self._build_root_index() | |
| def _load_shifts(self): | |
| """Load phonetic shifts from M1 sheet""" | |
| shifts = {} | |
| m1_data = self.reader.sheets_data.get('M1_PHONETIC_SHIFTS', []) | |
| for row in m1_data: | |
| shift_id = row.get('SHIFT_ID') or row.get('Π‘ΠΠΠΠ_ID') | |
| if shift_id: | |
| shifts[shift_id] = { | |
| 'ar_letter': row.get('AR_LETTER') or row.get('ΠΠ _ΠΠ£ΠΠΠ', ''), | |
| 'en_outputs': row.get('EN_OUTPUTS') or row.get('Π Π£Π‘_ΠΠ«Π₯ΠΠΠ«', ''), | |
| 'examples': row.get('EXAMPLES') or row.get('ΠΠ ΠΠΠΠ Π«', '') | |
| } | |
| return shifts | |
| def _load_networks(self): | |
| """Load networks from M4 sheet""" | |
| networks = {} | |
| m4_data = self.reader.sheets_data.get('M4_NETWORKS', []) | |
| for row in m4_data: | |
| net_id = row.get('NETWORK_ID') or row.get('Π‘ΠΠ’Π¬_ID') | |
| if net_id: | |
| networks[net_id] = { | |
| 'name': row.get('NAME') or row.get('ΠΠΠΠΠΠΠΠ', ''), | |
| 'entries': [] | |
| } | |
| return networks | |
| def _build_root_index(self): | |
| """Group entries by root""" | |
| roots = {} | |
| for node_id, node in self.graph.items(): | |
| root = node.get('root') | |
| if root: | |
| if root not in roots: | |
| roots[root] = [] | |
| roots[root].append(node_id) | |
| return roots | |
| def _extract_ratio_from_term(self, term): | |
| """Extract ratio from terms like 'musical fourth (4/3)'""" | |
| if not term: | |
| return None, None | |
| term_str = str(term) | |
| # Look for patterns like (4/3), (5/3), (7/3) etc. | |
| import re | |
| match = re.search(r'\((\d+)/(\d+)\)', term_str) | |
| if match: | |
| numerator = int(match.group(1)) | |
| denominator = int(match.group(2)) | |
| return numerator, denominator | |
| # Also check for "4/3" without parentheses | |
| match = re.search(r'(\d+)/(\d+)', term_str) | |
| if match: | |
| numerator = int(match.group(1)) | |
| denominator = int(match.group(2)) | |
| return numerator, denominator | |
| return None, None | |
| def get_existing_ratios_for_network(self, network): | |
| """Get all ratios already present in a network""" | |
| existing_ratios = set() | |
| for node_id, node in self.graph.items(): | |
| if node.get('network') == network: | |
| term = node.get('en_term', '') | |
| num, den = self._extract_ratio_from_term(term) | |
| if num and den: | |
| existing_ratios.add(f"{num}/{den}") | |
| return existing_ratios | |
| def detect_all(self): | |
| """Run all detection methods""" | |
| print("\nπ Detecting patterns and gaps...") | |
| self.find_networks_without_ratios() | |
| self.find_roots_with_multiple_entries() | |
| self.find_entries_without_networks() | |
| self.find_potential_ratio_entries() | |
| print(f" Found {len(self.gaps)} gaps, {len(self.candidates)} candidates") | |
| return self.gaps, self.candidates | |
| def find_networks_without_ratios(self): | |
| """Find networks that should have ratio entries but don't""" | |
| network_entries = {} | |
| for node_id, node in self.graph.items(): | |
| net = node.get('network') | |
| if net: | |
| if net not in network_entries: | |
| network_entries[net] = [] | |
| network_entries[net].append(node_id) | |
| for net, entries in network_entries.items(): | |
| if len(entries) >= 3: # Networks with at least 3 entries | |
| # Check if this network has any ratio entries using ratio extraction | |
| has_ratio = False | |
| for entry_id in entries: | |
| entry = self.graph[entry_id] | |
| term = entry.get('en_term', '') | |
| num, den = self._extract_ratio_from_term(term) | |
| if num and den: | |
| has_ratio = True | |
| break | |
| if not has_ratio: | |
| self.gaps.append({ | |
| 'type': 'network_needs_ratio', | |
| 'network': net, | |
| 'entries': entries, | |
| 'count': len(entries), | |
| 'priority': len(entries) * 2 | |
| }) | |
| def find_roots_with_multiple_entries(self): | |
| """Find roots that appear multiple times but aren't in networks""" | |
| for root, entries in self.roots.items(): | |
| if len(entries) >= 2: | |
| # Check if these entries share a network | |
| networks = set() | |
| for entry_id in entries: | |
| net = self.graph[entry_id].get('network') | |
| if net: | |
| networks.add(net) | |
| if len(networks) <= 1: # They don't have diverse networks | |
| self.candidates.append({ | |
| 'type': 'potential_network', | |
| 'root': root, | |
| 'entries': entries, | |
| 'count': len(entries), | |
| 'networks': list(networks) | |
| }) | |
| def find_entries_without_networks(self): | |
| """Find entries that don't belong to any network""" | |
| for node_id, node in self.graph.items(): | |
| if not node.get('network') and node.get('score', 0) >= 8: | |
| self.gaps.append({ | |
| 'type': 'entry_needs_network', | |
| 'entry': node_id, | |
| 'term': node.get('en_term'), | |
| 'score': node.get('score'), | |
| 'priority': 10 - node.get('score', 0) | |
| }) | |
| def find_potential_ratio_entries(self): | |
| """Find entries that might contain hidden ratios""" | |
| ratio_keywords = ['circle', 'moon', 'light', 'dombra', 'yurt', 'doira', | |
| 'drum', 'string', 'maqam', 'proportion', 'measure'] | |
| for node_id, node in self.graph.items(): | |
| term = node.get('en_term', '').lower() | |
| if any(keyword in term for keyword in ratio_keywords): | |
| if 'ratio' not in term: | |
| self.candidates.append({ | |
| 'type': 'potential_ratio', | |
| 'entry': node_id, | |
| 'term': node.get('en_term'), | |
| 'keywords': [k for k in ratio_keywords if k in term], | |
| 'priority': 5 | |
| }) | |
| # ============================================================================ | |
| # COMPONENT 3: GENERATOR ENGINE | |
| # ============================================================================ | |
| class GeneratorEngine: | |
| """Creates new entries from patterns and gaps""" | |
| def __init__(self, reader, detector): | |
| self.reader = reader | |
| self.detector = detector | |
| self.new_entries = [] | |
| self.next_id = self._find_next_id() | |
| self.ratio_templates = [ | |
| (4, 3, 'musical fourth', 'N08', 'Harmony - fourth interval'), | |
| (5, 3, 'musical sixth', 'N08', 'Harmony - sixth interval'), | |
| (7, 3, 'maqam proportion', 'N08', 'Harmony - maqam Bayyati'), | |
| (7, 5, 'prayer mat proportion', 'N06', 'Fitra - original design'), | |
| (11, 5, 'dombra proportion', 'N16', 'Gatherer - sacred proportion'), | |
| (22, 7, 'circle constant', 'N07', 'Light - circular perfection'), | |
| (19, 7, 'growth constant', 'N10', 'Cognition - angelic measure'), | |
| (12, 7, 'dome proportion', 'N07', 'Light - sacred geometry'), | |
| (28, 7, 'lunar proportion', 'N05', 'Numbering - moon cycles'), | |
| (99, 70, 'high precision β2', 'N05', 'Numbering - sacred precision'), | |
| (355, 113, 'high precision Ο', 'N05', 'Numbering - divine accuracy') | |
| ] | |
| def _extract_ratio_from_term(self, term): | |
| """Extract ratio from terms like 'musical fourth (4/3)'""" | |
| if not term: | |
| return None, None | |
| term_str = str(term) | |
| # Look for patterns like (4/3), (5/3), (7/3) etc. | |
| import re | |
| match = re.search(r'\((\d+)/(\d+)\)', term_str) | |
| if match: | |
| numerator = int(match.group(1)) | |
| denominator = int(match.group(2)) | |
| return numerator, denominator | |
| # Also check for "4/3" without parentheses | |
| match = re.search(r'(\d+)/(\d+)', term_str) | |
| if match: | |
| numerator = int(match.group(1)) | |
| denominator = int(match.group(2)) | |
| return numerator, denominator | |
| return None, None | |
| def _get_existing_ratios_for_network(self, network): | |
| """Get all ratios already present in a network""" | |
| existing_ratios = set() | |
| for node_id, node in self.reader.graph.items(): | |
| if node.get('network') == network: | |
| term = node.get('en_term', '') | |
| num, den = self._extract_ratio_from_term(term) | |
| if num and den: | |
| existing_ratios.add(f"{num}/{den}") | |
| return existing_ratios | |
| def _generate_fractal_variants(self, base_num, base_den, network): | |
| """Generate fractal variants of a ratio across different domains""" | |
| variants = [] | |
| # Domain templates: (domain_name, domain_description) | |
| domains = [ | |
| ("melodic", "musical interval"), | |
| ("rhythmic", "tempo ratio"), | |
| ("geometric", "sacred proportion"), | |
| ("harmonic", "string division"), | |
| ("temporal", "time cycle"), | |
| ("spatial", "architectural ratio"), | |
| ("spiritual", "prayer cycle"), | |
| ("botanical", "growth pattern"), | |
| ("celestial", "orbital ratio"), | |
| ("numerical", "mathematical constant"), | |
| ] | |
| # Check existing ratios for this network | |
| existing_ratios = self._get_existing_ratios_for_network(network) | |
| base_ratio_str = f"{base_num}/{base_den}" | |
| # If base ratio already exists, generate variants with different domains | |
| if base_ratio_str in existing_ratios: | |
| for domain_name, domain_desc in domains: | |
| # Create a unique variant by combining ratio with domain | |
| entry = self._create_ratio_entry( | |
| base_num, base_den, | |
| f"{domain_desc} {base_num}/{base_den}", | |
| network, | |
| f"Divine ratio {base_num}/{base_den} manifesting in {domain_name} domain β Q54:49" | |
| ) | |
| variants.append(entry) | |
| # Limit to 3 variants per generation cycle | |
| if len(variants) >= 3: | |
| break | |
| else: | |
| # Base ratio doesn't exist, create it first | |
| entry = self._create_ratio_entry( | |
| base_num, base_den, | |
| f"divine ratio {base_num}/{base_den}", | |
| network, | |
| f"Foundational ratio {base_num}/{base_den} β Q54:49" | |
| ) | |
| variants.append(entry) | |
| return variants | |
| def _find_next_id(self): | |
| """Find the next available ENTRY_ID""" | |
| max_num = 0 | |
| for node_id in self.reader.graph.keys(): | |
| if node_id and node_id.startswith('F'): | |
| try: | |
| num = int(node_id[1:]) | |
| max_num = max(max_num, num) | |
| except: | |
| pass | |
| return max_num + 1 | |
| def generate_from_gaps(self, gaps, candidates): | |
| """Generate new entries from detected gaps and candidates""" | |
| print("\nπ± Generating new entries from gaps...") | |
| # Process top 5 gaps | |
| gap_count = 0 | |
| for gap in gaps[:5]: | |
| if gap['type'] == 'network_needs_ratio': | |
| self._generate_ratio_for_network(gap) | |
| gap_count += 1 | |
| elif gap['type'] == 'entry_needs_network': | |
| self._assign_entry_to_network(gap) | |
| gap_count += 1 | |
| # If no gaps found, process top 3 candidates, avoiding duplicates | |
| if gap_count == 0: | |
| print(" No gaps found, checking candidates...") | |
| processed_ratios = set() # Track which ratios we've already generated variants for | |
| candidate_count = 0 | |
| for candidate in candidates: | |
| if candidate['type'] == 'potential_ratio': | |
| # Extract ratio from candidate | |
| term = candidate['term'] | |
| num, den = self._extract_ratio_from_term(term) | |
| if not num or not den: | |
| continue | |
| ratio_str = f"{num}/{den}" | |
| # Skip if we've already processed this ratio in this cycle | |
| if ratio_str in processed_ratios: | |
| print(f" Skipping duplicate ratio: {ratio_str}") | |
| continue | |
| # Generate fractal variants for this ratio | |
| self._generate_fractal_from_candidate(candidate) | |
| processed_ratios.add(ratio_str) | |
| candidate_count += 1 | |
| # Limit to 2 candidates per generation cycle | |
| if candidate_count >= 2: | |
| break | |
| print(f" Generated {len(self.new_entries)} new entries") | |
| return self.new_entries | |
| def _generate_fractal_from_candidate(self, candidate): | |
| """Generate fractal variants from a potential ratio candidate""" | |
| entry_id = candidate['entry'] | |
| term = candidate['term'] | |
| # Extract ratio from the candidate term | |
| num, den = self._extract_ratio_from_term(term) | |
| if not num or not den: | |
| print(f" Could not extract ratio from: {term}") | |
| return | |
| # Get the network from the entry | |
| entry = self.reader.graph.get(entry_id, {}) | |
| network = entry.get('network') | |
| if not network: | |
| # Default to N08 (Harmony) for ratio entries | |
| network = 'N08' | |
| # Generate fractal variants for this ratio | |
| variants = self._generate_fractal_variants(num, den, network) | |
| # Add variants to new entries | |
| for variant in variants: | |
| self.new_entries.append(variant) | |
| print(f" Generated: {variant['EN_TERM']}") | |
| def _generate_ratio_for_network(self, gap): | |
| """Generate fractal variant ratio entries for a network""" | |
| network = gap['network'] | |
| # Find matching ratio templates for this network | |
| matching_templates = [] | |
| for num, den, name, net, desc in self.ratio_templates: | |
| if net == network: | |
| matching_templates.append((num, den, name, net, desc)) | |
| if matching_templates: | |
| # Generate fractal variants for each matching template | |
| for num, den, name, net, desc in matching_templates: | |
| variants = self._generate_fractal_variants(num, den, network) | |
| self.new_entries.extend(variants) | |
| # Limit to 5 total variants per generation cycle | |
| if len(self.new_entries) >= 5: | |
| break | |
| else: | |
| # No matching templates, create a generic fractal variant | |
| variants = self._generate_fractal_variants(1, 1, network) | |
| self.new_entries.extend(variants[:2]) # Just 2 generic variants | |
| def _assign_entry_to_network(self, gap): | |
| """Create a network assignment for an entry""" | |
| entry_id = gap['entry'] | |
| term = gap['term'] | |
| # Find appropriate network based on term | |
| network = 'N08' # Default to Harmony | |
| if any(word in term.lower() for word in ['light', 'sun', 'moon', 'circle']): | |
| network = 'N07' | |
| elif any(word in term.lower() for word in ['number', 'count', 'zero', 'cipher']): | |
| network = 'N05' | |
| elif any(word in term.lower() for word in ['faith', 'amen', 'secure']): | |
| network = 'N06' | |
| # Create a note about the assignment | |
| entry = { | |
| 'ENTRY_ID': f"NOTE{self.next_id:04d}", | |
| 'SCORE': 8, | |
| 'EN_TERM': f"{term} network assignment", | |
| 'AR_WORD': 'β', | |
| 'ROOT_ID': gap['entry'], | |
| 'ROOT_LETTERS': 'β', | |
| 'QUR_MEANING': f"Should be in {network}", | |
| 'PATTERN': 'A', | |
| 'NETWORK_ID': network, | |
| 'PHONETIC_CHAIN': 'β', | |
| 'INVERSION_TYPE': 'HIDDEN', | |
| 'SOURCE_FORM': 'β', | |
| 'FOUNDATION_REF': f"GAP:{gap['type']}" | |
| } | |
| self.next_id += 1 | |
| self.new_entries.append(entry) | |
| def _create_ratio_entry(self, numerator, denominator, name, network, description): | |
| """Create a ratio entry""" | |
| entry_id = f"F{self.next_id:04d}" | |
| self.next_id += 1 | |
| return { | |
| 'ENTRY_ID': entry_id, | |
| 'SCORE': 9, | |
| 'EN_TERM': name, | |
| 'AR_WORD': f"({numerator}/{denominator})", | |
| 'ROOT_ID': f"R{self.next_id}", | |
| 'ROOT_LETTERS': 'β', | |
| 'QUR_MEANING': f"Divine ratio {numerator}/{denominator} - {description}", | |
| 'PATTERN': 'A', | |
| 'NETWORK_ID': network, | |
| 'PHONETIC_CHAIN': 'β'.join(['?'] * 3), | |
| 'INVERSION_TYPE': 'HIDDEN', | |
| 'SOURCE_FORM': f"ratio:{numerator}/{denominator}", | |
| 'FOUNDATION_REF': f"RATIO:{numerator}/{denominator}" | |
| } | |
| def generate_seed_entries(self): | |
| """Generate initial seed ratio entries""" | |
| print("\nπ± Planting seed entries...") | |
| for num, den, name, net, desc in self.ratio_templates: | |
| entry = self._create_ratio_entry(num, den, name, net, desc) | |
| self.new_entries.append(entry) | |
| print(f" Planted {len(self.new_entries)} seeds") | |
| return self.new_entries | |
| # ============================================================================ | |
| # COMPONENT 4: VALIDATION ENGINE | |
| # ============================================================================ | |
| class ValidationEngine: | |
| """Validates new entries against existing patterns""" | |
| def __init__(self, reader): | |
| self.reader = reader | |
| def validate_all(self, entries): | |
| """Validate all new entries""" | |
| print("\nβ Validating new entries...") | |
| validated = [] | |
| for entry in entries: | |
| valid_entry = self._validate_entry(entry) | |
| if valid_entry: | |
| validated.append(valid_entry) | |
| print(f" Validated {len(validated)} of {len(entries)} entries") | |
| return validated | |
| def _validate_entry(self, entry): | |
| """Validate a single entry""" | |
| # Check required fields | |
| required = ['ENTRY_ID', 'EN_TERM'] | |
| for field in required: | |
| if field not in entry or not entry[field]: | |
| return None | |
| # Auto-calculate score based on completeness | |
| score = 5 | |
| if entry.get('ROOT_ID') and entry['ROOT_ID'] != 'β': | |
| score += 1 | |
| if entry.get('NETWORK_ID'): | |
| score += 1 | |
| if entry.get('PHONETIC_CHAIN') and entry['PHONETIC_CHAIN'] != 'β'.join(['?'] * 3): | |
| score += 1 | |
| if entry.get('QUR_MEANING') and 'Divine' not in entry['QUR_MEANING']: | |
| score += 1 | |
| if entry.get('FOUNDATION_REF') and entry['FOUNDATION_REF'].startswith('RATIO'): | |
| score += 1 | |
| entry['SCORE'] = min(10, score) | |
| return entry | |
| # ============================================================================ | |
| # COMPONENT 5: SELF-WRITER ENGINE | |
| # ============================================================================ | |
| class SelfWriter: | |
| """Writes new entries back to the Excel file""" | |
| def __init__(self, reader): | |
| self.reader = reader | |
| self.filepath = reader.filepath | |
| def write_all(self, new_entries): | |
| """Write all new entries to the file""" | |
| if not new_entries: | |
| print("\nπΎ No new entries to write") | |
| return 0 | |
| print("\nπΎ Writing new entries to file...") | |
| try: | |
| # Load workbook fresh to avoid conflicts | |
| wb = load_workbook(self.filepath) | |
| # Get or create A1_ENTRIES sheet | |
| if 'A1_ENTRIES' in wb.sheetnames: | |
| sheet = wb['A1_ENTRIES'] | |
| else: | |
| sheet = wb.create_sheet('A1_ENTRIES') | |
| # Add headers | |
| headers = ['ENTRY_ID', 'SCORE', 'EN_TERM', 'AR_WORD', 'ROOT_ID', | |
| 'ROOT_LETTERS', 'QUR_MEANING', 'PATTERN', 'NETWORK_ID', | |
| 'PHONETIC_CHAIN', 'INVERSION_TYPE', 'SOURCE_FORM', 'FOUNDATION_REF'] | |
| for col, header in enumerate(headers, 1): | |
| sheet.cell(row=1, column=col, value=header) | |
| # Find next empty row | |
| next_row = sheet.max_row + 1 | |
| # Write each new entry | |
| for entry in new_entries: | |
| sheet.cell(row=next_row, column=1, value=entry['ENTRY_ID']) | |
| sheet.cell(row=next_row, column=2, value=entry['SCORE']) | |
| sheet.cell(row=next_row, column=3, value=entry['EN_TERM']) | |
| sheet.cell(row=next_row, column=4, value=entry['AR_WORD']) | |
| sheet.cell(row=next_row, column=5, value=entry['ROOT_ID']) | |
| sheet.cell(row=next_row, column=6, value=entry.get('ROOT_LETTERS', 'β')) | |
| sheet.cell(row=next_row, column=7, value=entry.get('QUR_MEANING', 'β')) | |
| sheet.cell(row=next_row, column=8, value=entry.get('PATTERN', 'A')) | |
| sheet.cell(row=next_row, column=9, value=entry.get('NETWORK_ID', '')) | |
| sheet.cell(row=next_row, column=10, value=entry.get('PHONETIC_CHAIN', 'β')) | |
| sheet.cell(row=next_row, column=11, value=entry.get('INVERSION_TYPE', 'HIDDEN')) | |
| sheet.cell(row=next_row, column=12, value=entry.get('SOURCE_FORM', 'β')) | |
| sheet.cell(row=next_row, column=13, value=entry.get('FOUNDATION_REF', 'β')) | |
| next_row += 1 | |
| # Save | |
| wb.save(self.filepath) | |
| print(f" β Wrote {len(new_entries)} new entries to {self.filepath.name}") | |
| return len(new_entries) | |
| except Exception as e: | |
| print(f" β Error writing: {e}") | |
| return 0 | |
| # ============================================================================ | |
| # COMPONENT 6: MAIN SYSTEM | |
| # ============================================================================ | |
| class SelfGrowingSystem: | |
| """The main orchestrator that runs all 6 components""" | |
| def __init__(self, filepath): | |
| self.filepath = Path(filepath) | |
| self.cycle_count = 0 | |
| self.growth_log = [] | |
| if not self.filepath.exists(): | |
| raise FileNotFoundError(f"File not found: {filepath}") | |
| print("\n" + "="*60) | |
| print("π³ USLaP SELF-GROWING FOREST SYSTEM") | |
| print("="*60) | |
| print(f"π File: {self.filepath.name}") | |
| print(f"π¦ Size: {self.filepath.stat().st_size / 1024 / 1024:.2f} MB") | |
| print("="*60) | |
| def run_full_cycle(self, seed_mode=False): | |
| """ | |
| Run all 6 components in sequence | |
| seed_mode=True: Plant initial ratio seeds | |
| seed_mode=False: Full growth cycle with pattern detection | |
| """ | |
| print(f"\n{'='*60}") | |
| print(f"CYCLE {self.cycle_count + 1} - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") | |
| print(f"{'='*60}") | |
| # COMPONENT 1: READ | |
| print("\nπ COMPONENT 1: Self-Reader") | |
| reader = SelfReader(self.filepath) | |
| reader.read_all() | |
| if seed_mode: | |
| # COMPONENT 2: Skip detection for seed mode | |
| gaps = [] | |
| candidates = [] | |
| # COMPONENT 3: Generate seeds | |
| print("\nπ± COMPONENT 3: Generator Engine (Seed Mode)") | |
| generator = GeneratorEngine(reader, None) | |
| new_entries = generator.generate_seed_entries() | |
| else: | |
| # COMPONENT 2: Detect patterns | |
| print("\nπ COMPONENT 2: Pattern Detector") | |
| detector = PatternDetector(reader) | |
| gaps, candidates = detector.detect_all() | |
| # COMPONENT 3: Generate from gaps | |
| print("\nπ± COMPONENT 3: Generator Engine") | |
| generator = GeneratorEngine(reader, detector) | |
| new_entries = generator.generate_from_gaps(gaps, candidates) | |
| # COMPONENT 4: Validate | |
| print("\nβ COMPONENT 4: Validation Engine") | |
| validator = ValidationEngine(reader) | |
| validated_entries = validator.validate_all(new_entries) | |
| # COMPONENT 5: Write | |
| print("\nπΎ COMPONENT 5: Self-Writer") | |
| writer = SelfWriter(reader) | |
| written = writer.write_all(validated_entries) | |
| # COMPONENT 6: Log | |
| self.cycle_count += 1 | |
| self.growth_log.append({ | |
| 'cycle': self.cycle_count, | |
| 'timestamp': datetime.now().isoformat(), | |
| 'mode': 'SEED' if seed_mode else 'GROWTH', | |
| 'new_entries': written, | |
| 'gaps_found': len(gaps) if not seed_mode else 0, | |
| 'candidates': len(candidates) if not seed_mode else 0 | |
| }) | |
| print(f"\n{'='*60}") | |
| print(f"β CYCLE {self.cycle_count} COMPLETE") | |
| print(f" Mode: {'π± SEED' if seed_mode else 'π³ GROWTH'}") | |
| print(f" Added: {written} new entries") | |
| print(f" Total entries now: {reader.total_entries + written}") | |
| print(f"{'='*60}\n") | |
| return self | |
| def show_log(self): | |
| """Display growth log""" | |
| print("\nπ GROWTH LOG") | |
| print("-" * 50) | |
| for entry in self.growth_log: | |
| mode_icon = "π±" if entry['mode'] == 'SEED' else "π³" | |
| print(f"{mode_icon} Cycle {entry['cycle']}: {entry['new_entries']} entries added") | |
| print("-" * 50) | |
| def run_forever(self, interval_hours=24): | |
| """Run cycles automatically at specified intervals""" | |
| import time | |
| print(f"\nβ° Running forever every {interval_hours} hours") | |
| print("Press Ctrl+C to stop\n") | |
| # First cycle: seed mode | |
| self.run_full_cycle(seed_mode=True) | |
| # Subsequent cycles: growth mode | |
| while True: | |
| time.sleep(interval_hours * 3600) | |
| self.run_full_cycle(seed_mode=False) | |
| self.show_log() | |
| # ============================================================================ | |
| # MAIN EXECUTION - THIS RUNS EVERYTHING | |
| # ============================================================================ | |
| def main(): | |
| """Main function - runs all 6 components""" | |
| # Get file path from command line or use default | |
| if len(sys.argv) > 1: | |
| filepath = sys.argv[1] | |
| else: | |
| filepath = "USLaP_Final_Data_Consolidated_Master.xlsx" | |
| # Check if file exists | |
| if not os.path.exists(filepath): | |
| print(f"\nβ File not found: {filepath}") | |
| print("\nPlease provide the path to your USLaP Excel file:") | |
| print(" python uslap_forest.py /path/to/your/file.xlsx") | |
| print("\nOr place this script in the same folder as your file.") | |
| return 1 | |
| try: | |
| # Create the system | |
| system = SelfGrowingSystem(filepath) | |
| # Ask user what they want to do | |
| print("\nWhat would you like to do?") | |
| print(" 1. Plant seeds (first run only)") | |
| print(" 2. Run one growth cycle") | |
| print(" 3. Run forever (automatic every 24h)") | |
| print(" 4. Just show what would happen (dry run)") | |
| choice = input("\nEnter choice (1-4): ").strip() | |
| if choice == '1': | |
| # Plant seeds only | |
| system.run_full_cycle(seed_mode=True) | |
| system.show_log() | |
| print("\nπ± Seeds planted! Run again with option 2 for growth.") | |
| elif choice == '2': | |
| # Run one growth cycle | |
| system.run_full_cycle(seed_mode=False) | |
| system.show_log() | |
| elif choice == '3': | |
| # Run forever | |
| hours = input("Enter interval in hours (default 24): ").strip() | |
| interval = int(hours) if hours else 24 | |
| system.run_forever(interval_hours=interval) | |
| elif choice == '4': | |
| # Dry run - just read and analyze | |
| print("\nπ DRY RUN - Reading only...") | |
| reader = SelfReader(filepath) | |
| reader.read_all() | |
| print("\nπ Analyzing patterns...") | |
| detector = PatternDetector(reader) | |
| gaps, candidates = detector.detect_all() | |
| print("\nπ ANALYSIS RESULTS") | |
| print(f" Total entries: {reader.total_entries}") | |
| print(f" Gaps found: {len(gaps)}") | |
| print(f" Network candidates: {len(candidates)}") | |
| print("\n Top gaps:") | |
| for gap in gaps[:5]: | |
| print(f" β’ {gap['type']}: {gap.get('network', gap.get('entry', '?'))}") | |
| print("\nβ Dry run complete. No changes made.") | |
| else: | |
| print("Invalid choice. Running default: plant seeds") | |
| system.run_full_cycle(seed_mode=True) | |
| print("\n⨠Done!") | |
| except KeyboardInterrupt: | |
| print("\n\nπ System stopped by user") | |
| except Exception as e: | |
| print(f"\nβ Error: {e}") | |
| return 1 | |
| return 0 | |
| # ============================================================================ | |
| # ENTRY POINT | |
| # ============================================================================ | |
| if __name__ == "__main__": | |
| sys.exit(main()) |