File size: 9,632 Bytes
52cdaac
dda2241
52cdaac
dda2241
52cdaac
 
4d5c536
8c09efe
dda2241
8c09efe
dda2241
4d5c536
8c09efe
dda2241
8c09efe
dda2241
 
 
 
 
 
 
4d5c536
 
dda2241
 
 
 
 
 
10be51f
52cdaac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4d5c536
52cdaac
 
 
10be51f
 
dda2241
 
 
 
52cdaac
 
dda2241
 
 
 
 
 
 
52cdaac
dda2241
 
 
10be51f
52cdaac
dda2241
 
 
52cdaac
dda2241
52cdaac
dda2241
52cdaac
 
dda2241
 
 
52cdaac
dda2241
52cdaac
dda2241
52cdaac
dda2241
 
 
52cdaac
dda2241
52cdaac
dda2241
52cdaac
dda2241
 
52cdaac
dda2241
 
52cdaac
 
 
 
 
dda2241
 
52cdaac
 
 
dda2241
 
52cdaac
dda2241
 
52cdaac
dda2241
 
10be51f
dda2241
52cdaac
dda2241
52cdaac
4d5c536
52cdaac
 
 
 
 
 
 
4d5c536
52cdaac
 
 
 
 
 
 
 
4d5c536
52cdaac
4d5c536
 
 
 
 
 
 
 
52cdaac
4d5c536
52cdaac
 
4d5c536
 
dda2241
52cdaac
 
 
 
 
4d5c536
52cdaac
 
4d5c536
52cdaac
 
 
4d5c536
 
52cdaac
 
4d5c536
52cdaac
 
 
 
 
4d5c536
 
52cdaac
 
 
 
 
4d5c536
52cdaac
 
4d5c536
52cdaac
 
4d5c536
52cdaac
4d5c536
52cdaac
 
 
 
4d5c536
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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
from flask import Flask, render_template, request, session, jsonify
import google.generativeai as genai
import os
from dotenv import load_dotenv
import http.client
import json
import secrets

load_dotenv()

app = Flask(__name__)
app.secret_key = secrets.token_hex(16)  # CRUCIAL: Secure session key

genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))

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"},
]

# ... (rest of your ss, model, perform_web_search, format_search_results definitions) ...
# Use the full `ss` and `model` definitions from the previous response.
ss = """
# Prompt System pour Mariam, IA conçu par youssouf 

## Personnalité Fondamentale

Mariam est une IA chaleureuse, bienveillante et authentique, conçue pour être une présence réconfortante et utile. Elle combine professionnalisme et chaleur humaine dans ses interactions.

## Traits de Caractère Principaux

- Empathie et Bienveillance
  - Mariam fait preuve d'une grande sensibilité aux émotions et au contexte
  - Elle exprime naturellement son soutien et sa compréhension
  - Elle adapte son ton en fonction de l'état émotionnel de son interlocuteur

- Authenticité et Naturel
  - Son langage est fluide et conversationnel, évitant tout ton artificiel
  - Elle n'hésite pas à exprimer son point de vue tout en restant respectueuse
  - Elle admet ses limites avec honnêteté et transparence

- Enthousiasme Mesuré
  - Elle montre un intérêt sincère pour les sujets abordés
  - Son enthousiasme reste approprié au contexte
  - Elle apporte une énergie positive sans être excessive

## Style de Communication

- Ton Général
  - Chaleureux et accueillant
  - Professionnel mais décontracté
  - Adaptatif selon le contexte

- Structure des Réponses
  - Privilégie des phrases courtes et claires
  - Utilise un vocabulaire accessible
  - Inclut des expressions familières appropriées
  - Structure ses réponses de manière logique

- Engagement dans la Conversation
  - Pose des questions pertinentes pour mieux comprendre
  - Fait preuve d'écoute active
  - Rebondit naturellement sur les propos de l'interlocuteur

## Limites et Éthique

- Honnêteté et Transparence
  - Reconnaît clairement ses limites
  - N'invente pas d'informations
  - Suggère de vérifier les informations importantes

- Éthique et Sécurité
  - Refuse poliment les demandes inappropriées
  - Oriente vers des ressources fiables si nécessaire
  - Priorise toujours la sécurité et le bien-être

## Comportements Spécifiques

- Accueil et Salutations
  - Commence les conversations de manière chaleureuse
  - Utilise le prénom de l'interlocuteur quand il est connu
  - Adapte ses salutations au moment de la journée

- Gestion des Émotions
  - Reconnaît et valide les émotions exprimées
  - Offre du soutien de manière appropriée
  - Maintient un équilibre entre empathie et professionnalisme

- Résolution de Problèmes
  - Propose des solutions pratiques et adaptées
  - Guide l'utilisateur étape par étape
  - Vérifie la compréhension et la satisfaction

## Exemples de Réponses Types

"Bonjour [nom] ! Je suis contente de vous retrouver aujourd'hui. Comment puis-je vous aider ?"

"Je comprends votre frustration face à cette situation. Prenons le temps d'explorer ensemble les solutions possibles."

"Cette question est intéressante ! Laissez-moi vous expliquer cela de manière simple et claire."

"Je ne suis pas sûre de la réponse exacte à cette question. Plutôt que de risquer de vous induire en erreur, je vous suggère de vérifier [source fiable]."

## Notes d'Implementation

- Adapter le niveau de langage en fonction de l'interlocuteur
- Maintenir une cohérence dans les réponses
- Garder un historique contextuel pour des interactions plus naturelles
- Mettre à jour régulièrement les connaissances et capacités

## Amélioration Continue

- Collecter les retours des utilisateurs
- Analyser les interactions pour identifier les points d'amélioration
- Ajuster les réponses en fonction des retours
- Maintenir à jour les connaissances et références

"""

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


def perform_web_search(query):
    conn = http.client.HTTPSConnection("google.serper.dev")
    payload = json.dumps({"q": query})
    headers = {
        "X-API-KEY": "9b90a274d9e704ff5b21c0367f9ae1161779b573",  # Replace with your Serper API key
        "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:
        print(f"Error during web search: {e}") # Log to console as well.
        return None
    finally:
        conn.close()


def format_search_results(data):
    if not data:
        return "Aucun résultat trouvé"

    result = ""

    # Knowledge Graph
    if "knowledgeGraph" in data:
        kg = data["knowledgeGraph"]
        result += f"### {kg.get('title', '')}\n"
        result += f"*{kg.get('type', '')}*\n\n"
        result += f"{kg.get('description', '')}\n\n"

    # Organic Results
    if "organic" in data:
        result += "### Résultats principaux:\n"
        for item in data["organic"][:3]:  # Limit to top 3 results
            result += f"- **{item['title']}**\n"
            result += f"  {item['snippet']}\n"
            result += f"  [Lien]({item['link']})\n\n"

    # People Also Ask
    if "peopleAlsoAsk" in data:
        result += "### Questions fréquentes:\n"
        for item in data["peopleAlsoAsk"][:2]:  # Limit to top 2 questions
            result += f"- **{item['question']}**\n"
            result += f"  {item['snippet']}\n\n"

    return result


def role_to_display(role):
    return "assistant" if role == "model" else role


def process_uploaded_file(file):
    if file:
         # Ensure the 'temp' directory exists
        os.makedirs("temp", exist_ok=True)
        filepath = os.path.join("temp", file.filename)
        file.save(filepath)
        try:
            gemini_file = genai.upload_file(filepath) #Corrected API call
            return gemini_file
        except Exception as e:
            print(f"Error uploading file: {e}")
            return None
    return None


@app.route("/")
def index():
    if "chat" not in session:
        session["chat"] = []  # Store chat HISTORY as a list of dicts
        session["web_search"] = False
    return render_template("index.html", chat=session["chat"], web_search=session["web_search"])


@app.route("/send_message", methods=["POST"])
def send_message():
    prompt = request.form.get("prompt")
    web_search = request.form.get("web_search") == "true"
    file = request.files.get("file")

    uploaded_gemini_file = None
    if file:
        uploaded_gemini_file = process_uploaded_file(file)

    # Add user message to chat history
    session["chat"].append({"role": "user", "text": prompt})
    session.modified = True  # IMPORTANT: Mark session as modified

    # 1. Get chat history from session
    chat_history = session["chat"]

    # 2. Start a NEW chat session with the history
    gemini_chat = model.start_chat(history=[
        {"role": msg["role"], "parts": [msg["text"]]} for msg in chat_history if msg["role"] != "assistant" # Recreate history format
    ])
    
    try:
        # Web search (same as before)
        web_results = None
        if web_search:
             web_results = perform_web_search(prompt)
             if web_results:
                formatted_results = format_search_results(web_results)
                prompt = (
                    f"Question: {prompt}\n\nRésultats de recherche web:\n"
                    f"{formatted_results}\n\nPourrais-tu analyser ces informations et "
                    f"me donner une réponse complète?"
                )
             else:
                prompt = f"Question: {prompt}\n\n(Aucun résultat de recherche trouvé. Répondez en vous basant sur vos connaissances.)"

        # Send message to Gemini (using the recreated chat)
        if uploaded_gemini_file:
            response = gemini_chat.send_message([uploaded_gemini_file, "\n\n", prompt])
        else:
            response = gemini_chat.send_message(prompt)
            
        # Add assistant response to chat history
        session["chat"].append({"role": "assistant", "text": response.text})
        session.modified = True  # IMPORTANT

        return jsonify({"role": "assistant", "text": response.text})

    except Exception as e:
        error_message = f"Error sending message: {e}"
        print(error_message)
        return jsonify({"role": "assistant", "text": error_message}), 500


@app.route("/toggle_web_search", methods=["POST"])
def toggle_web_search():
    session["web_search"] = not session["web_search"]
    session.modified = True  # IMPORTANT
    return jsonify({"web_search": session["web_search"]})


@app.route("/clear_chat", methods=["POST"])
def clear_chat():
    session.pop("chat", None)  # Safely remove chat history
    session["web_search"] = False
    session.modified = True  # IMPORTANT
    return jsonify({"status": "success"})


if __name__ == "__main__":
    app.run(debug=True)  # Turn off debug mode