klawdyoss's picture
salvando
8a0e39e
/* src/components/panels/APIKeysConfig.tsx */
import { useLocalStorage } from "react-use";
import { ChangeEvent, useState, useEffect } from "react";
import { toast } from "react-toastify";
import { FiAlertTriangle } from "react-icons/fi";
type RowProps = {
label: string;
link: string;
storageKey: string;
placeholder: string;
validator?: (key: string) => boolean;
};
function InputRow({ label, link, storageKey, placeholder, validator }: RowProps) {
const [value, setValue] = useLocalStorage<string>(storageKey, "");
const [error, setError] = useState<string | null>(null);
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.value.trim();
setValue(newValue);
if (validator && newValue) {
const isValid = validator(newValue);
if (!isValid) {
setError("Formato de chave inválido");
} else {
setError(null);
}
} else {
setError(null);
}
};
return (
<div className="mb-4">
<label className="block font-semibold mb-1">
{label}{" "}
<a
href={link}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 underline"
>
obter chave
</a>
</label>
<input
className={`w-full border ${error ? "border-red-500" : "border-gray-400"} px-2 py-1 text-sm`}
placeholder={placeholder}
type="text"
value={value ?? ""}
onChange={onChange}
/>
{error && <p className="text-red-500 text-xs mt-1">{error}</p>}
</div>
);
}
export default function APIKeysConfig() {
const validateOpenAI = (key: string) => key.startsWith("sk-");
const validateGemini = (key: string) => key.startsWith("AIza");
const validateHF = (key: string) => key.startsWith("hf_");
const [showQuotaWarning, setShowQuotaWarning] = useState(false);
// Verifica se deve mostrar o aviso de quota
useEffect(() => {
// Busca no localStorage se houve um erro de quota recentemente (armazenado pelo ChatInterface)
const hasQuotaError = localStorage.getItem("openai_quota_error") === "true";
setShowQuotaWarning(hasQuotaError);
}, []);
const testConnections = () => {
toast.info("Testando conexões...");
// Aqui poderíamos implementar um teste real de conexão
setTimeout(() => toast.success("Chaves salvas com sucesso!"), 1000);
};
return (
<div className="p-4">
<h1 className="text-2xl font-bold mb-6">Configurar chaves de API</h1>
{showQuotaWarning && (
<div className="mb-4 p-3 bg-yellow-800/30 border-l-4 border-yellow-500 text-yellow-200 rounded">
<h3 className="font-bold flex items-center">
<FiAlertTriangle className="mr-2" /> Problema de quota detectado
</h3>
<p className="mt-2">
Sua chave da OpenAI (ChatGPT) atingiu o limite de quota.
Você pode:
</p>
<ul className="list-disc pl-5 mt-2 space-y-1">
<li>Utilizar outra chave de API</li>
<li>Aguardar até o próximo ciclo quando sua quota for renovada</li>
<li>Atualizar seu plano na OpenAI para obter mais créditos</li>
<li>Usar outros agentes que não dependem da API do ChatGPT</li>
</ul>
<button
onClick={() => {
localStorage.removeItem("openai_quota_error");
setShowQuotaWarning(false);
}}
className="mt-2 text-xs bg-yellow-800 hover:bg-yellow-700 px-2 py-1 rounded"
>
Entendi, esconder este aviso
</button>
</div>
)}
<InputRow
label="OpenAI (ChatGPT)"
link="https://platform.openai.com/account/api-keys"
storageKey="chatgptKey"
placeholder="sk-..."
validator={validateOpenAI}
/>
<InputRow
label="Google Gemini"
link="https://makersuite.google.com/app/apikey"
storageKey="geminiKey"
placeholder="AIzaSy..."
validator={validateGemini}
/>
<InputRow
label="Hugging Face Token"
link="https://huggingface.co/settings/tokens"
storageKey="hfToken"
placeholder="hf_..."
validator={validateHF}
/>
<button
onClick={testConnections}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Salvar e Testar Conexões
</button>
<p className="text-sm text-gray-600 mt-4">
As chaves são salvas apenas no <i>localStorage</i> do seu navegador e
enviadas ao servidor somente quando você usa o respectivo modelo.
</p>
</div>
);
}