latexgrambot: inline LaTeX bot for Telegram in Go
Renders LaTeX expressions into PNG pictures, PDF documents and native Telegram rich text messages, entirely locally with TeX Live and poppler. - Chat mode with /image, /pdf, /rich plus per-user preamble and DPI - Inline mode delivering picture, PDF and rich text results - Broad default package set preloaded into a TeX format at image build - MongoDB persistence: settings, users, groups, render statistics - Private S3-compatible bucket with short-lived presigned URLs - OpenTelemetry traces over OTLP - Kubernetes manifests and Argo CD application, Docker Compose, GitHub Actions CI, BSD 3-Clause license
This commit is contained in:
48
k8s/configmap.yaml
Normal file
48
k8s/configmap.yaml
Normal file
@@ -0,0 +1,48 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: latexgrambot
|
||||
namespace: latexgrambot
|
||||
labels:
|
||||
app.kubernetes.io/name: latexgrambot
|
||||
data:
|
||||
HEALTH_ADDR: ":8080"
|
||||
|
||||
# MongoDB is the only hard dependency: per-chat settings, users, group
|
||||
# memberships, render statistics and the inline file-id cache live there.
|
||||
MONGODB_URI: "mongodb://mongo:27017"
|
||||
MONGODB_DATABASE: "latexgram"
|
||||
|
||||
# Private S3-compatible bucket for the inline PNG/PDF assets. Telegram
|
||||
# receives short-lived presigned GET URLs, so the public endpoint must be
|
||||
# reachable from the internet. Credentials come from the
|
||||
# latexgrambot-s3 secret. Leave all S3 values empty to disable the inline
|
||||
# picture/PDF results (rich text still works).
|
||||
S3_ENDPOINT_URL: "http://minio:9000"
|
||||
S3_REGION: "us-east-1"
|
||||
S3_BUCKET: "latexgrambot"
|
||||
S3_PREFIX: "content"
|
||||
S3_PUBLIC_ENDPOINT_URL: "https://s3.example.com"
|
||||
S3_PRESIGN_TTL: "1h"
|
||||
|
||||
# Preloaded TeX format shipped in the image: skips re-loading the default
|
||||
# package set on every render.
|
||||
LATEX_FORMAT: "latexgrambot"
|
||||
|
||||
RENDER_DPI: "600"
|
||||
RENDER_TIMEOUT: "30s"
|
||||
RENDER_MAX_CONCURRENCY: "2"
|
||||
MAX_EXPRESSION_LEN: "4000"
|
||||
MAX_PREAMBLE_LEN: "4000"
|
||||
|
||||
# Rich message replies (Bot API 10.x). Set to false for older Bot API
|
||||
# servers; chat and inline fall back to PNG/PDF only.
|
||||
RICH_TEXT_ENABLED: "true"
|
||||
# A bare source without delimiters/text commands renders as math (true)
|
||||
# or as text (false, formulas then need $...$).
|
||||
RICH_DEFAULT_MATH: "true"
|
||||
|
||||
# OpenTelemetry traces (OTLP gRPC). Leave the endpoint empty to disable.
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: ""
|
||||
OTEL_EXPORTER_OTLP_INSECURE: "true"
|
||||
OTEL_SERVICE_NAME: "latexgrambot"
|
||||
70
k8s/deployment.yaml
Normal file
70
k8s/deployment.yaml
Normal file
@@ -0,0 +1,70 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: latexgrambot
|
||||
namespace: latexgrambot
|
||||
labels:
|
||||
app.kubernetes.io/name: latexgrambot
|
||||
spec:
|
||||
# Exactly one replica: the bot long-polls Telegram (getUpdates) and
|
||||
# Telegram allows a single consumer per bot token.
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: latexgrambot
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: latexgrambot
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: latexgrambot
|
||||
# Replace with the image built by CI, e.g. your registry plus the
|
||||
# commit SHA tag.
|
||||
image: latexgrambot:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: latexgrambot
|
||||
- secretRef:
|
||||
name: latexgrambot-secrets
|
||||
- secretRef:
|
||||
name: latexgrambot-s3
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 30
|
||||
# pdflatex is CPU-bound; the memory limit has to cover a TeX Live
|
||||
# run (a few hundred MB per concurrent render).
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: "2"
|
||||
memory: 1Gi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
31
k8s/secret.example.yaml
Normal file
31
k8s/secret.example.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
# Copy to a private file, fill in the values and apply it manually:
|
||||
# kubectl apply -f latexgrambot-secrets.yaml
|
||||
#
|
||||
# Two secrets are used so the S3 credentials can be managed separately from
|
||||
# the Telegram token.
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: latexgrambot-secrets
|
||||
namespace: latexgrambot
|
||||
labels:
|
||||
app.kubernetes.io/name: latexgrambot
|
||||
type: Opaque
|
||||
stringData:
|
||||
# The token must not be long-polled by any other process (Telegram
|
||||
# delivers updates to a single consumer per token).
|
||||
TELEGRAM_BOT_TOKEN: "replace-with-bot-token"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: latexgrambot-s3
|
||||
namespace: latexgrambot
|
||||
labels:
|
||||
app.kubernetes.io/name: latexgrambot
|
||||
type: Opaque
|
||||
stringData:
|
||||
# Credentials of an S3-compatible bucket (read/write on S3_BUCKET).
|
||||
AWS_ACCESS_KEY_ID: "replace-with-s3-access-key"
|
||||
AWS_SECRET_ACCESS_KEY: "replace-with-s3-secret-key"
|
||||
15
k8s/service.yaml
Normal file
15
k8s/service.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: latexgrambot
|
||||
namespace: latexgrambot
|
||||
labels:
|
||||
app.kubernetes.io/name: latexgrambot
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: latexgrambot
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: http
|
||||
Reference in New Issue
Block a user