add files

This commit is contained in:
geezo 2025-09-15 19:44:06 +00:00
commit 556fb8bcf8
4 changed files with 245 additions and 0 deletions

204
app.py Normal file
View File

@ -0,0 +1,204 @@
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request
from fastapi.responses import HTMLResponse
import asyncio, json
from typing import Set
app = FastAPI()
class ConnectionManager:
def __init__(self):
self.active: Set[WebSocket] = set()
self._lock = asyncio.Lock()
async def connect(self, ws: WebSocket):
await ws.accept()
async with self._lock:
self.active.add(ws)
async def disconnect(self, ws: WebSocket):
async with self._lock:
self.active.discard(ws)
async def broadcast(self, message: str):
data = json.dumps({"text": message})
async with self._lock:
dead = []
for ws in self.active:
try:
await ws.send_text(data)
except Exception:
dead.append(ws)
for ws in dead:
self.active.discard(ws)
manager = ConnectionManager()
@app.get("/", response_class=HTMLResponse)
async def index():
return """
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Messages</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://unpkg.com/hack@0.8.1/dist/hack.css">
<link rel="stylesheet" href="https://unpkg.com/hack@0.8.1/dist/dark.css">
<style>
#log {
white-space: pre-wrap;
font-size: 1rem;
height: 70vh;
overflow-y: auto;
border: 1px solid #2a2a35;
border-radius: 14px;
padding: 1rem 1.25rem;
background: rgba(20, 20, 26, 0.7);
backdrop-filter: blur(6px);
scroll-behavior: smooth;
}
.line {
display: flex;
align-items: flex-start;
margin: 0.25rem 0;
line-height: 1.4;
animation: lineIn 200ms ease-out;
}
@keyframes lineIn {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
.icon {
flex: 0 0 1.5rem;
text-align: center;
opacity: 0.7;
margin-right: 0.5rem;
}
.text {
flex: 1;
}
.typing::after {
content: "";
display: inline-block;
margin-left: 2px;
animation: blink 1s steps(1, end) infinite;
color: rgba(255,255,255,0.8);
}
@keyframes blink {
0%, 49% { opacity: 1; }
50%, 100% { opacity: 0; }
}
.char {
opacity: 0;
transform: translateY(4px);
transition: opacity 140ms ease-out, transform 140ms ease-out;
}
.char.in {
opacity: 1;
transform: translateY(0);
}
</style>
</head>
<body class="hack dark">
<div class="container">
<h2>Messages</h2>
<div id="log"></div>
</div>
<script>
const log = document.getElementById('log');
const proto = location.protocol === 'https:' ? 'wss' : 'ws';
const ws = new WebSocket(proto + '://' + location.host + '/ws');
const nearBottom = () => (log.scrollHeight - log.scrollTop - log.clientHeight) < 40;
const scrollToBottom = () => { log.scrollTop = log.scrollHeight; };
function typeText(text) {
const line = document.createElement("div");
line.className = "line";
const icon = document.createElement("div");
icon.className = "icon";
icon.textContent = ""; // 🔑 change this to 💬 👉 etc.
const textDiv = document.createElement("div");
textDiv.className = "text typing";
line.appendChild(icon);
line.appendChild(textDiv);
log.appendChild(line);
let i = 0;
const interval = setInterval(() => {
if (i >= text.length) {
clearInterval(interval);
textDiv.classList.remove("typing");
if (nearBottom()) scrollToBottom();
return;
}
const span = document.createElement("span");
span.className = "char";
span.textContent = text[i++];
textDiv.appendChild(span);
requestAnimationFrame(() => span.classList.add("in"));
if (nearBottom()) scrollToBottom();
}, 50);
}
ws.onmessage = e => {
try {
const data = JSON.parse(e.data);
typeText(data.text || "");
} catch {
typeText("");
}
};
ws.onclose = () => {
const line = document.createElement("div");
line.className = "line";
const icon = document.createElement("div");
icon.className = "icon";
icon.textContent = "⚠️";
const textDiv = document.createElement("div");
textDiv.className = "text";
textDiv.textContent = "Disconnected";
line.appendChild(icon);
line.appendChild(textDiv);
log.appendChild(line);
scrollToBottom();
};
</script>
</body>
</html>
"""
@app.post("/send")
async def send(request: Request):
text = ""
try:
payload = await request.json()
if isinstance(payload, dict):
text = payload.get("text", "")
except Exception:
try:
form = await request.form()
text = form.get("text", "")
except Exception:
pass
await manager.broadcast(text or "")
return {"message": text or ""}
@app.websocket("/ws")
async def ws_endpoint(ws: WebSocket):
await manager.connect(ws)
try:
while True:
await ws.receive_text()
except WebSocketDisconnect:
await manager.disconnect(ws)

20
docker-compose.yml Normal file
View File

@ -0,0 +1,20 @@
version: "3.8"
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: always
ports:
- "5678:5678"
environment:
- GENERIC_TIMEZONE=America/New_York # adjust to your timezone
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=admin123
- N8N_SECURE_COOKIE=false
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:

20
dockerfile Normal file
View File

@ -0,0 +1,20 @@
# Minimal, production-ready image
FROM python:3.12-slim
# Prevent Python from writing .pyc files; ensure unbuffered logs
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
# Install only what we need
RUN pip install --no-cache-dir fastapi "uvicorn[standard]"
# Copy the application
COPY app.py /app/app.py
# Expose the app port
EXPOSE 8000
# Start the server
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

1
reddit.py Normal file
View File

@ -0,0 +1 @@
import