Redfire-1234's picture
Add chatbot application for deployment
49adc11
from groq import Groq
from typing import List, Dict, Tuple, Optional
class LLMService:
def __init__(self, api_key: str):
"""Initialize GROQ client"""
self.client = Groq(api_key=api_key)
self.model = "llama-3.3-70b-versatile"
def check_query_clarity(self, question: str, conversation_history: List[Dict[str, str]] = None) -> Tuple[bool, Optional[str]]:
"""Check if query is clear or needs clarification"""
# If there's conversation history, the query is likely clear in context
if conversation_history and len(conversation_history) > 0:
return True, None
# Only check clarity for first question or when no context
# Very short questions (< 10 chars) might need clarification
if len(question.strip()) < 10:
prompt = f"""Is this question too vague to answer without more context?
Question: "{question}"
Respond with ONLY a JSON object:
{{
"is_clear": true/false,
"suggested_clarification": "clarifying question if needed"
}}
Mark as clear (true) unless the question is extremely vague like "what?", "huh?", "more", etc."""
try:
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}],
temperature=0.1,
max_tokens=150
)
import json
result_text = response.choices[0].message.content.strip()
result_text = result_text.replace('```json', '').replace('```', '').strip()
result = json.loads(result_text)
if not result.get("is_clear", True):
return False, result.get("suggested_clarification")
except:
pass
# Default: assume query is clear
return True, None
def rephrase_query(self, question: str, conversation_history: List[Dict[str, str]]) -> str:
"""Rephrase query based on conversation context"""
if not conversation_history or len(conversation_history) == 0:
return question
# Build conversation context - include more history for better understanding
context_parts = []
for msg in conversation_history[-6:]: # Last 6 messages (3 exchanges)
role = "User" if msg['role'] == 'user' else "Assistant"
# Keep full user messages, truncate assistant messages
content = msg['content'] if msg['role'] == 'user' else msg['content'][:200]
context_parts.append(f"{role}: {content}")
context = "\n".join(context_parts)
prompt = f"""Given this conversation history, rephrase the user's latest question to be standalone and include necessary context.
CONVERSATION HISTORY:
{context}
LATEST USER QUESTION: "{question}"
TASK: Rephrase this question so it's clear even without the conversation history.
EXAMPLES:
- If user asks "proper alignment" after discussing "breathing with movement in hatha yoga", rephrase as: "What is proper alignment in breathing with movement in hatha yoga?"
- If user asks "tell me more" after discussing "Product X", rephrase as: "Tell me more about Product X"
- If user asks "benefits" after discussing "meditation", rephrase as: "What are the benefits of meditation?"
- If already clear and standalone, return the EXACT same question
RULES:
1. Include context from previous messages
2. Make it specific and searchable
3. If question is already clear, return it EXACTLY as-is
4. Keep it concise but complete
5. Return ONLY the rephrased question, nothing else
REPHRASED QUESTION:"""
try:
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}],
temperature=0.2,
max_tokens=150
)
rephrased = response.choices[0].message.content.strip()
# Clean up the response
rephrased = rephrased.strip('"').strip("'").strip()
# Remove any labels like "Rephrased question:" or "Answer:"
if ":" in rephrased:
parts = rephrased.split(":", 1)
if len(parts) == 2 and len(parts[0].split()) < 5:
rephrased = parts[1].strip()
# Only return rephrased if it's different and not empty
if rephrased and len(rephrased) > 0:
# Check if significantly different (not just punctuation changes)
if rephrased.lower().strip('?.,! ') != question.lower().strip('?.,! '):
return rephrased
return question
except Exception as e:
print(f"Rephrasing error: {e}")
return question
def generate_answer(
self,
context_chunks: List[str],
question: str,
conversation_history: List[Dict[str, str]] = None
) -> str:
"""Generate answer using GROQ LLM with conversation history"""
# Combine context chunks
context = "\n\n".join([f"[Document Section {i+1}]\n{chunk}" for i, chunk in enumerate(context_chunks)])
# Build conversation history for prompt
history_text = ""
if conversation_history and len(conversation_history) > 0:
# Include last 6 messages (3 exchanges)
recent_history = conversation_history[-6:]
history_text = "\n\nRECENT CONVERSATION:\n"
for msg in recent_history:
role = "User" if msg['role'] == 'user' else "Assistant"
# Keep user questions full, truncate assistant responses
if msg['role'] == 'user':
history_text += f"{role}: {msg['content']}\n"
else:
# Only show first 200 chars of previous answers
content = msg['content'][:200] + "..." if len(msg['content']) > 200 else msg['content']
history_text += f"{role}: {content}\n"
history_text += "\n(Use this conversation context to understand follow-up questions)"
# Create prompt
prompt = f"""You are a helpful AI assistant answering questions about documents.
DOCUMENT CONTENT:
{context}
{history_text}
CURRENT USER QUESTION: {question}
CRITICAL INSTRUCTIONS:
1. Answer ONLY using information from the DOCUMENT CONTENT above
2. Use the conversation history to understand context for follow-up questions
3. If the user refers to something from previous messages (like "it", "that", "the technique"), use the conversation to understand what they mean, but ANSWER from the documents
4. Include inline citations: "According to the document..." or "As mentioned in the guide..."
5. If documents don't contain the answer, say: "I don't have enough information in the provided documents to answer that question."
6. Be direct and helpful - don't ask for clarification unless absolutely necessary
7. Keep answers clear and concise
ANSWER:"""
try:
response = self.client.chat.completions.create(
model=self.model,
messages=[
{
"role": "system",
"content": "You are a document-based Q&A assistant. You understand conversation context but only answer from provided documents. You're helpful and direct."
},
{
"role": "user",
"content": prompt
}
],
temperature=0.3,
max_tokens=600,
top_p=0.9
)
return response.choices[0].message.content.strip()
except Exception as e:
raise Exception(f"Error generating answer: {str(e)}")