File size: 4,976 Bytes
c5bddce
 
6ca0885
c5bddce
 
 
 
25460b3
 
d3e3794
cac21d1
c5bddce
6ca0885
c5bddce
 
6ca0885
c5bddce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25460b3
c5bddce
 
 
 
 
 
25460b3
c5bddce
 
 
 
 
 
 
 
 
 
 
6ca0885
c5bddce
6ca0885
 
25460b3
 
6ca0885
c5bddce
 
 
 
 
533067f
 
c5bddce
25460b3
 
c5bddce
 
25460b3
 
 
6ca0885
 
25460b3
 
 
 
 
 
 
 
c5bddce
 
25460b3
c5bddce
 
 
 
 
 
25460b3
c5bddce
25460b3
c5bddce
 
 
 
25460b3
c5bddce
 
6ca0885
c5bddce
 
90e991c
c5bddce
 
 
533067f
c5bddce
25460b3
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
# app.py
import os
import logging
import json
from flask import Flask, jsonify, render_template, request
from pydantic import BaseModel, Field
from typing import List, Optional
# import psycopg2 # La base de données n'est pas utilisée
# from psycopg2.extras import RealDictCursor
from google import genai
from google.genai import types
from utils import load_prompt

# --- Configuration ---
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
app = Flask(__name__)
app.secret_key = os.environ.get("FLASK_SECRET_KEY", "un-secret-par-defaut")

# --- Modèles de Données Pydantic pour la sortie structurée ---
class Argument(BaseModel):
    paragraphe_argumentatif: str = Field(description="Un unique paragraphe formant un argument complet. Il doit commencer par un connecteur logique (ex: 'Premièrement,'), suivi de son développement.")

class Partie(BaseModel):
    chapeau: str = Field(description="Le paragraphe d'introduction de la partie.")
    arguments: list[Argument] = Field(description="La liste des paragraphes argumentatifs qui suivent le chapeau.")
    transition: Optional[str] = Field(description="Phrase ou court paragraphe de transition.", default=None)

class Dissertation(BaseModel):
    sujet: str = Field(description="Le sujet exact de la dissertation, tel que posé par l'utilisateur.")
    prof: str = Field(description="Le nom du professeur, qui est toujours 'Mariam AI'.", default="Mariam AI")
    introduction: str = Field(description="L'introduction complète de la dissertation.")
    parties: List[Partie]
    conclusion: str = Field(description="La conclusion complète de la dissertation.")

# --- Configuration Gemini (Ancien SDK) ---
try:
    GOOGLE_API_KEY = os.environ.get("TOKEN")
    if not GOOGLE_API_KEY:
        logging.warning("La variable d'environnement TOKEN (GOOGLE_API_KEY) n'est pas définie.")
        client = None
    else:
        # On utilise genai.Client comme dans votre code original
        client = genai.Client(api_key=GOOGLE_API_KEY)
except Exception as e:
    logging.error(f"Erreur lors de l'initialisation du client GenAI: {e}")
    client = None

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

# --- Route Principale ---
@app.route('/')
def philosophie():
    # Assurez-vous que le nom du template correspond à votre fichier HTML
    return render_template("philosophie (13).html")

# --- Route API pour la génération de dissertation ---
@app.route('/api/generate_dissertation', methods=['POST'])
def generate_dissertation_api():
    if not client:
        return jsonify({"error": "Le service IA n'est pas correctement configuré."}), 503

    data = request.json
    sujet = data.get('question', '').strip()
    dissertation_type = data.get('type', 'type1').strip() # Récupère le type

    if not sujet:
        return jsonify({"error": "Le champ 'question' est obligatoire."}), 400
        
    if dissertation_type not in ['type1', 'type2']:
        return jsonify({"error": "Type de méthodologie invalide."}), 400

    try:
        # Sélection dynamique du fichier de prompt
        prompt_filename = f"philo_dissertation_{dissertation_type}.txt"
        prompt_template = load_prompt(prompt_filename)
        
        if "Erreur:" in prompt_template:
             logging.error(f"Fichier de prompt non trouvé : {prompt_filename}")
             return jsonify({"error": "Configuration du prompt introuvable pour ce type."}), 500

        final_prompt = prompt_template.format(phi_prompt=sujet)

        # Configuration de la réponse structurée (comme dans votre code original)
        config = types.GenerateContentConfig(
            safety_settings=SAFETY_SETTINGS,
            response_mime_type="application/json",
            response_schema=Dissertation,
        )

        # Appel à l'API avec la syntaxe client.models.generate_content
        response = client.models.generate_content(
            model="gemini-2.5-flash", # Modèle performant compatible avec cette syntaxe
            contents=final_prompt,
            config=config
        )

        # Traitement de la réponse (comme dans votre code original)
        if response.parsed:
            return jsonify(response.parsed.dict())
        else:
            logging.error(f"Erreur de parsing de la réponse structurée. Réponse brute : {response.text}")
            return jsonify({"error": "Le modèle n'a pas pu générer une structure valide."}), 500

    except Exception as e:
        logging.error(f"Erreur de génération Gemini : {e}")
        return jsonify({"error": f"Une erreur est survenue avec le service IA : {e}"}), 500

if __name__ == '__main__':
    app.run(debug=True, port=5001)