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
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm ci --ignore-scripts
|
RUN npm ci
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
@ -18,16 +18,19 @@ ENV NODE_ENV=production
|
||||||
|
|
||||||
# Deps de produção apenas
|
# Deps de produção apenas
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm ci --omit=dev --ignore-scripts
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
# Artefatos do build
|
# Artefatos do build
|
||||||
COPY --from=builder /app/dist ./dist
|
COPY --from=builder /app/dist ./dist
|
||||||
COPY --from=builder /app/shared ./shared
|
COPY --from=builder /app/shared ./shared
|
||||||
COPY --from=builder /app/migrations ./migrations
|
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
|
EXPOSE 5000
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
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"]
|
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
|
condition: service_started
|
||||||
networks:
|
networks:
|
||||||
- arcadia-internal
|
- arcadia-internal
|
||||||
- arcadia-public
|
- coolify
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=coolify"
|
||||||
|
- "traefik.http.routers.arcadia.entrypoints=https"
|
||||||
- "traefik.http.routers.arcadia.rule=Host(`${DOMAIN}`)"
|
- "traefik.http.routers.arcadia.rule=Host(`${DOMAIN}`)"
|
||||||
- "traefik.http.routers.arcadia.tls=true"
|
- "traefik.http.routers.arcadia.tls=true"
|
||||||
- "traefik.http.routers.arcadia.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.arcadia.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.arcadia.loadbalancer.server.port=5000"
|
||||||
|
|
||||||
# ── Microserviços Python ─────────────────────────────────────────────────────
|
# ── Microserviços Python ─────────────────────────────────────────────────────
|
||||||
contabil:
|
contabil:
|
||||||
|
|
@ -153,6 +156,9 @@ services:
|
||||||
SERVICE_NAME: embeddings
|
SERVICE_NAME: embeddings
|
||||||
SERVICE_PORT: 8001
|
SERVICE_PORT: 8001
|
||||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
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:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
@ -170,12 +176,13 @@ services:
|
||||||
environment:
|
environment:
|
||||||
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
||||||
LITELLM_MASTER_KEY: ${LITELLM_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
|
# Ollama: se instalado no host use http://host-gateway:11434
|
||||||
# Se usar container Docker, mantém http://ollama:11434
|
# Se usar container Docker, mantém http://ollama:11434
|
||||||
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
||||||
# LLMFit: URL do serviço de modelos fine-tuned
|
# LLMFit: URL do serviço de modelos fine-tuned
|
||||||
LLMFIT_BASE_URL: ${LLMFIT_BASE_URL:-}
|
LLMFIT_BASE_URL: ${LLMFIT_BASE_URL:-}
|
||||||
|
LLMFIT_API_KEY: ${LLMFIT_API_KEY:-}
|
||||||
# Providers externos opcionais (soberania: só habilitados se configurados)
|
# Providers externos opcionais (soberania: só habilitados se configurados)
|
||||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
||||||
GROQ_API_KEY: ${GROQ_API_KEY:-}
|
GROQ_API_KEY: ${GROQ_API_KEY:-}
|
||||||
|
|
@ -184,6 +191,7 @@ services:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
networks:
|
networks:
|
||||||
- arcadia-internal
|
- arcadia-internal
|
||||||
|
- coolify
|
||||||
|
|
||||||
# ── Ollama (LLMs locais — soberania total) ────────────────────────────────────
|
# ── Ollama (LLMs locais — soberania total) ────────────────────────────────────
|
||||||
# OPÇÃO A (padrão): Ollama como container Docker
|
# OPÇÃO A (padrão): Ollama como container Docker
|
||||||
|
|
@ -215,7 +223,7 @@ services:
|
||||||
- litellm
|
- litellm
|
||||||
networks:
|
networks:
|
||||||
- arcadia-internal
|
- arcadia-internal
|
||||||
- arcadia-public
|
- coolify
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.webui.rule=Host(`ai.${DOMAIN}`)"
|
- "traefik.http.routers.webui.rule=Host(`ai.${DOMAIN}`)"
|
||||||
|
|
@ -227,8 +235,8 @@ services:
|
||||||
networks:
|
networks:
|
||||||
arcadia-internal:
|
arcadia-internal:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
arcadia-public:
|
coolify:
|
||||||
driver: bridge
|
external: true
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
|
|
|
||||||
|
|
@ -13,35 +13,22 @@
|
||||||
model_list:
|
model_list:
|
||||||
|
|
||||||
# ── TIER 1: LLMFit (modelos fine-tuned locais — máxima soberania) ────────────
|
# ── TIER 1: LLMFit (modelos fine-tuned locais — máxima soberania) ────────────
|
||||||
# Descomente quando o LLMFit estiver rodando no servidor
|
- model_name: arcadia-finetuned
|
||||||
# O LLMFit expõe API compatível com OpenAI — basta apontar a URL
|
litellm_params:
|
||||||
#
|
model: openai/llama3.2:3b
|
||||||
# - model_name: arcadia-finetuned
|
api_base: os.environ/LLMFIT_BASE_URL
|
||||||
# litellm_params:
|
api_key: os.environ/LLMFIT_API_KEY
|
||||||
# model: openai/arcadia-v1 # nome do modelo no LLMFit
|
|
||||||
# api_base: os.environ/LLMFIT_BASE_URL
|
- model_name: arcadia-embed
|
||||||
# api_key: llmfit-internal
|
litellm_params:
|
||||||
#
|
model: openai/nomic-embed-text:latest
|
||||||
# - model_name: arcadia-embed
|
api_base: os.environ/LLMFIT_BASE_URL
|
||||||
# litellm_params:
|
api_key: os.environ/LLMFIT_API_KEY
|
||||||
# model: openai/arcadia-embed-v1 # modelo de embeddings fine-tuned
|
|
||||||
# api_base: os.environ/LLMFIT_BASE_URL
|
|
||||||
# api_key: llmfit-internal
|
|
||||||
|
|
||||||
# ── TIER 2: Ollama (LLMs locais — soberania total) ───────────────────────────
|
# ── TIER 2: Ollama (LLMs locais — soberania total) ───────────────────────────
|
||||||
- model_name: llama3.3
|
- model_name: llama3.2
|
||||||
litellm_params:
|
litellm_params:
|
||||||
model: ollama/llama3.3
|
model: ollama/llama3.2:3b
|
||||||
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
|
|
||||||
api_base: os.environ/OLLAMA_BASE_URL
|
api_base: os.environ/OLLAMA_BASE_URL
|
||||||
|
|
||||||
- model_name: nomic-embed-text
|
- model_name: nomic-embed-text
|
||||||
|
|
@ -49,6 +36,12 @@ model_list:
|
||||||
model: ollama/nomic-embed-text
|
model: ollama/nomic-embed-text
|
||||||
api_base: os.environ/OLLAMA_BASE_URL
|
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) ─────────
|
# ── TIER 3: OpenAI (opt-in — só ativo se OPENAI_API_KEY configurado) ─────────
|
||||||
- model_name: gpt-4o
|
- model_name: gpt-4o
|
||||||
litellm_params:
|
litellm_params:
|
||||||
|
|
@ -73,29 +66,26 @@ model_list:
|
||||||
# api_key: os.environ/GROQ_API_KEY
|
# api_key: os.environ/GROQ_API_KEY
|
||||||
|
|
||||||
# ── Modelo padrão do Arcádia (Manus usa este) ─────────────────────────────────
|
# ── Modelo padrão do Arcádia (Manus usa este) ─────────────────────────────────
|
||||||
# Prioridade: LLMFit → OpenAI (se configurado) → Ollama (sempre disponível)
|
# Prioridade: LLMFit (TIER 1) → Ollama (TIER 2 — fallback)
|
||||||
# Para soberania total: remova o fallback para gpt-4o-mini
|
|
||||||
- model_name: arcadia-default
|
- model_name: arcadia-default
|
||||||
litellm_params:
|
litellm_params:
|
||||||
model: ollama/llama3.3
|
model: openai/llama3.2:3b
|
||||||
api_base: os.environ/OLLAMA_BASE_URL
|
api_base: os.environ/LLMFIT_BASE_URL
|
||||||
model_info:
|
api_key: os.environ/LLMFIT_API_KEY
|
||||||
# fallbacks: ["gpt-4o-mini"] # descomente para habilitar fallback externo
|
|
||||||
|
|
||||||
router_settings:
|
router_settings:
|
||||||
routing_strategy: least-busy
|
routing_strategy: least-busy
|
||||||
fallbacks:
|
fallbacks:
|
||||||
- {"gpt-4o": ["llama3.3"]}
|
- {"gpt-4o": ["llama3.2"]}
|
||||||
- {"gpt-4o-mini": ["llama3.3"]}
|
- {"gpt-4o-mini": ["llama3.2"]}
|
||||||
- {"arcadia-default": ["llama3.3"]}
|
- {"arcadia-default": ["llama3.2"]}
|
||||||
|
- {"arcadia-finetuned": ["llama3.2"]}
|
||||||
|
- {"arcadia-embed": ["nomic-embed-text"]}
|
||||||
|
|
||||||
litellm_settings:
|
litellm_settings:
|
||||||
drop_params: true
|
drop_params: true
|
||||||
request_timeout: 120
|
request_timeout: 120
|
||||||
set_verbose: false
|
set_verbose: false
|
||||||
# Loga todas as chamadas no banco — essencial para auditoria e soberania
|
|
||||||
success_callback: ["langfuse"]
|
|
||||||
failure_callback: ["langfuse"]
|
|
||||||
|
|
||||||
general_settings:
|
general_settings:
|
||||||
master_key: os.environ/LITELLM_MASTER_KEY
|
master_key: os.environ/LITELLM_MASTER_KEY
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@ import type { Express, Request, Response } from "express";
|
||||||
import multer from "multer";
|
import multer from "multer";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { createRequire } from "module";
|
|
||||||
import AdmZip from "adm-zip";
|
import AdmZip from "adm-zip";
|
||||||
import * as BSON from "bson";
|
import * as BSON from "bson";
|
||||||
import { db } from "../../db/index";
|
import { db } from "../../db/index";
|
||||||
import { biDatasets, stagedTables } from "@shared/schema";
|
import { biDatasets, stagedTables } from "@shared/schema";
|
||||||
import { sql } from "drizzle-orm";
|
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");
|
const uploadDir = path.join(process.cwd(), "uploads");
|
||||||
if (!fs.existsSync(uploadDir)) {
|
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,
|
password: hashedPassword,
|
||||||
name: "Administrador Master",
|
name: "Administrador Master",
|
||||||
email: "admin@arcadia.suite",
|
email: "admin@arcadia.suite",
|
||||||
role: "master",
|
role: "admin",
|
||||||
status: "active",
|
status: "active",
|
||||||
});
|
});
|
||||||
console.log("[Seed] Usuário master 'admin' criado com sucesso");
|
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