Feat: adds front and infra
This commit is contained in:
37
front/Dockerfile
Normal file
37
front/Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
||||
# Use uma imagem base Python oficial.
|
||||
# Escolha uma versão que seja compatível com suas dependências.
|
||||
FROM python:3.12-slim
|
||||
|
||||
# Copia os arquivos de requisitos primeiro para aproveitar o cache do Docker
|
||||
COPY requirements.txt ./requirements.txt
|
||||
|
||||
# Instala as dependências do backend
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copia o restante dos diretórios e arquivos da aplicação
|
||||
|
||||
COPY ./ ./
|
||||
|
||||
# Garante que o script de inicialização seja executável
|
||||
RUN chmod +x ./entrypoint.sh
|
||||
|
||||
# Cria os diretórios que a API FastAPI pode precisar (se eles não existirem)
|
||||
# Estes diretórios serão usados para persistência se volumes forem montados.
|
||||
#RUN mkdir -p /app/faiss_index_store && \
|
||||
# mkdir -p /app/uploaded_pdfs
|
||||
|
||||
# Expõe as portas que os aplicativos usarão
|
||||
# Porta 8000 para a API FastAPI
|
||||
EXPOSE 8000
|
||||
# Porta 8501 para o aplicativo Streamlit
|
||||
EXPOSE 8501
|
||||
|
||||
# Define a variável de ambiente GROQ_API_KEY.
|
||||
# É ALTAMENTE RECOMENDADO passar esta variável em tempo de execução
|
||||
# em vez de embuti-la aqui por questões de segurança.
|
||||
# Exemplo: docker run -e GROQ_API_KEY="sua_chave_aqui" ...
|
||||
# ENV GROQ_API_KEY="SUA_CHAVE_GROQ_AQUI_SE_NECESSARIO_MAS_NAO_RECOMENDADO_EMBUTIR"
|
||||
|
||||
# Comando para executar quando o contêiner iniciar
|
||||
# Executa o script start.sh que gerencia os dois processos
|
||||
CMD ["./entrypoint.sh"]
|
||||
BIN
front/app/__pycache__/st_auth.cpython-312.pyc
Normal file
BIN
front/app/__pycache__/st_auth.cpython-312.pyc
Normal file
Binary file not shown.
49
front/app/front.py
Normal file
49
front/app/front.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import streamlit as st
|
||||
from typing import Set
|
||||
import requests
|
||||
import json
|
||||
import yaml
|
||||
import st_auth
|
||||
import boto3
|
||||
|
||||
authenticator=st_auth.get_authenticator()
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
st_auth.st_authenticate(authenticator)
|
||||
st.header("Chatbot Editais")
|
||||
url="https://dcrwpxp8lj-vpce-08d695f6315d510eb.execute-api.us-east-1.amazonaws.com/dev"
|
||||
payload=[]
|
||||
message_history=[]
|
||||
if "user_prompt_history" not in st.session_state:
|
||||
st.session_state["user_prompt_history"]=[]
|
||||
if "chat_answer_history" not in st.session_state:
|
||||
st.session_state["chat_answer_history"]=[]
|
||||
if "chat_history" not in st.session_state:
|
||||
st.session_state["chat_history"] = []
|
||||
prompt=st.text_input("Prompt",placeholder="Enter your prompt here..")
|
||||
def create_sources_string(source_urls: Set[str])->str:
|
||||
if not source_urls:
|
||||
return ""
|
||||
source_list=list(source_urls)
|
||||
source_list.sort()
|
||||
sources_string="source:\n"
|
||||
for i, source in enumerate(source_list):
|
||||
sources_string+=f"{i+1}, {source}\n"
|
||||
return sources_string
|
||||
if prompt:
|
||||
with st.spinner("Generating response.."):
|
||||
payload=st.session_state["chat_history"]+[{"role":"user","content":prompt}]
|
||||
content={"message":payload}
|
||||
headers={"Content-type":"application/json","x-api-key":json.loads(st_auth.get_secret())['api-gateway-api-key']}
|
||||
generated_response=json.loads(requests.post(url,json=content,headers=headers).text)['json']
|
||||
#generated_response=[{"role":"user","content":prompt}]
|
||||
# sources= set([doc.metadata["source"] for doc in generated_response['context']])
|
||||
#formatted_response=f"{generated_response['answer']} \n\n {create_sources_string(sources)}"
|
||||
formatted_response=generated_response
|
||||
st.session_state["user_prompt_history"].append(prompt)
|
||||
st.session_state["chat_answer_history"].append(formatted_response)
|
||||
st.session_state["chat_history"]=st.session_state["chat_history"]+[{"role":"user","content":prompt}]
|
||||
if st.session_state["chat_answer_history"]:
|
||||
for generated_response, user_query in zip(st.session_state["chat_answer_history"],st.session_state["user_prompt_history"]):
|
||||
st.chat_message("user").write(user_query)
|
||||
st.chat_message("assistant").write(generated_response)
|
||||
102
front/app/st_auth.py
Normal file
102
front/app/st_auth.py
Normal file
@@ -0,0 +1,102 @@
|
||||
import streamlit_authenticator as stauth
|
||||
import yaml
|
||||
from yaml.loader import SafeLoader
|
||||
import streamlit as st
|
||||
import boto3
|
||||
from botocore.exceptions import ClientError
|
||||
def get_authenticator():
|
||||
# with open('.streamlit/users.yaml') as file:
|
||||
# cred_config = yaml.load(file, Loader=SafeLoader)
|
||||
|
||||
file_content = read_text_file_from_s3('chatbot-editais-auth', 'config.yaml')
|
||||
# Parse the YAML content safely
|
||||
cred_config = yaml.safe_load(file_content)
|
||||
|
||||
# Pre-hashing all plain text passwords once
|
||||
# hash_credentials = stauth.Hasher.hash_passwords(config['credentials'])
|
||||
|
||||
authenticator = stauth.Authenticate(
|
||||
cred_config['credentials'],
|
||||
cred_config['cookie']['name'],
|
||||
cred_config['cookie']['key'],
|
||||
cred_config['cookie']['expiry_days']
|
||||
)
|
||||
return authenticator
|
||||
|
||||
def st_authenticate(authenticator: stauth.Authenticate):
|
||||
# authenticator = get_authenticator()
|
||||
try:
|
||||
authenticator.login(
|
||||
location='sidebar',
|
||||
fields=dict(Username="Usuário",
|
||||
Password="Senha")
|
||||
)
|
||||
except Exception as e:
|
||||
st.error(e)
|
||||
authenticator.cookie_controller.delete_cookie()
|
||||
st.warning('Caso o erro persistir, tente recarregar a página.')
|
||||
st.stop()
|
||||
|
||||
if st.session_state['authentication_status']:
|
||||
with st.sidebar:
|
||||
st.write(f'Usuário: {st.session_state["name"]}')
|
||||
authenticator.logout()
|
||||
elif st.session_state['authentication_status'] is False:
|
||||
with st.sidebar:
|
||||
st.error('Usuário/senha incorreto')
|
||||
st.stop()
|
||||
elif st.session_state['authentication_status'] is None:
|
||||
st.warning('Por favor, informe o seu usuário e senha no painel lateral')
|
||||
st.stop()
|
||||
def read_text_file_from_s3(bucket, key):
|
||||
"""
|
||||
Read a YAML file from an S3 bucket using provided AWS credentials.
|
||||
|
||||
Args:
|
||||
bucket (str): Name of the S3 bucket
|
||||
key (str): Path to the YAML file in the bucket
|
||||
aws_access_key_id (str): AWS Access Key ID
|
||||
aws_secret_access_key (str): AWS Secret Access Key
|
||||
|
||||
Returns:
|
||||
dict: Parsed YAML content
|
||||
"""
|
||||
try:
|
||||
# Create an S3 client
|
||||
s3_client = boto3.client('s3')
|
||||
|
||||
# Download the file from S3
|
||||
response = s3_client.get_object(Bucket=bucket, Key=key)
|
||||
|
||||
# Read the file content
|
||||
file_content = response['Body'].read().decode('utf-8')
|
||||
|
||||
return file_content
|
||||
|
||||
except Exception as e:
|
||||
st.error(f"Error reading file from S3: {e}")
|
||||
return None
|
||||
|
||||
def get_secret():
|
||||
|
||||
secret_name = "dev/chatboteditais/apigateway/apikey"
|
||||
region_name = "us-east-1"
|
||||
|
||||
# Create a Secrets Manager client
|
||||
session = boto3.session.Session()
|
||||
client = session.client(
|
||||
service_name='secretsmanager',
|
||||
region_name=region_name
|
||||
)
|
||||
|
||||
try:
|
||||
get_secret_value_response = client.get_secret_value(
|
||||
SecretId=secret_name
|
||||
)
|
||||
except ClientError as e:
|
||||
# For a list of exceptions thrown, see
|
||||
# https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
|
||||
raise e
|
||||
|
||||
secret = get_secret_value_response['SecretString']
|
||||
return secret
|
||||
23
front/entrypoint.sh
Normal file
23
front/entrypoint.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define o diretório base da aplicação dentro do contêiner
|
||||
APP_DIR="/app"
|
||||
|
||||
# Navega para o diretório do backend e inicia a API FastAPI em segundo plano
|
||||
#echo "Iniciando API FastAPI na porta 8000..."
|
||||
#python app/backend/main.py &
|
||||
|
||||
# Aguarda alguns segundos para garantir que a API tenha tempo de iniciar
|
||||
# Isso é opcional, mas pode ajudar a evitar problemas de conexão imediata do frontend
|
||||
#echo "Aguardando a API iniciar..."
|
||||
#sleep 10 # Ajuste o tempo conforme necessário
|
||||
|
||||
# Navega para o diretório do frontend e inicia o aplicativo Streamlit em primeiro plano
|
||||
echo "Iniciando aplicativo Streamlit na porta 8501..."
|
||||
# --server.headless=true é importante para rodar Streamlit em ambientes sem GUI (como Docker)
|
||||
# --server.address=0.0.0.0 permite que o Streamlit seja acessado de fora do contêiner
|
||||
# --server.enableCORS=false pode ser necessário dependendo da configuração, mas geralmente não para localhost
|
||||
streamlit run app/front.py --server.port 8501 --server.address 0.0.0.0 --server.headless true
|
||||
|
||||
# O comando 'streamlit run' manterá o contêiner em execução.
|
||||
# Se o Streamlit parar por algum motivo, o script e, consequentemente, o contêiner, terminarão.
|
||||
1633
front/poetry.lock
generated
Normal file
1633
front/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
front/pyproject.toml
Normal file
17
front/pyproject.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[tool.poetry]
|
||||
name = "front"
|
||||
version = "0.1.0"
|
||||
description = "Front para o ChatBot editais do IFSP"
|
||||
authors = ["Lucas DNX"]
|
||||
readme = "README.md"
|
||||
package-mode = false
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
streamlit = "^1.49.1"
|
||||
streamlit-authenticator = "^0.4.2"
|
||||
boto3 = "^1.40.37"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
5
front/requirements.txt
Normal file
5
front/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
streamlit
|
||||
requests
|
||||
pyyaml
|
||||
boto3
|
||||
streamlit-authenticator
|
||||
Reference in New Issue
Block a user