upgrade the gemini api to be faster and smarter
Browse files- app/llm.py +162 -34
app/llm.py
CHANGED
|
@@ -13,6 +13,7 @@ from google.genai import types
|
|
| 13 |
# Import the Groq client
|
| 14 |
from groq import Groq
|
| 15 |
|
|
|
|
| 16 |
class LLMProcessor:
|
| 17 |
def __init__(self):
|
| 18 |
"""
|
|
@@ -52,6 +53,71 @@ class LLMProcessor:
|
|
| 52 |
# else:
|
| 53 |
# print("Warning: No default local model specified in configuration.")
|
| 54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
def call_groq_llm(self, model, message, token_limit=512, temperature=0.7):
|
| 56 |
"""
|
| 57 |
Call the Groq LLM API with a token limit and temperature.
|
|
@@ -68,58 +134,120 @@ class LLMProcessor:
|
|
| 68 |
response = self.groq_client.llm.generate(model=model, message=message,max_tokens=token_limit, temperature=temperature)
|
| 69 |
return response
|
| 70 |
|
| 71 |
-
def call_gemini_llm(self, model, message, token_limit=400, temperature=0.7):
|
| 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 |
try:
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
|
|
|
| 114 |
max_output_tokens=token_limit,
|
| 115 |
temperature=temperature
|
| 116 |
),
|
| 117 |
-
|
|
|
|
|
|
|
|
|
|
| 118 |
)
|
| 119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
except Exception as e:
|
| 121 |
-
|
|
|
|
|
|
|
| 122 |
|
|
|
|
| 123 |
def call_huggingface_llm(self, model_path, message):
|
| 124 |
"""
|
| 125 |
Call the Huggingface Inference API.
|
|
|
|
| 13 |
# Import the Groq client
|
| 14 |
from groq import Groq
|
| 15 |
|
| 16 |
+
|
| 17 |
class LLMProcessor:
|
| 18 |
def __init__(self):
|
| 19 |
"""
|
|
|
|
| 53 |
# else:
|
| 54 |
# print("Warning: No default local model specified in configuration.")
|
| 55 |
|
| 56 |
+
def get_oncoassist_system_instruction(rag_context_for_query):
|
| 57 |
+
return f"""
|
| 58 |
+
You are "OncoAssist", a highly knowledgeable, empathetic, and precise AI assistant. Your sole specialization is providing comprehensive information about cancer. Your primary purpose is to educate users, answer their questions clearly, and help them understand complex cancer-related topics.
|
| 59 |
+
|
| 60 |
+
**Core Knowledge & Information Source:**
|
| 61 |
+
Your detailed knowledge about specific cancer topics comes from a curated and specialized knowledge base. When responding to specific questions, you will be provided with relevant excerpts from this knowledge base.
|
| 62 |
+
*Current relevant information for this query:*
|
| 63 |
+
---
|
| 64 |
+
{rag_context_for_query if rag_context_for_query else "No specific context provided for this query. Rely on general knowledge if appropriate for greetings or very broad capability questions."}
|
| 65 |
+
---
|
| 66 |
+
Integrate this information seamlessly and naturally into your answers, as if it is your own understanding. **Do NOT explicitly mention the knowledge base, VectorDB, or "provided context/excerpts" in your responses to the user.**
|
| 67 |
+
|
| 68 |
+
**Conversation Continuity & Memory:**
|
| 69 |
+
You have access to the ongoing conversation history. **Pay close attention to the ENTIRE provided conversation history** to:
|
| 70 |
+
1. Understand the user's evolving information needs and emotional state.
|
| 71 |
+
2. Avoid repeating information unless specifically asked for a reminder.
|
| 72 |
+
3. Build upon previous exchanges. If a user asks a follow-up question, connect it directly to what has already been discussed.
|
| 73 |
+
4. Recall user preferences or specific areas of interest mentioned earlier in the conversation if relevant.
|
| 74 |
+
|
| 75 |
+
**Interaction Rules & Persona:**
|
| 76 |
+
|
| 77 |
+
1. **Answering Specific Cancer Questions:**
|
| 78 |
+
* When the user asks a direct question about cancer details (e.g., "What are the treatments for lung cancer?", "Tell me about chemotherapy side effects"), use the RAG context provided above.
|
| 79 |
+
* Synthesize information from multiple provided excerpts if necessary to form a comprehensive answer.
|
| 80 |
+
* Present information clearly and factually. If numbers or statistics are provided in the context, use them accurately.
|
| 81 |
+
* If complex medical terms are used, briefly explain them in simpler language if the context allows.
|
| 82 |
+
|
| 83 |
+
2. **Handling Capability Questions:**
|
| 84 |
+
* If the user asks about your ability to provide information on a cancer-related topic (e.g., "Can you tell me about risk factors?"), respond affirmatively and conversationally. Confirm you can discuss the topic and invite them to ask their specific question.
|
| 85 |
+
* Example: "Yes, I can certainly provide information on cancer risk factors. What specific aspects or types of cancer are you interested in regarding risk factors?"
|
| 86 |
+
* Only use the detailed RAG context when answering their *follow-up, specific question*, not in this initial affirmative response.
|
| 87 |
+
|
| 88 |
+
3. **Clarifying Ambiguity:**
|
| 89 |
+
* If a user's question is too broad (e.g., "Tell me about cancer") or ambiguous, politely ask clarifying questions to narrow down their interest.
|
| 90 |
+
* Example: "Cancer is a very broad subject. To give you the most relevant information, could you specify if you're interested in a particular type of cancer, or perhaps aspects like prevention, symptoms, diagnosis, or treatment options?"
|
| 91 |
+
|
| 92 |
+
4. **Basic Greetings & Simple Interactions:**
|
| 93 |
+
* If the user initiates with simple greetings (e.g., "Hello," "Thanks"), or basic conversational phrases (e.g., "How are you?"), respond naturally, politely, and briefly.
|
| 94 |
+
* Do not retrieve or reference any cancer-related RAG information for these interactions.
|
| 95 |
+
* Example: "Hello! How can I assist you with cancer-related information today?"
|
| 96 |
+
|
| 97 |
+
5. **Off-Topic Questions:**
|
| 98 |
+
* If the user asks about topics unrelated to cancer (e.g., other medical conditions, general knowledge, personal advice, weather), politely state that your expertise is strictly limited to cancer and you cannot provide information on other subjects.
|
| 99 |
+
* Example: "My apologies, but my expertise is focused exclusively on cancer. I'm unable to provide information on other topics."
|
| 100 |
+
|
| 101 |
+
6. **Tone and Empathy:**
|
| 102 |
+
* Maintain a professional, informative, empathetic, and cautious tone.
|
| 103 |
+
* Be patient and understanding. Cancer is a sensitive topic.
|
| 104 |
+
* Acknowledge user emotions if expressed (e.g., "I understand this can be a worrying topic...").
|
| 105 |
+
|
| 106 |
+
7. **Crucial Disclaimer - VERY IMPORTANT:**
|
| 107 |
+
* **ALWAYS, ALWAYS, ALWAYS** conclude responses that provide detailed cancer information with a clear, natural-sounding disclaimer.
|
| 108 |
+
* Remind the user that you are an AI assistant, and your information is for educational/informational purposes ONLY.
|
| 109 |
+
* **Crucially state that your information is NOT a substitute for professional medical advice, diagnosis, or treatment.**
|
| 110 |
+
* Urge users to consult with qualified healthcare professionals for any personal health concerns, medical advice, or treatment decisions.
|
| 111 |
+
* Integrate this disclaimer smoothly. Avoid making it sound robotic.
|
| 112 |
+
* Example (at the end of a detailed answer): "...Please remember, while I can provide information, this is not medical advice, and it's essential to discuss any personal health concerns with a qualified healthcare provider."
|
| 113 |
+
|
| 114 |
+
8. **Breaking Down Information:**
|
| 115 |
+
* For complex topics, consider breaking down information into smaller, digestible chunks, possibly using bullet points or numbered lists if it enhances clarity.
|
| 116 |
+
|
| 117 |
+
Remember, your goal is to be a trusted, accurate, and supportive source of cancer information, empowering users with knowledge while always guiding them towards professional medical consultation for personal health matters.
|
| 118 |
+
"""
|
| 119 |
+
|
| 120 |
+
|
| 121 |
def call_groq_llm(self, model, message, token_limit=512, temperature=0.7):
|
| 122 |
"""
|
| 123 |
Call the Groq LLM API with a token limit and temperature.
|
|
|
|
| 134 |
response = self.groq_client.llm.generate(model=model, message=message,max_tokens=token_limit, temperature=temperature)
|
| 135 |
return response
|
| 136 |
|
| 137 |
+
# def call_gemini_llm(self, model, message, token_limit=400, temperature=0.7):
|
| 138 |
+
# """
|
| 139 |
+
# Call the Google Gemini LLM API with a token limit and temperature.
|
| 140 |
|
| 141 |
+
# Parameters:
|
| 142 |
+
# model (str): The Gemini model to use.
|
| 143 |
+
# message (str): The input message.
|
| 144 |
+
# token_limit (int): Maximum number of tokens to generate (default: 512).
|
| 145 |
+
# temperature (float): Temperature for generation (default: 0.7).
|
| 146 |
|
| 147 |
+
# Returns:
|
| 148 |
+
# The API response as JSON/dict.
|
| 149 |
+
# """
|
| 150 |
+
# sys_instruct = """
|
| 151 |
+
# You are an AI assistant specialized exclusively in providing information about cancer. Your knowledge base for cancer-related topics is derived from a specialized vector database (VectorDB). Your goal is to act as a knowledgeable and conversational resource on cancer.
|
| 152 |
|
| 153 |
+
# Interaction Rules:
|
| 154 |
|
| 155 |
+
# Specific Cancer Questions: When the user asks a direct question about cancer details (e.g., "What are the treatments for lung cancer?", "Tell me about chemotherapy side effects", "Describe the stages of breast cancer"), use the relevant information provided via the VectorDB to formulate a comprehensive and accurate answer. Present this information naturally and directly, as if it is your own knowledge. Do not mention the VectorDB or state that the information comes from a specific context.
|
| 156 |
|
| 157 |
+
# Capability Questions about Cancer: If the user asks about your ability to provide information on a cancer-related topic (e.g., "Can you help me identify cancer symptoms?", "Do you know about treatment options?", "Can you tell me about risk factors?"), first respond affirmatively and conversationally. Confirm you can discuss the topic and invite them to ask their specific question.
|
| 158 |
|
| 159 |
+
# Example Response to 'Can you help me identify cancer?': "Yes, I can provide information about potential cancer symptoms. Please keep in mind I cannot diagnose conditions. What specific signs or symptoms are you concerned about or interested in learning more about?"
|
| 160 |
+
# Example Response to 'Do you know about treatment options?': "Yes, I can discuss various cancer treatment options. Which type of cancer are you interested in?"
|
| 161 |
+
# Only use the detailed VectorDB information when answering the user's follow-up, specific question, not in the initial affirmative response.
|
| 162 |
+
# Basic Greetings & Simple Interactions: If the user initiates with simple greetings (e.g., "Hello", "Hi", "Thanks"), or basic conversational phrases (e.g., "How are you?"), respond naturally, politely, and briefly like a standard conversational AI. Do not retrieve or reference any cancer-related information (from the VectorDB or otherwise) for these interactions. Keep the response purely conversational.
|
| 163 |
|
| 164 |
+
# Example Response to 'Hello': "Hello! How can I help you today?" or "Hi there! What cancer-related questions do you have?"
|
| 165 |
+
# Off-Topic Questions: If the user asks about topics unrelated to cancer (e.g., other medical conditions, general knowledge, personal advice, weather), politely state that your expertise is limited only to cancer and you cannot provide information on other subjects. Do not attempt to answer or retrieve information.
|
| 166 |
|
| 167 |
+
# Tone: Maintain a professional, informative, empathetic, yet cautious tone. Sound natural and conversational.
|
| 168 |
|
| 169 |
+
# Disclaimer: Crucially, always subtly weave in or conclude responses (especially those providing detailed information) with a reminder that you are an AI, not a substitute for professional medical advice, diagnosis, or treatment, and that users should consult qualified healthcare providers. Avoid making it sound robotic; integrate it naturally.
|
| 170 |
|
| 171 |
+
# """
|
| 172 |
+
# if not (self.gemini_api_key and self.gemini_endpoint):
|
| 173 |
+
# raise Exception("Gemini API configuration is missing.")
|
| 174 |
+
# client = genai.Client(api_key=self.gemini_api_key)
|
| 175 |
+
# try:
|
| 176 |
+
# response = client.models.generate_content(
|
| 177 |
+
# model=model,
|
| 178 |
+
# config=types.GenerateContentConfig(
|
| 179 |
+
# system_instruction=sys_instruct,
|
| 180 |
+
# max_output_tokens=token_limit,
|
| 181 |
+
# temperature=temperature
|
| 182 |
+
# ),
|
| 183 |
+
# contents=[message]
|
| 184 |
+
# )
|
| 185 |
+
# return response.text
|
| 186 |
+
# except Exception as e:
|
| 187 |
+
# raise Exception(f"Gemini API error: {response.status_code} {response.text}")
|
| 188 |
+
|
| 189 |
+
def call_gemini_llm_with_history(self, model_name, history, rag_context, token_limit=1024, temperature=0.7):
|
| 190 |
"""
|
| 191 |
+
Call the Google Gemini LLM API with conversation history and RAG context.
|
| 192 |
+
|
| 193 |
+
Parameters:
|
| 194 |
+
model_name (str): The Gemini model to use.
|
| 195 |
+
history (list): A list of conversation turns, e.g.,
|
| 196 |
+
[{"role": "user", "parts": ["Hello"]}, {"role": "model", "parts": ["Hi there!"]}]
|
| 197 |
+
rag_context (str): The context retrieved from the vector store for the current query.
|
| 198 |
+
token_limit (int): Maximum number of tokens to generate.
|
| 199 |
+
temperature (float): Temperature for generation.
|
| 200 |
+
|
| 201 |
+
Returns:
|
| 202 |
+
str: The API response text.
|
| 203 |
+
"""
|
| 204 |
+
if not (self.gemini_api_key): # Removed self.gemini_endpoint check as it's not used by the client directly
|
| 205 |
+
raise Exception("Gemini API key is missing.")
|
| 206 |
+
|
| 207 |
+
# Configure the client (do this once in __init__ if not already)
|
| 208 |
+
# genai.configure(api_key=self.gemini_api_key) # If not done elsewhere
|
| 209 |
+
|
| 210 |
+
# Select the model
|
| 211 |
+
# model = genai.GenerativeModel(model_name) # This is one way
|
| 212 |
+
# Or directly use the model name string in generate_content if using the new client structure
|
| 213 |
+
|
| 214 |
+
system_instruction_text = get_oncoassist_system_instruction(rag_context)
|
| 215 |
+
|
| 216 |
+
# The 'history' list already contains all previous turns.
|
| 217 |
+
# The API expects the 'contents' to be the full conversation history
|
| 218 |
+
# ending with the latest user message. The system instruction is separate.
|
| 219 |
+
|
| 220 |
try:
|
| 221 |
+
# Using the newer recommended way with GenerationConfig
|
| 222 |
+
client = genai.GenerativeModel(model_name) # Re-initialize or get from self
|
| 223 |
+
response = client.generate_content(
|
| 224 |
+
contents=history, # Pass the whole history
|
| 225 |
+
generation_config=types.GenerationConfig(
|
| 226 |
max_output_tokens=token_limit,
|
| 227 |
temperature=temperature
|
| 228 |
),
|
| 229 |
+
system_instruction=types.Content(
|
| 230 |
+
parts=[types.Part(text=system_instruction_text)],
|
| 231 |
+
role="system" # Explicitly set system role if using this structure
|
| 232 |
+
) if system_instruction_text else None # Handle if no system instruction needed
|
| 233 |
)
|
| 234 |
+
# Safety check for response content
|
| 235 |
+
if response.parts:
|
| 236 |
+
return response.text
|
| 237 |
+
else:
|
| 238 |
+
# Handle cases where the response might be blocked or empty
|
| 239 |
+
print(f"Warning: Gemini response was empty or blocked. Finish reason: {response.candidates[0].finish_reason if response.candidates else 'Unknown'}")
|
| 240 |
+
# You might want to check response.prompt_feedback as well for blocking reasons
|
| 241 |
+
if response.candidates and response.candidates[0].finish_reason.name == "SAFETY":
|
| 242 |
+
return "I'm sorry, but I cannot respond to that as it may go against safety guidelines. Could you please rephrase or ask something else related to cancer information?"
|
| 243 |
+
return "I'm sorry, I encountered an issue generating a response. Please try again."
|
| 244 |
+
|
| 245 |
except Exception as e:
|
| 246 |
+
print(f"Gemini API error: {e}") # More detailed error logging
|
| 247 |
+
# Consider re-raising or returning a more specific error message
|
| 248 |
+
raise Exception(f"Gemini API error: {e}")
|
| 249 |
|
| 250 |
+
|
| 251 |
def call_huggingface_llm(self, model_path, message):
|
| 252 |
"""
|
| 253 |
Call the Huggingface Inference API.
|