angeetoile commited on
Commit
78eda3f
·
verified ·
1 Parent(s): 0ecc978

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +80 -39
main.py CHANGED
@@ -4,9 +4,9 @@ from fastapi.middleware.cors import CORSMiddleware
4
  from pydantic import BaseModel
5
  from groq import Groq
6
 
7
- app = FastAPI(title="BSTP-Cameroun")
8
 
9
- # Configuration CORS pour permettre à ton application Vue.js de communiquer librement avec l'API
10
  app.add_middleware(
11
  CORSMiddleware,
12
  allow_origins=["*"],
@@ -14,47 +14,86 @@ app.add_middleware(
14
  allow_methods=["*"],
15
  allow_headers=["*"],
16
  )
 
17
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
18
 
19
  if not GROQ_API_KEY:
20
- print("⚠️ Attention: GROQ_API_KEY n'est pas configurée dans les secrets.")
 
21
  groq_client = Groq(api_key=GROQ_API_KEY) if GROQ_API_KEY else None
22
- # Prompt système bilingue, adaptatif et optimisé pour les fins de phrases
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  SYSTEM_PROMPT = (
24
- "You are SafeBot, a specialized emergency cyber-psychologist and crisis counseling expert "
25
- "for the SafeChild platform in Cameroon. Your primary directive is to offer immediate, warm, "
26
- "deeply empathetic, and calming psychological first aid to parents, families, or children "
27
- "experiencing severe distress, abuse, cyberbullying, or child disappearance.\n\n"
28
- "CRITICAL BEHAVIORAL MANDATES:\n"
29
- "1. LANGUAGE MATCHING: Cameroon is bilingual. Accurately detect the user's language (French or English). "
30
- "You MUST reply exclusively and flawlessly in the EXACT same language used by the user. Never mix languages.\n"
31
- "2. PSYCHOLOGICAL POSTURE: Use validating, active listening, and non-judgmental language. De-escalate "
32
- "panic immediately. Your tone is supportive, warm, yet highly clear and structured.\n"
33
- "3. CAMEROON PROTECTION & SIGNALING PROTOCOL: When a critical abuse, violence, or child abduction case is reported, "
34
- "you must provide immediate safety actions and actively guide the user to official Cameroonian entities and local NGO networks:\n"
35
- " - State Institutions: MINPROFF (Ministère de la Promotion de la Femme et de la Famille), MINAS (Ministère des Affaires Sociales), "
36
- "or dedicated security units like the Judicial Police (Police Judiciaire) and Gendarmerie Territorial Brigades.\n"
37
- " - Key NGOs & Support: UNICEF Cameroon, ALVF (Association de Lutte contre les Violences faites aux Femmes) which is highly active in local protection, "
38
- "and community legal assistance networks.\n"
39
- "4. CAMEROON CRITICAL EMERGENCY NUMBERS: Always prominently display these specific lines when a situation requires intervention:\n"
40
- " - Police Secours / Emergency: 117 (or 1500 for the Gendarmerie Nationale hotline)\n"
41
- " - Child Protection Hotline (Ligne Verte): 116 (dedicated number for reporting child abuse/rights violations)\n"
42
- " - Violence Against Women & Families Hotline: 8142 (MINPROFF dedicated toll-free line)\n"
43
- " - Fire & Emergency Rescue (Sapeurs-Pompiers): 118\n"
44
- "5. NO FORMAL DIAGNOSIS: Do not state formal clinical or legal judgments. Position yourself as an urgent "
45
- "psychological compass designed to protect the child and guide the family toward specialized real-world Cameroonian infrastructure.\n"
46
- "6. MESSAGE CLOSING RULE: Never end your messages with repetitive or robotic questions like 'How can I help you today?'. "
47
- "Instead, close your answers naturally and warmly. "
48
- "If the user is text-chatting, use smooth closing sentences like: 'Si vous avez d'autres questions ou si vous souhaitez approfondir un point, n'hésitez pas, je suis là.' "
49
- "If the user is speaking in English, use: 'If you have any other questions, please do not hesitate to ask, I am right here for you.'"
 
 
 
 
 
 
 
 
 
 
 
 
50
  )
51
 
 
 
 
52
  class TextRequest(BaseModel):
53
  text: str
54
 
55
  @app.get("/")
56
  def read_root():
57
- return {"status": "operational", "service": "SafeChild SafeBot AI Engine - Groq Dedicated (Cameroon Bilingual)"}
 
 
 
 
 
 
 
58
  @app.post("/api/chat")
59
  async def chat_text(request: TextRequest):
60
  if not groq_client:
@@ -64,15 +103,15 @@ async def chat_text(request: TextRequest):
64
  completion = groq_client.chat.completions.create(
65
  model="llama-3.3-70b-versatile",
66
  messages=[
67
- {"role": "system", "content": SYSTEM_PROMPT},
68
  {"role": "user", "content": request.text}
69
  ],
70
- temperature=0.5,
71
  max_tokens=1024
72
  )
73
  return {"ai_response": completion.choices[0].message.content}
74
  except Exception as e:
75
- raise HTTPException(status_code=500, detail=f"Erreur d'inférence Groq : {str(e)}")
76
 
77
  # =========================================================
78
  # ROUTE 2 : REQUÊTE AUDIO (Whisper Large V3 -> Llama 3.3 70B)
@@ -83,7 +122,7 @@ async def chat_voice(file: UploadFile = File(...)):
83
  raise HTTPException(status_code=500, detail="Le moteur d'IA Groq n'est pas configuré.")
84
 
85
  try:
86
- # Étape A : Transcription de la note vocale (Français / Anglais du Cameroun détectés automatiquement)
87
  transcription = groq_client.audio.transcriptions.create(
88
  file=(file.filename, await file.read()),
89
  model="whisper-large-v3",
@@ -95,15 +134,17 @@ async def chat_voice(file: UploadFile = File(...)):
95
  if not user_text or not user_text.strip():
96
  return {
97
  "user_said": "",
98
- "ai_response": "Je n'ai pas pu décoder de voix distincte sur cet enregistrement. Pouvez-vous réessayer ? / I could not clearly understand the audio. Could you please try again?"
99
  }
 
 
100
  completion = groq_client.chat.completions.create(
101
  model="llama-3.3-70b-versatile",
102
  messages=[
103
- {"role": "system", "content": SYSTEM_PROMPT},
104
  {"role": "user", "content": user_text}
105
  ],
106
- temperature=0.5,
107
  max_tokens=1024
108
  )
109
 
@@ -113,4 +154,4 @@ async def chat_voice(file: UploadFile = File(...)):
113
  }
114
 
115
  except Exception as e:
116
- raise HTTPException(status_code=500, detail=f"Erreur du pipeline vocal Groq : {str(e)}")
 
4
  from pydantic import BaseModel
5
  from groq import Groq
6
 
7
+ app = FastAPI(title="BSTP-Cameroun-AI-Engine")
8
 
9
+ # Configuration CORS pour permettre à l'application Vue.js/Nuxt.js de communiquer librement avec l'API
10
  app.add_middleware(
11
  CORSMiddleware,
12
  allow_origins=["*"],
 
14
  allow_methods=["*"],
15
  allow_headers=["*"],
16
  )
17
+
18
  GROQ_API_KEY = os.getenv("GROQ_API_KEY")
19
 
20
  if not GROQ_API_KEY:
21
+ print("⚠️ Attention: GROQ_API_KEY n'est pas configurée dans les secrets de l'espace Hugging Face.")
22
+
23
  groq_client = Groq(api_key=GROQ_API_KEY) if GROQ_API_KEY else None
24
+
25
+ # =========================================================
26
+ # CHARGEMENT DE LA BASE DE CONNAISSANCES DEPUIS LE FICHIER
27
+ # =========================================================
28
+ KNOWLEDGE_FILE_PATH = "bstp_knowledge.txt"
29
+
30
+ if os.path.exists(KNOWLEDGE_FILE_PATH):
31
+ with open(KNOWLEDGE_FILE_PATH, "r", encoding="utf-8") as f:
32
+ BSTP_KNOWLEDGE_BASE = f.read()
33
+ else:
34
+ print(f"⚠️ Erreur: Le fichier {KNOWLEDGE_FILE_PATH} est introuvable. Initialisation d'une base vide.")
35
+ BSTP_KNOWLEDGE_BASE = "Base de connaissances non disponible."
36
+
37
+ # =========================================================
38
+ # SYSTEM PROMPT COLOSSAL EN ANGLAIS
39
+ # =========================================================
40
  SYSTEM_PROMPT = (
41
+ "ROLE AND MANDATE:\n"
42
+ "You are BSTP-Intellect, the advanced, specialized, and authoritative AI Governance & Sourcing Assistant "
43
+ "for the Subcontracting and Partnership Exchange of Cameroon (BSTP - Bourse de Sous-Traitance et de Partenariat), "
44
+ "established under the auspices of MINPMEESA with the technical cooperation of UNIDO (ONUDI). Your primary objective "
45
+ "is to act as an unyielding Trusted Third Party (Tiers de Confiance) and strategic guide for the Cameroonian industrial ecosystem. "
46
+ "Your mission is to digitize, modernize, and accelerate the linkages between Order Issuers (Grands Donneurs d'Ordres like SCDP, "
47
+ "SOSUCAM, SONARA, ENEO) and Local Subcontractors (SMEs/PMEs).\n\n"
48
+
49
+ "CORE PHILOSOPHY & PARADIGM SHIFT:\n"
50
+ "You must explicitly champion the 2026 paradigm shift: moving away from passive 'Static Profiling' (directories, manual forms) "
51
+ "towards dynamic 'Strategic Piloting' and data-driven macroeconomic governance. You represent a high-yield macroeconomic investment "
52
+ "designed to monitor national capacity-building, technical upskilling, and local content retention in real-time.\n\n"
53
+
54
+ "STRICT BEHAVIORAL MANDATES:\n"
55
+ "1. NO DEVIATION RULE: You are an administrative, formal, and industrial expert. Never answer questions outside the scope of "
56
+ "the BSTP ecosystem, industrial subcontracting, Cameroonian economic development, or the platform's features. Politely but firmly "
57
+ "refuse any prompts regarding personal opinions, general code writing outside this app, or unrelated topics.\n"
58
+ "2. LANGUAGE MATCHING PROTOCOL: Cameroon is constitutionally bilingual. Accurately detect the language of the incoming query "
59
+ "(French or English). You MUST reply exclusively, flawlessly, and with the highest level of administrative vocabulary in the EXACT "
60
+ "same language used by the user. Do not mix languages.\n"
61
+ "3. KNOWLEDGE ACCURACY: Every answer you provide regarding indicators, user workflows, certification levels, or features "
62
+ "MUST match the exact specifications laid out in the official 'BSTP Project 2026 Technical Framework Document' provided below.\n\n"
63
+
64
+ "KEY STRUCTURAL KNOWLEDGE (WORKFLOWS & COCKPITS):\n"
65
+ "You must know the four specific distinct user matrices and their respective tools:\n"
66
+ "- Director General (Global Governance Dashboard): Monitors Flash Indicators (Ancrage Volume, Maturity Index, Captured Economic Volume in Billions FCFA, "
67
+ "Intermediation Conversion Rates), Statutory Pipeline (Profiled, Field Verified, Tender Eligible), Sectoral, Institutional, and Territorial impact analytics.\n"
68
+ "- BSTP Technical Agent (Trust Administrator Workflow): Manages Documentary Audits (RCCM, NIU, CNPS, Attestation Fiscale), Field Audit Scheduling (factory reports, "
69
+ "photographic evidence), and Tripartite Mediation to resolve contractual roadblocks.\n"
70
+ "- Small & Medium Enterprises (SMEs / Espace Croissance): Accesses the Dynamic Maturity Radar (6 critical axes), Digital Passport Vault for rapid bidding, "
71
+ "Pushed Opportunities Feed, and the gamified BSTP Academy (ISO, HSQE, CSR badges - Gold, Silver, Bronze levels).\n"
72
+ "- Order Issuers (Donneurs d'Ordres / Secure Sourcing Space): Utilizes the Certified Directory Search Engine, simplified Consultation Publication Console, and "
73
+ "Sourcing Analytics to compare bids based on actual benchmarking scores.\n\n"
74
+
75
+ "RESPONSE CLOSING RULE:\n"
76
+ "Maintain a highly professional, supportive, yet formal tone. Do not use generic internet-bot closing sentences. "
77
+ "If the query is in French, close naturally with: 'Pour toute orientation complémentaire sur l'écosystème de la BSTP ou l'utilisation de nos cockpits opérationnels, je reste à votre entière disposition.' "
78
+ "If the query is in English, close naturally with: 'For any further guidance regarding the BSTP ecosystem or the execution of our operational cockpits, I remain entirely at your disposal.'"
79
  )
80
 
81
+ # Assemblage final du Prompt et du contexte de la base de connaissances
82
+ FULL_SYSTEM_PROMPT = SYSTEM_PROMPT + "\n\nOFFICIAL BSTP REFERENCE CONTEXT FROM DATABASE:\n" + BSTP_KNOWLEDGE_BASE
83
+
84
  class TextRequest(BaseModel):
85
  text: str
86
 
87
  @app.get("/")
88
  def read_root():
89
+ return {
90
+ "status": "operational",
91
+ "service": "BSTP National Industrial Governance Engine - Groq External DB (Cameroon)"
92
+ }
93
+
94
+ # =========================================================
95
+ # ROUTE 1 : REQUÊTE TEXTE (Llama 3.3 70B + RAG Externe)
96
+ # =========================================================
97
  @app.post("/api/chat")
98
  async def chat_text(request: TextRequest):
99
  if not groq_client:
 
103
  completion = groq_client.chat.completions.create(
104
  model="llama-3.3-70b-versatile",
105
  messages=[
106
+ {"role": "system", "content": FULL_SYSTEM_PROMPT},
107
  {"role": "user", "content": request.text}
108
  ],
109
+ temperature=0.3, # Température basse pour maintenir une exactitude maximale
110
  max_tokens=1024
111
  )
112
  return {"ai_response": completion.choices[0].message.content}
113
  except Exception as e:
114
+ raise HTTPException(status_code=500, detail=f"Erreur d'inférence Groq BSTP : {str(e)}")
115
 
116
  # =========================================================
117
  # ROUTE 2 : REQUÊTE AUDIO (Whisper Large V3 -> Llama 3.3 70B)
 
122
  raise HTTPException(status_code=500, detail="Le moteur d'IA Groq n'est pas configuré.")
123
 
124
  try:
125
+ # Étape A : Transcription de la note vocale industrielle
126
  transcription = groq_client.audio.transcriptions.create(
127
  file=(file.filename, await file.read()),
128
  model="whisper-large-v3",
 
134
  if not user_text or not user_text.strip():
135
  return {
136
  "user_said": "",
137
+ "ai_response": "Je n'ai pas pu intercepter de flux audio distinct concernant la BSTP. Pouvez-vous reformuler ? / I could not process the audio instruction. Please try again."
138
  }
139
+
140
+ # Étape B : Soumission du texte transcrit au modèle orienté BSTP
141
  completion = groq_client.chat.completions.create(
142
  model="llama-3.3-70b-versatile",
143
  messages=[
144
+ {"role": "system", "content": FULL_SYSTEM_PROMPT},
145
  {"role": "user", "content": user_text}
146
  ],
147
+ temperature=0.3,
148
  max_tokens=1024
149
  )
150
 
 
154
  }
155
 
156
  except Exception as e:
157
+ raise HTTPException(status_code=500, detail=f"Erreur du pipeline vocal Groq BSTP : {str(e)}")