feat(agent): add automatic web search and rename uploads dir to workspace

- Add WEB_SEARCH_ENABLED and WEB_SEARCH_MAX_RESULTS config options
- Detect search-intent messages via trigger keywords and inject web
  results into the AI context
- Instruct the system prompt to use web search for factual, current,
  or time-sensitive questions instead of inventing data
- Rename uploads directory from `uploadsfiles/` to `workspace/`,
  updating .gitignore and backup instructions in DEPLOY.md
This commit is contained in:
2026-10-26 10:32:31 -03:00
parent 25288d2c0f
commit 237a1dfb53
5 changed files with 75 additions and 4 deletions
+4
View File
@@ -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
+1 -1
View File
@@ -1,2 +1,2 @@
uploadsfiles/
workspace/
uploads_metadata.json
+2 -2
View File
@@ -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
```
---
Binary file not shown.
+68 -1
View File
@@ -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)