"""Configuração privada do Gemini; respostas nunca incluem a chave.""" import json,os,re,threading,time from pathlib import Path import gemini from comum import gravar_atomico, ler_json class ConfigAPI: def __init__(self,path): self.path=Path(path);self.lock=threading.RLock();self.ultimo_teste=None try: d=json.loads(self.path.read_text(encoding='utf-8')) self.validar(d) if d.get('chave'):os.environ['GEMINI_API_KEY']=d['chave'] gemini.MODELO=d['modelo'] except (OSError,ValueError,KeyError,TypeError):pass @staticmethod def validar(d): if not isinstance(d,dict) or set(d)-{'modelo','chave'}:raise ValueError('Campos de API inválidos') if not isinstance(d.get('modelo'),str) or not re.fullmatch(r'[a-zA-Z0-9._-]{3,100}',d['modelo']):raise ValueError('Nome do modelo inválido') if 'chave' in d and (not isinstance(d['chave'],str) or not 20<=len(d['chave'])<=250 or not re.fullmatch(r'[A-Za-z0-9._-]+',d['chave'])):raise ValueError('Chave inválida') def status(self): with self.lock:return dict(provedor='Gemini',modelo=gemini.MODELO,configurada=bool(os.environ.get('GEMINI_API_KEY')),ultimo_teste=self.ultimo_teste) def salvar(self,d): self.validar(d) with self.lock: key=d.get('chave') or os.environ.get('GEMINI_API_KEY','') saved=dict(modelo=d['modelo']) if key:saved['chave']=key gravar_atomico(self.path,saved,privado=True) gemini.MODELO=d['modelo'] if key:os.environ['GEMINI_API_KEY']=key self.ultimo_teste=None return self.status() def testar(self): start=time.monotonic() try: gemini.gerar_json(dict(contents=[dict(role='user',parts=[dict(text='Responda JSON {"ok":true}. Teste de conexão do Carinha.')])],generationConfig=dict(maxOutputTokens=64,responseMimeType='application/json'))) result=dict(ok=True,segundos=round(time.monotonic()-start,2),mensagem='Gemini respondeu ao teste.') except Exception as e: result=dict(ok=False,mensagem=str(e) if isinstance(e,ValueError) else 'Falha de conexão com o Gemini. Confira a rede e tente novamente.') with self.lock:self.ultimo_teste=result return result def rotas(self,h,method): route=h.path.split('?',1)[0] if not route.startswith('/api/configuracao/'):return False try: if method=='GET' and route.endswith('/status'):result=self.status() elif method=='POST': d=ler_json(h,2048) if route.endswith('/salvar'):result=self.salvar(d) elif route.endswith('/testar'):result=self.testar() else:raise ValueError('Rota inválida') else:raise ValueError('Método inválido') h.enviar(json.dumps(result,ensure_ascii=False)) except (ValueError,TypeError,OSError):h.enviar(json.dumps(dict(erro='Não foi possível processar a configuração. Confira o modelo e a chave.')),codigo=400) return True