mirror of
https://github.com/mudler/LocalAI.git
synced 2026-07-08 07:18:31 -04:00
The `--generated-content-path` and `--upload-path` defaults were the fixed
shared locations `/tmp/generated/content` and `/tmp/localai/upload`. On any
multi-user host these collide across accounts: macOS routes `/tmp` to the
shared `/private/tmp` for every user, so whichever account starts LocalAI
first creates the parent with 0750 perms and every other account then fails
startup with:
unable to create ImageDir: "mkdir /tmp/generated/content: permission denied"
unable to create UploadDir: "mkdir /tmp/localai/upload: permission denied"
The same happens on Linux once a stale root-owned `/tmp/generated` (e.g. from
a prior `sudo` run) is left behind. This bites the desktop launcher and any
app embedding the raw binary (Wingman, nib-desktop), which start `local-ai
run` with no path flags.
Default both paths under the OS temp dir (`os.TempDir()`, honoring `$TMPDIR`;
already per-user on macOS) namespaced by the current UID
(`TMPDIR/localai-<uid>/...`), so accounts never collide while the paths stay
ephemeral. Wired via new kong vars in main.go so every consumer of the raw
binary inherits the fix. All content subdirs (audio, images) derive from
`GeneratedContentDir`, so they are fixed transitively.
As defense in depth, the launcher also anchors these two paths under its own
per-user data directory (mirroring the #10610 fix for data/config), extracted
into a testable `BuildRunArgs`.
Assisted-by: Claude:claude-opus-4-8 [Claude Code]
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
112 lines
3.5 KiB
Go
112 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/alecthomas/kong"
|
|
"github.com/joho/godotenv"
|
|
"github.com/mudler/LocalAI/core/cli"
|
|
"github.com/mudler/LocalAI/internal"
|
|
"github.com/mudler/xlog"
|
|
|
|
_ "github.com/mudler/LocalAI/swagger"
|
|
)
|
|
|
|
func main() {
|
|
var err error
|
|
|
|
// Initialize xlog at a level of INFO, we will set the desired level after we parse the CLI options
|
|
xlog.SetLogger(xlog.NewLogger(xlog.LogLevel("info"), "text"))
|
|
|
|
// handle loading environment variables from .env files
|
|
envFiles := []string{".env", "localai.env"}
|
|
homeDir, err := os.UserHomeDir()
|
|
if err == nil {
|
|
envFiles = append(envFiles, filepath.Join(homeDir, "localai.env"), filepath.Join(homeDir, ".config/localai.env"))
|
|
}
|
|
envFiles = append(envFiles, "/etc/localai.env")
|
|
|
|
for _, envFile := range envFiles {
|
|
if _, err := os.Stat(envFile); err == nil {
|
|
xlog.Debug("env file found, loading environment variables from file", "envFile", envFile)
|
|
err = godotenv.Load(envFile)
|
|
if err != nil {
|
|
xlog.Error("failed to load environment variables from file", "error", err, "envFile", envFile)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actually parse the CLI options
|
|
k := kong.Must(&cli.CLI,
|
|
kong.Description(
|
|
` LocalAI is a drop-in replacement OpenAI API for running LLM, GPT and genAI models locally on CPU, GPUs with consumer grade hardware.
|
|
|
|
For a list of all available models run local-ai models list
|
|
|
|
Copyright: Ettore Di Giacinto
|
|
|
|
Version: ${version}
|
|
|
|
For documentation and support:
|
|
Documentation: https://localai.io/
|
|
Getting Started: https://localai.io/basics/getting_started/
|
|
GitHub Issues: https://github.com/mudler/LocalAI/issues
|
|
`,
|
|
),
|
|
kong.UsageOnError(),
|
|
kong.Vars{
|
|
"basepath": kong.ExpandPath("."),
|
|
// Per-user temp locations for ephemeral writable content. A fixed
|
|
// shared name under /tmp collides across accounts on multi-user hosts
|
|
// (notably macOS, where /tmp is the shared /private/tmp for everyone),
|
|
// failing startup with "mkdir /tmp/generated/content: permission
|
|
// denied". See cli.DefaultGeneratedContentPath.
|
|
"generatedcontentpath": cli.DefaultGeneratedContentPath(),
|
|
"uploadpath": cli.DefaultUploadPath(),
|
|
"galleries": `[{"name":"localai", "url":"github:mudler/LocalAI/gallery/index.yaml@master"}]`,
|
|
"backends": `[{"name":"localai", "url":"github:mudler/LocalAI/backend/index.yaml@master"}]`,
|
|
"version": internal.PrintableVersion(),
|
|
},
|
|
)
|
|
ctx, err := k.Parse(os.Args[1:])
|
|
if err != nil {
|
|
k.FatalIfErrorf(err)
|
|
}
|
|
|
|
// Pass Kong model to the completion command for dynamic script generation
|
|
cli.CLI.Completion.SetApplication(k.Model)
|
|
|
|
// Configure the logging level before we run the application
|
|
// This is here to preserve the existing --debug flag functionality
|
|
logLevel := "info"
|
|
if cli.CLI.Debug && cli.CLI.LogLevel == nil {
|
|
logLevel = "debug"
|
|
cli.CLI.LogLevel = &logLevel
|
|
}
|
|
|
|
if cli.CLI.LogLevel == nil {
|
|
cli.CLI.LogLevel = &logLevel
|
|
}
|
|
|
|
// Set xlog logger with the desired level and text format.
|
|
// xlog auto-enables log deduplication when output is a terminal.
|
|
var logOpts []xlog.LoggerOption
|
|
if cli.CLI.LogDedupLogs != nil {
|
|
if *cli.CLI.LogDedupLogs {
|
|
logOpts = append(logOpts, xlog.WithDedup())
|
|
} else {
|
|
logOpts = append(logOpts, xlog.WithoutDedup())
|
|
}
|
|
}
|
|
|
|
xlog.SetLogger(xlog.NewLogger(xlog.LogLevel(*cli.CLI.LogLevel), *cli.CLI.LogFormat, logOpts...))
|
|
|
|
// Run the thing!
|
|
err = ctx.Run(&cli.CLI.Context)
|
|
if err != nil {
|
|
xlog.Fatal("Error running the application", "error", err)
|
|
}
|
|
}
|