Spaces:
Running
Running
import os | |
from langchain_openai import ChatOpenAI | |
from langchain_core.runnables import RunnableLambda | |
from langchain_core.output_parsers import StrOutputParser | |
#from tavily import TavilyClient | |
from dotenv import load_dotenv | |
import datetime | |
# 🔹 Load environment variables from .env file | |
load_dotenv() | |
# 🔹 Retrieve API keys from environment variables | |
# OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") | |
OPENAI_API_KEY = "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" | |
#TAVILY_API_KEY = os.getenv("TAVILY_API_KEY") | |
#if not OPENAI_API_KEY or not TAVILY_API_KEY: | |
# raise ValueError("❌ API keys are missing! Please check your .env file.") | |
# 🔹 Initialize OpenAI and Tavily clients | |
#tavily_client = TavilyClient(api_key=TAVILY_API_KEY) | |
llm = ChatOpenAI( | |
model_name="llama3-8b-8192", | |
temperature=0, | |
streaming=False, # Streaming is controlled by Streamlit | |
openai_api_key=OPENAI_API_KEY, | |
openai_api_base="https://api.groq.com/openai/v1" | |
) | |
# 🔎 Web search function using Tavily API | |
#def search_web_with_tavily(query): | |
# if len(query) < 5: # Ignore very short queries | |
# return "" | |
# | |
# print(f"🔍 Sending query to Tavily: {query}") | |
# search_results = tavily_client.search(query=query, max_results=3) | |
# | |
# # Extract and format the retrieved web results | |
# snippets = [f"{result['title']}: {result['content']}" for result in search_results['results'] if 'content' in result] | |
# | |
# print("✅ Web search results retrieved!") | |
# return "\n".join(snippets) if snippets else "" | |
# 📝 Prompt function for AI response generation | |
def prompt_fn(query: str, context: str, web_context: str = "") -> str: | |
""" | |
This is the main prompt template for the AI assistant. | |
The assistant must: | |
- Prioritize university knowledge first. | |
- Use web search only if internal knowledge is insufficient. | |
- If no relevant information is found, respond with: | |
"I’m sorry, but I don’t have information on this topic." | |
- Avoid unnecessary introductions, greetings, or explanations. | |
""" | |
# Include web search results only if available | |
#search_part = f"\nAdditionally, I found the following information from the web:\n{web_context}\n" if web_context else "" | |
return f""" | |
Below is the available information for answering student inquiries about Vistula University. | |
🔹 Follow this order when answering: | |
1️⃣ **Use internal university knowledge first.** | |
2️⃣ **If internal data lacks relevant details.** | |
3️⃣ **If no useful information is found, respond with: "I’m sorry, but I don’t have information on this topic."** | |
🔹 Important Rules: | |
- **Do not start with introductions.** Provide the answer directly. | |
- **If no information is available, do not add lengthy explanations.** | |
- **Never make up or guess information.** | |
🔹 Available Information: | |
{context} | |
🔹 Question: | |
{query} | |
--- | |
❗ **If no relevant information is found, simply say:** | |
- "I’m sorry, but I don’t have information on this topic." | |
""" | |
# 🔹 Define the AI pipeline (Prompt → LLM → Output Parsing) | |
prompt_runnable = RunnableLambda(lambda inputs: prompt_fn(inputs["query"], inputs["context"], inputs.get("web_context", ""))) | |
rag_chain = prompt_runnable | llm | StrOutputParser() | |
# 🔥 Response generation function | |
def generate_response(retriever, query): | |
# 📌 Eğer soru çok kısa veya selamlaşma ise, özel bir yanıt ver | |
greetings = ["hi", "hello", "hey", "merhaba", "greetings"] | |
if query.lower().strip() in greetings: | |
return "👋 Hello! How can I assist you today?" | |
# 📌 AI veritabanında eşleşen yanıtları getir | |
relevant_docs = retriever.invoke(query) | |
context = "\n".join([doc.page_content for doc in relevant_docs]) | |
# 📌 Eğer hiçbir veri bulunamazsa, AI modeline yönlendirme yap | |
if not relevant_docs or len(context.strip()) < 20: | |
return "I’m sorry, but I don’t have information on this topic." | |
# 📌 AI Modeli ile yanıt oluştur | |
inputs = {"query": query, "context": context} | |
response = rag_chain.invoke(inputs).strip() | |
# 📌 Eğer AI modeli boş veya gereksiz bir yanıt verirse, veritabanına dön | |
if not response or "I don't know" in response.lower(): | |
return context if context else "I’m sorry, but I don’t have information on this topic." | |
return response | |
# 🔹 Logging function for tracking interactions | |
def log_interaction(question, answer, source): | |
log_folder = "logs" | |
os.makedirs(log_folder, exist_ok=True) # Ensure logs directory exists | |
log_file = os.path.join(log_folder, "chat_log.txt") | |
with open(log_file, "a", encoding="utf-8") as f: | |
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Add timestamp | |
f.write(f"{timestamp} | Question: {question}\n") # Log user question | |
f.write(f"{timestamp} | Answer: {answer}\n") # Log AI response | |
f.write(f"{timestamp} | Source: {source}\n") # Indicate data source (VectorStore/Web) | |
f.write("-" * 80 + "\n") # Separator for readability | |