chore: sync prod state — LiteLLM/LLMFit integration + compose updates

- docker-compose.prod.yml: LiteLLM na rede coolify, LLMFIT_BASE_URL/API_KEY, rede coolify external
- docker/litellm-config.yaml: TIER 1 LLMFit ativo, fallback Ollama configurado
- Dockerfile: ajustes de build
- server/: novos módulos SOE, plus-sync, schemas compartilhados
This commit is contained in:
root 2026-03-17 11:28:43 -03:00
parent 9449b3614c
commit f29e61f335
11 changed files with 96 additions and 50 deletions

View File

@ -4,7 +4,7 @@ FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --ignore-scripts
RUN npm ci
COPY . .
RUN npm run build
@ -18,16 +18,19 @@ ENV NODE_ENV=production
# Deps de produção apenas
COPY package*.json ./
RUN npm ci --omit=dev --ignore-scripts
RUN npm ci --omit=dev
# Artefatos do build
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/shared ./shared
COPY --from=builder /app/migrations ./migrations
# Arquivos de runtime necessários (caminhos quebrados pelo bundler)
RUN cp /app/node_modules/connect-pg-simple/table.sql /app/dist/table.sql
EXPOSE 5000
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD wget -qO- http://localhost:5000/api/health || exit 1
CMD wget -qO- http://127.0.0.1:5000/ || exit 1
CMD ["node", "dist/index.cjs"]

View File

@ -0,0 +1,17 @@
import { createContext, useContext, ReactNode } from "react";
interface SoeMotorContextType {}
const SoeMotorContext = createContext<SoeMotorContextType>({});
export function SoeMotorProvider({ children }: { children: ReactNode }) {
return (
<SoeMotorContext.Provider value={{}}>
{children}
</SoeMotorContext.Provider>
);
}
export function useSoeMotor() {
return useContext(SoeMotorContext);
}

7
client/src/pages/SOE.tsx Normal file
View File

@ -0,0 +1,7 @@
export default function SOE() {
return (
<div className="flex items-center justify-center h-full">
<p className="text-muted-foreground">SOE em desenvolvimento</p>
</div>
);
}

View File

@ -72,12 +72,15 @@ services:
condition: service_started
networks:
- arcadia-internal
- arcadia-public
- coolify
labels:
- "traefik.enable=true"
- "traefik.docker.network=coolify"
- "traefik.http.routers.arcadia.entrypoints=https"
- "traefik.http.routers.arcadia.rule=Host(`${DOMAIN}`)"
- "traefik.http.routers.arcadia.tls=true"
- "traefik.http.routers.arcadia.tls.certresolver=letsencrypt"
- "traefik.http.services.arcadia.loadbalancer.server.port=5000"
# ── Microserviços Python ─────────────────────────────────────────────────────
contabil:
@ -153,6 +156,9 @@ services:
SERVICE_NAME: embeddings
SERVICE_PORT: 8001
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
LITELLM_BASE_URL: http://litellm:4000
LITELLM_API_KEY: ${LITELLM_API_KEY}
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
depends_on:
db:
condition: service_healthy
@ -170,12 +176,13 @@ services:
environment:
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
LITELLM_MASTER_KEY: ${LITELLM_API_KEY}
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/litellm
# Ollama: se instalado no host use http://host-gateway:11434
# Se usar container Docker, mantém http://ollama:11434
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
# LLMFit: URL do serviço de modelos fine-tuned
LLMFIT_BASE_URL: ${LLMFIT_BASE_URL:-}
LLMFIT_API_KEY: ${LLMFIT_API_KEY:-}
# Providers externos opcionais (soberania: só habilitados se configurados)
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
GROQ_API_KEY: ${GROQ_API_KEY:-}
@ -184,6 +191,7 @@ services:
condition: service_healthy
networks:
- arcadia-internal
- coolify
# ── Ollama (LLMs locais — soberania total) ────────────────────────────────────
# OPÇÃO A (padrão): Ollama como container Docker
@ -215,7 +223,7 @@ services:
- litellm
networks:
- arcadia-internal
- arcadia-public
- coolify
labels:
- "traefik.enable=true"
- "traefik.http.routers.webui.rule=Host(`ai.${DOMAIN}`)"
@ -227,8 +235,8 @@ services:
networks:
arcadia-internal:
driver: bridge
arcadia-public:
driver: bridge
coolify:
external: true
volumes:
pgdata:

View File

@ -13,35 +13,22 @@
model_list:
# ── TIER 1: LLMFit (modelos fine-tuned locais — máxima soberania) ────────────
# Descomente quando o LLMFit estiver rodando no servidor
# O LLMFit expõe API compatível com OpenAI — basta apontar a URL
#
# - model_name: arcadia-finetuned
# litellm_params:
# model: openai/arcadia-v1 # nome do modelo no LLMFit
# api_base: os.environ/LLMFIT_BASE_URL
# api_key: llmfit-internal
#
# - model_name: arcadia-embed
# litellm_params:
# model: openai/arcadia-embed-v1 # modelo de embeddings fine-tuned
# api_base: os.environ/LLMFIT_BASE_URL
# api_key: llmfit-internal
- model_name: arcadia-finetuned
litellm_params:
model: openai/llama3.2:3b
api_base: os.environ/LLMFIT_BASE_URL
api_key: os.environ/LLMFIT_API_KEY
- model_name: arcadia-embed
litellm_params:
model: openai/nomic-embed-text:latest
api_base: os.environ/LLMFIT_BASE_URL
api_key: os.environ/LLMFIT_API_KEY
# ── TIER 2: Ollama (LLMs locais — soberania total) ───────────────────────────
- model_name: llama3.3
- model_name: llama3.2
litellm_params:
model: ollama/llama3.3
api_base: os.environ/OLLAMA_BASE_URL
- model_name: qwen2.5-coder
litellm_params:
model: ollama/qwen2.5-coder:7b
api_base: os.environ/OLLAMA_BASE_URL
- model_name: deepseek-r1
litellm_params:
model: ollama/deepseek-r1:7b
model: ollama/llama3.2:3b
api_base: os.environ/OLLAMA_BASE_URL
- model_name: nomic-embed-text
@ -49,6 +36,12 @@ model_list:
model: ollama/nomic-embed-text
api_base: os.environ/OLLAMA_BASE_URL
# Alias OpenAI-compatible para embedding (Manus usa este nome por padrão)
- model_name: text-embedding-3-small
litellm_params:
model: ollama/nomic-embed-text
api_base: os.environ/OLLAMA_BASE_URL
# ── TIER 3: OpenAI (opt-in — só ativo se OPENAI_API_KEY configurado) ─────────
- model_name: gpt-4o
litellm_params:
@ -73,29 +66,26 @@ model_list:
# api_key: os.environ/GROQ_API_KEY
# ── Modelo padrão do Arcádia (Manus usa este) ─────────────────────────────────
# Prioridade: LLMFit → OpenAI (se configurado) → Ollama (sempre disponível)
# Para soberania total: remova o fallback para gpt-4o-mini
# Prioridade: LLMFit (TIER 1) → Ollama (TIER 2 — fallback)
- model_name: arcadia-default
litellm_params:
model: ollama/llama3.3
api_base: os.environ/OLLAMA_BASE_URL
model_info:
# fallbacks: ["gpt-4o-mini"] # descomente para habilitar fallback externo
model: openai/llama3.2:3b
api_base: os.environ/LLMFIT_BASE_URL
api_key: os.environ/LLMFIT_API_KEY
router_settings:
routing_strategy: least-busy
fallbacks:
- {"gpt-4o": ["llama3.3"]}
- {"gpt-4o-mini": ["llama3.3"]}
- {"arcadia-default": ["llama3.3"]}
- {"gpt-4o": ["llama3.2"]}
- {"gpt-4o-mini": ["llama3.2"]}
- {"arcadia-default": ["llama3.2"]}
- {"arcadia-finetuned": ["llama3.2"]}
- {"arcadia-embed": ["nomic-embed-text"]}
litellm_settings:
drop_params: true
request_timeout: 120
set_verbose: false
# Loga todas as chamadas no banco — essencial para auditoria e soberania
success_callback: ["langfuse"]
failure_callback: ["langfuse"]
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY

View File

@ -2,15 +2,15 @@ import type { Express, Request, Response } from "express";
import multer from "multer";
import path from "path";
import fs from "fs";
import { createRequire } from "module";
import AdmZip from "adm-zip";
import * as BSON from "bson";
import { db } from "../../db/index";
import { biDatasets, stagedTables } from "@shared/schema";
import { sql } from "drizzle-orm";
const require = createRequire(import.meta.url);
const XLSX = require("xlsx");
import * as XLSX from "xlsx";
const uploadDir = path.join(process.cwd(), "uploads");
if (!fs.existsSync(uploadDir)) {

View File

@ -1136,3 +1136,6 @@ export function registerErpRoutes(app: Express): void {
}
});
}
// SOE routes — placeholder
export function registerSoeRoutes(_app: Express): void {}

View File

@ -346,7 +346,7 @@ export function log(message: string, source = "express") {
password: hashedPassword,
name: "Administrador Master",
email: "admin@arcadia.suite",
role: "master",
role: "admin",
status: "active",
});
console.log("[Seed] Usuário master 'admin' criado com sucesso");

6
server/modules/loader.ts Normal file
View File

@ -0,0 +1,6 @@
import type { Express } from "express";
// Carregador de rotas modulares — placeholder
export async function loadModuleRoutes(_app: Express): Promise<void> {
// Módulos serão registrados aqui conforme forem criados
}

View File

@ -0,0 +1,9 @@
// Serviço de sincronização com Plus — placeholder
export const retailPlusSyncService = {
async getPlusStatus() { return { connected: false }; },
async syncAllPersonsToPlus(_tenantId: any, _empresaId: any) { return { synced: 0 }; },
async syncSaleToPlus(_saleId: any) { return { synced: false }; },
async emitirNFeSale(_saleId: any, _tipo?: string) { return { emitted: false }; },
async importClientesFromPlus(_tenantId: any, _empresaId: any) { return { imported: 0 }; },
async importProdutosFromPlus(_tenantId: any, _empresaId: any) { return { imported: 0 }; },
};

3
shared/schemas/index.ts Normal file
View File

@ -0,0 +1,3 @@
// Schemas modulares — gerados pelo Dev Center
// Arquivo placeholder: adicione exports conforme módulos forem criados
export {};