🚀 Add feature: Frontend app working stub

🚀 Add feature: Ruff linting
🚀 Add feature: Logging
This commit is contained in:
François Pelletier 2025-05-11 21:51:32 -04:00
parent 41299d4bf1
commit 0f1a07da49
12 changed files with 234 additions and 22 deletions

15
backend/app/config.py Normal file
View file

@ -0,0 +1,15 @@
import logging
from app.models import AvailableSource, AvailableSourcesResponse
logger = logging.getLogger("base_logger")
available_sources = AvailableSourcesResponse(
sources=[
AvailableSource(
display_name="LinkedIn Shares",
name="linkedin_shares",
format="csv",
),
],
)

View file

@ -1,4 +1,4 @@
from typing import Dict
from typing import Dict, List
from pydantic import BaseModel
@ -7,6 +7,7 @@ class AnalysisRequest(BaseModel):
analysis_type: str
filters: Dict
class AnalysisResponse(BaseModel):
result: str
@ -41,8 +42,19 @@ class GenerateResponse(BaseModel):
class ImportRequest(BaseModel):
type: str
data: str
class ImportResponse(BaseModel):
status: str
class AvailableSource(BaseModel):
display_name: str
name: str
format: str
class AvailableSourcesResponse(BaseModel):
sources: List[AvailableSource]

View file

@ -1,14 +1,20 @@
from app.config import logger
from app.models import AnalysisRequest, AnalysisResponse
from fastapi import APIRouter
from app.models import AnalysisResponse, AnalysisRequest
analysis_router = APIRouter(prefix="/analysis", tags=["Analysis"])
@analysis_router.post("/", response_model=AnalysisResponse)
def analysis_data(request: AnalysisRequest):
"""
Analysis imported data (e.g., sentiment, keywords, or patterns).
Analyse imported data (e.g., sentiment, keywords, or patterns).
"""
logger.info(
f"Analyse imported data "
f"on {request.analysis_type} "
f"with filters {request.filters}"
)
# Placeholder for analysis logic
analysis = ...
return {"analysis": analysis}

View file

@ -1,18 +1,20 @@
from app.config import logger
from app.models import ConversionRequest, ConversionResponse
from fastapi import APIRouter
from app.models import ConversionResponse, ConversionRequest
convert_router = APIRouter(prefix="/convert", tags=["Convert"])
@convert_router.post("/", response_model=ConversionResponse)
def convert_data(request: ConversionRequest):
"""
Convert data from one format to another (e.g., JSON to CSV, text to XML).
Convert data from a source to normalized JSON
"""
logger.info(f"Converting {request.source_type} data to normalized JSON")
# Example conversion logic (replace with actual implementation)
converted_data = ...
return {
"converted_data": converted_data,
"status": "success"
"status": "success",
}

View file

@ -1,13 +1,15 @@
from app.config import logger
from app.models import ExportRequest, ExportResponse
from fastapi import APIRouter
from app.models import ExportRequest, ExportResponse
export_router = APIRouter(prefix="/export", tags=["Export"])
@export_router.post("/", response_model=ExportResponse)
def export_data(request: ExportRequest):
"""
Export analysed data (e.g., as JSON, CSV, or PDF).
"""
logger.info(f"Exporting data as {request.format}")
exported_data_url = ...
return {"url": exported_data_url}

View file

@ -1,7 +1,7 @@
from app.config import logger
from app.models import GenerateRequest, GenerateResponse
from fastapi import APIRouter
from app.models import GenerateResponse, GenerateRequest
generate_router = APIRouter(prefix="/generate", tags=["Generate"])
@ -11,5 +11,5 @@ def generate_content(request: GenerateRequest):
Generate new content (e.g., text, images, or summaries).
"""
# Placeholder for generation logic (e.g., LLM, AI model)
response = ...
return response
logger.info(f"Generating content for request: {request.prompt}")
return ...

View file

@ -1,7 +1,7 @@
from app.config import available_sources, logger
from app.models import AvailableSourcesResponse, ImportRequest, ImportResponse
from fastapi import APIRouter
from app.models import ImportRequest, ImportResponse
import_router = APIRouter(prefix="/import", tags=["Import"])
@ -10,5 +10,17 @@ def import_data(request: ImportRequest):
"""
Import data (e.g., text, files, or structured data).
"""
response = ...
return response
logger.info(f"Receiver importation request: {request.type}")
return ...
@import_router.get(
"/available_sources", response_model=AvailableSourcesResponse
)
def get_available_sources():
"""
Get available sources from database
:return: Available sources in an AvailableSourcesResponse object
"""
logger.info("Get available sources from database")
return available_sources

View file

@ -1,10 +1,9 @@
from fastapi import FastAPI
from app.routers.convert_router import convert_router
from app.routers.import_router import import_router
from app.routers.analysis_router import analysis_router
from app.routers.convert_router import convert_router
from app.routers.export_router import export_router
from app.routers.generate_router import generate_router
from app.routers.import_router import import_router
from fastapi import FastAPI
app = FastAPI(title="Retro API", description="Retro content management system")

62
frontend/app.py Normal file
View file

@ -0,0 +1,62 @@
import os
import dotenv
import requests
import streamlit as st
dotenv.load_dotenv()
# Set the backend API base URL
BACKEND_URL = os.environ.get("BACKEND_URL")
# Database variables
available_sources = requests.get(
f"{BACKEND_URL}/import/available_sources"
).json()
# Application tabs
tabs = st.tabs(["Conversion", "Analysis", "Data", "Settings", "Dashboard"])
# Application core
with tabs[0]:
st.header("Conversion de source")
with st.form("conversion_form"):
input_file = st.file_uploader("Télécharge un fichier à convertir")
input_text = st.text_area("Saisis du texte à convertir")
source_type = st.selectbox(
label="Sélectionne la source",
options=[
source.get("name")
for source in available_sources.get("sources")
],
format_func=lambda x: {
source.get("name"): source.get("display_name")
for source in available_sources.get("sources")
}.get(x),
)
if input_text:
source_data = input_text
elif input_file:
source_data = input_file
else:
st.error("Tu dois fournir un fichier ou du texte")
submitted = st.form_submit_button("Convertir")
if submitted:
response = requests.post(
f"{BACKEND_URL}/convert",
json={"source_type": source_type, "source_data": source_data},
)
st.success("Conversion Result:")
st.write(response.json())
with tabs[1]:
st.header("Importer des données")
with tabs[2]:
st.header("Analyser des données")
with tabs[3]:
st.header("Exporter des données")
with tabs[4]:
st.header("Générer une publication")

View file

@ -1,2 +1,4 @@
streamlit
requests
python-dotenv

1
requirements.txt Normal file
View file

@ -0,0 +1 @@
ruff

99
ruff.toml Normal file
View file

@ -0,0 +1,99 @@
# This configuration file is based on PEP8 Style Guide for Python
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".ipynb_checkpoints",
".mypy_cache",
".nox",
".pants.d",
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"site-packages",
"venv",
]
# Same as PEP8.
line-length = 79
indent-width = 4
[lint]
preview = true
select = ["F", # Pyflakes
"E", # pycodestyle
"I", # isort
"N", # pep8-naming
"FBT", # flake8-boolean-trap
"B", # flake8-bugbear
"A", # flake8-builtins
"COM", # flake8-commas
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"EM", # flake8-errmsg
"EXE", # flake8-executable
"ISC", # flake8-implicit-str-concat
"ICN", # flake8-import-conventions
"LOG", # flake8-logging
"G", # flake8-logging-format
"PIE", # flake8-pie
"PYI", # flake8-pyi
"Q", # flake8-quotes
"RSE", # flake8-raise
"RET", # flake8-return
"SLOT", # flake8-slots
"SIM", # flake8-simplify
"TID", # flake8-tidy-imports
"TCH", # flake8-type-checking
"ARG", # flake8-unused-arguments
"PD", # pandas-vet
"TRY", # tryceratops
"PERF", # Perflint
"RUF"] # Ruff-specific rules
ignore = [
"COM812"
]
# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
[format]
line-ending = "auto" # Automatically detect the appropriate line ending.
# quote-style = "double" # Don't work when is flake8-quotes (Q) activated | Use double quotes for strings.
indent-style = "space" # Indent with spaces, rather than tabs.
skip-magic-trailing-comma = false # Respect magic trailing commas.
# Enable auto-formatting of code examples in docstrings. Markdown,
# reStructuredText code/literal blocks and doctests are all supported.
#
# This is currently disabled by default, but it is planned for this
# to be opt-out in the future.
docstring-code-format = false
# Set the line length limit used when formatting code snippets in
# docstrings.
#
# This only has an effect when the `docstring-code-format` setting is
# enabled.
docstring-code-line-length = "dynamic"