Spaces:
Running
Running
| import os | |
| from dotenv import load_dotenv | |
| from langchain_groq import ChatGroq | |
| load_dotenv() | |
| llm = ChatGroq( | |
| model_name="llama-3.3-70b-versatile", | |
| groq_api_key=os.getenv("GROQ_API_KEY"), | |
| temperature=0.3 | |
| ) | |
| def generate_answer(question, retrieved_chunks, language="arabic", | |
| recent_history=None, conversation_summary=None): | |
| """ | |
| Generates the final answer using Groq, grounded in retrieved | |
| document chunks and aware of conversation context. | |
| recent_history: list of the last 1-2 (question, answer) tuples, | |
| kept in full detail | |
| conversation_summary: short summary of everything OLDER than | |
| the recent history, kept compact | |
| """ | |
| context = "\n\n".join(retrieved_chunks) | |
| history_text = "" | |
| if conversation_summary: | |
| history_text += f"Summary of earlier conversation:\n{conversation_summary}\n\n" | |
| if recent_history: | |
| history_text += "Most recent exchange(s):\n" | |
| for past_question, past_answer in recent_history: | |
| history_text += f"Q: {past_question}\nA: {past_answer}\n\n" | |
| if language == "arabic": | |
| prompt = f"""أنت مساعد ذكي متخصص في الإجابة على الأسئلة بناءً على النص المعطى فقط. | |
| {history_text if history_text else ""} | |
| السياق المتاح من الوثيقة: | |
| {context} | |
| السؤال الحالي: | |
| {question} | |
| التعليمات: | |
| - أجب باللغة العربية فقط | |
| - إذا كان السؤال يشير إلى محادثة سابقة (مثل "ذلك" أو "هذا")، استخدم ملخص المحادثة أو آخر تبادل لفهم المرجع | |
| - استخدم فقط المعلومات الموجودة في السياق أعلاه | |
| - لا تضف أي معلومات غير موجودة في الوثيقة، حتى لو كانت معلومات عامة صحيحة | |
| - إذا لم تجد الإجابة، قل بوضوح أنك لا تملك معلومات كافية | |
| الإجابة:""" | |
| else: | |
| prompt = f"""You are a helpful assistant that answers questions based on the provided document context. | |
| {history_text if history_text else ""} | |
| Document context (in Arabic): | |
| {context} | |
| Current question: | |
| {question} | |
| Instructions: | |
| - Answer ONLY in English | |
| - If the question refers to earlier conversation (like "that" or "it"), use the summary or recent exchange to understand the reference | |
| - Use the information found in the context above | |
| - If the answer is not in the context, clearly say you don't have enough information | |
| - Don't give information which is not in the PDF if something is not there in the PDF simply say you don't have enough information | |
| Answer:""" | |
| response = llm.invoke(prompt) | |
| return response.content | |
| def translate_to_arabic(english_text): | |
| """ | |
| Translates an English question into Arabic using Groq, | |
| so we can search our all-Arabic vector store accurately. | |
| This fixes cross-lingual retrieval failures on larger, | |
| more complex documents. | |
| """ | |
| prompt = f"""Translate the following English question into Modern Standard Arabic. | |
| Only output the Arabic translation, nothing else - no explanation, no quotes. | |
| English: {english_text} | |
| Arabic translation:""" | |
| response = llm.invoke(prompt) | |
| return response.content.strip() | |
| def summarize_conversation(existing_summary, old_question, old_answer): | |
| """ | |
| Takes the current running summary plus one older exchange | |
| that's about to fall out of the "recent" window, and asks | |
| Groq to fold it into an updated, still-short summary. | |
| This keeps conversation memory compact regardless of how | |
| long the chat gets, instead of sending the full raw history | |
| every time. | |
| """ | |
| prompt = f"""You are maintaining a brief running summary of a conversation between a user and an assistant about a document. | |
| Existing summary so far: | |
| {existing_summary if existing_summary else "(no summary yet - this is the first exchange to summarize)"} | |
| New exchange to fold in: | |
| User asked: {old_question} | |
| Assistant answered: {old_answer} | |
| Update the summary to include this new exchange, staying concise. | |
| Keep it to 2-4 sentences maximum. Focus on WHAT TOPICS were discussed | |
| and any specific facts/numbers that might be referenced later, not | |
| the exact wording. Output ONLY the updated summary, nothing else. | |
| Updated summary:""" | |
| response = llm.invoke(prompt) | |
| return response.content.strip() |