| | """ |
| | Module pour les IA génératives légères |
| | """ |
| |
|
| | import numpy as np |
| | from typing import List, Optional |
| | import random |
| |
|
| |
|
| | class GenerativeAI: |
| | """ |
| | IA générative légère pour créer des noms et autres contenus |
| | |
| | Args: |
| | mode: Mode de génération ('name_generator', 'text_generator') |
| | **kwargs: Paramètres additionnels |
| | |
| | Example: |
| | >>> from sitiai import create |
| | >>> ai = create.ai('generative', mode='name_generator') |
| | >>> ai.load_data(['Alice', 'Bob', 'Charlie', 'David']) |
| | >>> ai.train(epochs=100) |
| | >>> new_name = ai.generate() |
| | """ |
| | |
| | def __init__(self, mode: str = 'name_generator', **kwargs): |
| | self.mode = mode |
| | self.data = [] |
| | self.char_to_idx = {} |
| | self.idx_to_char = {} |
| | self.transition_matrix = None |
| | self.is_trained = False |
| | |
| | def load_data(self, data: List[str]): |
| | """ |
| | Charge les données d'entraînement |
| | |
| | Args: |
| | data: Liste de chaînes de caractères pour l'entraînement |
| | """ |
| | self.data = [d.lower() for d in data] |
| | |
| | |
| | all_chars = set(''.join(self.data)) |
| | all_chars.add('^') |
| | all_chars.add('$') |
| | |
| | self.char_to_idx = {char: idx for idx, char in enumerate(sorted(all_chars))} |
| | self.idx_to_char = {idx: char for char, idx in self.char_to_idx.items()} |
| | |
| | def train(self, epochs: int = 100, ngram_size: int = 2): |
| | """ |
| | Entraîne le modèle génératif |
| | |
| | Args: |
| | epochs: Nombre d'époques (non utilisé pour les n-grammes, mais conservé pour l'API) |
| | ngram_size: Taille des n-grammes (par défaut 2 = bigrammes) |
| | """ |
| | if not self.data: |
| | raise ValueError("Aucune donnée chargée. Utilisez load_data() d'abord.") |
| | |
| | vocab_size = len(self.char_to_idx) |
| | self.transition_matrix = np.zeros((vocab_size, vocab_size)) |
| | |
| | |
| | for word in self.data: |
| | |
| | extended_word = '^' + word + '$' |
| | |
| | for i in range(len(extended_word) - 1): |
| | curr_char = extended_word[i] |
| | next_char = extended_word[i + 1] |
| | |
| | curr_idx = self.char_to_idx[curr_char] |
| | next_idx = self.char_to_idx[next_char] |
| | |
| | self.transition_matrix[curr_idx, next_idx] += 1 |
| | |
| | |
| | row_sums = self.transition_matrix.sum(axis=1, keepdims=True) |
| | row_sums[row_sums == 0] = 1 |
| | self.transition_matrix = self.transition_matrix / row_sums |
| | |
| | self.is_trained = True |
| | |
| | def generate(self, max_length: int = 20, temperature: float = 1.0) -> str: |
| | """ |
| | Génère un nouveau nom ou texte |
| | |
| | Args: |
| | max_length: Longueur maximale de la génération |
| | temperature: Contrôle la créativité (plus élevé = plus créatif) |
| | |
| | Returns: |
| | Texte généré |
| | """ |
| | if not self.is_trained: |
| | raise ValueError("Le modèle n'est pas entraîné. Utilisez train() d'abord.") |
| | |
| | |
| | current_idx = self.char_to_idx['^'] |
| | result = [] |
| | |
| | for _ in range(max_length): |
| | |
| | probs = self.transition_matrix[current_idx].copy() |
| | |
| | |
| | if temperature != 1.0: |
| | probs = np.power(probs, 1.0 / temperature) |
| | probs = probs / probs.sum() |
| | |
| | |
| | if probs.sum() == 0: |
| | break |
| | |
| | next_idx = np.random.choice(len(probs), p=probs) |
| | next_char = self.idx_to_char[next_idx] |
| | |
| | |
| | if next_char == '$': |
| | break |
| | |
| | result.append(next_char) |
| | current_idx = next_idx |
| | |
| | return ''.join(result).capitalize() |
| | |
| | def generate_batch(self, n: int = 5, max_length: int = 20, temperature: float = 1.0) -> List[str]: |
| | """ |
| | Génère plusieurs résultats |
| | |
| | Args: |
| | n: Nombre de générations |
| | max_length: Longueur maximale de chaque génération |
| | temperature: Contrôle la créativité |
| | |
| | Returns: |
| | Liste de textes générés |
| | """ |
| | return [self.generate(max_length, temperature) for _ in range(n)] |
| | |
| | def save_weights(self, filepath: str): |
| | """ |
| | Sauvegarde le modèle génératif dans un fichier |
| | |
| | Args: |
| | filepath: Chemin du fichier de sauvegarde (.npz) |
| | |
| | Example: |
| | >>> ai.save_weights('name_generator.npz') |
| | """ |
| | if not filepath.endswith('.npz'): |
| | filepath += '.npz' |
| | |
| | if not self.is_trained: |
| | print("⚠️ Attention: Le modèle n'est pas entraîné") |
| | |
| | save_data = { |
| | 'transition_matrix': self.transition_matrix, |
| | 'char_to_idx': np.array(list(self.char_to_idx.items()), dtype=object), |
| | 'idx_to_char': np.array(list(self.idx_to_char.items()), dtype=object), |
| | 'mode': np.array([self.mode]), |
| | 'is_trained': np.array([self.is_trained]) |
| | } |
| | |
| | np.savez(filepath, **save_data) |
| | print(f"✓ Modèle génératif sauvegardé dans '{filepath}'") |
| | |
| | def load_weights(self, filepath: str): |
| | """ |
| | Charge un modèle génératif depuis un fichier |
| | |
| | Args: |
| | filepath: Chemin du fichier de sauvegarde (.npz) |
| | |
| | Example: |
| | >>> ai = sitiai.create.ai('generative') |
| | >>> ai.load_weights('name_generator.npz') |
| | """ |
| | if not filepath.endswith('.npz'): |
| | filepath += '.npz' |
| | |
| | data = np.load(filepath, allow_pickle=True) |
| | |
| | self.transition_matrix = data['transition_matrix'] |
| | self.char_to_idx = dict(data['char_to_idx']) |
| | self.idx_to_char = {int(k): v for k, v in data['idx_to_char']} |
| | self.mode = str(data['mode'][0]) |
| | self.is_trained = bool(data['is_trained'][0]) |
| | |
| | print(f"✓ Modèle génératif chargé depuis '{filepath}'") |
| | |
| | def __repr__(self): |
| | status = "entraîné" if self.is_trained else "non entraîné" |
| | return f"GenerativeAI(mode='{self.mode}', status='{status}')" |
| |
|