✅ IMPLEMENTADO - Soporte para Anthropic Claude y Corrección de Configuración
🔧 Backend v1.2.0 | Frontend v1.2.5 He implementado completamente el soporte para Anthropic Claude y corregido el problema de visualización en el módulo de configuración: 🎯 Cambios Implementados: 1. Backend - Soporte para Anthropic Claude Nuevos modelos agregados: Claude Sonnet 4.5 (Recomendado) - Equilibrio perfecto Claude Opus 4.5 - Máxima capacidad Claude Haiku 4.5 - Ultra rápido y económico Integración completa: Chat Assistant con Anthropic Generación de resúmenes PDF con Anthropic Manejo correcto de formato de mensajes (system separado) Configuración por defecto: claude-sonnet-4.5
This commit is contained in:
@@ -276,7 +276,7 @@ def extract_pdf_text_smart(pdf_content: bytes, max_chars: int = None) -> dict:
|
||||
}
|
||||
|
||||
|
||||
BACKEND_VERSION = "1.1.2"
|
||||
BACKEND_VERSION = "1.2.0"
|
||||
app = FastAPI(title="Checklist Inteligente API", version=BACKEND_VERSION)
|
||||
|
||||
# S3/MinIO configuration
|
||||
@@ -1512,12 +1512,12 @@ REGLAS:
|
||||
"""
|
||||
|
||||
try:
|
||||
# Usar OpenAI o Gemini según configuración
|
||||
if config.provider == "openai" and config.openai_api_key:
|
||||
client = openai.OpenAI(api_key=config.openai_api_key)
|
||||
# Usar OpenAI, Anthropic o Gemini según configuración
|
||||
if config.provider == "openai":
|
||||
client = openai.OpenAI(api_key=config.api_key)
|
||||
response = await asyncio.to_thread(
|
||||
client.chat.completions.create,
|
||||
model=config.openai_model or "gpt-4o",
|
||||
model=config.model_name or "gpt-4o",
|
||||
messages=[{"role": "user", "content": summary_prompt}],
|
||||
temperature=0.3,
|
||||
max_tokens=800,
|
||||
@@ -1525,10 +1525,22 @@ REGLAS:
|
||||
)
|
||||
summary_json = response.choices[0].message.content
|
||||
|
||||
elif config.provider == "gemini" and config.gemini_api_key:
|
||||
genai.configure(api_key=config.gemini_api_key)
|
||||
elif config.provider == "anthropic":
|
||||
import anthropic as anthropic_lib
|
||||
client = anthropic_lib.Anthropic(api_key=config.api_key)
|
||||
response = await asyncio.to_thread(
|
||||
client.messages.create,
|
||||
model=config.model_name or "claude-sonnet-4-5",
|
||||
max_tokens=800,
|
||||
temperature=0.3,
|
||||
messages=[{"role": "user", "content": summary_prompt + "\n\nRespuesta en formato JSON:"}]
|
||||
)
|
||||
summary_json = response.content[0].text
|
||||
|
||||
elif config.provider == "gemini":
|
||||
genai.configure(api_key=config.api_key)
|
||||
model = genai.GenerativeModel(
|
||||
model_name=config.gemini_model or "gemini-2.0-flash-exp",
|
||||
model_name=config.model_name or "gemini-2.5-pro",
|
||||
generation_config={
|
||||
"temperature": 0.3,
|
||||
"max_output_tokens": 800,
|
||||
@@ -2726,6 +2738,25 @@ def get_available_ai_models(current_user: models.User = Depends(get_current_user
|
||||
"name": "Gemini 1.5 Flash Latest",
|
||||
"provider": "gemini",
|
||||
"description": "Modelo 1.5 rápido para análisis básicos"
|
||||
},
|
||||
# Anthropic Claude Models
|
||||
{
|
||||
"id": "claude-sonnet-4-5",
|
||||
"name": "Claude Sonnet 4.5 (Recomendado)",
|
||||
"provider": "anthropic",
|
||||
"description": "Equilibrio perfecto entre velocidad e inteligencia, ideal para diagnósticos automotrices"
|
||||
},
|
||||
{
|
||||
"id": "claude-opus-4-5",
|
||||
"name": "Claude Opus 4.5",
|
||||
"provider": "anthropic",
|
||||
"description": "Máxima capacidad para análisis complejos y razonamiento profundo"
|
||||
},
|
||||
{
|
||||
"id": "claude-haiku-4-5",
|
||||
"name": "Claude Haiku 4.5",
|
||||
"provider": "anthropic",
|
||||
"description": "Ultra rápido y económico, perfecto para análisis en tiempo real"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2771,6 +2802,8 @@ def create_ai_configuration(
|
||||
model_name = "gpt-4o"
|
||||
elif config.provider == "gemini":
|
||||
model_name = "gemini-2.5-pro"
|
||||
elif config.provider == "anthropic":
|
||||
model_name = "claude-sonnet-4-5"
|
||||
else:
|
||||
model_name = "default"
|
||||
|
||||
@@ -3510,6 +3543,28 @@ Longitud: {response_length}
|
||||
ai_response = response.choices[0].message.content
|
||||
confidence = 0.85 # OpenAI no devuelve confidence directo
|
||||
|
||||
elif ai_config.provider == 'anthropic':
|
||||
import anthropic
|
||||
|
||||
# Crear cliente de Anthropic
|
||||
client = anthropic.Anthropic(api_key=ai_config.api_key)
|
||||
|
||||
# Antropic usa un formato diferente: system separado de messages
|
||||
# El primer mensaje es el system prompt
|
||||
system_content = messages[0]['content'] if messages[0]['role'] == 'system' else ""
|
||||
user_messages = [msg for msg in messages if msg['role'] != 'system']
|
||||
|
||||
response = client.messages.create(
|
||||
model=ai_config.model_name or "claude-sonnet-4-5",
|
||||
max_tokens=max_tokens,
|
||||
system=system_content,
|
||||
messages=user_messages,
|
||||
temperature=0.7
|
||||
)
|
||||
|
||||
ai_response = response.content[0].text
|
||||
confidence = 0.85
|
||||
|
||||
elif ai_config.provider == 'gemini':
|
||||
import google.generativeai as genai
|
||||
genai.configure(api_key=ai_config.api_key)
|
||||
|
||||
@@ -269,7 +269,7 @@ class InspectionDetail(Inspection):
|
||||
|
||||
# AI Configuration Schemas
|
||||
class AIConfigurationBase(BaseModel):
|
||||
provider: str # openai, gemini
|
||||
provider: str # openai, gemini, anthropic
|
||||
api_key: str
|
||||
model_name: Optional[str] = None
|
||||
logo_url: Optional[str] = None
|
||||
|
||||
@@ -11,6 +11,7 @@ passlib==1.7.4
|
||||
bcrypt==4.0.1
|
||||
python-multipart==0.0.6
|
||||
openai==1.10.0
|
||||
anthropic==0.40.0
|
||||
google-generativeai==0.3.2
|
||||
Pillow==10.2.0
|
||||
reportlab==4.0.9
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "checklist-frontend",
|
||||
"private": true,
|
||||
"version": "1.2.4",
|
||||
"version": "1.2.5",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Service Worker para PWA con detección de actualizaciones
|
||||
// IMPORTANTE: Actualizar esta versión cada vez que se despliegue una nueva versión
|
||||
const CACHE_NAME = 'ayutec-v1.2.4';
|
||||
const CACHE_NAME = 'ayutec-v1.2.5';
|
||||
const urlsToCache = [
|
||||
'/',
|
||||
'/index.html'
|
||||
|
||||
@@ -654,6 +654,15 @@ function SettingsTab({ user }) {
|
||||
<div className="font-semibold">OpenAI</div>
|
||||
<div className="text-xs text-gray-600 mt-1">GPT-4, GPT-4 Vision</div>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setFormData({ ...formData, provider: 'anthropic', model_name: 'claude-sonnet-4-5' })}
|
||||
className={`p-4 border-2 rounded-lg transition ${formData.provider === 'anthropic' ? 'border-purple-500 bg-purple-50' : 'border-gray-300 hover:border-gray-400'}`}
|
||||
>
|
||||
<div className="text-4xl mb-2">🧠</div>
|
||||
<div className="font-semibold">Anthropic Claude</div>
|
||||
<div className="text-xs text-gray-600 mt-1">Sonnet, Opus, Haiku</div>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setFormData({ ...formData, provider: 'gemini', model_name: 'gemini-2.5-pro' })}
|
||||
@@ -669,19 +678,21 @@ function SettingsTab({ user }) {
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-4">API Key</h3>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
{formData.provider === 'openai' ? 'OpenAI API Key' : 'Google AI API Key'}
|
||||
{formData.provider === 'openai' ? 'OpenAI API Key' : formData.provider === 'anthropic' ? 'Anthropic API Key' : 'Google AI API Key'}
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
value={formData.api_key}
|
||||
onChange={(e) => setFormData({ ...formData, api_key: e.target.value })}
|
||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
placeholder={formData.provider === 'openai' ? 'sk-...' : 'AIza...'}
|
||||
placeholder={formData.provider === 'openai' ? 'sk-...' : formData.provider === 'anthropic' ? 'sk-ant-...' : 'AIza...'}
|
||||
required
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-2">
|
||||
{formData.provider === 'openai' ? (
|
||||
<>Obtén tu API key en <a href="https://platform.openai.com/api-keys" target="_blank" className="text-blue-600 hover:underline">OpenAI Platform</a></>
|
||||
) : formData.provider === 'anthropic' ? (
|
||||
<>Obtén tu API key en <a href="https://console.anthropic.com/" target="_blank" className="text-purple-600 hover:underline">Anthropic Console</a></>
|
||||
) : (
|
||||
<>Obtén tu API key en <a href="https://makersuite.google.com/app/apikey" target="_blank" className="text-blue-600 hover:underline">Google AI Studio</a></>
|
||||
)}
|
||||
|
||||
@@ -153,7 +153,7 @@ export default function Sidebar({ user, activeTab, setActiveTab, sidebarOpen, se
|
||||
className="w-10 h-10 object-contain bg-white rounded p-1"
|
||||
/>
|
||||
<p className="text-xs text-indigo-300 font-medium hover:text-indigo-200">
|
||||
Ayutec v1.2.4
|
||||
Ayutec v1.2.5
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user