Spaces:
Sleeping
Sleeping
Updated integration with Google Gemini AI, replacing the library with the new google-genai. Added new AI models, updated provider configuration, and improved query processing. Fixed bugs in response generation and logging. Changed default values for models in the configuration. Testing was successful.
Browse files- ai_client.py +33 -19
- ai_providers_config.py +12 -8
ai_client.py
CHANGED
|
@@ -21,8 +21,8 @@ from ai_providers_config import (
|
|
| 21 |
|
| 22 |
# Import provider-specific clients
|
| 23 |
try:
|
| 24 |
-
import google.
|
| 25 |
-
from google.
|
| 26 |
GEMINI_AVAILABLE = True
|
| 27 |
except ImportError:
|
| 28 |
GEMINI_AVAILABLE = False
|
|
@@ -93,52 +93,66 @@ class BaseAIClient(ABC):
|
|
| 93 |
logger.info(log_message)
|
| 94 |
|
| 95 |
class GeminiClient(BaseAIClient):
|
| 96 |
-
"""Google Gemini AI client"""
|
| 97 |
|
| 98 |
def __init__(self, model: AIModel, temperature: float = 0.3):
|
| 99 |
super().__init__(AIProvider.GEMINI, model, temperature)
|
| 100 |
|
| 101 |
if not GEMINI_AVAILABLE:
|
| 102 |
-
raise ImportError("Google
|
| 103 |
-
|
| 104 |
api_key = os.getenv("GEMINI_API_KEY")
|
| 105 |
if not api_key:
|
| 106 |
raise ValueError("GEMINI_API_KEY environment variable not set")
|
| 107 |
|
| 108 |
self.client = genai.Client(api_key=api_key)
|
|
|
|
| 109 |
|
| 110 |
def generate_response(self, system_prompt: str, user_prompt: str, temperature: Optional[float] = None) -> str:
|
| 111 |
-
"""Generate response from Gemini"""
|
| 112 |
-
|
| 113 |
-
|
|
|
|
| 114 |
try:
|
|
|
|
| 115 |
contents = [
|
| 116 |
types.Content(
|
| 117 |
role="user",
|
| 118 |
parts=[types.Part.from_text(text=user_prompt)],
|
| 119 |
-
)
|
| 120 |
]
|
| 121 |
|
|
|
|
| 122 |
config = types.GenerateContentConfig(
|
| 123 |
-
temperature=
|
| 124 |
-
|
| 125 |
-
types.Part.from_text(text=system_prompt),
|
| 126 |
-
],
|
| 127 |
)
|
| 128 |
|
| 129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
for chunk in self.client.models.generate_content_stream(
|
| 131 |
-
model=self.
|
| 132 |
contents=contents,
|
| 133 |
config=config,
|
| 134 |
):
|
| 135 |
-
|
|
|
|
| 136 |
|
| 137 |
-
|
| 138 |
-
|
|
|
|
|
|
|
| 139 |
|
| 140 |
except Exception as e:
|
| 141 |
-
|
|
|
|
|
|
|
| 142 |
|
| 143 |
class AnthropicClient(BaseAIClient):
|
| 144 |
"""Anthropic Claude AI client"""
|
|
|
|
| 21 |
|
| 22 |
# Import provider-specific clients
|
| 23 |
try:
|
| 24 |
+
import google.genai as genai
|
| 25 |
+
from google.genai import types
|
| 26 |
GEMINI_AVAILABLE = True
|
| 27 |
except ImportError:
|
| 28 |
GEMINI_AVAILABLE = False
|
|
|
|
| 93 |
logger.info(log_message)
|
| 94 |
|
| 95 |
class GeminiClient(BaseAIClient):
|
| 96 |
+
"""Google Gemini AI client using the new google-genai library"""
|
| 97 |
|
| 98 |
def __init__(self, model: AIModel, temperature: float = 0.3):
|
| 99 |
super().__init__(AIProvider.GEMINI, model, temperature)
|
| 100 |
|
| 101 |
if not GEMINI_AVAILABLE:
|
| 102 |
+
raise ImportError("Google GenAI library not available. Install with: pip install google-genai")
|
| 103 |
+
|
| 104 |
api_key = os.getenv("GEMINI_API_KEY")
|
| 105 |
if not api_key:
|
| 106 |
raise ValueError("GEMINI_API_KEY environment variable not set")
|
| 107 |
|
| 108 |
self.client = genai.Client(api_key=api_key)
|
| 109 |
+
self.model_name = model.value
|
| 110 |
|
| 111 |
def generate_response(self, system_prompt: str, user_prompt: str, temperature: Optional[float] = None) -> str:
|
| 112 |
+
"""Generate response from Gemini using the new API"""
|
| 113 |
+
if temperature is None:
|
| 114 |
+
temperature = self.temperature
|
| 115 |
+
|
| 116 |
try:
|
| 117 |
+
# Prepare the content parts
|
| 118 |
contents = [
|
| 119 |
types.Content(
|
| 120 |
role="user",
|
| 121 |
parts=[types.Part.from_text(text=user_prompt)],
|
| 122 |
+
)
|
| 123 |
]
|
| 124 |
|
| 125 |
+
# Configure generation settings
|
| 126 |
config = types.GenerateContentConfig(
|
| 127 |
+
temperature=temperature,
|
| 128 |
+
thinking_config=types.ThinkingConfig(thinking_budget=0),
|
|
|
|
|
|
|
| 129 |
)
|
| 130 |
|
| 131 |
+
# Add system prompt if provided
|
| 132 |
+
if system_prompt:
|
| 133 |
+
config.system_instruction = [
|
| 134 |
+
types.Part.from_text(text=system_prompt)
|
| 135 |
+
]
|
| 136 |
+
|
| 137 |
+
# Generate the response
|
| 138 |
+
response_text = ""
|
| 139 |
for chunk in self.client.models.generate_content_stream(
|
| 140 |
+
model=self.model_name,
|
| 141 |
contents=contents,
|
| 142 |
config=config,
|
| 143 |
):
|
| 144 |
+
if chunk.text:
|
| 145 |
+
response_text += chunk.text
|
| 146 |
|
| 147 |
+
# Log the interaction
|
| 148 |
+
self._log_interaction(system_prompt, user_prompt, response_text, "gemini")
|
| 149 |
+
|
| 150 |
+
return response_text
|
| 151 |
|
| 152 |
except Exception as e:
|
| 153 |
+
error_msg = f"Gemini API error: {str(e)}"
|
| 154 |
+
logging.error(error_msg)
|
| 155 |
+
raise RuntimeError(error_msg) from e
|
| 156 |
|
| 157 |
class AnthropicClient(BaseAIClient):
|
| 158 |
"""Anthropic Claude AI client"""
|
ai_providers_config.py
CHANGED
|
@@ -19,11 +19,13 @@ class AIModel(Enum):
|
|
| 19 |
"""Supported AI models"""
|
| 20 |
# Gemini models
|
| 21 |
GEMINI_2_5_FLASH = "gemini-2.5-flash"
|
|
|
|
| 22 |
GEMINI_2_5_PRO = "gemini-2.5-pro"
|
| 23 |
GEMINI_1_5_PRO = "gemini-1.5-pro"
|
| 24 |
|
| 25 |
# Anthropic models
|
| 26 |
CLAUDE_SONNET_4 = "claude-sonnet-4-20250514"
|
|
|
|
| 27 |
CLAUDE_SONNET_3_5 = "claude-3-5-sonnet-20241022"
|
| 28 |
CLAUDE_HAIKU_3_5 = "claude-3-5-haiku-20241022"
|
| 29 |
|
|
@@ -31,11 +33,12 @@ class AIModel(Enum):
|
|
| 31 |
PROVIDER_CONFIGS = {
|
| 32 |
AIProvider.GEMINI: {
|
| 33 |
"api_key_env": "GEMINI_API_KEY",
|
| 34 |
-
"default_model": AIModel.
|
| 35 |
"default_temperature": 0.3,
|
| 36 |
"max_tokens": None, # Gemini handles this automatically
|
| 37 |
"available_models": [
|
| 38 |
AIModel.GEMINI_2_5_FLASH,
|
|
|
|
| 39 |
AIModel.GEMINI_2_5_PRO,
|
| 40 |
AIModel.GEMINI_1_5_PRO
|
| 41 |
]
|
|
@@ -47,6 +50,7 @@ PROVIDER_CONFIGS = {
|
|
| 47 |
"max_tokens": 20000,
|
| 48 |
"available_models": [
|
| 49 |
AIModel.CLAUDE_SONNET_4,
|
|
|
|
| 50 |
AIModel.CLAUDE_SONNET_3_5,
|
| 51 |
AIModel.CLAUDE_HAIKU_3_5
|
| 52 |
]
|
|
@@ -59,42 +63,42 @@ AGENT_CONFIGURATIONS = {
|
|
| 59 |
"MainLifestyleAssistant": {
|
| 60 |
"provider": AIProvider.ANTHROPIC,
|
| 61 |
"model": AIModel.CLAUDE_SONNET_4,
|
| 62 |
-
"temperature": 0.
|
| 63 |
"reasoning": "Complex lifestyle coaching requires advanced reasoning capabilities"
|
| 64 |
},
|
| 65 |
|
| 66 |
# All other agents use Google Gemini
|
| 67 |
"EntryClassifier": {
|
| 68 |
"provider": AIProvider.GEMINI,
|
| 69 |
-
"model": AIModel.
|
| 70 |
"temperature": 0.1,
|
| 71 |
"reasoning": "Fast classification task, optimized for speed"
|
| 72 |
},
|
| 73 |
|
| 74 |
"TriageExitClassifier": {
|
| 75 |
"provider": AIProvider.GEMINI,
|
| 76 |
-
"model": AIModel.
|
| 77 |
"temperature": 0.2,
|
| 78 |
"reasoning": "Medical triage decisions require consistency"
|
| 79 |
},
|
| 80 |
|
| 81 |
"MedicalAssistant": {
|
| 82 |
-
"provider": AIProvider.
|
| 83 |
-
"model": AIModel.
|
| 84 |
"temperature": 0.2,
|
| 85 |
"reasoning": "Medical guidance requires reliable, consistent responses"
|
| 86 |
},
|
| 87 |
|
| 88 |
"SoftMedicalTriage": {
|
| 89 |
"provider": AIProvider.GEMINI,
|
| 90 |
-
"model": AIModel.
|
| 91 |
"temperature": 0.3,
|
| 92 |
"reasoning": "Gentle triage can use faster model"
|
| 93 |
},
|
| 94 |
|
| 95 |
"LifestyleProfileUpdater": {
|
| 96 |
"provider": AIProvider.GEMINI,
|
| 97 |
-
"model": AIModel.
|
| 98 |
"temperature": 0.2,
|
| 99 |
"reasoning": "Profile analysis requires detailed processing"
|
| 100 |
}
|
|
|
|
| 19 |
"""Supported AI models"""
|
| 20 |
# Gemini models
|
| 21 |
GEMINI_2_5_FLASH = "gemini-2.5-flash"
|
| 22 |
+
GEMINI_2_0_FLASH = "gemini-2.0-flash"
|
| 23 |
GEMINI_2_5_PRO = "gemini-2.5-pro"
|
| 24 |
GEMINI_1_5_PRO = "gemini-1.5-pro"
|
| 25 |
|
| 26 |
# Anthropic models
|
| 27 |
CLAUDE_SONNET_4 = "claude-sonnet-4-20250514"
|
| 28 |
+
CLAUDE_SONNET_3_7 = "claude-3-7-sonnet-20250219"
|
| 29 |
CLAUDE_SONNET_3_5 = "claude-3-5-sonnet-20241022"
|
| 30 |
CLAUDE_HAIKU_3_5 = "claude-3-5-haiku-20241022"
|
| 31 |
|
|
|
|
| 33 |
PROVIDER_CONFIGS = {
|
| 34 |
AIProvider.GEMINI: {
|
| 35 |
"api_key_env": "GEMINI_API_KEY",
|
| 36 |
+
"default_model": AIModel.GEMINI_2_0_FLASH,
|
| 37 |
"default_temperature": 0.3,
|
| 38 |
"max_tokens": None, # Gemini handles this automatically
|
| 39 |
"available_models": [
|
| 40 |
AIModel.GEMINI_2_5_FLASH,
|
| 41 |
+
AIModel.GEMINI_2_0_FLASH,
|
| 42 |
AIModel.GEMINI_2_5_PRO,
|
| 43 |
AIModel.GEMINI_1_5_PRO
|
| 44 |
]
|
|
|
|
| 50 |
"max_tokens": 20000,
|
| 51 |
"available_models": [
|
| 52 |
AIModel.CLAUDE_SONNET_4,
|
| 53 |
+
AIModel.CLAUDE_SONNET_3_7,
|
| 54 |
AIModel.CLAUDE_SONNET_3_5,
|
| 55 |
AIModel.CLAUDE_HAIKU_3_5
|
| 56 |
]
|
|
|
|
| 63 |
"MainLifestyleAssistant": {
|
| 64 |
"provider": AIProvider.ANTHROPIC,
|
| 65 |
"model": AIModel.CLAUDE_SONNET_4,
|
| 66 |
+
"temperature": 0.2,
|
| 67 |
"reasoning": "Complex lifestyle coaching requires advanced reasoning capabilities"
|
| 68 |
},
|
| 69 |
|
| 70 |
# All other agents use Google Gemini
|
| 71 |
"EntryClassifier": {
|
| 72 |
"provider": AIProvider.GEMINI,
|
| 73 |
+
"model": AIModel.GEMINI_2_0_FLASH,
|
| 74 |
"temperature": 0.1,
|
| 75 |
"reasoning": "Fast classification task, optimized for speed"
|
| 76 |
},
|
| 77 |
|
| 78 |
"TriageExitClassifier": {
|
| 79 |
"provider": AIProvider.GEMINI,
|
| 80 |
+
"model": AIModel.GEMINI_2_0_FLASH,
|
| 81 |
"temperature": 0.2,
|
| 82 |
"reasoning": "Medical triage decisions require consistency"
|
| 83 |
},
|
| 84 |
|
| 85 |
"MedicalAssistant": {
|
| 86 |
+
"provider": AIProvider.ANTHROPIC,
|
| 87 |
+
"model": AIModel.CLAUDE_SONNET_4,
|
| 88 |
"temperature": 0.2,
|
| 89 |
"reasoning": "Medical guidance requires reliable, consistent responses"
|
| 90 |
},
|
| 91 |
|
| 92 |
"SoftMedicalTriage": {
|
| 93 |
"provider": AIProvider.GEMINI,
|
| 94 |
+
"model": AIModel.GEMINI_2_0_FLASH,
|
| 95 |
"temperature": 0.3,
|
| 96 |
"reasoning": "Gentle triage can use faster model"
|
| 97 |
},
|
| 98 |
|
| 99 |
"LifestyleProfileUpdater": {
|
| 100 |
"provider": AIProvider.GEMINI,
|
| 101 |
+
"model": AIModel.GEMINI_2_5_FLASH,
|
| 102 |
"temperature": 0.2,
|
| 103 |
"reasoning": "Profile analysis requires detailed processing"
|
| 104 |
}
|