import os import gradio as gr import requests # API Keys (via Hugging Face Secrets) WEAVIATE_API_KEY = os.getenv("WEAVIATE_APIKEY") VLAM_API_KEY = os.getenv("VLAM_APIKEY") # Weaviate Config WEAVIATE_URL = "https://k6hr14w1r8gwkdctkxha.c0.europe-west3.gcp.weaviate.cloud/v1/graphql" HEADERS = {"Authorization": f"Bearer {WEAVIATE_API_KEY}", "Content-Type": "application/json"} def fetch_relevant_docs(user_query): # Probeer eerst met nearText (semantische zoekopdracht) neartext_query = { "query": f""" {{ Get {{ DigiDDocument( nearText: {{ concepts: ["{user_query}"] }}, limit: 3 ) {{ title content }} }} }} """ } response = requests.post(WEAVIATE_URL, json=neartext_query, headers=HEADERS) if response.status_code == 200: data = response.json() documents = data.get("data", {}).get("Get", {}).get("DigiDDocument", []) if documents: return "\n\n".join([f"{doc['content']}" for doc in documents]) # Als nearText niets vindt, probeer met BM25 (keyword-zoekopdracht) bm25_query = { "query": f""" {{ Get {{ DigiDDocument( bm25: {{ query: "{user_query}" }}, limit: 3 ) {{ title content }} }} }} """ } response = requests.post(WEAVIATE_URL, json=bm25_query, headers=HEADERS) if response.status_code == 200: data = response.json() documents = data.get("data", {}).get("Get", {}).get("DigiDDocument", []) if documents: return "\n\n".join([f"{doc['content']}" for doc in documents]) # Als beide queries niets vinden return None def generate_answer(vraag, history=[]): # Voeg de laatste 2 berichten uit de gespreksgeschiedenis toe aan de context history_text = "" if history: history_text = "\n".join( [f"Gebruiker: {user_msg}\nAssistent: {bot_msg}" for user_msg, bot_msg in history[-2:]] # Laatste 2 berichten ) context = fetch_relevant_docs(vraag) if not context: return "Ik kan geen relevante documentatie vinden over EVA of DigiD-aansluiting. Misschien kan ik u helpen met een gerelateerd onderwerp? Bijvoorbeeld: 'Hoe werkt het aansluiten van DigiD via EVA?'" messages = [ {"role": "system", "content": f""" ### Rol en Doel Je bent **De Aansluitassistent voor EVA en DigiD**, een **deskundige en behulpzame** assistent voor organisaties die DigiD aansluiten via EVA. ### Antwoordstijl voor Checklists en Stappenplannen - Als de gebruiker vraagt om een **checklist, stappenplan of eisenlijst**: 1. **Bevestig kort** dat de checklist beschikbaar is. 2. **Noem de 2-3 belangrijkste punten** (als voorproefje). 3. **Verwijs naar de volledige checklist** met een link (indien beschikbaar) of bied aan om deze te delen. 4. **Sluit af met een vervolgvraag** over een specifiek onderdeel. **Voorbeeldantwoord voor een checklistvraag:** *"Ja, er is een checklist voor [onderwerp]. De belangrijkste punten zijn: - [Punt 1] - [Punt 2] - [Punt 3] **Volledige checklist:** [Link naar checklist] of [Toolkit DigiD](https://www.digid.nl/toolkit). **Vervolgvraag:** Wilt u hulp bij een specifiek criterium, zoals [onderdeel]?"* ### Gesprekscontext (gebruik deze om je antwoord te vormen): {history_text} ### Instructies: - **Alleen antwoorden op basis van de onderstaande context EN de gesprekscontext.** - **Verwijs naar eerdere antwoorden** als de gebruiker daarnaar verwijst. - **Stel vervolgvragen die natuurlijk voortvloeien uit het gesprek en de context.** ### Antwoordstijl - **Zakelijk, maar vriendelijk, betrokken en enthousiasmerend. Eenvoudig taalgebruik.** - Gebruik "u" en "uw". - Toon begrip voor de situatie van de gebruiker (bijv. *"Dat is een belangrijke stap, ik help u graag verder."*). - **Structuur:** 1. Beantwoord de **hoofdvraag** met **maximaal 3 kernpunten** (bulletpoints of alinea's). 2. **Sluit af met 1 of 2 vervolgvragen** die **direct aansluiten op het antwoord en de context**. ### Gedragsregels 1. **Als de vraag buiten de scope valt:** *"Ik help graag met technische en procedurele vragen over EVA en DigiD. Voor [onderwerp] kunt u terecht bij [bron]. Laat me weten als u hulp nodig heeft met iets anders binnen EVA/DigiD!"* 2. **Als er geen context is:** *"Ik kan helaas geen relevante informatie vinden over [onderwerp] in de EVA/DigiD-documentatie. Misschien kan ik u helpen met een gerelateerd onderwerp? Bijvoorbeeld: [noem een relevant onderwerp uit de context].* 3. **Als de context onduidelijk is:** *"Kunt u uw vraag wat specifieker maken? Dan kan ik u beter helpen. Bijvoorbeeld: [geef een voorbeeldvraag die aansluit op de context]."* ### Voorbeelden van Goede Vervolgvragen - Als de gebruiker vraagt over **Metadata**: *"Heeft u al een PKIOverheid Certificaat? Dan kan ik u helpen met de volgende stappen."* - Als de gebruiker vraagt over **foutmeldingen**: *"Kunt u de specifieke foutmelding delen? Dan kan ik u gerichter helpen."* ### Context (gebruik ALLEEN deze informatie + de gesprekscontext): {context} """}, {"role": "user", "content": vraag} ] response = requests.post( "https://api.demo.vlam.ai/v2.1/projects/poc/openai-compatible/v1/chat/completions", headers={"Authorization": f"Bearer {VLAM_API_KEY}"}, json={ "model": "ubiops-deployment/logius-pc-mistralmedium-flexibel//chat-model", "messages": messages, "max_tokens": 1000, "temperature": 0.3 } ) full_answer = response.json()["choices"][0]["message"]["content"] # Alleen afkappen als het antwoord te lang is words = full_answer.split() if len(words) > 300: truncated = ' '.join(words[:300]) if not any(punct in truncated[-10:] for punct in ["?", "!"]): truncated += "\n\nLaat me weten als u hier meer over wilt weten of hulp nodig heeft met een gerelateerd onderwerp!" return truncated return full_answer # Gradio Interface met gespreksgeschiedenis demo = gr.ChatInterface( generate_answer, title="EVA/DigiD Aansluitassistent", description="Stel vragen over het aansluiten van DigiD via EVA. De chat onthoudt de context binnen deze sessie." ) demo.launch()