Subida da versão estável
This commit is contained in:
BIN
.BD_manager_Mysql.py.swn
Normal file
BIN
.BD_manager_Mysql.py.swn
Normal file
Binary file not shown.
BIN
.BD_manager_Mysql.py.swo
Normal file
BIN
.BD_manager_Mysql.py.swo
Normal file
Binary file not shown.
207
.gitignore
vendored
Normal file
207
.gitignore
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[codz]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
#poetry.toml
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||
#pdm.lock
|
||||
#pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# pixi
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||
#pixi.lock
|
||||
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||
.pixi
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.envrc
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Abstra
|
||||
# Abstra is an AI-powered process automation framework.
|
||||
# Ignore directories containing user credentials, local state, and settings.
|
||||
# Learn more at https://abstra.io/docs
|
||||
.abstra/
|
||||
|
||||
# Visual Studio Code
|
||||
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||
# you could uncomment the following to ignore the entire vscode folder
|
||||
# .vscode/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# Cursor
|
||||
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
||||
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
||||
# refer to https://docs.cursor.com/context/ignore-files
|
||||
.cursorignore
|
||||
.cursorindexingignore
|
||||
|
||||
# Marimo
|
||||
marimo/_static/
|
||||
marimo/_lsp/
|
||||
__marimo__/
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
18
.idea/V1.iml
generated
Normal file
18
.idea/V1.iml
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="Flask">
|
||||
<option name="enabled" value="true" />
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
<option name="format" value="PLAIN" />
|
||||
<option name="myDocStringFormat" value="Plain" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
||||
</component>
|
||||
</module>
|
||||
16
.idea/checkstyle-idea.xml
generated
Normal file
16
.idea/checkstyle-idea.xml
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CheckStyle-IDEA" serialisationVersion="2">
|
||||
<checkstyleVersion>10.24.0</checkstyleVersion>
|
||||
<scanScope>JavaOnly</scanScope>
|
||||
<copyLibs>true</copyLibs>
|
||||
<option name="thirdPartyClasspath" />
|
||||
<option name="activeLocationIds" />
|
||||
<option name="locations">
|
||||
<list>
|
||||
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
|
||||
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
7
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/V1.iml" filepath="$PROJECT_DIR$/.idea/V1.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
175
BD_manager.py
Normal file
175
BD_manager.py
Normal file
@@ -0,0 +1,175 @@
|
||||
import sqlite3
|
||||
from typing import Optional, Dict, List, Any
|
||||
|
||||
db_path = "agenda.db"
|
||||
|
||||
def inserir_acompanhamento(chat_id: int, status: str, nome: str) -> None:
|
||||
"""
|
||||
Insere um registro na tabela usuarios.
|
||||
|
||||
:param db_path: Caminho do banco de dados SQLite
|
||||
:param chat_id: ID do chat (ex: Telegram)
|
||||
:param status: Status do usuário
|
||||
"""
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
query = """
|
||||
INSERT INTO acompanhamento (chat_id, status, nome)
|
||||
VALUES (?, ?, ?)
|
||||
"""
|
||||
|
||||
cursor.execute(query, (chat_id, status, nome))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
|
||||
|
||||
def atualizar_acompanhamento(
|
||||
chat_id: int,
|
||||
campo: str,
|
||||
information: str
|
||||
) -> bool:
|
||||
"""
|
||||
Atualiza o status do último registro (maior id) de um chat_id.
|
||||
|
||||
:param db_path: Caminho do banco SQLite
|
||||
:param chat_id: Chat ID a ser atualizado
|
||||
:param novo_status: Novo status
|
||||
:return: True se atualizou, False se não encontrou registro
|
||||
"""
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Localiza o último registro do chat_id
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id
|
||||
FROM acompanhamento
|
||||
WHERE chat_id = ?
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
""",
|
||||
(chat_id,)
|
||||
)
|
||||
|
||||
row = cursor.fetchone()
|
||||
|
||||
if row is None:
|
||||
conn.close()
|
||||
return False
|
||||
|
||||
ultimo_id = row[0]
|
||||
|
||||
# Atualiza apenas o registro mais recente
|
||||
cursor.execute(
|
||||
f"UPDATE acompanhamento SET {campo} = ? WHERE id = ?"
|
||||
,
|
||||
(information, ultimo_id)
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
#atualizar_acompanhamento(614413127, "nome","zézé")
|
||||
|
||||
|
||||
def buscar_ultimo_chat(
|
||||
chat_id: int
|
||||
) -> Optional[Dict[str, object]]:
|
||||
"""
|
||||
Retorna o último registro (maior id) de um chat_id.
|
||||
|
||||
:param db_path: Caminho do banco SQLite
|
||||
:param chat_id: Chat ID a ser consultado
|
||||
:return: Dicionário com os dados ou None se não encontrar
|
||||
"""
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id, chat_id, status, nome, data_event, time_event, horarios_disponiveis
|
||||
FROM acompanhamento
|
||||
WHERE chat_id = ?
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
""",
|
||||
(chat_id,)
|
||||
)
|
||||
|
||||
row = cursor.fetchone()
|
||||
conn.close()
|
||||
|
||||
if row is None:
|
||||
return None
|
||||
|
||||
return {
|
||||
"id": row["id"],
|
||||
"chat_id": row["chat_id"],
|
||||
"status": row["status"],
|
||||
"nome": row["nome"],
|
||||
"data_event": row["data_event"],
|
||||
"time_event": row["time_event"],
|
||||
"horarios_disponiveis": row["horarios_disponiveis"],
|
||||
|
||||
}
|
||||
|
||||
#print(buscar_ultimo_chat(614413127)['horarios_disponiveis'])
|
||||
|
||||
def inserir_evento(event_date, start_time, end_time, title, description, chat_id, name, created_by) -> None:
|
||||
"""
|
||||
Insere um registro na tabela usuarios.
|
||||
|
||||
:param db_path: Caminho do banco de dados SQLite
|
||||
:param chat_id: ID do chat (ex: Telegram)
|
||||
:param status: Status do usuário
|
||||
"""
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
query = """
|
||||
INSERT INTO events (event_date, start_time, end_time, title, description, chat_id, name, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"""
|
||||
|
||||
cursor.execute(query, (event_date, start_time, end_time, title, description, chat_id, name, created_by))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
#--- Query agenda
|
||||
def listar_agenda(campo: str, parametro: Any) -> List[Dict[str, Any]]:
|
||||
colunas_permitidas = {"id","periodo", "data", "nome", "status"} # ajuste conforme sua tabela
|
||||
|
||||
if campo not in colunas_permitidas:
|
||||
raise ValueError("Campo inválido para consulta.")
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
cursor = conn.cursor()
|
||||
|
||||
query = f"SELECT * FROM agenda WHERE {campo} = ?;"
|
||||
cursor.execute(query, (parametro,))
|
||||
|
||||
rows = cursor.fetchall()
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
except sqlite3.Error as e:
|
||||
print(f"Erro na consulta: {e}")
|
||||
return []
|
||||
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
|
||||
'''a = listar_agenda("periodo","manhã")
|
||||
print(a)
|
||||
print(a[1]['horario'])
|
||||
|
||||
for z in a:
|
||||
print(z['horario'])'''
|
||||
229
BD_manager_Mysql.py
Normal file
229
BD_manager_Mysql.py
Normal file
@@ -0,0 +1,229 @@
|
||||
import mysql.connector
|
||||
from mysql.connector import Error
|
||||
from typing import Optional, Dict, List, Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
|
||||
|
||||
DB_CONFIG = {
|
||||
"host": "mysql-1ee2345c-glauberroberto-0e4e.h.aivencloud.com",
|
||||
"user": "avnadmin",
|
||||
"password": "AVNS_rmoyFuLW827cdgCMPwh",
|
||||
"database": "agenda",
|
||||
"port": 27341
|
||||
}
|
||||
|
||||
def get_connection():
|
||||
return mysql.connector.connect(**DB_CONFIG)
|
||||
|
||||
def inserir_acompanhamento(chat_id: int, status: str, nome: str) -> None:
|
||||
conn = get_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
query = """
|
||||
INSERT INTO acompanhamento (chat_id, status, nome)
|
||||
VALUES (%s, %s, %s)
|
||||
"""
|
||||
|
||||
cursor.execute(query, (chat_id, status, nome))
|
||||
conn.commit()
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
def atualizar_acompanhamento(chat_id: int, campo: str, information: str) -> bool:
|
||||
campos_permitidos = {"status", "nome", "data_event", "time_event"}
|
||||
|
||||
if campo not in campos_permitidos:
|
||||
raise ValueError("Campo não permitido")
|
||||
|
||||
conn = get_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id
|
||||
FROM acompanhamento
|
||||
WHERE chat_id = %s
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
""",
|
||||
(chat_id,)
|
||||
)
|
||||
|
||||
row = cursor.fetchone()
|
||||
|
||||
if row is None:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return False
|
||||
|
||||
ultimo_id = row[0]
|
||||
|
||||
query = f"UPDATE acompanhamento SET {campo} = %s WHERE id = %s"
|
||||
cursor.execute(query, (information, ultimo_id))
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
def buscar_ultimo_chat(chat_id: int) -> Optional[Dict[str, object]]:
|
||||
conn = get_connection()
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id, chat_id, status, nome, data_event, time_event
|
||||
FROM acompanhamento
|
||||
WHERE chat_id = %s
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
""",
|
||||
(chat_id,)
|
||||
)
|
||||
|
||||
row = cursor.fetchone()
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return row
|
||||
|
||||
|
||||
def get_events():
|
||||
conn = get_connection()
|
||||
cur = conn.cursor(dictionary=True)
|
||||
cur.execute("""
|
||||
SELECT * FROM events
|
||||
""")
|
||||
events = cur.fetchall()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return events
|
||||
|
||||
def update_events(id, campo, informacao):
|
||||
try:
|
||||
# Conexão com o banco de dados
|
||||
conn = get_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Query de atualização
|
||||
sql = f"""
|
||||
UPDATE events
|
||||
SET {campo} = {informacao}
|
||||
WHERE id = {id};
|
||||
"""
|
||||
|
||||
cursor.execute(sql)
|
||||
conn.commit() # Confirma a transação
|
||||
|
||||
print(f"{cursor.rowcount} registros atualizados.")
|
||||
|
||||
except mysql.connector.Error as erro:
|
||||
print(f"Erro ao atualizar: {erro}")
|
||||
finally:
|
||||
if conn.is_connected():
|
||||
cursor.close()
|
||||
conn.close()
|
||||
print("Conexão encerrada.")
|
||||
#update_events(18, "avisos","1")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def inserir_evento(
|
||||
event_date,
|
||||
start_time,
|
||||
end_time,
|
||||
title,
|
||||
description,
|
||||
chat_id,
|
||||
name,
|
||||
created_by
|
||||
) -> None:
|
||||
conn = get_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
query = """
|
||||
INSERT INTO events
|
||||
(event_date, start_time, end_time, title, description, chat_id, name, created_by)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
|
||||
cursor.execute(
|
||||
query,
|
||||
(event_date, start_time, end_time, title, description, chat_id, name, created_by)
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
|
||||
|
||||
#--- Query agenda
|
||||
def listar_agenda(campo: str, parametro: Any) -> List[Dict[str, Any]]:
|
||||
colunas_permitidas = {"id", "periodo", "data", "nome", "status"} # ajuste conforme sua tabela
|
||||
|
||||
if campo not in colunas_permitidas:
|
||||
raise ValueError("Campo inválido para consulta.")
|
||||
|
||||
try:
|
||||
conn = get_connection()
|
||||
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
query = f"SELECT * FROM agenda WHERE {campo} = %s AND disponibilidade = 'sim';"
|
||||
cursor.execute(query, (parametro,))
|
||||
|
||||
rows = cursor.fetchall()
|
||||
return rows
|
||||
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Erro na consulta: {e}")
|
||||
return []
|
||||
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def atualizar_agenda(id, campo, informacao):
|
||||
try:
|
||||
# Conexão com o banco de dados
|
||||
conn = get_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Query de atualização
|
||||
sql = f"""
|
||||
UPDATE agenda
|
||||
SET {campo} = {informacao}
|
||||
WHERE id = {id};
|
||||
"""
|
||||
|
||||
cursor.execute(sql)
|
||||
conn.commit() # Confirma a transação
|
||||
|
||||
print(f"{cursor.rowcount} registros atualizados.")
|
||||
|
||||
except mysql.connector.Error as erro:
|
||||
print(f"Erro ao atualizar: {erro}")
|
||||
finally:
|
||||
if conn.is_connected():
|
||||
cursor.close()
|
||||
conn.close()
|
||||
print("Conexão encerrada.")
|
||||
|
||||
|
||||
#atualizar_agenda(6, "disponibilidade", 7)
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Glauberrf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
117
Lembrator.py
Normal file
117
Lembrator.py
Normal file
@@ -0,0 +1,117 @@
|
||||
from BD_manager_Mysql import get_events
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
import asyncio
|
||||
from telegram import Bot
|
||||
import os
|
||||
from twilio.rest import Client
|
||||
from dotenv import load_dotenv
|
||||
from BD_manager_Mysql import update_events
|
||||
|
||||
|
||||
|
||||
# ==========================
|
||||
# Enviar mensagem WhatsApp
|
||||
# ==========================
|
||||
def enviar_whatsapp(numero_destino, mensagem):
|
||||
|
||||
# Carrega variáveis do arquivo .env
|
||||
load_dotenv()
|
||||
|
||||
# Credenciais Twilio
|
||||
ACCOUNT_SID = os.getenv("TWILIO_ACCOUNT_SID")
|
||||
AUTH_TOKEN = os.getenv("TWILIO_AUTH_TOKEN")
|
||||
TWILIO_WHATSAPP_NUMBER = os.getenv("TWILIO_WHATSAPP_NUMBER")
|
||||
|
||||
|
||||
|
||||
|
||||
# Cria cliente Twilio
|
||||
client = Client(ACCOUNT_SID, AUTH_TOKEN)
|
||||
|
||||
numero_destino = numero_destino.replace("whatsapp:", "")
|
||||
message = client.messages.create(
|
||||
from_=TWILIO_WHATSAPP_NUMBER,
|
||||
body=mensagem,
|
||||
to=f"whatsapp:{numero_destino}"
|
||||
)
|
||||
|
||||
return message.sid
|
||||
|
||||
|
||||
TOKEN = "8402367863:AAGoEBHvoK7YRdTLXCBqaZ-PVQlFp_1V3zI"
|
||||
|
||||
def enviar_mensagem_telegram(chat_id, mensagem):
|
||||
async def enviar_mensagem(chat_id, mensagem):
|
||||
bot = Bot(token=TOKEN)
|
||||
await bot.send_message(chat_id=chat_id, text=mensagem)
|
||||
|
||||
# chamada da função
|
||||
asyncio.run(enviar_mensagem(chat_id, mensagem))
|
||||
|
||||
|
||||
while True:
|
||||
sleep(3600) # Espera 10 segundos antes de verificar novamente
|
||||
events = get_events()
|
||||
|
||||
for event in events:
|
||||
#print(f"ID: {event['id']}, Date: {event['event_date']}, Start: {event['start_time']}, End: {event['end_time']}, Title: {event['title']}, Description: {event['description']}, Chat ID: {event['chat_id']}, Name: {event['name']}, Created By: {event['created_by']}")
|
||||
#print(event['event_date'],event['start_time'])
|
||||
id_envent = event['id']
|
||||
event_date = event['event_date']
|
||||
start_time = event['start_time']
|
||||
name = event['name']
|
||||
chat_id = event['chat_id']
|
||||
avisos = event['avisos']
|
||||
created_by = event['created_by']
|
||||
|
||||
# Juntar data + hora em um único datetime
|
||||
evento_datetime = datetime.strptime(
|
||||
f"{event_date} {start_time}",
|
||||
"%Y-%m-%d %H:%M:%S"
|
||||
)
|
||||
|
||||
agora = datetime.now() # horário atual
|
||||
|
||||
diferenca = evento_datetime - agora
|
||||
horas_faltando = diferenca.total_seconds() / 3600
|
||||
|
||||
#quando faltar 24 horas um aviso será enviado
|
||||
if(horas_faltando <= 24 and horas_faltando > 0 and avisos == "0"):
|
||||
|
||||
print(f"Evento em {evento_datetime} - faltam {horas_faltando:.2f} horas")
|
||||
if(created_by == "Telegram"):
|
||||
mensagem = f"Olá {name}, voce tem um horario agendado dia {event_date} as {start_time}"
|
||||
update_events(id_envent, "avisos", "1")
|
||||
enviar_mensagem_telegram(str(chat_id), mensagem)
|
||||
if(created_by == "Whatsapp"):
|
||||
mensagem = f"Olá {name}, voce tem um horario agendado dia {event_date} as {start_time}"
|
||||
update_events(id_envent, "avisos", "1")
|
||||
enviar_whatsapp(chat_id, mensagem)
|
||||
|
||||
#quando faltar 12 horas um aviso será enviado
|
||||
if(horas_faltando <= 12 and horas_faltando > 0 and avisos == "1"):
|
||||
|
||||
print(f"Evento em {evento_datetime} - faltam {horas_faltando:.2f} horas")
|
||||
if(created_by == "Telegram"):
|
||||
mensagem = f"Olá {name}, voce tem um horario agendado dia {event_date} as {start_time}"
|
||||
update_events(id_envent, "avisos", "2")
|
||||
enviar_mensagem_telegram(str(chat_id), mensagem)
|
||||
if(created_by == "Whatsapp"):
|
||||
mensagem = f"Olá {name}, voce tem um horario agendado dia {event_date} as {start_time}"
|
||||
update_events(id_envent, "avisos", "2")
|
||||
enviar_whatsapp(chat_id, mensagem)
|
||||
|
||||
|
||||
#quando faltar 3 horas um aviso será enviado
|
||||
if(horas_faltando <= 3 and horas_faltando > 0 and avisos == "2"):
|
||||
|
||||
print(f"Evento em {evento_datetime} - faltam {horas_faltando:.2f} horas")
|
||||
if(created_by == "Telegram"):
|
||||
mensagem = f"Olá {name}, voce tem um horario agendado dia {event_date} as {start_time}"
|
||||
update_events(id_envent, "avisos", "3")
|
||||
enviar_mensagem_telegram(str(chat_id), mensagem)
|
||||
if(created_by == "Whatsapp"):
|
||||
mensagem = f"Olá {name}, voce tem um horario agendado dia {event_date} as {start_time}"
|
||||
update_events(id_envent, "avisos", "3")
|
||||
enviar_whatsapp(chat_id, mensagem)
|
||||
35
Limpar_Sessoes.py
Normal file
35
Limpar_Sessoes.py
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
from BD_manager_Mysql import limpar_sessoes_expiradas
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
LOG_FILE = os.path.join(SCRIPT_DIR, "log_limpeza.txt")
|
||||
|
||||
def log_msg(msg):
|
||||
"""Escreve a mensagem no arquivo de log e imprime no console."""
|
||||
try:
|
||||
with open(LOG_FILE, "a") as f:
|
||||
f.write(f"{msg}\n")
|
||||
print(msg)
|
||||
except Exception as e:
|
||||
print(f"Erro ao escrever no log: {e}")
|
||||
|
||||
def limpar_registros_expirados():
|
||||
agora = datetime.now()
|
||||
limite = agora - timedelta(minutes=2)
|
||||
|
||||
try:
|
||||
ids_removidos = limpar_sessoes_expiradas(limite)
|
||||
|
||||
if ids_removidos:
|
||||
ids_str = ",".join(map(str, ids_removidos))
|
||||
log_msg(f"[{agora.strftime('%Y-%m-%d %H:%M:%S')}] 🗑️ Removidos IDs: {ids_str}")
|
||||
else:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
log_msg(f"[{agora.strftime('%Y-%m-%d %H:%M:%S')}] ❌ Erro: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
limpar_registros_expirados()
|
||||
260
Main_Receiver-Twilio01.py
Normal file
260
Main_Receiver-Twilio01.py
Normal file
@@ -0,0 +1,260 @@
|
||||
import os
|
||||
from flask import Flask, request, jsonify
|
||||
from twilio.rest import Client
|
||||
from twilio.twiml.messaging_response import MessagingResponse
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
###
|
||||
from BD_manager_Mysql import inserir_acompanhamento, buscar_ultimo_chat, atualizar_acompanhamento, inserir_evento, listar_agenda, atualizar_agenda
|
||||
|
||||
###
|
||||
|
||||
load_dotenv()
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Credenciais
|
||||
ACCOUNT_SID = os.getenv("TWILIO_ACCOUNT_SID")
|
||||
AUTH_TOKEN = os.getenv("TWILIO_AUTH_TOKEN")
|
||||
TWILIO_WHATSAPP_NUMBER = os.getenv("TWILIO_WHATSAPP_NUMBER")
|
||||
|
||||
client = Client(ACCOUNT_SID, AUTH_TOKEN)
|
||||
|
||||
|
||||
#Funções de fluxo
|
||||
def MostrarPeriodos(chat_id, name, status):
|
||||
#
|
||||
|
||||
if(status == "10" or status == "null"):
|
||||
inserir_acompanhamento(chat_id, "2", name)
|
||||
|
||||
else:
|
||||
atualizar_acompanhamento(chat_id, "status", "2")
|
||||
|
||||
|
||||
resposta = f"Qual periodo você gostaria de agendar ?\n1-Manhã\n2-Tarde\n3-Noite"
|
||||
return resposta
|
||||
|
||||
def MostrarHorarios(texto_recebido, chat_id):
|
||||
print("Entrou na função de consultar os horarios")
|
||||
z = ""
|
||||
try:
|
||||
if(texto_recebido == "1"):
|
||||
horarios = listar_agenda("periodo","manhã")
|
||||
resposta = horarios
|
||||
for horario in horarios:
|
||||
z = z + str(horario['id'])+" - "+horario['data'].strftime("%d/%m/%Y")+" as "+str(horario['horario'])+"\n"
|
||||
resposta = f"Qual horario você gostaria de agendar ?\n"+z+"\n0 - Voltar"
|
||||
atualizar_acompanhamento(chat_id, "status", "3")
|
||||
return resposta
|
||||
|
||||
elif(texto_recebido == "2"):
|
||||
horarios = listar_agenda("periodo","tarde")
|
||||
resposta = horarios
|
||||
for horario in horarios:
|
||||
z = z + str(horario['id'])+" - "+horario['data'].strftime("%d/%m/%Y")+" as "+str(horario['horario'])+"\n"
|
||||
resposta = f"Qual horario você gostaria de agendar ?\n"+z+"\n0 - Voltar"
|
||||
atualizar_acompanhamento(chat_id, "status", "3")
|
||||
return resposta
|
||||
|
||||
elif(texto_recebido == "3"):
|
||||
horarios = listar_agenda("periodo","noite")
|
||||
resposta = horarios
|
||||
for horario in horarios:
|
||||
z = z + str(horario['id'])+" - "+horario['data'].strftime("%d/%m/%Y")+" as "+str(horario['horario'])+"\n"
|
||||
resposta = f"Qual horario você gostaria de agendar ?\n"+z+"\n0 - Voltar"
|
||||
atualizar_acompanhamento(chat_id, "status", "3")
|
||||
return resposta
|
||||
|
||||
|
||||
|
||||
|
||||
else:
|
||||
resposta = "Opção inválida, por favor digite um periodo válido\n1 - manhã\n2 - tarde\n3 - noite"
|
||||
return resposta
|
||||
except ValueError:
|
||||
resposta = f"Você não digitou uma opção válida"
|
||||
return resposta
|
||||
|
||||
###############
|
||||
|
||||
|
||||
# ==========================
|
||||
# WEBHOOK (receber mensagem)
|
||||
# ==========================
|
||||
@app.route("/webhook", methods=["POST"])
|
||||
def webhook():
|
||||
texto_recebido = request.form.get("Body", "").strip().lower()
|
||||
name = request.form.get("ProfileName")
|
||||
sender = request.form.get("From")
|
||||
|
||||
print(f"Mensagem recebida de {name}: {sender}: {texto_recebido}")
|
||||
|
||||
chat_id = sender
|
||||
|
||||
response = MessagingResponse()
|
||||
resposta = response.message()
|
||||
|
||||
|
||||
|
||||
print(f"Mensagem recebida de {chat_id}: {texto_recebido}")
|
||||
|
||||
# Remove sufixo "@c.us" do número
|
||||
#numero_remetente = numero_remetente.replace("@c.us", "")
|
||||
chat_id = chat_id.replace("@c.us", "")
|
||||
|
||||
try:
|
||||
status = buscar_ultimo_chat(chat_id)['status']
|
||||
except:
|
||||
status = "null"
|
||||
|
||||
print("Status: ", status)
|
||||
|
||||
#Começo do atendimento (Fluxo iniciado)
|
||||
'''if(texto_recebido.lower() == "oi" or texto_recebido.lower() == "sim"):
|
||||
resposta = f"Olá! você gostaria de agendar um horário?\n Digite\n1-SIM\n2-NÃO"
|
||||
inserir_acompanhamento(chat_id, "1", name)'''
|
||||
if(texto_recebido == "2" and status == "10") :
|
||||
resposta.body("Sem problemas, qualquer coisa estou aqui")
|
||||
print("ChatID: ", chat_id)
|
||||
print("Status: ", status)
|
||||
print("Status type: ", type(status))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#Mostrar periodos Manhã, tarde e Noite
|
||||
elif(texto_recebido == "1" and status == "10" or texto_recebido == "1" and status == "null") :
|
||||
print("Mostrar os periodos manhã, tarde e noite")
|
||||
resposta.body(MostrarPeriodos(chat_id, name, status))
|
||||
|
||||
'''atualizar_acompanhamento(chat_id, "status", "2")
|
||||
resposta = f"Qual periodo você gostaria de agendar ?\n1-Manhã\n2-Tarde\n3-Noite"'''
|
||||
|
||||
|
||||
##mostrar horarios
|
||||
elif(status == "2") :
|
||||
print("mostrar os horarios disponiveis")
|
||||
resposta.body(MostrarHorarios(texto_recebido, chat_id))
|
||||
|
||||
#Seleção dos horarios disponiveis
|
||||
elif(texto_recebido != "0" and status == "3") :
|
||||
|
||||
try:
|
||||
#converter data
|
||||
id = texto_recebido
|
||||
data_horario_agenda = listar_agenda("id",id)
|
||||
|
||||
print("Data Agenda: ",data_horario_agenda)
|
||||
print("Data agenda data: ",data_horario_agenda[0]['data'])
|
||||
|
||||
#sqlite
|
||||
#data_convertida = datetime.strptime(data_horario_agenda[0]['data'], "%d/%m/%Y").strftime("%Y-%m-%d")
|
||||
#mysql
|
||||
data_convertida = data_horario_agenda[0]['data'].strftime("%Y-%m-%d")
|
||||
datetime.strptime(data_convertida, "%Y-%m-%d")
|
||||
|
||||
atualizar_acompanhamento(chat_id, "data_event", data_convertida)
|
||||
|
||||
atualizar_acompanhamento(chat_id, "time_event", data_horario_agenda[0]['horario'])
|
||||
|
||||
atualizar_acompanhamento(chat_id, "status", "4")
|
||||
|
||||
#atualizar a disponibilidade da agenda para não aparecer depois da data ser agendada
|
||||
atualizar_agenda(int(texto_recebido), "disponibilidade", "'nao'")
|
||||
|
||||
resposta.body(f"Você gostaria de adicionar algum comentários ?\n1 - Sim\n2 -Não")
|
||||
|
||||
|
||||
except ValueError:
|
||||
resposta.body(f"A data que você digitou não está no formato correto.\nDigite a data no seguinte formato dd/mm/yyyy")
|
||||
except IndexError:
|
||||
resposta.body("Nenhum evento encontrado para esse ID, por favor, selecione uma das datas que lhe enviei.")
|
||||
|
||||
#Adicionar comentário caso a resposta seja sim para adicionar
|
||||
elif(texto_recebido == "1" and status == "4"):
|
||||
atualizar_acompanhamento(chat_id, "status", "5")
|
||||
resposta.body("Por favor, escreva o seu comentário")
|
||||
|
||||
#Capturando a mensagem para ser inserida no banco
|
||||
elif(status == "5"):
|
||||
atualizar_acompanhamento(chat_id, "status", "10")
|
||||
data_agendada = buscar_ultimo_chat(chat_id)["data_event"]
|
||||
#data_agendada = datetime.strptime(data_agendada, "%Y-%m-%d")
|
||||
data_agendada_formatada = data_agendada.strftime("%d/%m/%Y")
|
||||
|
||||
horario_agendado = buscar_ultimo_chat(chat_id)["time_event"]
|
||||
|
||||
inserir_evento(buscar_ultimo_chat(chat_id)["data_event"],buscar_ultimo_chat(chat_id)["time_event"],"00:30:00","Padão Titulo",texto_recebido,chat_id,name,"Whatsapp")
|
||||
resposta.body(f"Então agendamos para {data_agendada_formatada} as {horario_agendado} !\nObrigado !")
|
||||
|
||||
#Caso a resposta de inserir uma mensagem seja "Não"
|
||||
elif(texto_recebido == "2" and status == "4"):
|
||||
atualizar_acompanhamento(chat_id, "status", "10")
|
||||
data_agendada = buscar_ultimo_chat(chat_id)["data_event"]
|
||||
#data_agendada = datetime.strptime(data_agendada, "%Y-%m-%d")
|
||||
data_agendada_formatada = data_agendada.strftime("%d/%m/%Y")
|
||||
|
||||
horario_agendado = buscar_ultimo_chat(chat_id)["time_event"]
|
||||
|
||||
inserir_evento(buscar_ultimo_chat(chat_id)["data_event"],buscar_ultimo_chat(chat_id)["time_event"],"00:30:00","Padão Titulo",texto_recebido,chat_id,name,"Whatsapp")
|
||||
resposta.body(f"Então agendamos para {data_agendada_formatada} as {horario_agendado} !\nObrigado !")
|
||||
|
||||
|
||||
#voltar para priodo
|
||||
elif(texto_recebido == "0" and status == "3"):
|
||||
|
||||
atualizar_acompanhamento(chat_id, "status", "2")
|
||||
resposta.body(MostrarPeriodos(chat_id, name, status))
|
||||
|
||||
|
||||
|
||||
|
||||
#Tratamento de mensagem inválida ao bot
|
||||
elif(texto_recebido.lower() == "quem é você?" or texto_recebido.lower() == "quem e você?"):
|
||||
resposta.body(f"Eu sou um Bot de agendamento!")
|
||||
#await update.message.reply_text(resposta)
|
||||
#resposta = f"Você escreveu: {texto_recebido}"
|
||||
|
||||
elif(texto_recebido.lower() == "2" and status == "null" or texto_recebido.lower() == "2" and status == "10"):
|
||||
resposta.body(f"Então tudo bem !\nSe precisar é só me chamar.")
|
||||
|
||||
else:
|
||||
resposta.body(f"Olá, você gostaria de agendar um horario ?\n1 - Sim\n2 - Não")
|
||||
|
||||
return str(response)
|
||||
|
||||
|
||||
# ==========================
|
||||
# ENVIO ATIVO (via API REST)
|
||||
# ==========================
|
||||
@app.route("/send", methods=["POST"])
|
||||
def send_message():
|
||||
data = request.json
|
||||
to_number = data.get("to")
|
||||
message_text = data.get("message")
|
||||
|
||||
try:
|
||||
message = client.messages.create(
|
||||
from_=TWILIO_WHATSAPP_NUMBER,
|
||||
body=message_text,
|
||||
to=f"whatsapp:{to_number}"
|
||||
)
|
||||
|
||||
return jsonify({
|
||||
"status": "success",
|
||||
"sid": message.sid
|
||||
}), 200
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
"status": "error",
|
||||
"message": str(e)
|
||||
}), 500
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(port=5000, debug=True)
|
||||
241
Main_Receiver-Whatsapp.py
Normal file
241
Main_Receiver-Whatsapp.py
Normal file
@@ -0,0 +1,241 @@
|
||||
|
||||
from flask import Flask, request, jsonify
|
||||
import requests
|
||||
from datetime import datetime
|
||||
|
||||
###
|
||||
from BD_manager_Mysql import inserir_acompanhamento, buscar_ultimo_chat, atualizar_acompanhamento, inserir_evento, listar_agenda, atualizar_agenda
|
||||
|
||||
###
|
||||
|
||||
|
||||
#Funções de fluxo
|
||||
def MostrarPeriodos(chat_id, name, status):
|
||||
#
|
||||
|
||||
if(status == "10" or status == "null"):
|
||||
inserir_acompanhamento(chat_id, "2", name)
|
||||
|
||||
else:
|
||||
atualizar_acompanhamento(chat_id, "status", "2")
|
||||
|
||||
|
||||
resposta = f"Qual periodo você gostaria de agendar ?\n1-Manhã\n2-Tarde\n3-Noite"
|
||||
return resposta
|
||||
|
||||
def MostrarHorarios(texto_recebido, chat_id):
|
||||
print("Entrou na função de consultar os horarios")
|
||||
z = ""
|
||||
try:
|
||||
if(texto_recebido == "1"):
|
||||
horarios = listar_agenda("periodo","manhã")
|
||||
resposta = horarios
|
||||
for horario in horarios:
|
||||
z = z + str(horario['id'])+" - "+horario['data'].strftime("%d/%m/%Y")+" as "+str(horario['horario'])+"\n"
|
||||
resposta = f"Qual horario você gostaria de agendar ?\n"+z+"\n0 - Voltar"
|
||||
atualizar_acompanhamento(chat_id, "status", "3")
|
||||
return resposta
|
||||
|
||||
elif(texto_recebido == "2"):
|
||||
horarios = listar_agenda("periodo","tarde")
|
||||
resposta = horarios
|
||||
for horario in horarios:
|
||||
z = z + str(horario['id'])+" - "+horario['data'].strftime("%d/%m/%Y")+" as "+str(horario['horario'])+"\n"
|
||||
resposta = f"Qual horario você gostaria de agendar ?\n"+z+"\n0 - Voltar"
|
||||
atualizar_acompanhamento(chat_id, "status", "3")
|
||||
return resposta
|
||||
|
||||
elif(texto_recebido == "3"):
|
||||
horarios = listar_agenda("periodo","noite")
|
||||
resposta = horarios
|
||||
for horario in horarios:
|
||||
z = z + str(horario['id'])+" - "+horario['data'].strftime("%d/%m/%Y")+" as "+str(horario['horario'])+"\n"
|
||||
resposta = f"Qual horario você gostaria de agendar ?\n"+z+"\n0 - Voltar"
|
||||
atualizar_acompanhamento(chat_id, "status", "3")
|
||||
return resposta
|
||||
|
||||
|
||||
|
||||
|
||||
else:
|
||||
resposta = "Opção inválida, por favor digite um periodo válido\n1 - manhã\n2 - tarde\n3 - noite"
|
||||
return resposta
|
||||
except ValueError:
|
||||
resposta = f"Você não digitou uma opção válida"
|
||||
return resposta
|
||||
|
||||
###############
|
||||
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# 🔧 Configurações da sua instância UltraMsg
|
||||
INSTANCE_ID = ""
|
||||
TOKEN = ""
|
||||
|
||||
# URL da API para enviar mensagens
|
||||
API_URL = f"https://api.ultramsg.com/{INSTANCE_ID}/messages/chat"
|
||||
|
||||
@app.route('/webhook', methods=['POST'])
|
||||
def webhook():
|
||||
payload = request.json
|
||||
print("🔵 DADOS RECEBIDOS:")
|
||||
print(payload)
|
||||
|
||||
# Extrai a mensagem de dentro de 'data'
|
||||
data = payload.get("data", {})
|
||||
texto_recebido = data.get("body", "")
|
||||
#numero_remetente = data.get("from", "")
|
||||
chat_id = data.get("from", "")
|
||||
name = data.get("pushname", "")
|
||||
|
||||
resposta = ""
|
||||
|
||||
print(f"Mensagem recebida de {chat_id}: {texto_recebido}")
|
||||
|
||||
# Remove sufixo "@c.us" do número
|
||||
#numero_remetente = numero_remetente.replace("@c.us", "")
|
||||
chat_id = chat_id.replace("@c.us", "")
|
||||
|
||||
try:
|
||||
status = buscar_ultimo_chat(chat_id)['status']
|
||||
except:
|
||||
status = "null"
|
||||
|
||||
print("Status: ", status)
|
||||
|
||||
#Começo do atendimento (Fluxo iniciado)
|
||||
'''if(texto_recebido.lower() == "oi" or texto_recebido.lower() == "sim"):
|
||||
resposta = f"Olá! você gostaria de agendar um horário?\n Digite\n1-SIM\n2-NÃO"
|
||||
inserir_acompanhamento(chat_id, "1", name)'''
|
||||
if(texto_recebido == "2" and status == "10") :
|
||||
resposta = "Sem problemas, qualquer coisa estou aqui"
|
||||
print("ChatID: ", chat_id)
|
||||
print("Status: ", status)
|
||||
print("Status type: ", type(status))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#Mostrar periodos Manhã, tarde e Noite
|
||||
elif(texto_recebido == "1" and status == "10" or texto_recebido == "1" and status == "null") :
|
||||
print("Mostrar os periodos manhã, tarde e noite")
|
||||
resposta = MostrarPeriodos(chat_id, name, status)
|
||||
|
||||
'''atualizar_acompanhamento(chat_id, "status", "2")
|
||||
resposta = f"Qual periodo você gostaria de agendar ?\n1-Manhã\n2-Tarde\n3-Noite"'''
|
||||
|
||||
|
||||
##mostrar horarios
|
||||
elif(status == "2") :
|
||||
print("mostrar os horarios disponiveis")
|
||||
resposta = MostrarHorarios(texto_recebido, chat_id)
|
||||
|
||||
#Seleção dos horarios disponiveis
|
||||
elif(texto_recebido != "0" and status == "3") :
|
||||
|
||||
try:
|
||||
#converter data
|
||||
id = texto_recebido
|
||||
data_horario_agenda = listar_agenda("id",id)
|
||||
|
||||
print("Data Agenda: ",data_horario_agenda)
|
||||
print("Data agenda data: ",data_horario_agenda[0]['data'])
|
||||
|
||||
#sqlite
|
||||
#data_convertida = datetime.strptime(data_horario_agenda[0]['data'], "%d/%m/%Y").strftime("%Y-%m-%d")
|
||||
#mysql
|
||||
data_convertida = data_horario_agenda[0]['data'].strftime("%Y-%m-%d")
|
||||
datetime.strptime(data_convertida, "%Y-%m-%d")
|
||||
|
||||
atualizar_acompanhamento(chat_id, "data_event", data_convertida)
|
||||
|
||||
atualizar_acompanhamento(chat_id, "time_event", data_horario_agenda[0]['horario'])
|
||||
|
||||
atualizar_acompanhamento(chat_id, "status", "4")
|
||||
|
||||
#atualizar a disponibilidade da agenda para não aparecer depois da data ser agendada
|
||||
atualizar_agenda(int(texto_recebido), "disponibilidade", "1")
|
||||
|
||||
resposta = f"Você gostaria de adicionar algum comentários ?\n1 - Sim\n2 -Não"
|
||||
|
||||
|
||||
except ValueError:
|
||||
resposta = f"A data que você digitou não está no formato correto.\nDigite a data no seguinte formato dd/mm/yyyy"
|
||||
except IndexError:
|
||||
resposta = "Nenhum evento encontrado para esse ID, por favor, selecione uma das datas que lhe enviei."
|
||||
|
||||
#Adicionar comentário caso a resposta seja sim para adicionar
|
||||
elif(texto_recebido == "1" and status == "4"):
|
||||
atualizar_acompanhamento(chat_id, "status", "5")
|
||||
resposta = "Por favor, escreva o seu comentário"
|
||||
|
||||
#Capturando a mensagem para ser inserida no banco
|
||||
elif(status == "5"):
|
||||
atualizar_acompanhamento(chat_id, "status", "10")
|
||||
data_agendada = buscar_ultimo_chat(chat_id)["data_event"]
|
||||
#data_agendada = datetime.strptime(data_agendada, "%Y-%m-%d")
|
||||
data_agendada_formatada = data_agendada.strftime("%d/%m/%Y")
|
||||
|
||||
horario_agendado = buscar_ultimo_chat(chat_id)["time_event"]
|
||||
|
||||
inserir_evento(buscar_ultimo_chat(chat_id)["data_event"],buscar_ultimo_chat(chat_id)["time_event"],"00:30:00","Padão Titulo",texto_recebido,chat_id,name,"Telegram")
|
||||
resposta = f"Então agendamos para {data_agendada_formatada} as {horario_agendado} !\nObrigado !"
|
||||
|
||||
#Caso a resposta de inserir uma mensagem seja "Não"
|
||||
elif(texto_recebido == "2" and status == "4"):
|
||||
atualizar_acompanhamento(chat_id, "status", "10")
|
||||
data_agendada = buscar_ultimo_chat(chat_id)["data_event"]
|
||||
#data_agendada = datetime.strptime(data_agendada, "%Y-%m-%d")
|
||||
data_agendada_formatada = data_agendada.strftime("%d/%m/%Y")
|
||||
|
||||
horario_agendado = buscar_ultimo_chat(chat_id)["time_event"]
|
||||
|
||||
inserir_evento(buscar_ultimo_chat(chat_id)["data_event"],buscar_ultimo_chat(chat_id)["time_event"],"00:30:00","Padão Titulo",texto_recebido,chat_id,name,"Telegram")
|
||||
resposta = f"Então agendamos para {data_agendada_formatada} as {horario_agendado} !\nObrigado !"
|
||||
|
||||
|
||||
#voltar para priodo
|
||||
elif(texto_recebido == "0" and status == "3"):
|
||||
|
||||
atualizar_acompanhamento(chat_id, "status", "2")
|
||||
resposta = MostrarPeriodos(chat_id, name, status)
|
||||
|
||||
|
||||
|
||||
|
||||
#Tratamento de mensagem inválida ao bot
|
||||
elif(texto_recebido.lower() == "quem é você?" or texto_recebido.lower() == "quem e você?"):
|
||||
resposta = f"Eu sou um Bot de agendamento!"
|
||||
#await update.message.reply_text(resposta)
|
||||
#resposta = f"Você escreveu: {texto_recebido}"
|
||||
|
||||
elif(texto_recebido.lower() == "2" and status == "null" or texto_recebido.lower() == "2" and status == "10"):
|
||||
resposta = f"Então tudo bem !\nSe precisar é só me chamar."
|
||||
|
||||
else:
|
||||
resposta = f"Olá, você gostaria de agendar um horario ?\n1 - Sim\n2 - Não"
|
||||
|
||||
|
||||
|
||||
# Envia a resposta
|
||||
API_URL = f"https://api.ultramsg.com/{INSTANCE_ID}/messages/chat"
|
||||
payload_resposta = {
|
||||
"token": TOKEN,
|
||||
#"to": numero_remetente,
|
||||
"to": chat_id,
|
||||
"body": resposta
|
||||
}
|
||||
|
||||
r = requests.post(API_URL, data=payload_resposta)
|
||||
print("🟢 Enviando resposta:", resposta)
|
||||
print("🟡 Status da API:", r.status_code)
|
||||
print("🔴 Resposta da API:", r.text)
|
||||
|
||||
return jsonify({"status": "mensagem processada"}), 200
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(port=5000)
|
||||
232
Main_Receiver_Telegram.py
Normal file
232
Main_Receiver_Telegram.py
Normal file
@@ -0,0 +1,232 @@
|
||||
from telegram import Update
|
||||
from telegram.ext import (
|
||||
ApplicationBuilder,
|
||||
ContextTypes,
|
||||
MessageHandler,
|
||||
CommandHandler,
|
||||
filters
|
||||
)
|
||||
from datetime import datetime
|
||||
|
||||
import json
|
||||
|
||||
|
||||
#from BD_manager import inserir_acompanhamento, buscar_ultimo_chat, atualizar_acompanhamento, inserir_evento, listar_agenda
|
||||
|
||||
from BD_manager_Mysql import inserir_acompanhamento, buscar_ultimo_chat, atualizar_acompanhamento, inserir_evento, listar_agenda, atualizar_agenda
|
||||
|
||||
TOKEN = "8402367863:AAGoEBHvoK7YRdTLXCBqaZ-PVQlFp_1V3zI"
|
||||
#TOKEN = st.secrets["api"]["token"]
|
||||
|
||||
|
||||
#Funções de fluxo
|
||||
def MostrarPeriodos(chat_id, name, status):
|
||||
#
|
||||
|
||||
if(status == "10" or status == "null"):
|
||||
inserir_acompanhamento(chat_id, "2", name)
|
||||
|
||||
else:
|
||||
atualizar_acompanhamento(chat_id, "status", "2")
|
||||
|
||||
|
||||
resposta = f"Qual periodo você gostaria de agendar ?\n1-Manhã\n2-Tarde\n3-Noite"
|
||||
return resposta
|
||||
|
||||
def MostrarHorarios(texto_recebido, chat_id):
|
||||
print("Entrou na função de consultar os horarios")
|
||||
z = ""
|
||||
try:
|
||||
if(texto_recebido == "1"):
|
||||
horarios = listar_agenda("periodo","manhã")
|
||||
resposta = horarios
|
||||
for horario in horarios:
|
||||
z = z + str(horario['id'])+" - "+horario['data'].strftime("%d/%m/%Y")+" as "+str(horario['horario'])+"\n"
|
||||
resposta = f"Qual horario você gostaria de agendar ?\n"+z+"\n0 - Voltar"
|
||||
atualizar_acompanhamento(chat_id, "status", "3")
|
||||
return resposta
|
||||
|
||||
elif(texto_recebido == "2"):
|
||||
horarios = listar_agenda("periodo","tarde")
|
||||
resposta = horarios
|
||||
for horario in horarios:
|
||||
z = z + str(horario['id'])+" - "+horario['data'].strftime("%d/%m/%Y")+" as "+str(horario['horario'])+"\n"
|
||||
resposta = f"Qual horario você gostaria de agendar ?\n"+z+"\n0 - Voltar"
|
||||
atualizar_acompanhamento(chat_id, "status", "3")
|
||||
return resposta
|
||||
|
||||
elif(texto_recebido == "3"):
|
||||
horarios = listar_agenda("periodo","noite")
|
||||
resposta = horarios
|
||||
for horario in horarios:
|
||||
z = z + str(horario['id'])+" - "+horario['data'].strftime("%d/%m/%Y")+" as "+str(horario['horario'])+"\n"
|
||||
resposta = f"Qual horario você gostaria de agendar ?\n"+z+"\n0 - Voltar"
|
||||
atualizar_acompanhamento(chat_id, "status", "3")
|
||||
return resposta
|
||||
|
||||
|
||||
|
||||
|
||||
else:
|
||||
resposta = "Opção inválida, por favor digite um periodo válido\n1 - manhã\n2 - tarde\n3 - noite"
|
||||
return resposta
|
||||
except ValueError:
|
||||
resposta = f"Você não digitou uma opção válida"
|
||||
return resposta
|
||||
|
||||
###############
|
||||
|
||||
# Comando /start
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
await update.message.reply_text(
|
||||
"Olá! Eu sou um bot de agendamento da Malu.\nComo vai ?"
|
||||
|
||||
|
||||
)
|
||||
|
||||
# Recebe mensagens de texto
|
||||
async def receber_mensagem(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
texto_recebido = update.message.text
|
||||
chat_id = update.effective_chat.id
|
||||
name = update.effective_chat.full_name
|
||||
print(f"{chat_id=}, {name=}")
|
||||
|
||||
print(f"{texto_recebido=}")
|
||||
|
||||
try:
|
||||
status = buscar_ultimo_chat(chat_id)['status']
|
||||
except:
|
||||
status = "null"
|
||||
|
||||
print("Status: ", status)
|
||||
|
||||
#Começo do atendimento (Fluxo iniciado)
|
||||
'''if(texto_recebido.lower() == "oi" or texto_recebido.lower() == "sim"):
|
||||
resposta = f"Olá! você gostaria de agendar um horário?\n Digite\n1-SIM\n2-NÃO"
|
||||
inserir_acompanhamento(chat_id, "1", name)'''
|
||||
if(texto_recebido == "2" and status == "10") :
|
||||
resposta = "Sem problemas, qualquer coisa estou aqui"
|
||||
print("ChatID: ", chat_id)
|
||||
print("Status: ", status)
|
||||
print("Status type: ", type(status))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#Mostrar periodos Manhã, tarde e Noite
|
||||
elif(texto_recebido == "1" and status == "10" or texto_recebido == "1" and status == "null") :
|
||||
print("Mostrar os periodos manhã, tarde e noite")
|
||||
resposta = MostrarPeriodos(chat_id, name, status)
|
||||
|
||||
'''atualizar_acompanhamento(chat_id, "status", "2")
|
||||
resposta = f"Qual periodo você gostaria de agendar ?\n1-Manhã\n2-Tarde\n3-Noite"'''
|
||||
|
||||
|
||||
##mostrar horarios
|
||||
elif(status == "2") :
|
||||
print("mostrar os horarios disponiveis")
|
||||
resposta = MostrarHorarios(texto_recebido, chat_id)
|
||||
|
||||
#Seleção dos horarios disponiveis
|
||||
elif(texto_recebido != "0" and status == "3") :
|
||||
|
||||
try:
|
||||
#converter data
|
||||
id = texto_recebido
|
||||
data_horario_agenda = listar_agenda("id",id)
|
||||
|
||||
print("Data Agenda: ",data_horario_agenda)
|
||||
print("Data agenda data: ",data_horario_agenda[0]['data'])
|
||||
|
||||
#sqlite
|
||||
#data_convertida = datetime.strptime(data_horario_agenda[0]['data'], "%d/%m/%Y").strftime("%Y-%m-%d")
|
||||
#mysql
|
||||
data_convertida = data_horario_agenda[0]['data'].strftime("%Y-%m-%d")
|
||||
datetime.strptime(data_convertida, "%Y-%m-%d")
|
||||
|
||||
atualizar_acompanhamento(chat_id, "data_event", data_convertida)
|
||||
|
||||
atualizar_acompanhamento(chat_id, "time_event", data_horario_agenda[0]['horario'])
|
||||
|
||||
atualizar_acompanhamento(chat_id, "status", "4")
|
||||
|
||||
#atualizar a disponibilidade da agenda para não aparecer depois da data ser agendada
|
||||
atualizar_agenda(int(texto_recebido), "disponibilidade", "'nao'")
|
||||
|
||||
resposta = f"Você gostaria de adicionar algum comentários ?\n1 - Sim\n2 -Não"
|
||||
|
||||
|
||||
except ValueError:
|
||||
resposta = f"A data que você digitou não está no formato correto.\nDigite a data no seguinte formato dd/mm/yyyy"
|
||||
except IndexError:
|
||||
resposta = "Nenhum evento encontrado para esse ID, por favor, selecione uma das datas que lhe enviei."
|
||||
|
||||
#Adicionar comentário caso a resposta seja sim para adicionar
|
||||
elif(texto_recebido == "1" and status == "4"):
|
||||
atualizar_acompanhamento(chat_id, "status", "5")
|
||||
resposta = "Por favor, escreva o seu comentário"
|
||||
|
||||
#Capturando a mensagem para ser inserida no banco
|
||||
elif(status == "5"):
|
||||
atualizar_acompanhamento(chat_id, "status", "10")
|
||||
data_agendada = buscar_ultimo_chat(chat_id)["data_event"]
|
||||
#data_agendada = datetime.strptime(data_agendada, "%Y-%m-%d")
|
||||
data_agendada_formatada = data_agendada.strftime("%d/%m/%Y")
|
||||
|
||||
horario_agendado = buscar_ultimo_chat(chat_id)["time_event"]
|
||||
|
||||
inserir_evento(buscar_ultimo_chat(chat_id)["data_event"],buscar_ultimo_chat(chat_id)["time_event"],"00:30:00","Padão Titulo",texto_recebido,chat_id,name,"Telegram")
|
||||
resposta = f"Então agendamos para {data_agendada_formatada} as {horario_agendado} !\nObrigado !"
|
||||
|
||||
#Caso a resposta de inserir uma mensagem seja "Não"
|
||||
elif(texto_recebido == "2" and status == "4"):
|
||||
atualizar_acompanhamento(chat_id, "status", "10")
|
||||
data_agendada = buscar_ultimo_chat(chat_id)["data_event"]
|
||||
#data_agendada = datetime.strptime(data_agendada, "%Y-%m-%d")
|
||||
data_agendada_formatada = data_agendada.strftime("%d/%m/%Y")
|
||||
|
||||
horario_agendado = buscar_ultimo_chat(chat_id)["time_event"]
|
||||
|
||||
inserir_evento(buscar_ultimo_chat(chat_id)["data_event"],buscar_ultimo_chat(chat_id)["time_event"],"00:30:00","Padão Titulo",texto_recebido,chat_id,name,"Telegram")
|
||||
resposta = f"Então agendamos para {data_agendada_formatada} as {horario_agendado} !\nObrigado !"
|
||||
|
||||
|
||||
#voltar para priodo
|
||||
elif(texto_recebido == "0" and status == "3"):
|
||||
|
||||
atualizar_acompanhamento(chat_id, "status", "2")
|
||||
resposta = MostrarPeriodos(chat_id, name, status)
|
||||
|
||||
|
||||
|
||||
|
||||
#Tratamento de mensagem inválida ao bot
|
||||
elif(texto_recebido.lower() == "quem é você?" or texto_recebido.lower() == "quem e você?"):
|
||||
resposta = f"Eu sou um Bot de agendamento!"
|
||||
#await update.message.reply_text(resposta)
|
||||
#resposta = f"Você escreveu: {texto_recebido}"
|
||||
elif(texto_recebido.lower() == "2" and status == "null" or texto_recebido.lower() == "2" and status == "10"):
|
||||
#elif(texto_recebido.lower() == "2" and buscar_ultimo_chat(chat_id)['status'] == "1"):
|
||||
resposta = f"Então tudo bem !\nSe precisar é só me chamar."
|
||||
|
||||
else:
|
||||
resposta = f"Olá, você gostaria de agendar um horario ?\n1 - Sim\n2 - Não"
|
||||
await update.message.reply_text(resposta)
|
||||
|
||||
def main():
|
||||
app = ApplicationBuilder().token(TOKEN).build()
|
||||
|
||||
# Comandos
|
||||
app.add_handler(CommandHandler("start", start))
|
||||
|
||||
# Mensagens de texto
|
||||
app.add_handler(
|
||||
MessageHandler(filters.TEXT & ~filters.COMMAND, receber_mensagem)
|
||||
)
|
||||
|
||||
print("Bot em execução...")
|
||||
app.run_polling()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
240
Painel_Prestador_Mysql.py
Normal file
240
Painel_Prestador_Mysql.py
Normal file
@@ -0,0 +1,240 @@
|
||||
import streamlit as st
|
||||
import mysql.connector
|
||||
import hashlib
|
||||
from datetime import date, time, datetime, timedelta
|
||||
from streamlit_calendar import calendar
|
||||
|
||||
# =========================
|
||||
# CONFIG
|
||||
# =========================
|
||||
st.set_page_config(page_title="Agenda Compartilhada", layout="wide")
|
||||
|
||||
DB_CONFIG = {
|
||||
"host": st.secrets["db"]["host"],
|
||||
"user": st.secrets["db"]["user"],
|
||||
"password": st.secrets["db"]["password"],
|
||||
"database": st.secrets["db"]["database"],
|
||||
"port": st.secrets["db"]["port"]
|
||||
}
|
||||
|
||||
# =========================
|
||||
# UTILS
|
||||
# =========================
|
||||
def timedelta_to_time(td):
|
||||
seconds = int(td.total_seconds())
|
||||
return time(seconds // 3600, (seconds % 3600) // 60)
|
||||
|
||||
# =========================
|
||||
# DATABASE
|
||||
# =========================
|
||||
def get_connection():
|
||||
return mysql.connector.connect(**DB_CONFIG)
|
||||
|
||||
# =========================
|
||||
# AUTH
|
||||
# =========================
|
||||
def hash_password(password):
|
||||
return hashlib.sha256(password.encode()).hexdigest()
|
||||
|
||||
def authenticate(username, password):
|
||||
conn = get_connection()
|
||||
cur = conn.cursor(dictionary=True)
|
||||
cur.execute(
|
||||
"SELECT id FROM users WHERE username=%s AND password_hash=%s",
|
||||
(username, hash_password(password))
|
||||
)
|
||||
user = cur.fetchone()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return user is not None
|
||||
|
||||
# =========================
|
||||
# EVENTS
|
||||
# =========================
|
||||
def get_events():
|
||||
conn = get_connection()
|
||||
cur = conn.cursor(dictionary=True)
|
||||
cur.execute("SELECT * FROM events")
|
||||
rows = cur.fetchall()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
def add_event(data):
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
INSERT INTO events
|
||||
(event_date,start_time,end_time,title,description,chat_id,name,created_by)
|
||||
VALUES (%s,%s,%s,%s,%s,%s,%s,%s)
|
||||
""", tuple(data.values()))
|
||||
conn.commit()
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
def update_event(event_id, data):
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
UPDATE events SET
|
||||
event_date=%s,start_time=%s,end_time=%s,
|
||||
title=%s,description=%s,chat_id=%s,name=%s
|
||||
WHERE id=%s
|
||||
""", (*data.values(), event_id))
|
||||
conn.commit()
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
def delete_event(event_id):
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
cur.execute("DELETE FROM events WHERE id=%s", (event_id,))
|
||||
conn.commit()
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
# =========================
|
||||
# SESSION
|
||||
# =========================
|
||||
st.session_state.setdefault("logged_in", False)
|
||||
st.session_state.setdefault("mode", "idle")
|
||||
st.session_state.setdefault("selected_event", None)
|
||||
st.session_state.setdefault("selected_date", None)
|
||||
|
||||
# =========================
|
||||
# LOGIN
|
||||
# =========================
|
||||
if not st.session_state.logged_in:
|
||||
st.title("🔐 Login")
|
||||
u = st.text_input("Usuário")
|
||||
p = st.text_input("Senha", type="password")
|
||||
if st.button("Entrar"):
|
||||
if authenticate(u, p):
|
||||
st.session_state.logged_in = True
|
||||
st.session_state.username = u
|
||||
st.rerun()
|
||||
else:
|
||||
st.error("Credenciais inválidas")
|
||||
st.stop()
|
||||
|
||||
# =========================
|
||||
# APP
|
||||
# =========================
|
||||
st.title("📅 Agenda Compartilhada")
|
||||
|
||||
col_cal, col_form = st.columns([2, 1])
|
||||
|
||||
events_db = get_events()
|
||||
|
||||
calendar_events = []
|
||||
for ev in events_db:
|
||||
calendar_events.append({
|
||||
"id": ev["id"],
|
||||
"title": ev["title"],
|
||||
"start": datetime.combine(
|
||||
ev["event_date"],
|
||||
timedelta_to_time(ev["start_time"])
|
||||
).isoformat(),
|
||||
"end": datetime.combine(
|
||||
ev["event_date"],
|
||||
timedelta_to_time(ev["end_time"])
|
||||
).isoformat(),
|
||||
})
|
||||
|
||||
# =========================
|
||||
# CALENDAR (LEFT)
|
||||
# =========================
|
||||
with col_cal:
|
||||
cal = calendar(
|
||||
events=calendar_events,
|
||||
options={"initialView": "dayGridMonth", "selectable": True},
|
||||
custom_css=".fc { font-size: 0.85rem; }"
|
||||
)
|
||||
|
||||
# =========================
|
||||
# CALENDAR INTERACTIONS
|
||||
# =========================
|
||||
if cal.get("dateClick"):
|
||||
st.session_state.mode = "new"
|
||||
st.session_state.selected_date = datetime.fromisoformat(
|
||||
cal["dateClick"]["date"]
|
||||
).date()
|
||||
|
||||
if cal.get("eventClick"):
|
||||
st.session_state.mode = "edit"
|
||||
st.session_state.selected_event = next(
|
||||
e for e in events_db if e["id"] == int(cal["eventClick"]["event"]["id"])
|
||||
)
|
||||
|
||||
# =========================
|
||||
# SIDE PANEL (RIGHT)
|
||||
# =========================
|
||||
with col_form:
|
||||
st.subheader("🛠 Ações")
|
||||
|
||||
# -------------------------
|
||||
# NEW EVENT
|
||||
# -------------------------
|
||||
if st.session_state.mode == "new":
|
||||
st.info(f"Novo evento em {st.session_state.selected_date}")
|
||||
|
||||
with st.form("new_event"):
|
||||
d = st.date_input("Data", st.session_state.selected_date)
|
||||
s = st.time_input("Início", time(9, 0))
|
||||
e = st.time_input("Fim", time(10, 0))
|
||||
t = st.text_input("Título")
|
||||
desc = st.text_area("Descrição")
|
||||
chat = st.text_input("Chat ID")
|
||||
name = st.text_input("Nome")
|
||||
|
||||
if st.form_submit_button("Salvar"):
|
||||
add_event({
|
||||
"event_date": d,
|
||||
"start_time": s,
|
||||
"end_time": e,
|
||||
"title": t,
|
||||
"description": desc,
|
||||
"chat_id": chat,
|
||||
"name": name,
|
||||
"created_by": st.session_state.username
|
||||
})
|
||||
st.session_state.mode = "idle"
|
||||
st.rerun()
|
||||
|
||||
# -------------------------
|
||||
# EDIT EVENT
|
||||
# -------------------------
|
||||
elif st.session_state.mode == "edit":
|
||||
ev = st.session_state.selected_event
|
||||
st.info(f"Editando: {ev['title']}")
|
||||
|
||||
with st.form("edit_event"):
|
||||
d = st.date_input("Data", ev["event_date"])
|
||||
s = st.time_input("Início", timedelta_to_time(ev["start_time"]))
|
||||
e = st.time_input("Fim", timedelta_to_time(ev["end_time"]))
|
||||
t = st.text_input("Título", ev["title"])
|
||||
desc = st.text_area("Descrição", ev["description"])
|
||||
chat = st.text_input("Chat ID", ev["chat_id"])
|
||||
name = st.text_input("Nome", ev["name"])
|
||||
|
||||
if st.form_submit_button("Atualizar"):
|
||||
update_event(ev["id"], {
|
||||
"event_date": d,
|
||||
"start_time": s,
|
||||
"end_time": e,
|
||||
"title": t,
|
||||
"description": desc,
|
||||
"chat_id": chat,
|
||||
"name": name
|
||||
})
|
||||
st.session_state.mode = "idle"
|
||||
st.rerun()
|
||||
|
||||
if st.form_submit_button("Excluir"):
|
||||
delete_event(ev["id"])
|
||||
st.session_state.mode = "idle"
|
||||
st.rerun()
|
||||
|
||||
else:
|
||||
st.write("⬅️ Clique em um dia ou evento no calendário")
|
||||
|
||||
88
README.md
88
README.md
@@ -0,0 +1,88 @@
|
||||
# Sistema de Agendamento Multi-Canal
|
||||
|
||||
Este projeto é um sistema completo de agendamento que permite aos clientes marcarem horários de forma automatizada via WhatsApp (integrações Twilio e UltraMsg) e Telegram. O sistema inclui também um painel administrativo web para gestão da agenda e um serviço de lembretes automáticos.
|
||||
|
||||
## 🚀 Funcionalidades
|
||||
|
||||
* **Agendamento via Chatbot:** Fluxo automatizado onde o cliente escolhe o período (Manhã/Tarde/Noite) e o horário disponível.
|
||||
* **Múltiplos Canais de Atendimento:**
|
||||
* **WhatsApp:** Suporte via API oficial (Twilio) e não-oficial (UltraMsg).
|
||||
* **Telegram:** Bot nativo para agendamentos.
|
||||
* **Painel Administrativo (Dashboard):** Interface visual desenvolvida em Streamlit para que o prestador de serviço possa:
|
||||
* Visualizar agendamentos em formato de calendário.
|
||||
* Criar, editar e excluir eventos manualmente.
|
||||
* **Lembretes Automáticos (`Lembrator`):** Serviço em segundo plano que notifica os clientes sobre seus horários com antecedência de 24h, 12h e 3h.
|
||||
* **Banco de Dados:** Persistência de dados utilizando MySQL (com suporte legado/local para SQLite).
|
||||
|
||||
## 📂 Estrutura de Arquivos
|
||||
|
||||
### Principais
|
||||
* **`Main_Receiver-Twilio01.py`**: Servidor Flask que atua como Webhook para o Twilio (WhatsApp).
|
||||
* **`Main_Receiver-Whatsapp.py`**: Servidor Flask para integração com a API UltraMsg (WhatsApp).
|
||||
* **`Main_Receiver_Telegram.py`**: Bot do Telegram que utiliza a biblioteca `python-telegram-bot`.
|
||||
* **`Painel_Prestador_Mysql.py`**: Aplicação Streamlit para gestão da agenda pelo prestador.
|
||||
* **`Lembrator.py`**: Script de automação para envio de lembretes.
|
||||
|
||||
### Banco de Dados
|
||||
* **`BD_manager_Mysql.py`**: Gerenciador de conexão e queries para MySQL (usado em produção).
|
||||
* **`BD_manager.py`**: Versão SQLite (uso local/teste).
|
||||
|
||||
## 🛠️ Instalação e Configuração
|
||||
|
||||
1. **Instale as dependências:**
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
2. **Configuração de Ambiente:**
|
||||
Crie um arquivo `.env` na raiz do projeto para armazenar suas credenciais sensíveis:
|
||||
```env
|
||||
# Twilio
|
||||
TWILIO_ACCOUNT_SID=seu_sid
|
||||
TWILIO_AUTH_TOKEN=seu_token
|
||||
TWILIO_WHATSAPP_NUMBER=whatsapp:+14155238886
|
||||
|
||||
# Banco de Dados (se não usar st.secrets)
|
||||
DB_HOST=seu_host
|
||||
DB_USER=seu_user
|
||||
DB_PASSWORD=sua_senha
|
||||
DB_NAME=agenda
|
||||
DB_PORT=porta
|
||||
```
|
||||
*Nota: O painel Streamlit utiliza `st.secrets` para configuração do banco.*
|
||||
|
||||
3. **Banco de Dados:**
|
||||
Certifique-se de que as tabelas `events`, `acompanhamento` e `agenda` estejam criadas no seu banco de dados MySQL conforme esperado pelos scripts `BD_manager_Mysql.py`.
|
||||
|
||||
## ▶️ Como Executar
|
||||
|
||||
### 1. Iniciar os Chatbots
|
||||
Para ativar o atendimento automático, execute o script correspondente à plataforma desejada:
|
||||
|
||||
* **WhatsApp (Twilio):**
|
||||
```bash
|
||||
python Main_Receiver-Twilio01.py
|
||||
```
|
||||
* **Telegram:**
|
||||
```bash
|
||||
python Main_Receiver_Telegram.py
|
||||
```
|
||||
|
||||
### 2. Painel Administrativo
|
||||
Para abrir a interface de gestão:
|
||||
```bash
|
||||
streamlit run Painel_Prestador_Mysql.py
|
||||
```
|
||||
|
||||
### 3. Serviço de Lembretes
|
||||
Para iniciar o monitoramento e envio de avisos:
|
||||
```bash
|
||||
python Lembrator.py
|
||||
```
|
||||
|
||||
## 📦 Dependências Principais
|
||||
* `Flask`: Servidor web para os webhooks.
|
||||
* `mysql-connector-python`: Driver de conexão com o MySQL.
|
||||
* `streamlit` & `streamlit-calendar`: Interface do painel administrativo.
|
||||
* `twilio`: SDK para envio de mensagens via Twilio.
|
||||
* `python-telegram-bot`: SDK para o bot do Telegram.
|
||||
|
||||
BIN
requirements.txt
Normal file
BIN
requirements.txt
Normal file
Binary file not shown.
Reference in New Issue
Block a user