88c1ea297e
All feature containers now POST messages to ai-service (port 8010) instead of calling AI providers directly. ai-service routes to LM Studio, Ollama, or Anthropic based on /config/ai_service_config.json. doc-service AI providers removed; replaced by httpx ai_client.py. Backend settings restructured to /api/settings/ai. Frontend gets dedicated AIAdminSettingsPage and AI Service card in AppsPage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
55 lines
1.8 KiB
Python
55 lines
1.8 KiB
Python
import asyncio
|
|
|
|
import anthropic
|
|
|
|
from app.providers.base import AIProvider
|
|
from app.schemas.chat import ChatMessage
|
|
|
|
|
|
class AnthropicProvider(AIProvider):
|
|
def __init__(self, config: dict) -> None:
|
|
self._client = anthropic.AsyncAnthropic(api_key=config.get("api_key", ""))
|
|
self.model_name = config.get("model", "claude-haiku-4-5-20251001")
|
|
self.provider_name = "anthropic"
|
|
|
|
async def chat(
|
|
self,
|
|
messages: list[ChatMessage],
|
|
max_tokens: int,
|
|
temperature: float,
|
|
) -> tuple[str, int | None, int | None]:
|
|
# Anthropic uses a top-level `system=` param, not a role in the messages array
|
|
system_content = ""
|
|
user_messages = []
|
|
for msg in messages:
|
|
if msg.role == "system":
|
|
system_content += msg.content + "\n"
|
|
else:
|
|
user_messages.append({"role": msg.role, "content": msg.content})
|
|
|
|
try:
|
|
response = await self._client.messages.create(
|
|
model=self.model_name,
|
|
max_tokens=max_tokens,
|
|
temperature=temperature,
|
|
system=system_content.strip() or anthropic.NOT_GIVEN,
|
|
messages=user_messages,
|
|
)
|
|
except anthropic.APIConnectionError as exc:
|
|
raise ProviderConnectionError(str(exc)) from exc
|
|
except anthropic.APITimeoutError as exc:
|
|
raise ProviderTimeoutError(str(exc)) from exc
|
|
except anthropic.APIStatusError as exc:
|
|
raise ProviderConnectionError(f"Anthropic API error {exc.status_code}: {exc.message}") from exc
|
|
|
|
content = response.content[0].text
|
|
return content, response.usage.input_tokens, response.usage.output_tokens
|
|
|
|
|
|
class ProviderConnectionError(Exception):
|
|
pass
|
|
|
|
|
|
class ProviderTimeoutError(Exception):
|
|
pass
|