pdf_chat_assistant / src /services /gemini_client.py
Seif-aber
implemented pdf chat assistant with gemini and RAG
edac567
import sys
import os
import google.generativeai as genai
from typing import List, Dict, Optional, Iterator
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')))
from config.settings import Config
class GeminiClient:
"""Generate responses (full or streaming) using Gemini with optional context & history."""
def __init__(self) -> None:
"""Configure model instance."""
Config.validate()
genai.configure(api_key=Config.GEMINI_API_KEY)
self.model = genai.GenerativeModel(Config.GEMINI_MODEL)
def generate_response(self, prompt: str, context: str = "", chat_history: Optional[List[Dict]] = None) -> str:
"""
Produce a model response.
Args:
prompt: User question.
context: Retrieved PDF context.
chat_history: Prior messages list.
Returns:
Response string (or error message).
"""
try:
full_prompt = self._build_prompt(prompt, context, chat_history)
resp = self.model.generate_content(full_prompt)
return getattr(resp, "text", "").strip() or "No response generated."
except Exception as e:
return f"Error generating response: {e}"
def stream_response(self, prompt: str, context: str = "", chat_history: Optional[List[Dict]] = None) -> Iterator[str]:
"""
Stream model tokens/chunks. Yields incremental text fragments.
"""
try:
full_prompt = self._build_prompt(prompt, context, chat_history)
for chunk in self.model.generate_content(full_prompt, stream=True):
txt = getattr(chunk, "text", "")
if txt:
yield txt
except Exception as e:
yield f"[Error] {e}"
def _build_prompt(self, user_prompt: str, context: str, chat_history: Optional[List[Dict]]) -> str:
"""
Construct final prompt sent to LLM.
Args:
user_prompt: Current question.
context: Retrieved context text.
chat_history: List of previous user/assistant dicts.
Returns:
Combined prompt string.
"""
system = (
"You are an assistant answering questions about an uploaded PDF. "
"Base answers only on provided context. If unknown, say you lack the info."
)
parts = [system]
if context:
parts.append(f"\nContext:\n{context}")
if chat_history:
parts.append("\nRecent conversation:")
for m in chat_history[-5:]:
role = m.get("role", "user")
content = m.get("content", "")
parts.append(f"{role}: {content}")
parts.append(f"\nQuestion: {user_prompt}\nAnswer:")
return "\n".join(parts)