from jyquickhelper import add_notebook_menu
add_notebook_menu()

"""
Explanation: Reconstruction de synonymes - correction
On s'intéresse la construction automatiquement de synonymes. En résumé :

les synonymes via la base WOLF
on ne garde que les synonymes composé d'un seul mot
on prend ensuite un texte quelconque qu'on découpe en phrase
pour chaque phrase qu'on rencontre, on remplace des mots au hasard par leur synonymes
chaque phrase sera présente une fois à l'identique et plusieurs fois avec des synonymes différents

L'objectif est alors de proposer une méthode pour reconstruire la base de synonymes.
End of explanation
"""


from actuariat_python.data import wolf_xml
wolf_xml()

import os
if not os.path.exists("wolf-1.0b4.xml"):
    raise FileNotFoundError("wolf-1.0b4.xml")
if os.stat("wolf-1.0b4.xml").st_size < 3000000:
    raise FileNotFoundError("Size of 'wolf-1.0b4.xml' is very small: {0}".format(os.stat("wolf-1.0b4.xml").st_size))

from actuariat_python.data import enumerate_wolf_synonyms
for syn in enumerate_wolf_synonyms("wolf-1.0b4.xml", errors="ignore"):
    print(syn)
    break

"""
Explanation: Génération des données
Construction de la base de synonymes
End of explanation
"""


allsyn = {}
for line, syn in enumerate(enumerate_wolf_synonyms("wolf-1.0b4.xml")):
    if line % 10000 == 0: print("line", line, "allsyn", len(allsyn))
    clean = [_.lower() for _ in syn if " " not in _]
    if len(clean) > 1:
        for word in clean:
            if word not in allsyn:
                allsyn[word] = set(clean)
                continue
            else:
                for cl in clean:
                    allsyn[word].add(cl)
    if len(allsyn) > 10000:
        break
len(allsyn)

"""
Explanation: On passe en revue toute la basse (il y a environ 120.000 lignes) et on s'arrête après 10000 synonymes car sinon, cela prend un temps fou.
End of explanation
"""


i = 0
for k, v in allsyn.items():
    print(k,v)
    i += 1
    if i > 10:
        break

"""
Explanation: On affiche les premiers groupes :
End of explanation
"""


import urllib.request
with urllib.request.urlopen("http://www.gutenberg.org/cache/epub/4647/pg4647.txt") as u:
    content = u.read()

char = content.decode(encoding="utf-8")

"""
Explanation: Génération d'une base de phrases modifiées
On utilise Zadig.
End of explanation
"""


import re
reg = re.compile("([- a-zA-Zâàäéèëêîïôöùûü']+)")
phrases = [_.lower() for _ in reg.findall(char)]

for i, phrase in enumerate(phrases):
    if i >= 990:
        print(phrase)
    if i >= 1000:
        break

"""
Explanation: On découpe en mot.
End of explanation
"""


import random
def modification(phrase, allsyn, nmax=10):
    mots = phrase.split()
    options = []
    nb = 1
    for mot in mots:
        if mot in allsyn:
            options.append(list(set([mot] + list(allsyn[mot]))))
        else:
            options.append([mot])
        nb *= len(options[-1])
    if nb == 1:
        return [phrase]
    else:
        res = []
        for i in range(0, min(nmax, nb//2+1, nb)):
            sol = []
            for mot in options:
                h = random.randint(0, len(mot)-1)
                sol.append(mot[h])
            res.append(sol)
        return res
            
modification("chatouiller le cérébral", allsyn)

"""
Explanation: On génère les phrases modifiées :
End of explanation
"""


len(phrases)

with open("zadig_augmente.txt", "w", encoding="utf-8") as f:
    total = 0
    init = 0
    for i, phrase in enumerate(phrases):
        augm = modification(phrase, allsyn)
        init += 1
        for au in augm:
            f.write(" ".join(au) + "\n")
            total += 1
"total", total, "initial", init

"""
Explanation: On traite tous les mots :
End of explanation
"""


from pyensae.datasource import download_data
download_data("zadig_augmente.zip")

"""
Explanation: Exercice : retrouver une partie des synonymes à partir du dernier fichier créé
Le fichier utilisé peut être généré à partir du code précédent ou utiliser cette version : zadig_augmente.zip.
End of explanation
"""


with open("zadig_augmente.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()
len(lines)

lines[10000:10005]

"""
Explanation: On lit le texte pour voir un peu de qu'il contient :
End of explanation
"""


lines = [ line.strip("\n \t\r") for line in lines ]
lines[10000:10005]

"""
Explanation: On supprime les caractères indésirables avec la fonction strip :
End of explanation
"""


from pyquickhelper.helpgen import NbImage
NbImage("synoym.png")

"""
Explanation: Pour détecter les synonymes, on imagine le processus suivant qu'on pourra améliorer au vu des premiers résultats :
End of explanation
"""


garde = []
for line in lines:
    nbchar = len(line.replace(" ", ""))
    nbword = len(line.split())
    if nbchar > nbword:
        garde.append(line)
len(garde), len(lines)

garde[:5]

"""
Explanation: On supprime les phrases qui incluent des espaces entre chaque lettre. On a la choix entre les garder, les jeter ou les corriger. On choisit l'option la plus simple : les jeter quitte à y revenir plus tard. Si un espace existe en chaque lettre, cela veut que le nombre de lettres (sans espace) est égal au nombre de mot.
End of explanation
"""


mots = [line.split() for line in garde]
mots[:5]

"""
Explanation: On découpe en mot avec la fonction split :
End of explanation
"""


def pourcentage_mots_communs(p1, p2):
    n = 0
    for p in p1:
        if p in p2:
            n += 1
    return n * 1.0 / max(len(p1),len(p2))

p1, p2 = mots[0:2]
print(p1)
print(p2)
pourcentage_mots_communs(p1, p2)

"""
Explanation: On code les petits bouts :
End of explanation
"""


def mots_differents(p1, p2):
    diff1 = []
    for p in p1:
        if p not in p2:
            diff1.append(p)
    diff2 = []
    for p in p2:
        if p not in p1:
            diff2.append(p)
    return diff1, diff2

#p1, p2 = mots[0:2]
p1, p2 = ["a", "a", "b", "c"], ["a", "f", "g"]
print(p1)
print(p2)
mots_differents(p1, p2)

"""
Explanation: Et l'autre :
End of explanation
"""


for i in range(0,len(mots)):
    p1 = mots[i]
    p2 = mots[i+1]
    print("----")
    print(p1)
    print(p2)
    print(pourcentage_mots_communs(p1,p2))
    print(mots_differents(p1,p2))
    if i > 3 :
        break

"""
Explanation: Pour la boucle final, on procède par étape, on affiche des résultats intermédiaires :
End of explanation
"""


compteur = {}
for i in range(0,len(mots)-1):
    p1 = mots[i]
    p2 = mots[i+1]
    if pourcentage_mots_communs(p1, p2) >= 0.5:
        diff1, diff2 = mots_differents(p1, p2)
        if len(diff1) == len(diff2) == 1:
            m1 = diff1[0]
            m2 = diff2[0]
            l = [m1, m2]
            l.sort()  # on trie les deux mots pour aggréger les deux paires m1, m2 et m2, m1
            key = tuple(l)  # une liste ne peut être la clé d'un dictionnaire
            if key not in compteur:
                compteur[key] = 0
            compteur[key] += 1

"""
Explanation: On complète cette première boucle en supposant qu'une bonne paire de synonymes doit provenir d'une paire de mots ayant en pourcentage de mots communs supérieur à 50% et une seule paire de synonymes :
End of explanation
"""


l = [ (compteur[k],k) for k in compteur]
l[:5]

l.sort(reverse=True)
l[:20]

"""
Explanation: On regarde le résultat en triant par ordre de fréquence décroissante :
End of explanation
"""


allsyn.get("lombric", None)

allsyn.get("flétan", None)

allsyn.get("niet", None)

"""
Explanation: Vérifications
Ces mots ne paraissent pas très pertinents au regard de la langue française. La méthode est néanmoins valable si elle permet de retrouver des synonymes qui ont permis de générer ce texte zadig_augmente.txt.
End of explanation
"""


stopwords = {"de", "ou", "a", "un", "du"}
compteur = {}
for i in range(0,len(mots)-1):
    p1 = mots[i]
    p2 = mots[i+1]
    if pourcentage_mots_communs(p1, p2) >= 0.5:
        diff1, diff2 = mots_differents(p1, p2)
        if len(diff1) == len(diff2) == 1:
            m1 = diff1[0]
            m2 = diff2[0]
            if m1 not in  stopwords and m2 not in stopwords:
                l = [m1, m2]
                l.sort()
                key = tuple(l)
                if key not in compteur:
                    compteur[key] = 0
                compteur[key] += 1

l = [ (compteur[k],k) for k in compteur]
l.sort(reverse=True)
l[:20]

"""
Explanation: Améliorations
stop words
End of explanation
"""


stopwords = {"de", "ou", "a", "un", "du"}
compteur = {}
for i in range(0,len(mots)-1):
    p1 = mots[i]
    for k in range(0,10):
        if i+k >= len(mots):
            break
        p2 = mots[i+k]
        if pourcentage_mots_communs(p1, p2) >= 0.5:
            diff1, diff2 = mots_differents(p1, p2)
            if len(diff1) == len(diff2) == 1:
                m1 = diff1[0]
                m2 = diff2[0]
                if m1 not in  stopwords and m2 not in stopwords:
                    l = [m1, m2]
                    l.sort()
                    key = tuple(l)
                    if key not in compteur:
                        compteur[key] = 0
                    compteur[key] += 1

l = [ (compteur[k],k) for k in compteur]
l.sort(reverse=True)
l[:20]

"""
Explanation: prise en compte de plus ligne
Et pas seulement deux lignes consécutives
End of explanation
"""


