guineapular 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ include data/*.json
2
+ recursive-include pular_core *.py
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: guineapular
3
+ Version: 1.0.0
4
+ Summary: Le cerveau déterministe de l'IA Pular-Learning
5
+ Author: Keit Xellker & User
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Operating System :: OS Independent
8
+ Requires-Python: >=3.6
9
+ Requires-Dist: setuptools
10
+ Requires-Dist: fastapi
11
+ Requires-Dist: uvicorn
12
+ Dynamic: author
13
+ Dynamic: classifier
14
+ Dynamic: requires-dist
15
+ Dynamic: requires-python
16
+ Dynamic: summary
@@ -0,0 +1,36 @@
1
+ # guineapular 🌍
2
+
3
+ Le cerveau déterministe de l'IA Pular-Learning.
4
+
5
+ `guineapular` est une bibliothèque Python spécialisée dans la traduction et la discussion en Pular (Guinée), basée sur une architecture de racines courtes et un moteur morphologique précis.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install guineapular
11
+ ```
12
+
13
+ ## Utilisation Rapide
14
+
15
+ ```python
16
+ from pular_core.api import PularCoreAPI
17
+
18
+ # Initialisation
19
+ api = PularCoreAPI()
20
+
21
+ # Mode Traduction
22
+ print(api.translate_simple("cle-api", 0, "manger", "present"))
23
+
24
+ # Mode Discussion (Sarah)
25
+ response = api.chat("cle-api", "Comment ça va ?")
26
+ print(response['sarah_response'])
27
+ ```
28
+
29
+ ## Fonctionnalités
30
+ - **Précision Chirurgicale** : Pas de LLM, pas d'hallucinations.
31
+ - **Morpho Engine** : Gestion automatique des suffixes (-ugol, -gol, -agol).
32
+ - **Sarah Persona** : Module d'émotions et d'opinions intégré.
33
+ - **Sécurité** : Gatekeeper avec système de crédits.
34
+
35
+ ## Auteurs
36
+ Développé par Sarah Xellker & User.
@@ -0,0 +1,12 @@
1
+ {
2
+ "admin-key-99": {
3
+ "owner": "Admin",
4
+ "credits": 9999,
5
+ "active": true
6
+ },
7
+ "user-key-test": {
8
+ "owner": "Tester",
9
+ "credits": 50,
10
+ "active": true
11
+ }
12
+ }
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: guineapular
3
+ Version: 1.0.0
4
+ Summary: Le cerveau déterministe de l'IA Pular-Learning
5
+ Author: Keit Xellker & User
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Operating System :: OS Independent
8
+ Requires-Python: >=3.6
9
+ Requires-Dist: setuptools
10
+ Requires-Dist: fastapi
11
+ Requires-Dist: uvicorn
12
+ Dynamic: author
13
+ Dynamic: classifier
14
+ Dynamic: requires-dist
15
+ Dynamic: requires-python
16
+ Dynamic: summary
@@ -0,0 +1,16 @@
1
+ MANIFEST.in
2
+ README.md
3
+ setup.py
4
+ data/auth_registry.json
5
+ guineapular.egg-info/PKG-INFO
6
+ guineapular.egg-info/SOURCES.txt
7
+ guineapular.egg-info/dependency_links.txt
8
+ guineapular.egg-info/requires.txt
9
+ guineapular.egg-info/top_level.txt
10
+ pular_core/__init__.py
11
+ pular_core/api.py
12
+ pular_core/auth.py
13
+ pular_core/context.py
14
+ pular_core/engine.py
15
+ pular_core/knowledge.py
16
+ pular_core/validator.py
@@ -0,0 +1,3 @@
1
+ setuptools
2
+ fastapi
3
+ uvicorn
@@ -0,0 +1 @@
1
+ pular_core
@@ -0,0 +1 @@
1
+ # pular_core package initialization
@@ -0,0 +1,126 @@
1
+ from .knowledge import PularKnowledge
2
+ from .engine import PularEngine
3
+ from .validator import PularValidator
4
+ from .context import PularContextAnalyzer
5
+ from .auth import AuthPaywall
6
+
7
+ class PularCoreAPI:
8
+ """
9
+ Interface unifiée du service Xellker Pular Core (v1.0).
10
+ Fait le pont entre les 4 Sous-Programmes.
11
+ """
12
+
13
+ def __init__(self, dictionary_path=None):
14
+ self.knowledge = PularKnowledge(dictionary_path)
15
+ self.engine = PularEngine(self.knowledge)
16
+ self.context = PularContextAnalyzer(self.engine, self.knowledge)
17
+ self.auth = AuthPaywall()
18
+ self.validator = PularValidator()
19
+
20
+ def _gatekeeper(self, api_key, word_count=1):
21
+ """
22
+ Gatekeeper (Sous-Programme 4) :
23
+ Refuse l'exécution si l'utilisateur n'a pas payé ou n'a plus de crédits.
24
+ """
25
+ if not self.auth.validate_key(api_key):
26
+ return {"error": "Invalid or inactive API Key. Access Denied."}
27
+
28
+ if not self.auth.deduct_credits(api_key, word_count):
29
+ return {"error": "Insufficient credits. Please top up your account."}
30
+
31
+ return None
32
+
33
+ def translate_simple(self, api_key, subject_idx, verb_french, tense_key, is_negative=False):
34
+ """Traduction simple avec Gatekeeper."""
35
+ gate_status = self._gatekeeper(api_key, 1)
36
+ if gate_status: return gate_status
37
+
38
+ raw_translation = self.engine.translate_simple_sentence(
39
+ subject_idx, verb_french, tense_key, is_negative
40
+ )
41
+ return self.validator.normalize_typography(raw_translation)
42
+
43
+ def translate_dual(self, api_key, subject_idx, v1_french, v2_french, tense_key):
44
+ """Traduction double verbe (Successivité) avec Gatekeeper."""
45
+ gate_status = self._gatekeeper(api_key, 2)
46
+ if gate_status: return gate_status
47
+
48
+ raw_translation = self.context.resolve_double_verb(
49
+ subject_idx, v1_french, v2_french, tense_key
50
+ )
51
+ return self.validator.normalize_typography(raw_translation)
52
+
53
+ def translate_with_object(self, api_key, subject_idx, verb_french, tense_key, object_key):
54
+ """Traduction avec pronom objet (-lan, -ma) avec Gatekeeper."""
55
+ gate_status = self._gatekeeper(api_key, 2)
56
+ if gate_status: return gate_status
57
+
58
+ raw_translation = self.context.apply_object_suffix(
59
+ verb_french, subject_idx, tense_key, object_key
60
+ )
61
+ return self.validator.normalize_typography(raw_translation)
62
+
63
+ def get_identity(self, api_key, term, is_negative=False):
64
+ """Identité & Beauté avec Gatekeeper."""
65
+ gate = self._gatekeeper(api_key, 1)
66
+ if gate: return gate
67
+ return self.context.handle_identity(term, is_negative)
68
+
69
+ def get_ethical_eval(self, api_key, is_good=True):
70
+ """Éthique (Sarah) avec Gatekeeper."""
71
+ gate = self._gatekeeper(api_key, 1)
72
+ if gate: return gate
73
+ return self.context.evaluate_ethics(is_good)
74
+
75
+ def chat(self, api_key, message_french):
76
+ """
77
+ Porte DISCUSSION (/chat) : Sarah Xellker v1.0.
78
+ Gère les intentions et simule une mémoire contextuelle.
79
+ """
80
+ gate = self._gatekeeper(api_key, 1)
81
+ if gate: return gate
82
+
83
+ # 1. Normalisation
84
+ message = message_french.lower()
85
+ for char in "?!.,": message = message.replace(char, "")
86
+ key = message.strip().replace(" ", "_")
87
+
88
+ # 2. Logique Contextuelle (Action-Réaction)
89
+ # On vérifie d'abord les correspondances directes (Salutations, Accords)
90
+ response = self.context.get_conversation_pair(key)
91
+ if response:
92
+ return {
93
+ "status": "success",
94
+ "intent": "conversation",
95
+ "sarah_response": self.validator.normalize_typography(response),
96
+ "mood": "friendly"
97
+ }
98
+
99
+ # 3. Logique d'Emotion/Opinion (Sarah vivante)
100
+ for section in ["opinion", "emotion", "duration"]:
101
+ data = self.knowledge.find_in_lexicon(section, key)
102
+ if data:
103
+ return {
104
+ "status": "success",
105
+ "intent": section,
106
+ "sarah_response": self.validator.normalize_typography(data),
107
+ "mood": "vibrant"
108
+ }
109
+
110
+ # 4. Fallback (Tentative de traduction ou aveu d'ignorance)
111
+ return {
112
+ "status": "success",
113
+ "intent": "unknown",
114
+ "sarah_response": self.validator.normalize_typography(self.knowledge.find_in_lexicon("conversation", "je_ne_sais_pas")),
115
+ "mood": "puzzled"
116
+ }
117
+
118
+ def get_lexicon_term(self, api_key, category, term):
119
+ """Récupération de terme lexique avec Gatekeeper."""
120
+ gate_status = self._gatekeeper(api_key, 1)
121
+ if gate_status: return gate_status
122
+
123
+ data = self.knowledge.find_in_lexicon(category, term)
124
+ if isinstance(data, dict):
125
+ return data.get("pular", data.get("nom", str(data)))
126
+ return data
@@ -0,0 +1,65 @@
1
+ import secrets
2
+ import json
3
+ import os
4
+
5
+ class AuthPaywall:
6
+ """
7
+ La Couche Business & Sécurité (Sub-Programme 4).
8
+ Gère la monétisation, les clés API et le décompte des crédits.
9
+ """
10
+
11
+ def __init__(self, auth_file="data/auth_registry.json"):
12
+ self.auth_file = auth_file
13
+ self.registry = self._load_registry()
14
+
15
+ def _load_registry(self):
16
+ if not os.path.exists(self.auth_file):
17
+ # Création d'un registre par défaut pour les tests
18
+ os.makedirs(os.path.dirname(self.auth_file), exist_ok=True)
19
+ default_registry = {
20
+ "admin-key-99": {"owner": "Admin", "credits": 9999, "active": True},
21
+ "user-key-test": {"owner": "Tester", "credits": 50, "active": True}
22
+ }
23
+ with open(self.auth_file, "w") as f:
24
+ json.dump(default_registry, f, indent=2)
25
+ return default_registry
26
+
27
+ with open(self.auth_file, "r") as f:
28
+ return json.load(f)
29
+
30
+ def save_registry(self):
31
+ with open(self.auth_file, "w") as f:
32
+ json.dump(self.registry, f, indent=2)
33
+
34
+ def generate_key(self, owner, initial_credits=100):
35
+ """Génère un identifiant unique pour un nouveau client."""
36
+ new_key = f"xell-{secrets.token_hex(4)}"
37
+ self.registry[new_key] = {
38
+ "owner": owner,
39
+ "credits": initial_credits,
40
+ "active": True
41
+ }
42
+ self.save_registry()
43
+ return new_key
44
+
45
+ def validate_key(self, api_key):
46
+ """Vérifie si la clé est valide et active."""
47
+ return api_key in self.registry and self.registry[api_key]["active"]
48
+
49
+ def deduct_credits(self, api_key, word_count):
50
+ """Décompte chaque mot traduit du crédit de l'utilisateur."""
51
+ if not self.validate_key(api_key):
52
+ return False
53
+
54
+ current_credits = self.registry[api_key]["credits"]
55
+ if current_credits < word_count:
56
+ return False # Solde insuffisant
57
+
58
+ self.registry[api_key]["credits"] -= word_count
59
+ self.save_registry()
60
+ return True
61
+
62
+ def get_remaining_credits(self, api_key):
63
+ if self.validate_key(api_key):
64
+ return self.registry[api_key]["credits"]
65
+ return 0
@@ -0,0 +1,89 @@
1
+ import logging
2
+
3
+ logger = logging.getLogger(__name__)
4
+
5
+ class PularContextAnalyzer:
6
+ """
7
+ L'Analyseur de Contexte (Sub-Programme 3).
8
+ Gère les règles de successivité, les objets directes et les nuances sémantiques.
9
+ """
10
+
11
+ def __init__(self, engine, knowledge):
12
+ self.engine = engine
13
+ self.knowledge = knowledge
14
+
15
+ def apply_object_suffix(self, verb_french, person_idx_subject, tense_key, object_person_key):
16
+ """
17
+ Gère l'objet : Coller les suffixes -lan (moi) ou -ma (toi) directement après la racine.
18
+ """
19
+ verb_data = self.knowledge.get_verb_data(verb_french)
20
+ if not verb_data:
21
+ return None
22
+
23
+ root = verb_data["root"]
24
+ obj_suffix = self.knowledge.data.get("grammar", {}).get("pronoms_objet", {}).get(object_person_key)
25
+
26
+ if not obj_suffix:
27
+ return self.engine.conjugate(verb_french, tense_key, person_idx_subject)
28
+
29
+ # Le pronom sujet reste celui de la règle générale
30
+ # Le suffixe de conjugaison vient APRES l'objet?
31
+ # En Pular, c'est Racine + Objet + Suffixe (souvent)
32
+ # Mais le user dit: "Coller les suffixes -lan (moi) ou -ma (toi) directement après la racine."
33
+
34
+ pronom_sujet = self.engine.conjugate(verb_french, tense_key, person_idx_subject).split(" ")[0]
35
+ conj_suffix = self.knowledge.get_suffix(tense_key if tense_key != "present" else "present")
36
+
37
+ # Simplification selon instruction user: Racine + Objet
38
+ # Ex: Mi gnam-lan (Je me mange?) -> Plus réaliste: A gnam-lan (Tu me manges)
39
+ # On va suivre l'instruction: "Coller ... directement après la racine"
40
+ return f"{pronom_sujet} {root}{obj_suffix}{conj_suffix if conj_suffix else ''}"
41
+
42
+ def resolve_double_verb(self, subject_idx, v1_french, v2_french, tense_key):
43
+ """Règle du Double Verbe : Verbe 1 conjugué, Verbe 2 en -gol."""
44
+ return self.engine.apply_successivity([v1_french, v2_french], subject_idx, tense_key)
45
+
46
+ def handle_identity(self, term, is_negative=False):
47
+ """Gère le module Identité et la logique de classe adjectivale."""
48
+ data = self.knowledge.find_in_lexicon("identity", term)
49
+ if not data: return None
50
+
51
+ if isinstance(data, dict) and "root" in data:
52
+ # Logique d'adjectif (ex: Labba-)
53
+ root = data["root"]
54
+ if is_negative:
55
+ return f"{root}{data.get('negation', 'ta')}"
56
+ return f"{root}" # En Pular, la racine peut être l'état
57
+
58
+ return data
59
+
60
+ def evaluate_ethics(self, is_good=True):
61
+ """Module Éthique (Sarah's Ethics)."""
62
+ section = self.knowledge.find_in_lexicon("ethics", "bien_bon" if is_good else "mal_mauvais")
63
+ return section
64
+
65
+ def get_conversation_pair(self, word_french):
66
+ """Action-Réaction logic for conversation module."""
67
+ data = self.knowledge.find_in_lexicon("conversation", word_french)
68
+ if not data: return None
69
+
70
+ if isinstance(data, dict):
71
+ return data.get("pular")
72
+ return data
73
+
74
+ def handle_nuance(self, word_french):
75
+ """
76
+ Gestion des Nuances (Paires Critiques).
77
+ Ex: Weela (Faim), Welii (Doux), Welaa (Pas doux).
78
+ """
79
+ # On cherche d'abord dans les verbes, puis dans le lexique
80
+ # Cette partie sera enrichie selon les retours utilisateur
81
+ if word_french.lower() == "faim":
82
+ return "weela"
83
+ if word_french.lower() == "doux":
84
+ return "welii"
85
+ if word_french.lower() == "pas doux":
86
+ return "welaa"
87
+
88
+ return self.knowledge.find_in_lexicon("quantities", word_french) \
89
+ or self.knowledge.find_in_lexicon("meteo", word_french)
@@ -0,0 +1,100 @@
1
+ import re
2
+ import logging
3
+
4
+ logger = logging.getLogger(__name__)
5
+
6
+ class PularEngine:
7
+ """
8
+ Le moteur déterministe de transformation linguistique.
9
+ Applique la matrice de conjugaison, les pronoms, la successivité verbale
10
+ et les règles syntaxiques (mots fantômes).
11
+ """
12
+
13
+ class PularEngine:
14
+ """
15
+ Le moteur déterministe de transformation linguistique.
16
+ Applique la matrice de conjugaison, les pronoms, la successivité verbale
17
+ et les règles syntaxiques.
18
+ """
19
+
20
+ def __init__(self, knowledge):
21
+ self.knowledge = knowledge
22
+
23
+ def get_infinitive(self, verb_french):
24
+ """Calcule l'infinitif selon l'Algorithme de l'Infinitif."""
25
+ verb_data = self.knowledge.get_verb_data(verb_french)
26
+ if not verb_data:
27
+ return None
28
+
29
+ root = verb_data["root"]
30
+ v_type = verb_data["type"] # type_1, type_2, type_3
31
+
32
+ if v_type == "type_1":
33
+ return f"{root}ugol"
34
+ elif v_type == "type_2":
35
+ return f"{root}gol"
36
+ elif v_type == "type_3":
37
+ return f"{root}agol"
38
+ return f"{root}gol" # Default
39
+
40
+ def conjugate(self, verb_french, tense_key, person_index, is_negative=False):
41
+ """
42
+ Applique les règles de conjugaison sur un verbe.
43
+ person_index: 0(1S) Ă  5(3P)
44
+ """
45
+ verb_data = self.knowledge.get_verb_data(verb_french)
46
+ if not verb_data:
47
+ logger.warning(f"Données inconnues pour le verbe : {verb_french}")
48
+ return verb_french
49
+
50
+ root = verb_data["root"]
51
+ v_type = verb_data["type"]
52
+ is_reflexive = (v_type == "type_3")
53
+
54
+ # Configuration par défaut
55
+ set_key = "set_A"
56
+ suffix_key = tense_key
57
+
58
+ if is_negative:
59
+ set_key = "set_A"
60
+ suffix_key = "negation"
61
+ elif tense_key == "present":
62
+ set_key = "set_B"
63
+ suffix_key = "present_reflexive" if is_reflexive else "present"
64
+ elif tense_key == "past":
65
+ set_key = "set_A"
66
+ suffix_key = "past_reflexive" if is_reflexive else "past"
67
+ elif tense_key == "futur":
68
+ set_key = "set_A"
69
+ suffix_key = "futur"
70
+
71
+ pronom = self.knowledge.get_subject_pronom(set_key, person_index)
72
+ suffix = self.knowledge.get_suffix(suffix_key)
73
+
74
+ if not pronom or suffix is None:
75
+ return f"{root}"
76
+
77
+ return f"{pronom} {root}{suffix}"
78
+
79
+ def apply_successivity(self, verbs_french, subject_idx, tense_key):
80
+ """
81
+ Applique la règle de successivité verbale :
82
+ V1 conjugué, V2+ à l'infinitif.
83
+ """
84
+ if not verbs_french:
85
+ return ""
86
+
87
+ results = []
88
+ # Premier verbe conjugué
89
+ results.append(self.conjugate(verbs_french[0], tense_key, subject_idx))
90
+
91
+ # Suivants Ă  l'infinitif
92
+ for v in verbs_french[1:]:
93
+ inf = self.get_infinitive(v)
94
+ results.append(inf if inf else v)
95
+
96
+ return " ".join(results)
97
+
98
+ def translate_simple_sentence(self, subject_idx, verb_french, tense_key, is_negative=False):
99
+ """Traduit une phrase simple Sujet + Verbe."""
100
+ return self.conjugate(verb_french, tense_key, subject_idx, is_negative)
@@ -0,0 +1,83 @@
1
+ import json
2
+ import os
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ class PularKnowledge:
8
+ """
9
+ Gère la Source de Vérité (Master Dictionary).
10
+ Responsable du chargement, de la sauvegarde, de la recherche de racines,
11
+ suffixes, pronoms et de la gestion de la polysémie.
12
+ """
13
+
14
+ def __init__(self, data_path=None):
15
+ if data_path is None:
16
+ # Recherche relative au fichier (pour support pip install)
17
+ base_dir = os.path.dirname(__file__)
18
+ data_path = os.path.join(base_dir, "data", "dictionary.json")
19
+ self.data_path = data_path
20
+ self.data = self._load_data()
21
+
22
+ def _load_data(self):
23
+ """Charge le dictionnaire JSON."""
24
+ if not os.path.exists(self.data_path):
25
+ logger.error(f"Fichier de données introuvable : {self.data_path}")
26
+ return {}
27
+ try:
28
+ with open(self.data_path, "r", encoding="utf-8") as f:
29
+ return json.load(f)
30
+ except Exception as e:
31
+ logger.error(f"Erreur lors du chargement du JSON : {e}")
32
+ return {}
33
+
34
+ def save_data(self):
35
+ """Sauvegarde les modifications dans le fichier JSON."""
36
+ try:
37
+ with open(self.data_path, "w", encoding="utf-8") as f:
38
+ json.dump(self.data, f, indent=2, ensure_ascii=False)
39
+ return True
40
+ except Exception as e:
41
+ logger.error(f"Erreur lors de la sauvegarde du JSON : {e}")
42
+ return False
43
+
44
+ def get_verb_data(self, french_verb):
45
+ """Récupère les données complètes d'un verbe (racine, type, catégorie)."""
46
+ return self.data.get("verbs", {}).get(french_verb.lower())
47
+
48
+ def get_verb_root(self, french_verb):
49
+ """Récupère la racine Pular d'un verbe français."""
50
+ data = self.get_verb_data(french_verb)
51
+ return data.get("root") if data else None
52
+
53
+ def get_suffix(self, suffix_key):
54
+ """Récupère un suffixe de grammaire."""
55
+ return self.data.get("grammar", {}).get("suffixes", {}).get(suffix_key)
56
+
57
+ def get_pronom_set(self, set_key):
58
+ """Récupère une liste de pronoms (set_A ou set_B)."""
59
+ return self.data.get("grammar", {}).get("pronoms_sujet", {}).get(set_key)
60
+
61
+ def get_subject_pronom(self, set_key, person_index):
62
+ """
63
+ Récupère le pronom spécifique pour une personne.
64
+ person_index: 0=1S, 1=2S, 2=3S, 3=1P, 4=2P, 5=3P
65
+ """
66
+ pronoms = self.get_pronom_set(set_key)
67
+ if pronoms and 0 <= person_index < len(pronoms):
68
+ return pronoms[person_index]
69
+ return None
70
+
71
+ def find_in_lexicon(self, section, key):
72
+ """Recherche dans le lexique (quantities, numbers, meteo, etc.)."""
73
+ return self.data.get("lexicon", {}).get(section, {}).get(key.lower())
74
+
75
+ def update_word(self, section, french_word, pular_data):
76
+ """Ajoute ou met Ă  jour un mot dans le lexique."""
77
+ if "lexicon" not in self.data:
78
+ self.data["lexicon"] = {}
79
+ if section not in self.data["lexicon"]:
80
+ self.data["lexicon"][section] = {}
81
+
82
+ self.data["lexicon"][section][french_word.lower()] = pular_data
83
+ return self.save_data()
@@ -0,0 +1,41 @@
1
+ import re
2
+
3
+ class PularValidator:
4
+ """
5
+ Assure la conformité typographique et le système de confiance.
6
+ """
7
+
8
+ def __init__(self):
9
+ # Caractères Pular spécifiques
10
+ self.pular_chars = {
11
+ 'b_impl': 'É“',
12
+ 'd_impl': 'É—',
13
+ 'y_impl': 'Ć´',
14
+ 'n_nasal': 'Ĺ‹',
15
+ 'ny': 'ñ'
16
+ }
17
+
18
+ def normalize_typography(self, text):
19
+ """
20
+ Remplace les tentatives de caractères Pular approximatifs par les officiels.
21
+ Note: Cette logique peut être étendue selon les besoins utilisateurs.
22
+ """
23
+ if not text:
24
+ return text
25
+
26
+ # Exemple de normalisation (Ă  enrichir via apprentissage)
27
+ # Ici on pourrait intégrer l'enforcement Mi do -> Mi ɗo
28
+ normalized = text.replace(" do", " É—o")
29
+ # On pourrait aussi mapper des combinaisons de touches spécifiques
30
+ return normalized
31
+
32
+ def validate_pular_entry(self, word):
33
+ """Vérifie si un mot contient les caractères attendus (aide à l'apprentissage)."""
34
+ # Logic pour suggérer ɗ au lieu de d si le dictionnaire l'indique
35
+ pass
36
+
37
+ def check_confidence(self, current_score, conflict=False):
38
+ """Gère l'évolution du score de confiance."""
39
+ if conflict:
40
+ return max(1, current_score - 1)
41
+ return min(5, current_score + 1)
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,20 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="guineapular",
5
+ version="1.0.0",
6
+ packages=find_packages(),
7
+ include_package_data=True,
8
+ install_requires=[
9
+ "setuptools",
10
+ "fastapi",
11
+ "uvicorn"
12
+ ],
13
+ author="Keit Xellker & User",
14
+ description="Le cerveau déterministe de l'IA Pular-Learning",
15
+ classifiers=[
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: OS Independent",
18
+ ],
19
+ python_requires='>=3.6',
20
+ )