Spaces:
Sleeping
Sleeping
Commit ·
27d1bb9
1
Parent(s): 308053f
feat: upgrade RAG conversational intent classification to multi-lingual LLM
Browse files- RAG_FULL_APPLICATION_BACKEND/app/services/advanced_services.py +17 -1
- RAG_FULL_APPLICATION_BACKEND/app/techniques/agentic_rag.py +1 -2
- RAG_FULL_APPLICATION_BACKEND/app/techniques/base.py +12 -0
- RAG_FULL_APPLICATION_BACKEND/app/techniques/colbert.py +1 -2
- RAG_FULL_APPLICATION_BACKEND/app/techniques/hybrid_search.py +1 -2
- RAG_FULL_APPLICATION_BACKEND/app/techniques/metadata_filter.py +1 -2
- RAG_FULL_APPLICATION_BACKEND/app/techniques/query_expansion.py +1 -2
- RAG_FULL_APPLICATION_BACKEND/app/techniques/reranking.py +1 -2
- test_gemini.py +10 -0
- test_models.py +50 -0
- test_rag_doc.txt +1 -0
RAG_FULL_APPLICATION_BACKEND/app/services/advanced_services.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
from abc import ABC, abstractmethod
|
| 2 |
from typing import List, Dict, Any, Tuple
|
| 3 |
import re
|
|
|
|
| 4 |
|
| 5 |
# ==========================================
|
| 6 |
# 1. GRAPH RAG SERVICE (SOLID: Interface & Implementation)
|
|
@@ -70,7 +71,22 @@ class CorrectiveRAGService(ICorrectiveRAGService):
|
|
| 70 |
else:
|
| 71 |
max_similarity = max([c.get("similarity", 0.0) for c in retrieved_chunks] or [0.0])
|
| 72 |
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
if is_low_confidence:
|
| 76 |
# Perform web search fallback simulation
|
|
|
|
| 1 |
from abc import ABC, abstractmethod
|
| 2 |
from typing import List, Dict, Any, Tuple
|
| 3 |
import re
|
| 4 |
+
from ..services.llm_service import llm_service
|
| 5 |
|
| 6 |
# ==========================================
|
| 7 |
# 1. GRAPH RAG SERVICE (SOLID: Interface & Implementation)
|
|
|
|
| 71 |
else:
|
| 72 |
max_similarity = max([c.get("similarity", 0.0) for c in retrieved_chunks] or [0.0])
|
| 73 |
|
| 74 |
+
intent_prompt = f"""Analyze the following user query: "{query}"
|
| 75 |
+
Determine if the query is EITHER:
|
| 76 |
+
1. A conversational greeting (e.g., "hi", "namaste", "hello there", "namaskaram") OR
|
| 77 |
+
2. A general summarization or document inquiry (e.g., "what is this document about?", "summarize this", "idi emiti")
|
| 78 |
+
|
| 79 |
+
Return ONLY a JSON object:
|
| 80 |
+
{{"is_conversational": true/false}}
|
| 81 |
+
"""
|
| 82 |
+
try:
|
| 83 |
+
intent_res = llm_service.evaluate_json(intent_prompt)
|
| 84 |
+
is_conversational = intent_res.get("is_conversational", False)
|
| 85 |
+
except Exception:
|
| 86 |
+
# Fallback to simple heuristic if LLM fails
|
| 87 |
+
is_conversational = len(query.split()) < 3
|
| 88 |
+
|
| 89 |
+
is_low_confidence = (max_similarity < 0.50) and not is_conversational
|
| 90 |
|
| 91 |
if is_low_confidence:
|
| 92 |
# Perform web search fallback simulation
|
RAG_FULL_APPLICATION_BACKEND/app/techniques/agentic_rag.py
CHANGED
|
@@ -96,6 +96,5 @@ Respond ONLY with a JSON object:
|
|
| 96 |
return self.final_agent_answer
|
| 97 |
|
| 98 |
await self.emit("GENERATE", "#7C3AED", "Qwen3 generating final summary...")
|
| 99 |
-
|
| 100 |
-
prompt = f"Context:\n{context}\n\nQuestion: {query}\n\nAnswer based ONLY on the context:"
|
| 101 |
return self.llm.generate(prompt)
|
|
|
|
| 96 |
return self.final_agent_answer
|
| 97 |
|
| 98 |
await self.emit("GENERATE", "#7C3AED", "Qwen3 generating final summary...")
|
| 99 |
+
prompt = self.build_prompt(query, chunks)
|
|
|
|
| 100 |
return self.llm.generate(prompt)
|
RAG_FULL_APPLICATION_BACKEND/app/techniques/base.py
CHANGED
|
@@ -15,6 +15,18 @@ class BaseRAGTechnique(ABC):
|
|
| 15 |
self.supabase = supabase_service
|
| 16 |
self.llm = llm_service
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
@abstractmethod
|
| 19 |
async def retrieve(self, query: str, document_id: str, top_k: int, **kwargs) -> List[Dict[str, Any]]:
|
| 20 |
pass
|
|
|
|
| 15 |
self.supabase = supabase_service
|
| 16 |
self.llm = llm_service
|
| 17 |
|
| 18 |
+
def build_prompt(self, query: str, chunks: List[Dict[str, Any]]) -> str:
|
| 19 |
+
context = "\n\n".join([c["text"] for c in chunks])
|
| 20 |
+
return f"""Context:
|
| 21 |
+
{context}
|
| 22 |
+
|
| 23 |
+
Question: {query}
|
| 24 |
+
|
| 25 |
+
Instructions:
|
| 26 |
+
1. If the user is just saying a general greeting (e.g., "hi", "hello"), respond politely without using the context.
|
| 27 |
+
2. If the user asks a general question about the document itself (e.g., "what is this document about?", "summarize"), summarize the provided context to answer.
|
| 28 |
+
3. Otherwise, answer the question based ONLY on the provided context. If the answer is not in the context, state that clearly."""
|
| 29 |
+
|
| 30 |
@abstractmethod
|
| 31 |
async def retrieve(self, query: str, document_id: str, top_k: int, **kwargs) -> List[Dict[str, Any]]:
|
| 32 |
pass
|
RAG_FULL_APPLICATION_BACKEND/app/techniques/colbert.py
CHANGED
|
@@ -71,6 +71,5 @@ class ColBERT(BaseRAGTechnique):
|
|
| 71 |
|
| 72 |
async def generate(self, query: str, chunks: List[Dict[str, Any]]) -> str:
|
| 73 |
await self.emit("GENERATE", "#7C3AED", "Qwen3 generating answer...")
|
| 74 |
-
|
| 75 |
-
prompt = f"Context:\n{context}\n\nQuestion: {query}\n\nAnswer based ONLY on the context:"
|
| 76 |
return self.llm.generate(prompt)
|
|
|
|
| 71 |
|
| 72 |
async def generate(self, query: str, chunks: List[Dict[str, Any]]) -> str:
|
| 73 |
await self.emit("GENERATE", "#7C3AED", "Qwen3 generating answer...")
|
| 74 |
+
prompt = self.build_prompt(query, chunks)
|
|
|
|
| 75 |
return self.llm.generate(prompt)
|
RAG_FULL_APPLICATION_BACKEND/app/techniques/hybrid_search.py
CHANGED
|
@@ -56,7 +56,6 @@ class HybridSearch(BaseRAGTechnique):
|
|
| 56 |
"context_chunks": len(chunks),
|
| 57 |
"temperature": 0.1
|
| 58 |
})
|
| 59 |
-
|
| 60 |
-
prompt = f"Context:\n{context}\n\nQuestion: {query}\n\nAnswer based ONLY on the context:"
|
| 61 |
return self.llm.generate(prompt)
|
| 62 |
|
|
|
|
| 56 |
"context_chunks": len(chunks),
|
| 57 |
"temperature": 0.1
|
| 58 |
})
|
| 59 |
+
prompt = self.build_prompt(query, chunks)
|
|
|
|
| 60 |
return self.llm.generate(prompt)
|
| 61 |
|
RAG_FULL_APPLICATION_BACKEND/app/techniques/metadata_filter.py
CHANGED
|
@@ -33,6 +33,5 @@ class MetadataFilter(BaseRAGTechnique):
|
|
| 33 |
|
| 34 |
async def generate(self, query: str, chunks: List[Dict[str, Any]]) -> str:
|
| 35 |
await self.emit("GENERATE", "#7C3AED", "Qwen3 generating answer...")
|
| 36 |
-
|
| 37 |
-
prompt = f"Context:\n{context}\n\nQuestion: {query}\n\nAnswer based ONLY on the context:"
|
| 38 |
return self.llm.generate(prompt)
|
|
|
|
| 33 |
|
| 34 |
async def generate(self, query: str, chunks: List[Dict[str, Any]]) -> str:
|
| 35 |
await self.emit("GENERATE", "#7C3AED", "Qwen3 generating answer...")
|
| 36 |
+
prompt = self.build_prompt(query, chunks)
|
|
|
|
| 37 |
return self.llm.generate(prompt)
|
RAG_FULL_APPLICATION_BACKEND/app/techniques/query_expansion.py
CHANGED
|
@@ -68,7 +68,6 @@ class QueryExpansion(BaseRAGTechnique):
|
|
| 68 |
"llm": "Primary Qwen / Backup GLM-4.7-Flash",
|
| 69 |
"chunks_used": len(chunks)
|
| 70 |
})
|
| 71 |
-
|
| 72 |
-
prompt = f"Context:\n{context}\n\nQuestion: {query}\n\nAnswer based ONLY on the context:"
|
| 73 |
return self.llm.generate(prompt)
|
| 74 |
|
|
|
|
| 68 |
"llm": "Primary Qwen / Backup GLM-4.7-Flash",
|
| 69 |
"chunks_used": len(chunks)
|
| 70 |
})
|
| 71 |
+
prompt = self.build_prompt(query, chunks)
|
|
|
|
| 72 |
return self.llm.generate(prompt)
|
| 73 |
|
RAG_FULL_APPLICATION_BACKEND/app/techniques/reranking.py
CHANGED
|
@@ -25,6 +25,5 @@ class ReRanking(BaseRAGTechnique):
|
|
| 25 |
|
| 26 |
async def generate(self, query: str, chunks: List[Dict[str, Any]]) -> str:
|
| 27 |
await self.emit("GENERATE", "#7C3AED", "Qwen3 generating answer...")
|
| 28 |
-
|
| 29 |
-
prompt = f"Context:\n{context}\n\nQuestion: {query}\n\nAnswer based ONLY on the context:"
|
| 30 |
return self.llm.generate(prompt)
|
|
|
|
| 25 |
|
| 26 |
async def generate(self, query: str, chunks: List[Dict[str, Any]]) -> str:
|
| 27 |
await self.emit("GENERATE", "#7C3AED", "Qwen3 generating answer...")
|
| 28 |
+
prompt = self.build_prompt(query, chunks)
|
|
|
|
| 29 |
return self.llm.generate(prompt)
|
test_gemini.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import requests
|
| 2 |
+
key = "YOUR_GEMINI_API_KEY"
|
| 3 |
+
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-lite:generateContent?key={key}"
|
| 4 |
+
payload = {
|
| 5 |
+
"contents": [{"parts": [{"text": "Hello"}]}],
|
| 6 |
+
"systemInstruction": {"parts": [{"text": ""}]}
|
| 7 |
+
}
|
| 8 |
+
res = requests.post(url, headers={'Content-Type': 'application/json'}, json=payload)
|
| 9 |
+
print(res.status_code)
|
| 10 |
+
print(res.text)
|
test_models.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from gradio_client import Client
|
| 2 |
+
import time
|
| 3 |
+
|
| 4 |
+
def test_hy3():
|
| 5 |
+
try:
|
| 6 |
+
print("Testing Tencent/Hy3...")
|
| 7 |
+
client = Client("tencent/Hy3")
|
| 8 |
+
result = client.predict(
|
| 9 |
+
message="Hello",
|
| 10 |
+
system_prompt="",
|
| 11 |
+
history=None,
|
| 12 |
+
think_level="high",
|
| 13 |
+
temperature=0.7,
|
| 14 |
+
max_tokens=100,
|
| 15 |
+
top_p=0.8,
|
| 16 |
+
functions_json_str="",
|
| 17 |
+
api_name="/chat"
|
| 18 |
+
)
|
| 19 |
+
print("Hy3 Response:", str(result)[:200])
|
| 20 |
+
return True
|
| 21 |
+
except Exception as e:
|
| 22 |
+
print("Hy3 Error:", e)
|
| 23 |
+
return False
|
| 24 |
+
|
| 25 |
+
def test_qwen_omni():
|
| 26 |
+
try:
|
| 27 |
+
print("\nTesting Qwen3.5-Omni-Offline-Demo...")
|
| 28 |
+
client = Client("Qwen/Qwen3.5-Omni-Offline-Demo")
|
| 29 |
+
client.predict(api_name="/clear_history_offline")
|
| 30 |
+
result = client.predict(
|
| 31 |
+
text="Hello",
|
| 32 |
+
audio=None,
|
| 33 |
+
image=None,
|
| 34 |
+
video=None,
|
| 35 |
+
history=[],
|
| 36 |
+
system_prompt="",
|
| 37 |
+
temperature=0.7,
|
| 38 |
+
top_p=0.8,
|
| 39 |
+
top_k=20,
|
| 40 |
+
api_name="/chat_predict"
|
| 41 |
+
)
|
| 42 |
+
print("Qwen Omni Response:", str(result)[:200])
|
| 43 |
+
return True
|
| 44 |
+
except Exception as e:
|
| 45 |
+
print("Qwen Omni Error:", e)
|
| 46 |
+
return False
|
| 47 |
+
|
| 48 |
+
if __name__ == "__main__":
|
| 49 |
+
test_hy3()
|
| 50 |
+
test_qwen_omni()
|
test_rag_doc.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
This is a test document for RAG ingestion. The sky is blue and water is wet.
|