File size: 8,608 Bytes
12fb52c
 
 
73da356
12fb52c
 
e5b4007
8775026
 
 
 
 
 
 
 
12fb52c
 
 
9bdae24
e5b4007
73da356
12fb52c
aa38f56
e5b4007
 
 
38d62de
 
9bdae24
e5b4007
 
 
d4108c0
12fb52c
9bdae24
 
 
 
 
9cf77d0
9bdae24
8775026
12fb52c
8775026
9bdae24
9cf77d0
8775026
 
 
 
 
 
9cf77d0
8775026
9bdae24
 
12fb52c
 
 
 
 
 
 
 
 
9bdae24
c09849c
 
9cf77d0
 
e5b4007
c09849c
e5b4007
c09849c
 
 
9cf77d0
 
 
c09849c
9cf77d0
c09849c
 
 
 
9cf77d0
e5b4007
12fb52c
8c2b49e
78d147f
12fb52c
9cf77d0
e5b4007
12fb52c
 
 
 
 
 
e5b4007
 
 
c09849c
9cf77d0
c09849c
e5b4007
 
c09849c
 
12fb52c
9cf77d0
e5b4007
c09849c
e5b4007
d4108c0
 
c09849c
12fb52c
e5b4007
d4108c0
9cf77d0
d4108c0
 
e5b4007
 
9cf77d0
e5b4007
8c2b49e
12fb52c
 
 
 
 
 
 
 
 
 
9cf77d0
12fb52c
9cf77d0
12fb52c
 
 
 
 
 
 
 
9cf77d0
12fb52c
38d62de
9cf77d0
38d62de
8c2b49e
9bdae24
9cf77d0
 
38d62de
 
8c2b49e
e5b4007
9cf77d0
 
 
38d62de
 
9cf77d0
 
 
 
 
 
 
38d62de
 
9cf77d0
 
e5b4007
38d62de
 
 
9cf77d0
 
12fb52c
 
 
 
9cf77d0
e5b4007
9cf77d0
 
 
 
12fb52c
9cf77d0
 
12fb52c
 
9cf77d0
 
 
 
 
 
12fb52c
 
 
 
 
 
 
 
8c2b49e
12fb52c
 
 
 
 
 
 
 
e5b4007
12fb52c
 
9bdae24
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
import gradio as gr
from transformers import pipeline
from langdetect import detect
from huggingface_hub import InferenceClient
import pandas as pd
import os
import asyncio
import nltk
from nltk.tokenize import sent_tokenize

# Téléchargement de punkt_tab avec gestion d'erreur
try:
    nltk.download('punkt_tab', download_dir='/usr/local/share/nltk_data')
except Exception as e:
    raise Exception(f"Erreur lors du téléchargement de punkt_tab : {str(e)}. Veuillez vérifier votre connexion réseau et les permissions du répertoire /usr/local/share/nltk_data.")

HF_TOKEN = os.getenv("HF_TOKEN")

# Fonction pour appeler l'API Zephyr avec des paramètres ajustés
async def call_zephyr_api(prompt, mode, hf_token=HF_TOKEN):
    client = InferenceClient("HuggingFaceH4/zephyr-7b-beta", token=hf_token)
    try:
        if mode == "Rapide":
            max_new_tokens = 50
            temperature = 0.3
        elif mode == "Équilibré":
            max_new_tokens = 100
            temperature = 0.5
        else:  # Précis
            max_new_tokens = 150
            temperature = 0.7
        response = await asyncio.to_thread(client.text_generation, prompt, max_new_tokens=max_new_tokens, temperature=temperature)
        return response
    except Exception as e:
        raise gr.Error(f"❌ Erreur d'appel API Hugging Face : {str(e)}")

# Chargement du modèle de sentiment pour analyser les réponses
classifier = pipeline("sentiment-analysis", model="mrm8488/distilroberta-finetuned-financial-news-sentiment-analysis")

# Modèles de traduction
translator_to_en = pipeline("translation", model="Helsinki-NLP/opus-mt-mul-en")
translator_to_fr = pipeline("translation", model="Helsinki-NLP/opus-mt-en-fr")

# Traduction en français avec Helsinki-NLP
def safe_translate_to_fr(text, max_length=512):
    try:
        sentences = sent_tokenize(text)
        translated_sentences = []
        for sentence in sentences:
            translated = translator_to_fr(sentence, max_length=max_length)[0]['translation_text']
            translated_sentences.append(translated)
        return " ".join(translated_sentences)
    except Exception as e:
        return f"Erreur de traduction : {str(e)}"

# Fonction pour suggérer le meilleur modèle
def suggest_model(text):
    word_count = len(text.split())
    if word_count < 50:
        return "Rapide"
    elif word_count <= 200:
        return "Équilibré"
    else:
        return "Précis"

# Fonction pour créer une jauge de sentiment
def create_sentiment_gauge(sentiment, score):
    score_percentage = score * 100
    color = "#A9A9A9"
    if sentiment.lower() == "positive":
        color = "#2E8B57"
    elif sentiment.lower() == "negative":
        color = "#DC143C"

    html = f"""
    <div style='width: 100%; max-width: 300px; margin: 10px 0;'>
        <div style='background-color: #D3D3D3; border-radius: 5px; height: 20px; position: relative;'>
            <div style='background-color: {color}; width: {score_percentage}%; height: 100%; border-radius: 5px;'></div>
            <span style='position: absolute; top: 0; left: 50%; transform: translateX(-50%); font-weight: bold;'>{score_percentage:.1f}%</span>
        </div>
        <div style='text-align: center; margin-top: 5px;'>Sentiment : {sentiment}</div>
    </div>
    """
    return html

# Fonction d'analyse
async def full_analysis(text, mode, detail_mode, count, history):
    if not text:
        yield "Entrez une phrase.", "", "", "", 0, history, "", "Aucune analyse effectuée."
        return

    yield "Analyse en cours... (Étape 1 : Détection de la langue)", "", "", "", count, history, "", "Détection de la langue"

    try:
        lang = detect(text)
    except:
        lang = "unknown"

    if lang != "en":
        text_en = translator_to_en(text, max_length=512)[0]['translation_text']
    else:
        text_en = text

    yield "Analyse en cours... (Étape 2 : Analyse du sentiment)", "", "", "", count, history, "", "Analyse du sentiment"

    result = await asyncio.to_thread(classifier, text_en)
    result = result[0]
    sentiment_output = f"Sentiment prédictif : {result['label']} (Score: {result['score']:.2f})"
    sentiment_gauge = create_sentiment_gauge(result['label'], result['score'])

    yield "Analyse en cours... (Étape 3 : Explication IA)", "", "", "", count, history, "", "Génération de l'explication"

    explanation_prompt = f"""<|system|>
You are a professional financial analyst AI with expertise in economic forecasting.
</s>
<|user|>
Given the following question about a potential economic event: "{text}"

The predicted sentiment for this event is: {result['label'].lower()}.

Assume the event happens. Explain why this event would likely have a {result['label'].lower()} economic impact.
</s>
<|assistant|>"""
    explanation_en = await call_zephyr_api(explanation_prompt, mode)

    yield "Analyse en cours... (Étape 4 : Traduction en français)", "", "", "", count, history, "", "Traduction en français"

    explanation_fr = safe_translate_to_fr(explanation_en)

    count += 1
    history.append({
        "Texte": text,
        "Sentiment": result['label'],
        "Score": f"{result['score']:.2f}",
        "Explication_EN": explanation_en,
        "Explication_FR": explanation_fr
    })

    yield sentiment_output, text, explanation_en, explanation_fr, count, history, sentiment_gauge, "✅ Analyse terminée."

# Historique CSV
def download_history(history):
    if not history:
        return None
    df = pd.DataFrame(history)
    file_path = "/tmp/analysis_history.csv"
    df.to_csv(file_path, index=False)
    return file_path

# Lancement Gradio avec l'interface restaurée
def launch_app():
    custom_css = """
    /* CSS restauré à la version précédente, avant les changements esthétiques non demandés */
    body {
        background: linear-gradient(135deg, #0A1D37 0%, #1A3C34 100%);
        font-family: 'Inter', sans-serif;
        color: #E0E0E0;
        padding: 20px;
    }
    .gr-box {
        background: #2A4A43 !important;
        border: 1px solid #FFD700 !important;
        border-radius: 12px !important;
        padding: 20px !important;
        box-shadow: 0px 4px 12px rgba(255, 215, 0, 0.4);
    }
    .gr-button {
        background: linear-gradient(90deg, #FFD700, #D4AF37);
        color: #0A1D37;
        font-weight: bold;
        border: none;
        border-radius: 8px;
        padding: 12px 24px;
        transition: transform 0.2s;
    }
    .gr-button:hover {
        transform: translateY(-2px);
        box-shadow: 0 6px 12px rgba(255, 215, 0, 0.5);
    }
    """

    with gr.Blocks(theme=gr.themes.Base(), css=custom_css) as iface:
        gr.Markdown("# 📈 Analyse Financière Premium avec IA")
        gr.Markdown("**Posez une question économique.** L'IA analyse et explique l'impact.")

        count = gr.State(0)
        history = gr.State([])

        with gr.Row():
            with gr.Column(scale=2):
                input_text = gr.Textbox(lines=4, label="Votre question économique")
            with gr.Column(scale=1):
                mode_selector = gr.Dropdown(choices=["Rapide", "Équilibré", "Précis"], value="Équilibré", label="Mode de réponse")
                detail_mode_selector = gr.Dropdown(choices=["Normal", "Expert"], value="Normal", label="Niveau de détail")

        analyze_btn = gr.Button("Analyser")
        download_btn = gr.Button("Télécharger l'historique")

        with gr.Row():
            sentiment_output = gr.Textbox(label="Sentiment prédictif")
            displayed_prompt = gr.Textbox(label="Votre question", interactive=False)
            explanation_output_en = gr.Textbox(label="Explication en anglais")
            explanation_output_fr = gr.Textbox(label="Explication en français")
            sentiment_gauge = gr.HTML()
            progress_message = gr.Textbox(label="Progression", interactive=False)

        download_file = gr.File(label="Fichier CSV")

        input_text.change(lambda t: gr.update(value=suggest_model(t)), inputs=[input_text], outputs=[mode_selector])

        analyze_btn.click(
            full_analysis,
            inputs=[input_text, mode_selector, detail_mode_selector, count, history],
            outputs=[sentiment_output, displayed_prompt, explanation_output_en, explanation_output_fr, count, history, sentiment_gauge, progress_message]
        )

        download_btn.click(
            download_history,
            inputs=[history],
            outputs=[download_file]
        )

    iface.launch(share=True)

if __name__ == "__main__":
    launch_app()