diff --git a/.env b/.env index 81b4287..9230aa2 100755 --- a/.env +++ b/.env @@ -35,6 +35,10 @@ MAX_INTERVAL_MINUTES=90 # Maximum conversation history length per context (messages) MAX_HISTORY_LENGTH=50 +# Enable automatic web search when needed +WEB_SEARCH_ENABLED=true +WEB_SEARCH_MAX_RESULTS=5 + # Upload file context max characters sent to AI (0 = no truncation) UPLOAD_CONTEXT_MAX_CHARS=0 diff --git a/.gitignore b/.gitignore index 81fece3..f2c1ee0 100755 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -uploadsfiles/ +workspace/ uploads_metadata.json \ No newline at end of file diff --git a/DEPLOY.md b/DEPLOY.md index 1a3f320..d9053e2 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -216,12 +216,12 @@ Faça backup regular dos arquivos de dados dentro de `/app`: - `system_improvements.json` - `uploads_metadata.json` - pasta `contexts/` -- pasta `uploadsfiles/` +- pasta `workspace/` Exemplo simples de backup diário: ```bash -tar czf /root/backups/psagentai-$(date +%F).tar.gz -C /opt/psagentai/app user_profile.json agent_profile.json system_improvements.json uploads_metadata.json contexts uploadsfiles +tar czf /root/backups/psagentai-$(date +%F).tar.gz -C /opt/psagentai/app user_profile.json agent_profile.json system_improvements.json uploads_metadata.json contexts workspace ``` --- diff --git a/__pycache__/psagentai_agent.cpython-311.pyc b/__pycache__/psagentai_agent.cpython-311.pyc index b2880a2..c34347f 100644 Binary files a/__pycache__/psagentai_agent.cpython-311.pyc and b/__pycache__/psagentai_agent.cpython-311.pyc differ diff --git a/psagentai_agent.py b/psagentai_agent.py index 1e4b1ee..53d7b11 100755 --- a/psagentai_agent.py +++ b/psagentai_agent.py @@ -69,6 +69,8 @@ MIN_INTERVAL_MINUTES = int(os.getenv("MIN_INTERVAL_MINUTES", "3")) MAX_INTERVAL_MINUTES = int(os.getenv("MAX_INTERVAL_MINUTES", "30")) MAX_HISTORY_LENGTH = int(os.getenv("MAX_HISTORY_LENGTH", "50")) UPLOAD_CONTEXT_MAX_CHARS = int(os.getenv("UPLOAD_CONTEXT_MAX_CHARS", "8000")) +WEB_SEARCH_ENABLED = os.getenv("WEB_SEARCH_ENABLED", "true").lower() in ("true", "1", "yes") +WEB_SEARCH_MAX_RESULTS = int(os.getenv("WEB_SEARCH_MAX_RESULTS", "5")) USER_PROFILE_FILE = os.getenv("USER_PROFILE_FILE", "user_profile.json") AGENT_PROFILE_FILE = os.getenv("AGENT_PROFILE_FILE", "agent_profile.json") @@ -309,7 +311,7 @@ def ensure_contexts_dir(): # ===================== FILE UPLOAD SYSTEM ===================== -UPLOADS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "uploadsfiles") +UPLOADS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "workspace") UPLOADS_META_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "uploads_metadata.json") @@ -414,6 +416,51 @@ def find_matching_upload(query: str) -> Optional[Dict[str, Any]]: return None +_WEB_SEARCH_TRIGGERS = [ + "pesquise", + "pesquisa", + "busque", + "buscar", + "procure", + "procurar", + "na internet", + "internet", + "web", + "google", + "o que é", + "quem é", + "qual a", + "qual o", + "como funciona", + "notícia", + "noticias", + "notícias", + "atualidade", + "atual", + "hoje", + "agora", + "tempo real", + "tempo real", + "previsão", + "clima", + "tempo", + "onde fica", + "onde é", + "localização", + "localizacao", + "mapa", + "endereço", + "endereco", +] + + +def _looks_like_search_request(user_message: str) -> bool: + q = user_message.lower().strip() + if len(q.split()) < 2: + return False + return any(t in q for t in _WEB_SEARCH_TRIGGERS) + + def get_all_uploads_for_chat(chat_id: int) -> Dict[str, Dict[str, Any]]: meta = load_uploads_metadata() return {fn: info for fn, info in meta.items() if info.get("chat_id") == chat_id} @@ -1330,6 +1377,12 @@ def build_system_prompt(profile: Dict[str, Any]) -> str: prompt += f"\n\nData atual: {current_date}." prompt += f"\nHora atual: {current_time} ({time_period})." prompt += f"\nFuso horário configurado: {tz}." + prompt += ( + "\n\nIMPORTANTE SOBRE INFORMAÇÕES ATUALIZADAS:" + "\n- Se a pergunta do usuário pedir algo factual, atual, notícia, previsão do tempo, cotação, data futura/passada, horário de funcionamento, endereço atualizado, etc., USE A BUSCA NA INTERNET para responder." + "\n- Não invente dados, não use conhecimento desatualizado." + "\n- Se não tiver acesso a busca, diga que não pode consultar agora." + ) except Exception: pass prompt += f"\n\nIMPORTANTE: Seu nome é {agent_name} e ele nunca muda. Se houver mensagens antigas no histórico onde você usou outro nome, ignore-as — o nome correto é {agent_name}. Sempre se apresente como {agent_name}." @@ -3887,6 +3940,20 @@ async def process_text_message(update: Update, context: ContextTypes.DEFAULT_TYP else: modified = user_message + if WEB_SEARCH_ENABLED and _looks_like_search_request(user_message): + search_query = user_message + for prefix in ["pesquise", "pesquisa", "busque", "buscar", "procure", "procurar", "me diga", "me informe", "qual", "quem", "como", "onde", "quando", "por que"]: + if search_query.lower().startswith(prefix): + search_query = search_query[len(prefix):].strip(" :,-") + break + if search_query: + web_results = _web_search(search_query, max_results=WEB_SEARCH_MAX_RESULTS) + if web_results: + web_context = "\n\nResultados da busca na internet:\n" + for i, result in enumerate(web_results, 1): + web_context += f"{i}. {result.get('title', '')}\nURL: {result.get('url', '')}\n" + modified = modified + "\n\n" + web_context + response = await get_psagentai_response(modified) if response: add_to_context("assistant", response)