mirror of
https://github.com/smkrv/ha-text-ai.git
synced 2026-07-22 23:24:03 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6e73e847d | ||
|
|
440c734214 |
@@ -259,40 +259,107 @@ class APIClient:
|
|||||||
contents = []
|
contents = []
|
||||||
system_instruction = ""
|
system_instruction = ""
|
||||||
|
|
||||||
|
# Process messages and ensure proper role alternation
|
||||||
|
current_role = None
|
||||||
|
current_content = ""
|
||||||
|
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
if msg['role'] == 'system':
|
if msg['role'] == 'system':
|
||||||
system_instruction += msg['content'] + "\n"
|
system_instruction += msg['content'] + "\n"
|
||||||
else:
|
else:
|
||||||
contents.append({
|
role = "user" if msg['role'] == 'user' else "model"
|
||||||
"role": "user" if msg['role'] == 'user' else "model",
|
|
||||||
"parts": [{"text": msg['content']}]
|
|
||||||
})
|
|
||||||
|
|
||||||
|
# If same role as previous, combine content
|
||||||
|
if role == current_role:
|
||||||
|
current_content += "\n" + msg['content']
|
||||||
|
else:
|
||||||
|
# Add previous message if exists
|
||||||
|
if current_role is not None:
|
||||||
|
contents.append({
|
||||||
|
"role": current_role,
|
||||||
|
"parts": [{"text": current_content}]
|
||||||
|
})
|
||||||
|
# Start new message
|
||||||
|
current_role = role
|
||||||
|
current_content = msg['content']
|
||||||
|
|
||||||
|
# Add the last message if exists
|
||||||
|
if current_role is not None:
|
||||||
|
contents.append({
|
||||||
|
"role": current_role,
|
||||||
|
"parts": [{"text": current_content}]
|
||||||
|
})
|
||||||
|
|
||||||
|
# Ensure contents starts with user message if not empty
|
||||||
|
if contents and contents[0]["role"] != "user":
|
||||||
|
# Add a placeholder user message if needed
|
||||||
|
contents.insert(0, {
|
||||||
|
"role": "user",
|
||||||
|
"parts": [{"text": "I need your assistance."}]
|
||||||
|
})
|
||||||
|
|
||||||
|
# Ensure contents is not empty
|
||||||
|
if not contents:
|
||||||
|
contents.append({
|
||||||
|
"role": "user",
|
||||||
|
"parts": [{"text": "I need your assistance."}]
|
||||||
|
})
|
||||||
|
|
||||||
|
# Create payload with snake_case keys as required by Gemini API
|
||||||
payload = {
|
payload = {
|
||||||
"contents": contents,
|
"contents": contents,
|
||||||
"generationConfig": {
|
"generation_config": { # Changed from camelCase to snake_case
|
||||||
"temperature": temperature,
|
"temperature": temperature,
|
||||||
"maxOutputTokens": max_tokens
|
"max_output_tokens": max_tokens # Changed from camelCase to snake_case
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if system_instruction:
|
if system_instruction:
|
||||||
payload["systemInstruction"] = {
|
payload["system_instruction"] = { # Changed from camelCase to snake_case
|
||||||
"parts": [{"text": system_instruction}]
|
"parts": [{"text": system_instruction.strip()}]
|
||||||
}
|
}
|
||||||
|
|
||||||
data = await self._make_request(url, payload)
|
try:
|
||||||
return {
|
data = await self._make_request(url, payload)
|
||||||
"choices": [{
|
|
||||||
"message": {
|
# Safely extract response data with fallbacks
|
||||||
"content": data["candidates"][0]["content"]["parts"][0]["text"]
|
candidates = data.get("candidates", [])
|
||||||
|
if not candidates:
|
||||||
|
raise HomeAssistantError("Gemini API returned no candidates")
|
||||||
|
|
||||||
|
content = candidates[0].get("content", {})
|
||||||
|
parts = content.get("parts", [])
|
||||||
|
if not parts:
|
||||||
|
raise HomeAssistantError("Gemini API response contains no content parts")
|
||||||
|
|
||||||
|
answer_text = parts[0].get("text", "")
|
||||||
|
|
||||||
|
# Safely extract usage data
|
||||||
|
usage = data.get("usageMetadata", {})
|
||||||
|
prompt_tokens = usage.get("promptTokenCount", 0)
|
||||||
|
completion_tokens = usage.get("candidatesTokenCount", 0)
|
||||||
|
|
||||||
|
# Handle case where candidatesTokenCount might be a list
|
||||||
|
if isinstance(completion_tokens, list):
|
||||||
|
completion_tokens = sum(completion_tokens)
|
||||||
|
|
||||||
|
total_tokens = usage.get("totalTokenCount", prompt_tokens + completion_tokens)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"choices": [{
|
||||||
|
"message": {
|
||||||
|
"content": answer_text
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"usage": {
|
||||||
|
"prompt_tokens": prompt_tokens,
|
||||||
|
"completion_tokens": completion_tokens,
|
||||||
|
"total_tokens": total_tokens
|
||||||
}
|
}
|
||||||
}],
|
|
||||||
"usage": {
|
|
||||||
"prompt_tokens": data["usageMetadata"]["promptTokenCount"],
|
|
||||||
"completion_tokens": data["usageMetadata"]["candidatesTokenCount"],
|
|
||||||
"total_tokens": data["usageMetadata"]["totalTokenCount"]
|
|
||||||
}
|
}
|
||||||
}
|
except Exception as e:
|
||||||
|
_LOGGER.error(f"Gemini API error: {str(e)}")
|
||||||
|
raise HomeAssistantError(f"Gemini API error: {str(e)}")
|
||||||
|
|
||||||
async def shutdown(self) -> None:
|
async def shutdown(self) -> None:
|
||||||
"""Shutdown API client."""
|
"""Shutdown API client."""
|
||||||
|
|||||||
@@ -24,6 +24,6 @@
|
|||||||
"single_config_entry": false,
|
"single_config_entry": false,
|
||||||
"ssdp": [],
|
"ssdp": [],
|
||||||
"usb": [],
|
"usb": [],
|
||||||
"version": "2.1.3",
|
"version": "2.1.4",
|
||||||
"zeroconf": []
|
"zeroconf": []
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user