File size: 7,001 Bytes
b0d9b56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import streamlit as st
import google.generativeai as genai
import os
from dotenv import load_dotenv
import http.client
import json
import shutil
import streamlit.components.v1 as components

# Charger les variables d'environnement
load_dotenv()
genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))

# Paramètres de sécurité
safety_settings = [
    {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
    {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
    {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"},
    {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
]

# Instructions système (inchangées pour brièveté)
ss = """
# Prompt System pour Mariam, IA conçu par youssouf 
[...]
"""

model = genai.GenerativeModel('gemini-2.0-flash-exp', tools='code_execution',
                              safety_settings=safety_settings,
                              system_instruction=ss)

# Fonctions de recherche web (inchangées)
def perform_web_search(query):
    conn = http.client.HTTPSConnection("google.serper.dev")
    payload = json.dumps({"q": query})
    headers = {'X-API-KEY': '9b90a274d9e704ff5b21c0367f9ae1161779b573', 'Content-Type': 'application/json'}
    try:
        conn.request("POST", "/search", payload, headers)
        res = conn.getresponse()
        data = json.loads(res.read().decode("utf-8"))
        return data
    except Exception as e:
        st.error(f"Erreur lors de la recherche web : {e}")
        return None
    finally:
        conn.close()

def format_search_results(data):
    if not data:
        return "Aucun résultat trouvé"
    result = ""
    if 'knowledgeGraph' in data:
        kg = data['knowledgeGraph']
        result += f"### {kg.get('title', '')}\n*{kg.get('type', '')}*\n\n{kg.get('description', '')}\n\n"
    if 'organic' in data:
        result += "### Résultats principaux:\n"
        for item in data['organic'][:3]:
            result += f"- **{item['title']}**\n  {item['snippet']}\n  [Lien]({item['link']})\n\n"
    return result

# Initialisation de l’état
if "chat" not in st.session_state:
    st.session_state.chat = model.start_chat(history=[])
if "web_search" not in st.session_state:
    st.session_state.web_search = False
if "messages" not in st.session_state:
    st.session_state.messages = []

# Fonction pour effacer l’historique
def clear_chat_history():
    st.session_state.chat = model.start_chat(history=[])
    st.session_state.messages = []

# CSS personnalisé pour mobile
st.markdown("""
    <style>
    .chat-container {
        height: 60vh;
        overflow-y: auto;
        padding: 10px;
        background-color: #f9f9f9;
        border-radius: 10px;
    }
    .user-message {
        background-color: #007bff;
        color: white;
        padding: 10px;
        border-radius: 10px;
        margin: 5px 0;
        max-width: 80%;
        align-self: flex-end;
    }
    .assistant-message {
        background-color: #e9ecef;
        color: black;
        padding: 10px;
        border-radius: 10px;
        margin: 5px 0;
        max-width: 80%;
    }
    .input-container {
        position: fixed;
        bottom: 0;
        width: 100%;
        padding: 10px;
        background-color: white;
        box-shadow: 0 -2px 5px rgba(0,0,0,0.1);
    }
    @media (max-width: 600px) {
        .chat-container {
            height: 70vh;
        }
        .stTextArea textarea {
            height: 80px !important;
        }
    }
    </style>
""", unsafe_allow_html=True)

# Titre
st.title("Mariam AI")

# Section des paramètres (expansible)
with st.expander("Paramètres"):
    st.session_state.web_search = st.toggle("Activer la recherche web", value=st.session_state.web_search, 
                                            help="Permet des réponses enrichies avec des données du web.")
    if st.button("Effacer l’historique"):
        clear_chat_history()
        st.success("Historique effacé.")

# Section de téléchargement
with st.expander("Télécharger un fichier"):
    st.info("Types acceptés : jpg, jpeg, png, pdf, txt")
    uploaded_file = st.file_uploader("Choisir un fichier", type=['jpg', 'jpeg', 'png', 'pdf', 'txt'])

# Zone de conversation
st.markdown('<div class="chat-container">', unsafe_allow_html=True)
for message in st.session_state.messages:
    if message["role"] == "user":
        st.markdown(f'<div class="user-message">{message["content"]}</div>', unsafe_allow_html=True)
    else:
        st.markdown(f'<div class="assistant-message">{message["content"]}</div>', unsafe_allow_html=True)
st.markdown('</div>', unsafe_allow_html=True)

# JavaScript pour défiler automatiquement
components.html("""
    <script>
    const chatContainer = document.querySelector('.chat-container');
    chatContainer.scrollTop = chatContainer.scrollHeight;
    </script>
""")

# Zone de saisie
st.markdown('<div class="input-container">', unsafe_allow_html=True)
user_input = st.text_area("Votre message", height=80, key="input")
col1, col2 = st.columns([3, 1])
with col1:
    pass
with col2:
    send_button = st.button("Envoyer")
st.markdown('</div>', unsafe_allow_html=True)

# Traitement de l’entrée utilisateur
if send_button and user_input:
    st.session_state.messages.append({"role": "user", "content": user_input})
    
    # Traitement du fichier
    uploaded_gemini_file = None
    if uploaded_file:
        file_ext = uploaded_file.name.split('.')[-1].lower()
        if file_ext in ['jpg', 'jpeg', 'png', 'pdf', 'txt']:
            with open(os.path.join("temp", uploaded_file.name), "wb") as f:
                f.write(uploaded_file.getbuffer())
            try:
                uploaded_gemini_file = genai.upload_file(os.path.join("temp", uploaded_file.name))
            except Exception as e:
                st.error(f"Erreur lors de l’upload : {e}")
        else:
            st.error("Type de fichier non accepté.")
    
    # Recherche web
    web_results = None
    if st.session_state.web_search:
        with st.spinner("Recherche web en cours..."):
            web_results = perform_web_search(user_input)
            if web_results:
                formatted_results = format_search_results(web_results)
                user_input = f"{user_input}\n\nRésultats de recherche :\n{formatted_results}\nAnalyse ces informations et réponds-moi."

    # Réponse de Mariam
    try:
        if uploaded_gemini_file:
            response = st.session_state.chat.send_message([uploaded_gemini_file, "\n\n", user_input])
        else:
            response = st.session_state.chat.send_message(user_input)
        st.session_state.messages.append({"role": "assistant", "content": response.text})
    except Exception as e:
        st.error(f"Erreur : {e}")
    
    # Nettoyage
    if uploaded_file:
        shutil.rmtree("temp", ignore_errors=True)
    os.makedirs("temp", exist_ok=True)
    
    # Rafraîchir la page pour afficher la réponse
    st.rerun()