Spaces:
Sleeping
Sleeping
File size: 7,074 Bytes
85ff768 814245b 85ff768 814245b 85ff768 814245b 85ff768 814245b 85ff768 814245b 85ff768 814245b e4ec6e0 814245b 85ff768 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | """
Gemini AI Client for Chat Search
Uses Gemini 1.5 Flash to summarize search results and answer questions.
"""
import os
from typing import List, Dict, Optional
# Try importing Google GenAI (new package)
try:
from google import genai
HAS_GEMINI = True
except ImportError:
HAS_GEMINI = False
class GeminiClient:
"""Client for Gemini AI API."""
def __init__(self, api_key: Optional[str] = None):
self.api_key = api_key or os.environ.get('GEMINI_API_KEY')
self.client = None
self._initialized = False
def _initialize(self):
"""Initialize the Gemini client."""
if self._initialized:
return True
if not HAS_GEMINI:
print("google-genai not installed")
return False
if not self.api_key:
print("GEMINI_API_KEY not set")
return False
try:
self.client = genai.Client(api_key=self.api_key)
self._initialized = True
print("Gemini client initialized")
return True
except Exception as e:
print(f"Failed to initialize Gemini: {e}")
return False
def answer_from_context(self, query: str, search_results: List[Dict],
max_results: int = 5) -> Dict:
"""
Generate an answer based on search results.
Args:
query: User's question
search_results: List of search results with context
max_results: Max results to include in context
Returns:
Dict with 'answer', 'sources', and 'success'
"""
if not self._initialize():
return {
'success': False,
'error': 'Gemini not available',
'answer': None
}
# Build context from search results
context_parts = []
sources = []
for i, result in enumerate(search_results[:max_results]):
# Handle different result formats
if 'message' in result:
# search_with_context format
msg = result['message']
context_parts.append(f"""
--- 转讜爪讗讛 {i+1} (爪讬讜谉: {result.get('score', 0):.2f}) ---
诪讗转: {msg.get('from_name', '诇讗 讬讚讜注')}
转讗专讬讱: {msg.get('date', '诇讗 讬讚讜注')}
讛讜讚注讛: {msg.get('text', '')}
""")
sources.append({
'from_name': msg.get('from_name'),
'date': msg.get('date'),
'message_id': result.get('message_id')
})
# Add context if available
if result.get('context_before'):
context_parts.append("讛拽砖专 诇驻谞讬:")
for ctx in result['context_before']:
context_parts.append(f" [{ctx.get('from_name', '?')}] {ctx.get('text_plain', '')[:100]}")
if result.get('context_after'):
context_parts.append("讛拽砖专 讗讞专讬:")
for ctx in result['context_after']:
context_parts.append(f" [{ctx.get('from_name', '?')}] {ctx.get('text_plain', '')[:100]}")
elif 'chunk_text' in result:
# hybrid_search format
context_parts.append(f"""
--- 转讜爪讗讛 {i+1} (爪讬讜谉: {result.get('score', 0):.2f}) ---
{result.get('chunk_text', '')}
""")
sources.append({
'message_id': result.get('message_id'),
'score': result.get('score')
})
context = "\n".join(context_parts)
# Build prompt
prompt = f"""讗转讛 注讜讝专 砖诪谞转讞 砖讬讞讜转 诪拽讘讜爪转 讟诇讙专诐 讜注讜谞讛 注诇 砖讗诇讜转.
讛砖讗诇讛: {query}
诇讛诇谉 转讜爪讗讜转 讞讬驻讜砖 专诇讜讜谞讟讬讜转 诪讛砖讬讞讜转:
{context}
讛谞讞讬讜转:
1. 注谞讛 讘注讘专讬转
2. 转谉 转砖讜讘讛 拽爪专讛 讜诪诪讜拽讚转 (1-3 诪砖驻讟讬诐)
3. 讗诐 讛诪讬讚注 诇讗 讘专讜专 讗讜 诇讗 拽讬讬诐 讘转讜爪讗讜转, 讗诪讜专 "诇讗 诪爪讗转讬 诪讬讚注 讘专讜专"
4. 爪讬讬谉 讗转 讛诪拽讜专 (砖诐 讛砖讜诇讞 讜讛转讗专讬讱) 讗诐 专诇讜讜谞讟讬
5. 讗诇 转诪爪讬讗 诪讬讚注 砖诇讗 诪讜驻讬注 讘转讜爪讗讜转
讛转砖讜讘讛:"""
try:
response = self.client.models.generate_content(
model='gemini-2.5-flash',
contents=prompt
)
answer = response.text.strip()
return {
'success': True,
'answer': answer,
'sources': sources,
'query': query,
'results_used': len(context_parts)
}
except Exception as e:
return {
'success': False,
'error': str(e),
'answer': None
}
def is_available(self) -> bool:
"""Check if Gemini is available."""
return self._initialize()
# Singleton instance
_gemini_client = None
def get_gemini_client() -> GeminiClient:
"""Get or create Gemini client instance."""
global _gemini_client
if _gemini_client is None:
_gemini_client = GeminiClient()
return _gemini_client
def ai_search(query: str, limit: int = 5) -> Dict:
"""
Perform AI-powered search: hybrid search + Gemini summarization.
Args:
query: Search query
limit: Max results to use
Returns:
Dict with answer and metadata
"""
from hybrid_search import get_hybrid_search
# Get hybrid search results
hs = get_hybrid_search()
results = hs.search_with_context(query, limit=limit)
if not results:
return {
'success': False,
'error': 'No search results found',
'answer': '诇讗 谞诪爪讗讜 转讜爪讗讜转 诇讞讬驻讜砖 讝讛',
'query': query
}
# Get AI answer
client = get_gemini_client()
response = client.answer_from_context(query, results, max_results=limit)
# Add raw results for transparency
response['search_results'] = results
return response
# CLI for testing
if __name__ == '__main__':
import sys
if len(sys.argv) < 2:
print("Usage: python gemini_client.py 'search query'")
print("\nChecking Gemini availability...")
client = get_gemini_client()
if client.is_available():
print("Gemini is available!")
else:
print("Gemini is NOT available. Set GEMINI_API_KEY environment variable.")
sys.exit(0)
query = ' '.join(sys.argv[1:])
print(f"\n=== AI Search: {query} ===\n")
result = ai_search(query)
if result['success']:
print(f"Answer: {result['answer']}")
print(f"\nSources: {len(result.get('sources', []))} results used")
else:
print(f"Error: {result.get('error')}")
|