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:
parent
9449b3614c
commit
f29e61f335
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -1136,3 +1136,6 @@ export function registerErpRoutes(app: Express): void {
|
|||
}
|
||||
});
|
||||
}
|
||||
// SOE routes — placeholder
|
||||
|
||||
export function registerSoeRoutes(_app: Express): void {}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 }; },
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
// Schemas modulares — gerados pelo Dev Center
|
||||
// Arquivo placeholder: adicione exports conforme módulos forem criados
|
||||
export {};
|
||||
Loading…
Reference in New Issue