Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: add static-checker #2781

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

ci: add static-checker #2781

wants to merge 2 commits into from

Conversation

mudler
Copy link
Owner

@mudler mudler commented Jul 12, 2024

Description

This PR adds a static-checker pipeline as part of our workflows.

Notes for Reviewers
It's good to assess the state of the code, plus trying to identifying shortcomings before entering the code

Signed commits

  • Yes, I signed my commits.

**Description**

This PR adds a static-checker pipeline as part of our workflows

**Notes for Reviewers**
N/A

**[Signed commits](../CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin)**
- [x] Yes, I signed my commits.

Signed-off-by: Ettore Di Giacinto <mudler@users.noreply.github.com>
Copy link

PR description is too short and seems to not fulfill PR template, please fill in

Repository owner deleted a comment from github-actions bot Jul 12, 2024
Copy link

netlify bot commented Jul 12, 2024

Deploy Preview for localai ready!

Name Link
🔨 Latest commit c28e8ca
🔍 Latest deploy log https://app.netlify.com/sites/localai/deploys/6699549fa5ab460008c00f42
😎 Deploy Preview https://deploy-preview-2781--localai.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link

⚠ golint failed (.)

Found 617 lint suggestions; failing.

Show Detail
backend/go/image/stablediffusion/stablediffusion.go:11:6: exported type Image should have comment or be unexported
backend/go/image/stablediffusion/stablediffusion.go:16:1: exported method Image.Load should have comment or be unexported
backend/go/image/stablediffusion/stablediffusion.go:23:1: exported method Image.GenerateImage should have comment or be unexported
backend/go/image/tinydream/tinydream.go:11:6: exported type Image should have comment or be unexported
backend/go/image/tinydream/tinydream.go:16:1: exported method Image.Load should have comment or be unexported
backend/go/image/tinydream/tinydream.go:23:1: exported method Image.GenerateImage should have comment or be unexported
backend/go/llm/bert/bert.go:12:6: exported type Embeddings should have comment or be unexported
backend/go/llm/bert/bert.go:17:1: exported method Embeddings.Load should have comment or be unexported
backend/go/llm/bert/bert.go:23:1: exported method Embeddings.Embeddings should have comment or be unexported
backend/go/llm/gpt4all/gpt4all.go:13:6: exported type LLM should have comment or be unexported
backend/go/llm/gpt4all/gpt4all.go:19:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/gpt4all/gpt4all.go:41:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/gpt4all/gpt4all.go:45:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/langchain/langchain.go:14:6: exported type LLM should have comment or be unexported
backend/go/llm/langchain/langchain.go:21:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/langchain/langchain.go:32:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/langchain/langchain.go:46:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/llama/llama.go:14:6: exported type LLM should have comment or be unexported
backend/go/llm/llama/llama.go:21:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/llama/llama.go:201:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/llama/llama.go:208:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/llama/llama.go:233:1: exported method LLM.Embeddings should have comment or be unexported
backend/go/llm/llama/llama.go:247:1: exported method LLM.TokenizeString should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:13:6: exported type LLM should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:19:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:169:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:173:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:192:1: exported method LLM.Embeddings should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:16:6: exported type LLM should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:22:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:40:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:55:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:78:1: exported method LLM.TokenizeString should have comment or be unexported
backend/go/stores/store.go:17:6: exported type Store should have comment or be unexported
backend/go/stores/store.go:32:1: comment on exported type Pair should be of the form "Pair ..." (with optional leading article)
backend/go/stores/store.go:39:1: exported function NewStore should have comment or be unexported
backend/go/stores/store.go:101:1: exported method Store.Load should have comment or be unexported
backend/go/stores/store.go:105:1: comment on exported method Store.StoresSet should be of the form "StoresSet ..."
backend/go/stores/store.go:151:2: don't use underscores in Go names; var merge_ks should be mergeKs
backend/go/stores/store.go:152:2: don't use underscores in Go names; var merge_vs should be mergeVs
backend/go/stores/store.go:200:1: exported method Store.StoresDelete should have comment or be unexported
backend/go/stores/store.go:220:2: don't use underscores in Go names; var merge_ks should be mergeKs
backend/go/stores/store.go:221:2: don't use underscores in Go names; var merge_vs should be mergeVs
backend/go/stores/store.go:223:2: don't use underscores in Go names; var tail_ks should be tailKs
backend/go/stores/store.go:224:2: don't use underscores in Go names; var tail_vs should be tailVs
backend/go/stores/store.go:266:1: exported method Store.StoresGet should have comment or be unexported
backend/go/stores/store.go:283:2: don't use underscores in Go names; var tail_k should be tailK
backend/go/stores/store.go:284:2: don't use underscores in Go names; var tail_v should be tailV
backend/go/stores/store.go:337:6: exported type PriorityItem should have comment or be unexported
backend/go/stores/store.go:343:6: exported type PriorityQueue should have comment or be unexported
backend/go/stores/store.go:356:1: exported method PriorityQueue.Push should have comment or be unexported
backend/go/stores/store.go:361:1: exported method PriorityQueue.Pop should have comment or be unexported
backend/go/stores/store.go:369:1: exported method Store.StoresFindNormalized should have comment or be unexported
backend/go/stores/store.go:371:2: don't use underscores in Go names; var top_ks should be topKs
backend/go/stores/store.go:426:1: exported method Store.StoresFindFallback should have comment or be unexported
backend/go/stores/store.go:428:2: don't use underscores in Go names; var top_ks should be topKs
backend/go/stores/store.go:473:1: exported method Store.StoresFind should have comment or be unexported
backend/go/stores/store.go:494:9: if block ends with a return statement, so drop this else and outdent its block
backend/go/transcribe/transcript.go:32:1: exported function Transcript should have comment or be unexported
backend/go/transcribe/whisper.go:12:6: exported type Whisper should have comment or be unexported
backend/go/transcribe/whisper.go:17:1: exported method Whisper.Load should have comment or be unexported
backend/go/transcribe/whisper.go:24:1: exported method Whisper.AudioTranscription should have comment or be unexported
backend/go/tts/piper.go:15:6: exported type Piper should have comment or be unexported
backend/go/tts/piper.go:20:1: exported method Piper.Load should have comment or be unexported
backend/go/tts/piper.go:30:1: exported method Piper.TTS should have comment or be unexported
backend/go/tts/piper.go:34:6: exported type PiperB should have comment or be unexported
backend/go/tts/piper.go:38:1: exported function New should have comment or be unexported
backend/go/tts/piper.go:47:1: exported method PiperB.TTS should have comment or be unexported
core/application.go:9:1: comment on exported type Application should be of the form "Application ..." (with optional leading article)
core/application.go:35:1: comment on exported type ApplicationState should be of the form "ApplicationState ..." (with optional leading article)
core/backend/embeddings.go:12:1: exported function ModelEmbedding should have comment or be unexported
core/backend/image.go:10:1: exported function ImageGeneration should have comment or be unexported
core/backend/image.go:10:59: don't use underscores in Go names; func parameter positive_prompt should be positivePrompt
core/backend/image.go:10:76: don't use underscores in Go names; func parameter negative_prompt should be negativePrompt
core/backend/llm.go:22:6: exported type LLMResponse should have comment or be unexported
core/backend/llm.go:27:6: exported type TokenUsage should have comment or be unexported
core/backend/llm.go:32:1: exported function ModelInference should have comment or be unexported
core/backend/llm.go:150:10: if block ends with a return statement, so drop this else and outdent its block
core/backend/llm.go:175:1: exported function Finetune should have comment or be unexported
core/backend/rerank.go:12:1: exported function Rerank should have comment or be unexported
core/backend/stores.go:10:1: exported function StoreBackend should have comment or be unexported
core/backend/transcript.go:14:1: exported function ModelTranscription should have comment or be unexported
core/backend/tts.go:32:1: exported function ModelTTS should have comment or be unexported
core/cli/cli.go:8:5: exported var CLI should have comment or be unexported
core/cli/federated.go:21:6: exported type FederatedCLI should have comment or be unexported
core/cli/federated.go:26:1: exported method FederatedCLI.Run should have comment or be unexported
core/cli/federated.go:44:1: exported function Proxy should have comment or be unexported
core/cli/models.go:18:6: exported type ModelsCMDFlags should have comment or be unexported
core/cli/models.go:23:6: exported type ModelsList should have comment or be unexported
core/cli/models.go:27:6: exported type ModelsInstall should have comment or be unexported
core/cli/models.go:34:6: exported type ModelsCMD should have comment or be unexported
core/cli/models.go:39:1: exported method ModelsList.Run should have comment or be unexported
core/cli/models.go:59:1: exported method ModelsInstall.Run should have comment or be unexported
core/cli/run.go:20:6: exported type RunCMD should have comment or be unexported
core/cli/run.go:68:1: exported method RunCMD.Run should have comment or be unexported
core/cli/transcript.go:15:6: exported type TranscriptCMD should have comment or be unexported
core/cli/transcript.go:27:1: exported method TranscriptCMD.Run should have comment or be unexported
core/cli/tts.go:17:6: exported type TTSCMD should have comment or be unexported
core/cli/tts.go:29:1: exported method TTSCMD.Run should have comment or be unexported
core/cli/util.go:17:6: exported type UtilCMD should have comment or be unexported
core/cli/util.go:22:6: exported type GGUFInfoCMD should have comment or be unexported
core/cli/util.go:27:6: exported type HFScanCMD should have comment or be unexported
core/cli/util.go:33:1: exported method GGUFInfoCMD.Run should have comment or be unexported
core/cli/util.go:69:1: exported method HFScanCMD.Run should have comment or be unexported
core/cli/util.go:85:9: if block ends with a return statement, so drop this else and outdent its block
core/cli/context/context.go:1:1: don't use MixedCaps in package name; cliContext should be clicontext
core/cli/context/context.go:5:6: exported type Context should have comment or be unexported
core/cli/worker/worker.go:3:6: exported type WorkerFlags should have comment or be unexported
core/cli/worker/worker.go:3:6: type name will be used as worker.WorkerFlags by other packages, and that stutters; consider calling this Flags
core/cli/worker/worker.go:7:6: exported type Worker should have comment or be unexported
core/cli/worker/worker_llamacpp.go:14:6: exported type LLamaCPP should have comment or be unexported
core/cli/worker/worker_llamacpp.go:19:1: exported method LLamaCPP.Run should have comment or be unexported
core/cli/worker/worker_nop2p.go:12:6: exported type P2P should have comment or be unexported
core/cli/worker/worker_nop2p.go:14:1: exported method P2P.Run should have comment or be unexported
core/clients/store.go:11:1: comment on exported type StoreClient should be of the form "StoreClient ..." (with optional leading article)
core/clients/store.go:17:6: exported type SetRequest should have comment or be unexported
core/clients/store.go:22:6: exported type GetRequest should have comment or be unexported
core/clients/store.go:26:6: exported type GetResponse should have comment or be unexported
core/clients/store.go:31:6: exported type DeleteRequest should have comment or be unexported
core/clients/store.go:35:6: exported type FindRequest should have comment or be unexported
core/clients/store.go:40:6: exported type FindResponse should have comment or be unexported
core/clients/store.go:46:1: comment on exported function NewStoreClient should be of the form "NewStoreClient ..."
core/clients/store.go:47:21: func parameter baseUrl should be baseURL
core/clients/store.go:54:1: comment on exported method StoreClient.Set should be of the form "Set ..."
core/clients/store.go:59:1: comment on exported method StoreClient.Get should be of the form "Get ..."
core/clients/store.go:75:1: comment on exported method StoreClient.Delete should be of the form "Delete ..."
core/clients/store.go:80:1: comment on exported method StoreClient.Find should be of the form "Find ..."
core/config/application_config.go:13:6: exported type ApplicationConfig should have comment or be unexported
core/config/application_config.go:33:2: struct field ApiKeys should be APIKeys
core/config/application_config.go:61:6: exported type AppOption should have comment or be unexported
core/config/application_config.go:63:1: exported function NewApplicationConfig should have comment or be unexported
core/config/application_config.go:76:1: exported function WithModelsURL should have comment or be unexported
core/config/application_config.go:82:1: exported function WithModelPath should have comment or be unexported
core/config/application_config.go:88:1: exported function WithCors should have comment or be unexported
core/config/application_config.go:94:1: exported function WithCsrf should have comment or be unexported
core/config/application_config.go:100:1: exported function WithP2PToken should have comment or be unexported
core/config/application_config.go:106:1: exported function WithModelLibraryURL should have comment or be unexported
core/config/application_config.go:112:1: exported function WithLibPath should have comment or be unexported
core/config/application_config.go:118:5: exported var EnableWatchDog should have comment or be unexported
core/config/application_config.go:122:5: exported var EnableWatchDogIdleCheck should have comment or be unexported
core/config/application_config.go:127:5: exported var EnableWatchDogBusyCheck should have comment or be unexported
core/config/application_config.go:132:5: exported var DisableWebUI should have comment or be unexported
core/config/application_config.go:136:1: exported function SetWatchDogBusyTimeout should have comment or be unexported
core/config/application_config.go:142:1: exported function SetWatchDogIdleTimeout should have comment or be unexported
core/config/application_config.go:148:5: exported var EnableSingleBackend should have comment or be unexported
core/config/application_config.go:152:5: exported var EnableParallelBackendRequests should have comment or be unexported
core/config/application_config.go:156:5: exported var EnableGalleriesAutoload should have comment or be unexported
core/config/application_config.go:160:1: exported function WithExternalBackend should have comment or be unexported
core/config/application_config.go:169:1: exported function WithCorsAllowOrigins should have comment or be unexported
core/config/application_config.go:175:1: exported function WithBackendAssetsOutput should have comment or be unexported
core/config/application_config.go:181:1: exported function WithBackendAssets should have comment or be unexported
core/config/application_config.go:187:1: exported function WithStringGalleries should have comment or be unexported
core/config/application_config.go:201:1: exported function WithGalleries should have comment or be unexported
core/config/application_config.go:207:1: exported function WithContext should have comment or be unexported
core/config/application_config.go:213:1: exported function WithYAMLConfigPreload should have comment or be unexported
core/config/application_config.go:219:1: exported function WithJSONStringPreload should have comment or be unexported
core/config/application_config.go:224:1: exported function WithConfigFile should have comment or be unexported
core/config/application_config.go:230:1: exported function WithUploadLimitMB should have comment or be unexported
core/config/application_config.go:236:1: exported function WithThreads should have comment or be unexported
core/config/application_config.go:245:1: exported function WithContextSize should have comment or be unexported
core/config/application_config.go:251:1: exported function WithF16 should have comment or be unexported
core/config/application_config.go:257:1: exported function WithDebug should have comment or be unexported
core/config/application_config.go:263:1: exported function WithAudioDir should have comment or be unexported
core/config/application_config.go:269:1: exported function WithImageDir should have comment or be unexported
core/config/application_config.go:275:1: exported function WithUploadDir should have comment or be unexported
core/config/application_config.go:281:1: exported function WithConfigsDir should have comment or be unexported
core/config/application_config.go:287:1: exported function WithDynamicConfigDir should have comment or be unexported
core/config/application_config.go:293:1: exported function WithDynamicConfigDirPollInterval should have comment or be unexported
core/config/application_config.go:299:1: exported function WithApiKeys should have comment or be unexported
core/config/application_config.go:299:6: func WithApiKeys should be WithAPIKeys
core/config/application_config.go:305:1: exported function WithEnforcedPredownloadScans should have comment or be unexported
core/config/application_config.go:311:1: exported function WithOpaqueErrors should have comment or be unexported
core/config/backend_config.go:15:2: don't use ALL_CAPS in Go names; use CamelCase
core/config/backend_config.go:15:2: exported const RAND_SEED should have comment (or a comment on this block) or be unexported
core/config/backend_config.go:18:6: exported type TTSConfig should have comment or be unexported
core/config/backend_config.go:27:6: exported type BackendConfig should have comment or be unexported
core/config/backend_config.go:74:6: exported type File should have comment or be unexported
core/config/backend_config.go:80:6: exported type VallE should have comment or be unexported
core/config/backend_config.go:84:6: exported type FeatureFlag should have comment or be unexported
core/config/backend_config.go:86:1: exported method FeatureFlag.Enabled should have comment or be unexported
core/config/backend_config.go:91:6: exported type GRPC should have comment or be unexported
core/config/backend_config.go:96:6: exported type Diffusers should have comment or be unexported
core/config/backend_config.go:197:1: exported method BackendConfig.SetFunctionCallString should have comment or be unexported
core/config/backend_config.go:201:1: exported method BackendConfig.SetFunctionCallNameString should have comment or be unexported
core/config/backend_config.go:205:1: exported method BackendConfig.ShouldUseFunctions should have comment or be unexported
core/config/backend_config.go:209:1: exported method BackendConfig.ShouldCallSpecificFunction should have comment or be unexported
core/config/backend_config.go:224:1: exported method BackendConfig.IsMMProjURL should have comment or be unexported
core/config/backend_config.go:228:1: exported method BackendConfig.IsModelURL should have comment or be unexported
core/config/backend_config.go:243:1: exported method BackendConfig.FunctionToCall should have comment or be unexported
core/config/backend_config.go:252:1: exported method BackendConfig.SetDefaults should have comment or be unexported
core/config/backend_config.go:252:1: receiver name cfg should be consistent with previous receiver name c for BackendConfig
core/config/backend_config.go:375:1: exported method BackendConfig.Validate should have comment or be unexported
core/config/backend_config.go:402:1: exported method BackendConfig.HasTemplate should have comment or be unexported
core/config/backend_config_loader.go:21:6: exported type BackendConfigLoader should have comment or be unexported
core/config/backend_config_loader.go:27:1: exported function NewBackendConfigLoader should have comment or be unexported
core/config/backend_config_loader.go:34:6: exported type LoadOptions should have comment or be unexported
core/config/backend_config_loader.go:41:1: exported function LoadOptionDebug should have comment or be unexported
core/config/backend_config_loader.go:47:1: exported function LoadOptionThreads should have comment or be unexported
core/config/backend_config_loader.go:53:1: exported function LoadOptionContextSize should have comment or be unexported
core/config/backend_config_loader.go:59:1: exported function ModelPath should have comment or be unexported
core/config/backend_config_loader.go:65:1: exported function LoadOptionF16 should have comment or be unexported
core/config/backend_config_loader.go:71:6: exported type ConfigLoaderOption should have comment or be unexported
core/config/backend_config_loader.go:71:6: type name will be used as config.ConfigLoaderOption by other packages, and that stutters; consider calling this LoaderOption
core/config/backend_config_loader.go:73:1: exported method LoadOptions.Apply should have comment or be unexported
core/config/backend_config_loader.go:114:1: comment on exported method BackendConfigLoader.LoadBackendConfigFileByName should be of the form "LoadBackendConfigFileByName ..."
core/config/backend_config_loader.go:148:1: comment on exported method BackendConfigLoader.LoadMultipleBackendConfigsSingleFile should be of the form "LoadMultipleBackendConfigsSingleFile ..."
core/config/backend_config_loader.go:165:1: exported method BackendConfigLoader.LoadBackendConfig should have comment or be unexported
core/config/backend_config_loader.go:182:1: exported method BackendConfigLoader.GetBackendConfig should have comment or be unexported
core/config/backend_config_loader.go:189:1: exported method BackendConfigLoader.GetAllBackendConfigs should have comment or be unexported
core/config/backend_config_loader.go:204:1: exported method BackendConfigLoader.RemoveBackendConfig should have comment or be unexported
core/config/gallery.go:3:6: exported type Gallery should have comment or be unexported
core/config/guesser.go:16:2: exported const Unknown should have comment (or a comment on this block) or be unexported
core/dependencies_manager/manager.go:13:6: exported type Asset should have comment or be unexported
core/gallery/gallery.go:17:1: comment on exported function InstallModelFromGallery should be of the form "InstallModelFromGallery ..."
core/gallery/gallery.go:86:1: exported function FindModel should have comment or be unexported
core/gallery/gallery.go:113:1: comment on exported function AvailableGalleryModels should be of the form "AvailableGalleryModels ..."
core/gallery/gallery.go:178:1: exported function GetLocalModelConfiguration should have comment or be unexported
core/gallery/gallery.go:184:1: exported function DeleteModelFromSystem should have comment or be unexported
core/gallery/gallery.go:232:1: comment on exported function SafetyScanGalleryModels should be of the form "SafetyScanGalleryModels ..."
core/gallery/gallery.go:247:1: exported function SafetyScanGalleryModel should have comment or be unexported
core/gallery/models.go:18:1: comment on exported type Config should be of the form "Config ..." (with optional leading article)
core/gallery/models.go:58:6: exported type File should have comment or be unexported
core/gallery/models.go:64:6: exported type PromptTemplate should have comment or be unexported
core/gallery/models.go:69:1: exported function GetGalleryConfigFromURL should have comment or be unexported
core/gallery/models.go:81:1: exported function ReadConfigFile should have comment or be unexported
core/gallery/models.go:98:1: exported function InstallModel should have comment or be unexported
core/gallery/op.go:5:6: exported type GalleryOp should have comment or be unexported
core/gallery/op.go:5:6: type name will be used as gallery.GalleryOp by other packages, and that stutters; consider calling this Op
core/gallery/op.go:6:2: struct field Id should be ID
core/gallery/op.go:15:6: exported type GalleryOpStatus should have comment or be unexported
core/gallery/op.go:15:6: type name will be used as gallery.GalleryOpStatus by other packages, and that stutters; consider calling this OpStatus
core/gallery/request.go:13:6: type name will be used as gallery.GalleryModel by other packages, and that stutters; consider calling this Model
core/gallery/request.go:33:1: exported method GalleryModel.ID should have comment or be unexported
core/gallery/request.go:37:6: exported type GalleryModels should have comment or be unexported
core/gallery/request.go:37:6: type name will be used as gallery.GalleryModels by other packages, and that stutters; consider calling this Models
core/gallery/request.go:39:1: exported method GalleryModels.Search should have comment or be unexported
core/gallery/request.go:53:1: exported method GalleryModels.FindByName should have comment or be unexported
core/http/app.go:36:2: var xApiKey should be xAPIKey
core/http/app.go:68:1: exported function App should have comment or be unexported
core/http/render.go:27:9: if block ends with a return statement, so drop this else and outdent its block
core/http/ctx/fiber.go:1:1: don't use MixedCaps in package name; fiberContext should be fibercontext
core/http/elements/gallery.go:27:1: exported function DoneProgress should have comment or be unexported
core/http/elements/gallery.go:51:1: exported function ErrorProgress should have comment or be unexported
core/http/elements/gallery.go:67:1: exported function ProgressBar should have comment or be unexported
core/http/elements/gallery.go:84:1: exported function P2PNodeStats should have comment or be unexported
core/http/elements/gallery.go:134:1: exported function P2PNodeBoxes should have comment or be unexported
core/http/elements/gallery.go:213:1: exported function StartProgressBar should have comment or be unexported
core/http/elements/gallery.go:375:1: exported function ListModels should have comment or be unexported
core/http/endpoints/jina/rerank.go:15:1: exported function JINARerankEndpoint should have comment or be unexported
core/http/endpoints/jina/rerank.go:15:6: func name will be used as jina.JINARerankEndpoint by other packages, and that stutters; consider calling this RerankEndpoint
core/http/endpoints/localai/backend_monitor.go:9:1: exported function BackendMonitorEndpoint should have comment or be unexported
core/http/endpoints/localai/backend_monitor.go:26:1: exported function BackendShutdownEndpoint should have comment or be unexported
core/http/endpoints/localai/gallery.go:16:6: exported type ModelGalleryEndpointService should have comment or be unexported
core/http/endpoints/localai/gallery.go:22:6: exported type GalleryModel should have comment or be unexported
core/http/endpoints/localai/gallery.go:28:1: exported function CreateModelGalleryEndpointService should have comment or be unexported
core/http/endpoints/localai/gallery.go:36:1: exported method ModelGalleryEndpointService.GetOpStatusEndpoint should have comment or be unexported
core/http/endpoints/localai/gallery.go:46:1: exported method ModelGalleryEndpointService.GetAllStatusEndpoint should have comment or be unexported
core/http/endpoints/localai/gallery.go:52:1: exported method ModelGalleryEndpointService.ApplyModelGalleryEndpoint should have comment or be unexported
core/http/endpoints/localai/gallery.go:78:1: exported method ModelGalleryEndpointService.DeleteModelGalleryEndpoint should have comment or be unexported
core/http/endpoints/localai/gallery.go:99:1: exported method ModelGalleryEndpointService.ListModelFromGalleryEndpoint should have comment or be unexported
core/http/endpoints/localai/gallery.go:119:1: comment on exported method ModelGalleryEndpointService.ListModelGalleriesEndpoint should be of the form "ListModelGalleriesEndpoint ..."
core/http/endpoints/localai/gallery.go:131:1: exported method ModelGalleryEndpointService.AddModelGalleryEndpoint should have comment or be unexported
core/http/endpoints/localai/gallery.go:153:1: exported method ModelGalleryEndpointService.RemoveModelGalleryEndpoint should have comment or be unexported
core/http/endpoints/localai/metrics.go:12:1: exported function LocalAIMetricsEndpoint should have comment or be unexported
core/http/endpoints/localai/metrics.go:12:6: func name will be used as localai.LocalAIMetricsEndpoint by other packages, and that stutters; consider calling this MetricsEndpoint
core/http/endpoints/localai/metrics.go:22:1: exported function LocalAIMetricsAPIMiddleware should have comment or be unexported
core/http/endpoints/localai/metrics.go:22:6: func name will be used as localai.LocalAIMetricsAPIMiddleware by other packages, and that stutters; consider calling this MetricsAPIMiddleware
core/http/endpoints/localai/stores.go:12:1: exported function StoresSetEndpoint should have comment or be unexported
core/http/endpoints/localai/stores.go:39:1: exported function StoresDeleteEndpoint should have comment or be unexported
core/http/endpoints/localai/stores.go:60:1: exported function StoresGetEndpoint should have comment or be unexported
core/http/endpoints/localai/stores.go:91:1: exported function StoresFindEndpoint should have comment or be unexported
core/http/endpoints/localai/welcome.go:13:1: exported function WelcomeEndpoint should have comment or be unexported
core/http/endpoints/localai/welcome.go:55:10: if block ends with a return statement, so drop this else and outdent its block
core/http/endpoints/openai/assistant.go:24:2: exported const CodeInterpreter should have comment (or a comment on this block) or be unexported
core/http/endpoints/openai/assistant.go:32:2: const MaxFileIdSize should be MaxFileIDSize
core/http/endpoints/openai/assistant.go:37:6: exported type Tool should have comment or be unexported
core/http/endpoints/openai/assistant.go:56:2: exported var Assistants should have comment or be unexported
core/http/endpoints/openai/assistant.go:60:6: exported type AssistantRequest should have comment or be unexported
core/http/endpoints/openai/assistant.go:121:5: var currentId should be currentID
core/http/endpoints/openai/assistant.go:128:1: exported function ListAssistantsEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:233:1: exported function DeleteAssistantEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:267:1: exported function GetAssistantEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:284:6: exported type AssistantFile should have comment or be unexported
core/http/endpoints/openai/assistant.go:292:2: exported var AssistantFiles should have comment or be unexported
core/http/endpoints/openai/assistant.go:296:6: exported type AssistantFileRequest should have comment or be unexported
core/http/endpoints/openai/assistant.go:300:6: exported type DeleteAssistantFileResponse should have comment or be unexported
core/http/endpoints/openai/assistant.go:306:1: exported function CreateAssistantFileEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:347:1: exported function ListAssistantFilesEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:409:1: exported function ModifyAssistantEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:448:1: exported function DeleteAssistantFileEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:451:3: var fileId should be fileID
core/http/endpoints/openai/assistant.go:458:12: range var fileId should be fileID
core/http/endpoints/openai/assistant.go:502:1: exported function GetAssistantFileEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:505:3: var fileId should be fileID
core/http/endpoints/openai/assistant_test.go:270:3: var modifiedArJson should be modifiedArJSON
core/http/endpoints/openai/assistant_test.go:377:68: func parameter assistantId should be assistantID
core/http/endpoints/openai/assistant_test.go:378:2: var afrJson should be afrJSON
core/http/endpoints/openai/assistant_test.go:444:57: func parameter fileId should be fileID
core/http/endpoints/openai/assistant_test.go:444:65: func parameter assistantId should be assistantID
core/http/endpoints/openai/edit.go:19:1: exported function EditEndpoint should have comment or be unexported
core/http/endpoints/openai/files.go:17:5: exported var UploadedFiles should have comment or be unexported
core/http/endpoints/openai/files.go:19:7: exported const UploadedFilesFile should have comment or be unexported
core/http/endpoints/openai/files.go:79:5: var currentFileId should be currentFileID
core/http/endpoints/openai/files.go:81:6: func getNextFileId should be getNextFileID
core/http/endpoints/openai/files.go:141:6: exported type DeleteStatus should have comment or be unexported
core/http/endpoints/openai/files.go:142:2: struct field Id should be ID
core/http/endpoints/openai/files_test.go:185:61: func parameter fileId should be fileID
core/http/endpoints/openai/files_test.go:229:60: func parameter fileId should be fileID
core/http/endpoints/openai/image.go:49:1: comment on exported function ImageEndpoint should be of the form "ImageEndpoint ..."
core/http/endpoints/openai/image.go:163:5: don't use underscores in Go names; var positive_prompt should be positivePrompt
core/http/endpoints/openai/image.go:164:5: don't use underscores in Go names; var negative_prompt should be negativePrompt
core/http/endpoints/openai/inference.go:11:1: exported function ComputeChoices should have comment or be unexported
core/http/routes/elevenlabs.go:10:1: exported function RegisterElevenLabsRoutes should have comment or be unexported
core/http/routes/jina.go:11:1: exported function RegisterJINARoutes should have comment or be unexported
core/http/routes/localai.go:14:1: exported function RegisterLocalAIRoutes should have comment or be unexported
core/http/routes/openai.go:11:1: exported function RegisterOpenAIRoutes should have comment or be unexported
core/http/routes/ui.go:24:1: exported function RegisterUIRoutes should have comment or be unexported
core/p2p/node.go:9:7: exported const FederatedID should have comment or be unexported
core/p2p/node.go:11:6: exported type NodeData should have comment or be unexported
core/p2p/node.go:18:1: exported method NodeData.IsOnline should have comment or be unexported
core/p2p/node.go:27:1: exported function GetAvailableNodes should have comment or be unexported
core/p2p/node.go:40:1: exported function AddNode should have comment or be unexported
core/p2p/p2p_disabled.go:13:1: exported function GenerateToken should have comment or be unexported
core/p2p/p2p_disabled.go:17:1: exported function ServiceDiscoverer should have comment or be unexported
core/p2p/p2p_disabled.go:21:1: exported function ExposeService should have comment or be unexported
core/p2p/p2p_disabled.go:25:1: exported function IsP2PEnabled should have comment or be unexported
core/p2p/p2p_disabled.go:29:1: exported function NewNode should have comment or be unexported
core/schema/elevenlabs.go:3:6: exported type ElevenLabsTTSRequest should have comment or be unexported
core/schema/jina.go:3:1: comment on exported type JINARerankRequest should be of the form "JINARerankRequest ..." (with optional leading article)
core/schema/jina.go:11:1: comment on exported type JINADocumentResult should be of the form "JINADocumentResult ..." (with optional leading article)
core/schema/jina.go:18:1: comment on exported type JINAText should be of the form "JINAText ..." (with optional leading article)
core/schema/jina.go:23:1: comment on exported type JINARerankResponse should be of the form "JINARerankResponse ..." (with optional leading article)
core/schema/jina.go:30:1: comment on exported type JINAUsageInfo should be of the form "JINAUsageInfo ..." (with optional leading article)
core/schema/localai.go:7:6: exported type BackendMonitorRequest should have comment or be unexported
core/schema/localai.go:11:6: exported type BackendMonitorResponse should have comment or be unexported
core/schema/localai.go:17:1: comment on exported type TTSRequest should be of the form "TTSRequest ..." (with optional leading article)
core/schema/localai.go:26:6: exported type StoresSet should have comment or be unexported
core/schema/localai.go:33:6: exported type StoresDelete should have comment or be unexported
core/schema/localai.go:39:6: exported type StoresGet should have comment or be unexported
core/schema/localai.go:45:6: exported type StoresGetResponse should have comment or be unexported
core/schema/localai.go:50:6: exported type StoresFind should have comment or be unexported
core/schema/localai.go:57:6: exported type StoresFindResponse should have comment or be unexported
core/schema/openai.go:17:6: exported type ErrorResponse should have comment or be unexported
core/schema/openai.go:21:6: exported type OpenAIUsage should have comment or be unexported
core/schema/openai.go:27:6: exported type Item should have comment or be unexported
core/schema/openai.go:37:6: exported type OpenAIResponse should have comment or be unexported
core/schema/openai.go:48:6: exported type Choice should have comment or be unexported
core/schema/openai.go:56:6: exported type Content should have comment or be unexported
core/schema/openai.go:62:6: exported type ContentURL should have comment or be unexported
core/schema/openai.go:66:6: exported type Message should have comment or be unexported
core/schema/openai.go:85:6: exported type ToolCall should have comment or be unexported
core/schema/openai.go:92:6: exported type FunctionCall should have comment or be unexported
core/schema/openai.go:97:6: exported type OpenAIModel should have comment or be unexported
core/schema/openai.go:102:6: exported type ImageGenerationResponseFormat should have comment or be unexported
core/schema/openai.go:104:6: exported type ChatCompletionResponseFormatType should have comment or be unexported
core/schema/openai.go:106:6: exported type ChatCompletionResponseFormat should have comment or be unexported
core/schema/openai.go:110:6: exported type OpenAIRequest should have comment or be unexported
core/schema/openai.go:159:6: exported type ModelsDataResponse should have comment or be unexported
core/schema/prediction.go:3:6: exported type PredictionOptions should have comment or be unexported
core/schema/transcription.go:5:6: exported type Segment should have comment or be unexported
core/schema/transcription.go:6:2: struct field Id should be ID
core/schema/transcription.go:13:6: exported type TranscriptionResult should have comment or be unexported
core/services/backend_monitor.go:18:6: exported type BackendMonitorService should have comment or be unexported
core/services/backend_monitor.go:24:1: exported function NewBackendMonitorService should have comment or be unexported
core/services/backend_monitor.go:34:6: var backendId should be backendID
core/services/backend_monitor.go:49:1: exported method BackendMonitorService.SampleLocalBackendProcess should have comment or be unexported
core/services/backend_monitor.go:104:1: exported method BackendMonitorService.CheckAndSample should have comment or be unexported
core/services/backend_monitor.go:105:2: var backendId should be backendID
core/services/backend_monitor.go:134:1: exported method BackendMonitorService.ShutdownModel should have comment or be unexported
core/services/backend_monitor.go:135:2: var backendId should be backendID
core/services/gallery.go:18:6: exported type GalleryService should have comment or be unexported
core/services/gallery.go:25:1: exported function NewGalleryService should have comment or be unexported
core/services/gallery.go:45:1: exported method GalleryService.UpdateStatus should have comment or be unexported
core/services/gallery.go:51:1: exported method GalleryService.GetStatus should have comment or be unexported
core/services/gallery.go:58:1: exported method GalleryService.GetAllStatus should have comment or be unexported
core/services/gallery.go:65:1: exported method GalleryService.Start should have comment or be unexported
core/services/gallery.go:193:1: exported function ApplyGalleryFromFile should have comment or be unexported
core/services/gallery.go:207:1: exported function ApplyGalleryFromString should have comment or be unexported
core/services/list_models.go:10:1: exported function ListModels should have comment or be unexported
core/services/metrics.go:13:6: exported type LocalAIMetricsService should have comment or be unexported
core/services/metrics.go:15:2: struct field ApiTimeMetric should be APITimeMetric
core/services/metrics.go:18:1: exported method LocalAIMetricsService.ObserveAPICall should have comment or be unexported
core/services/metrics.go:26:1: comment on exported function NewLocalAIMetricsService should be of the form "NewLocalAIMetricsService ..."
core/services/metrics.go:47:1: exported method LocalAIMetricsService.Shutdown should have comment or be unexported
core/services/metrics.go:47:1: receiver name lams should be consistent with previous receiver name m for LocalAIMetricsService
core/startup/config_file_watcher.go:130:6: func readApiKeysJson should be readAPIKeysJSON
core/startup/config_file_watcher.go:157:6: func readExternalBackendsJson should be readExternalBackendsJSON
core/startup/startup.go:19:1: exported function Startup should have comment or be unexported
embedded/embedded.go:24:1: exported function ModelShortURL should have comment or be unexported
embedded/embedded.go:39:1: exported function GetRemoteLibraryShorteners should have comment or be unexported
examples/semantic-todo/main.go:21:6: exported type Task should have comment or be unexported
examples/semantic-todo/main.go:26:6: exported type AppState should have comment or be unexported
examples/semantic-todo/main.go:29:2: exported const StateRoot should have comment (or a comment on this block) or be unexported
examples/semantic-todo/main.go:34:6: exported type App should have comment or be unexported
examples/semantic-todo/main.go:42:1: exported function NewApp should have comment or be unexported
examples/semantic-todo/main.go:95:6: exported type StoresSet should have comment or be unexported
examples/semantic-todo/main.go:151:6: exported type StoresFind should have comment or be unexported
examples/semantic-todo/main.go:158:6: exported type StoresFindResponse should have comment or be unexported
internal/version.go:5:5: exported var Version should have comment or be unexported
internal/version.go:6:5: exported var Commit should have comment or be unexported
internal/version.go:8:1: exported function PrintableVersion should have comment or be unexported
pkg/assets/extract.go:13:1: exported function ResolvePath should have comment or be unexported
pkg/assets/extract.go:17:1: exported function ExtractFiles should have comment or be unexported
pkg/assets/list.go:10:1: exported function ListFiles should have comment or be unexported
pkg/downloader/uri.go:24:2: exported const HuggingFacePrefix should have comment (or a comment on this block) or be unexported
pkg/downloader/uri.go:33:1: exported function DownloadAndUnmarshal should have comment or be unexported
pkg/downloader/uri.go:81:1: exported function LooksLikeURL should have comment or be unexported
pkg/downloader/uri.go:91:1: exported function LooksLikeOCI should have comment or be unexported
pkg/downloader/uri.go:95:1: exported function ConvertURL should have comment or be unexported
pkg/downloader/uri.go:164:1: exported function DownloadFile should have comment or be unexported
pkg/downloader/uri.go:301:1: comment on exported function GetBase64Image should be of the form "GetBase64Image ..."
pkg/downloader/uri.go:360:6: exported type HuggingFaceScanResult should have comment or be unexported
pkg/downloader/uri.go:361:2: struct field RepositoryId should be RepositoryID
pkg/downloader/uri.go:369:5: exported var ErrNonHuggingFaceFile should have comment or be unexported
pkg/downloader/uri.go:370:5: exported var ErrUnsafeFilesFound should have comment or be unexported
pkg/downloader/uri.go:372:1: exported function HuggingFaceScan should have comment or be unexported
pkg/functions/functions.go:9:6: exported type Function should have comment or be unexported
pkg/functions/functions.go:14:6: exported type Functions should have comment or be unexported
pkg/functions/functions.go:16:6: exported type Tool should have comment or be unexported
pkg/functions/functions.go:20:6: exported type Tools should have comment or be unexported
pkg/functions/grammar_json_schema.go:16:2: exported const JSONBNF should have comment (or a comment on this block) or be unexported
pkg/functions/grammar_json_schema.go:43:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:43:2: exported var SPACE_RULE should have comment or be unexported
pkg/functions/grammar_json_schema.go:45:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:63:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:64:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:65:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:72:6: exported type JSONSchemaConverter should have comment or be unexported
pkg/functions/grammar_json_schema.go:77:1: exported function NewJSONSchemaConverter should have comment or be unexported
pkg/functions/grammar_json_schema.go:334:1: exported method JSONSchemaConverter.Grammar should have comment or be unexported
pkg/functions/grammar_json_schema.go:340:1: exported method JSONSchemaConverter.GrammarFromBytes should have comment or be unexported
pkg/functions/grammar_json_schema.go:351:6: exported type FunctionName should have comment or be unexported
pkg/functions/grammar_json_schema.go:355:6: exported type FunctionProperties should have comment or be unexported
pkg/functions/grammar_json_schema.go:360:6: exported type NameProperties should have comment or be unexported
pkg/functions/grammar_json_schema.go:365:6: exported type Argument should have comment or be unexported
pkg/functions/grammar_json_schema.go:370:6: exported type ItemName should have comment or be unexported
pkg/functions/grammar_json_schema.go:375:6: exported type ItemFunction should have comment or be unexported
pkg/functions/grammar_json_schema.go:380:6: exported type JSONFunctionStructureName should have comment or be unexported
pkg/functions/grammar_json_schema.go:386:1: exported method JSONFunctionStructureName.Grammar should have comment or be unexported
pkg/functions/grammar_json_schema.go:394:6: exported type JSONFunctionStructureFunction should have comment or be unexported
pkg/functions/grammar_json_schema.go:400:1: exported method JSONFunctionStructureFunction.Grammar should have comment or be unexported
pkg/functions/options.go:3:6: exported type GrammarOption should have comment or be unexported
pkg/functions/options.go:13:1: exported method GrammarOption.Apply should have comment or be unexported
pkg/functions/options.go:19:5: exported var EnableMaybeArray should have comment or be unexported
pkg/functions/options.go:23:5: exported var DisableParallelNewLines should have comment or be unexported
pkg/functions/options.go:27:5: exported var EnableMaybeString should have comment or be unexported
pkg/functions/options.go:31:5: exported var NoMixedFreeString should have comment or be unexported
pkg/functions/options.go:40:1: exported function SetPrefix should have comment or be unexported
pkg/functions/options.go:46:1: exported function SetPropOrder should have comment or be unexported
pkg/functions/parse.go:12:6: exported type GrammarConfig should have comment or be unexported
pkg/functions/parse.go:45:6: type name will be used as functions.FunctionsConfig by other packages, and that stutters; consider calling this Config
pkg/functions/parse.go:82:6: exported type ReplaceResult should have comment or be unexported
pkg/functions/parse.go:87:6: exported type FuncCallResults should have comment or be unexported
pkg/functions/parse.go:92:1: exported method GrammarConfig.Options should have comment or be unexported
pkg/functions/parse.go:117:1: exported function CleanupLLMResult should have comment or be unexported
pkg/functions/parse.go:131:1: exported function ParseTextContent should have comment or be unexported
pkg/functions/parse.go:148:1: exported function ParseFunctionCall should have comment or be unexported
pkg/functions/parse.go:192:5: don't use underscores in Go names; var func_name should be funcName
pkg/grpc/backend.go:13:1: exported function Provide should have comment or be unexported
pkg/grpc/backend.go:17:1: exported function NewClient should have comment or be unexported
pkg/grpc/backend.go:24:1: exported function NewGrpcClient should have comment or be unexported
pkg/grpc/backend.go:35:6: exported type Backend should have comment or be unexported
pkg/grpc/client.go:16:6: exported type Client should have comment or be unexported
pkg/grpc/client.go:25:6: exported type WatchDog should have comment or be unexported
pkg/grpc/client.go:30:1: exported method Client.IsBusy should have comment or be unexported
pkg/grpc/client.go:42:1: exported method Client.HealthCheck should have comment or be unexported
pkg/grpc/client.go:72:1: exported method Client.Embeddings should have comment or be unexported
pkg/grpc/client.go:93:1: exported method Client.Predict should have comment or be unexported
pkg/grpc/client.go:114:1: exported method Client.LoadModel should have comment or be unexported
pkg/grpc/client.go:134:1: exported method Client.PredictStream should have comment or be unexported
pkg/grpc/client.go:173:1: exported method Client.GenerateImage should have comment or be unexported
pkg/grpc/client.go:193:1: exported method Client.TTS should have comment or be unexported
pkg/grpc/client.go:213:1: exported method Client.AudioTranscription should have comment or be unexported
pkg/grpc/client.go:253:1: exported method Client.TokenizeString should have comment or be unexported
pkg/grpc/client.go:279:1: exported method Client.Status should have comment or be unexported
pkg/grpc/client.go:295:1: exported method Client.StoresSet should have comment or be unexported
pkg/grpc/client.go:311:1: exported method Client.StoresDelete should have comment or be unexported
pkg/grpc/client.go:327:1: exported method Client.StoresGet should have comment or be unexported
pkg/grpc/client.go:343:1: exported method Client.StoresFind should have comment or be unexported
pkg/grpc/client.go:359:1: exported method Client.Rerank should have comment or be unexported
pkg/grpc/interface.go:8:6: exported type LLM should have comment or be unexported
pkg/grpc/server.go:218:1: exported function StartServer should have comment or be unexported
pkg/grpc/server.go:233:1: exported function RunServer should have comment or be unexported
pkg/grpc/base/base.go:20:1: exported method Base.Locking should have comment or be unexported
pkg/grpc/base/base.go:24:1: exported method Base.Lock should have comment or be unexported
pkg/grpc/base/base.go:28:1: exported method Base.Unlock should have comment or be unexported
pkg/grpc/base/base.go:32:1: exported method Base.Busy should have comment or be unexported
pkg/grpc/base/base.go:36:1: exported method Base.Load should have comment or be unexported
pkg/grpc/base/base.go:40:1: exported method Base.Predict should have comment or be unexported
pkg/grpc/base/base.go:44:1: exported method Base.PredictStream should have comment or be unexported
pkg/grpc/base/base.go:48:1: exported method Base.Embeddings should have comment or be unexported
pkg/grpc/base/base.go:52:1: exported method Base.GenerateImage should have comment or be unexported
pkg/grpc/base/base.go:56:1: exported method Base.AudioTranscription should have comment or be unexported
pkg/grpc/base/base.go:60:1: exported method Base.TTS should have comment or be unexported
pkg/grpc/base/base.go:64:1: exported method Base.TokenizeString should have comment or be unexported
pkg/grpc/base/base.go:68:1: comment on exported method Base.Status should be of the form "Status ..."
pkg/grpc/base/base.go:75:1: exported method Base.StoresSet should have comment or be unexported
pkg/grpc/base/base.go:79:1: exported method Base.StoresGet should have comment or be unexported
pkg/grpc/base/base.go:83:1: exported method Base.StoresDelete should have comment or be unexported
pkg/grpc/base/base.go:87:1: exported method Base.StoresFind should have comment or be unexported
pkg/grpc/base/singlethread.go:23:1: exported method SingleThread.Lock should have comment or be unexported
pkg/grpc/base/singlethread.go:27:1: exported method SingleThread.Unlock should have comment or be unexported
pkg/grpc/base/singlethread.go:31:1: exported method SingleThread.Busy should have comment or be unexported
pkg/grpc/base/singlethread.go:39:1: comment on exported method SingleThread.Status should be of the form "Status ..."
pkg/langchain/huggingface.go:11:6: exported type HuggingFace should have comment or be unexported
pkg/langchain/huggingface.go:16:1: exported function NewHuggingFace should have comment or be unexported
pkg/langchain/huggingface.go:16:21: func parameter repoId should be repoID
pkg/langchain/huggingface.go:26:1: exported method HuggingFace.PredictHuggingFace should have comment or be unexported
pkg/langchain/langchain.go:3:6: exported type PredictOptions should have comment or be unexported
pkg/langchain/langchain.go:13:6: exported type PredictOption should have comment or be unexported
pkg/langchain/langchain.go:15:5: exported var DefaultOptions should have comment or be unexported
pkg/langchain/langchain.go:22:6: exported type Predict should have comment or be unexported
pkg/langchain/langchain.go:26:1: exported function SetModel should have comment or be unexported
pkg/langchain/langchain.go:32:1: exported function SetTemperature should have comment or be unexported
pkg/langchain/langchain.go:38:1: exported function SetMaxTokens should have comment or be unexported
pkg/langchain/langchain.go:44:1: exported function SetStopWords should have comment or be unexported
pkg/model/initializers.go:24:5: exported var Aliases should have comment or be unexported
pkg/model/initializers.go:34:2: exported const LlamaGGML should have comment (or a comment on this block) or be unexported
pkg/model/initializers.go:407:1: exported method ModelLoader.BackendLoader should have comment or be unexported
pkg/model/initializers.go:455:1: exported method ModelLoader.GreedyLoader should have comment or be unexported
pkg/model/initializers.go:549:11: if block ends with a return statement, so drop this else and outdent its block
pkg/model/loader.go:21:1: comment on exported type PromptTemplateData should be of the form "PromptTemplateData ..." (with optional leading article)
pkg/model/loader.go:33:6: exported type ChatMessageTemplateData should have comment or be unexported
pkg/model/loader.go:47:1: comment on exported type ModelLoader should be of the form "ModelLoader ..." (with optional leading article)
pkg/model/loader.go:48:6: type name will be used as model.ModelLoader by other packages, and that stutters; consider calling this Loader
pkg/model/loader.go:59:6: exported type ModelAddress should have comment or be unexported
pkg/model/loader.go:59:6: type name will be used as model.ModelAddress by other packages, and that stutters; consider calling this Address
pkg/model/loader.go:61:1: exported method ModelAddress.GRPC should have comment or be unexported
pkg/model/loader.go:69:1: exported function NewModelLoader should have comment or be unexported
pkg/model/loader.go:81:1: exported method ModelLoader.SetWatchDog should have comment or be unexported
pkg/model/loader.go:85:1: exported method ModelLoader.ExistsInModelPath should have comment or be unexported
pkg/model/loader.go:107:1: exported method ModelLoader.ListFilesInModelPath should have comment or be unexported
pkg/model/loader.go:141:1: exported method ModelLoader.LoadModel should have comment or be unexported
pkg/model/loader.go:171:1: exported method ModelLoader.ShutdownModel should have comment or be unexported
pkg/model/loader.go:187:1: exported method ModelLoader.CheckIsLoaded should have comment or be unexported
pkg/model/loader.go:218:2: exported const ChatPromptTemplate should have comment (or a comment on this block) or be unexported
pkg/model/loader.go:225:1: exported method ModelLoader.EvaluateTemplateForPrompt should have comment or be unexported
pkg/model/loader.go:233:1: exported method ModelLoader.EvaluateTemplateForChatMessage should have comment or be unexported
pkg/model/options.go:9:6: exported type Options should have comment or be unexported
pkg/model/options.go:26:6: exported type Option should have comment or be unexported
pkg/model/options.go:28:5: exported var EnableParallelRequests should have comment or be unexported
pkg/model/options.go:32:1: exported function WithExternalBackend should have comment or be unexported
pkg/model/options.go:41:1: exported function WithGRPCAttempts should have comment or be unexported
pkg/model/options.go:47:1: exported function WithGRPCAttemptsDelay should have comment or be unexported
pkg/model/options.go:53:1: exported function WithBackendString should have comment or be unexported
pkg/model/options.go:59:1: exported function WithModel should have comment or be unexported
pkg/model/options.go:65:1: exported function WithLoadGRPCLoadModelOpts should have comment or be unexported
pkg/model/options.go:71:1: exported function WithThreads should have comment or be unexported
pkg/model/options.go:77:1: exported function WithAssetDir should have comment or be unexported
pkg/model/options.go:83:1: exported function WithContext should have comment or be unexported
pkg/model/options.go:89:1: exported function WithSingleActiveBackend should have comment or be unexported
pkg/model/options.go:95:1: exported function NewOptions should have comment or be unexported
pkg/model/process.go:18:1: exported method ModelLoader.StopAllExcept should have comment or be unexported
pkg/model/process.go:43:6: exported type GRPCProcessFilter should have comment or be unexported
pkg/model/process.go:49:1: exported method ModelLoader.StopGRPC should have comment or be unexported
pkg/model/process.go:60:1: exported method ModelLoader.StopAllGRPC should have comment or be unexported
pkg/model/process.go:64:1: exported method ModelLoader.GetGRPCPID should have comment or be unexported
pkg/model/watchdog.go:19:6: exported type WatchDog should have comment or be unexported
pkg/model/watchdog.go:32:6: exported type ProcessManager should have comment or be unexported
pkg/model/watchdog.go:36:1: exported function NewWatchDog should have comment or be unexported
pkg/model/watchdog.go:50:1: exported method WatchDog.Shutdown should have comment or be unexported
pkg/model/watchdog.go:56:1: exported method WatchDog.AddAddressModelMap should have comment or be unexported
pkg/model/watchdog.go:62:1: exported method WatchDog.Add should have comment or be unexported
pkg/model/watchdog.go:68:1: exported method WatchDog.Mark should have comment or be unexported
pkg/model/watchdog.go:75:1: exported method WatchDog.UnMark should have comment or be unexported
pkg/model/watchdog.go:82:1: exported method WatchDog.Run should have comment or be unexported
pkg/oci/blob.go:15:1: exported function FetchImageBlob should have comment or be unexported
pkg/oci/image.go:71:1: exported function ParseImageParts should have comment or be unexported
pkg/oci/image.go:137:1: exported function GetOCIImageSize should have comment or be unexported
pkg/oci/ollama.go:12:1: comment on exported type Manifest should be of the form "Manifest ..." (with optional leading article)
pkg/oci/ollama.go:20:1: comment on exported type Config should be of the form "Config ..." (with optional leading article)
pkg/oci/ollama.go:27:1: comment on exported type LayerDetail should be of the form "LayerDetail ..." (with optional leading article)
pkg/oci/ollama.go:34:1: exported function OllamaModelManifest should have comment or be unexported
pkg/oci/ollama.go:63:1: exported function OllamaModelBlob should have comment or be unexported
pkg/oci/ollama.go:79:1: exported function OllamaFetchModel should have comment or be unexported
pkg/stablediffusion/generate_unsupported.go:8:1: exported function GenerateImage should have comment or be unexported
pkg/stablediffusion/generate_unsupported.go:8:57: don't use underscores in Go names; func parameter positive_prompt should be positivePrompt
pkg/stablediffusion/generate_unsupported.go:8:74: don't use underscores in Go names; func parameter negative_prompt should be negativePrompt
pkg/stablediffusion/generate_unsupported.go:8:96: don't use underscores in Go names; func parameter asset_dir should be assetDir
pkg/stablediffusion/stablediffusion.go:5:6: exported type StableDiffusion should have comment or be unexported
pkg/stablediffusion/stablediffusion.go:9:1: exported function New should have comment or be unexported
pkg/stablediffusion/stablediffusion.go:18:1: exported method StableDiffusion.GenerateImage should have comment or be unexported
pkg/stablediffusion/stablediffusion.go:18:78: don't use underscores in Go names; method parameter positive_prompt should be positivePrompt
pkg/stablediffusion/stablediffusion.go:18:95: don't use underscores in Go names; method parameter negative_prompt should be negativePrompt
pkg/startup/model_preload.go:147:1: error should be the last type when returning multiple items
pkg/startup/model_preload.go:171:6: func filenameFromUrl should be filenameFromURL
pkg/templates/cache.go:16:1: comment on exported type TemplateType should be of the form "TemplateType ..." (with optional leading article)
pkg/templates/cache.go:20:6: exported type TemplateCache should have comment or be unexported
pkg/templates/cache.go:26:1: exported function NewTemplateCache should have comment or be unexported
pkg/templates/cache.go:40:1: exported method TemplateCache.EvaluateTemplate should have comment or be unexported
pkg/tinydream/generate_unsupported.go:8:1: exported function GenerateImage should have comment or be unexported
pkg/tinydream/generate_unsupported.go:8:51: don't use underscores in Go names; func parameter positive_prompt should be positivePrompt
pkg/tinydream/generate_unsupported.go:8:68: don't use underscores in Go names; func parameter negative_prompt should be negativePrompt
pkg/tinydream/generate_unsupported.go:8:90: don't use underscores in Go names; func parameter asset_dir should be assetDir
pkg/tinydream/tinydream.go:5:6: exported type TinyDream should have comment or be unexported
pkg/tinydream/tinydream.go:9:1: exported function New should have comment or be unexported
pkg/tinydream/tinydream.go:18:1: exported method TinyDream.GenerateImage should have comment or be unexported
pkg/tinydream/tinydream.go:18:67: don't use underscores in Go names; method parameter positive_prompt should be positivePrompt
pkg/tinydream/tinydream.go:18:84: don't use underscores in Go names; method parameter negative_prompt should be negativePrompt
pkg/utils/base64.go:19:1: comment on exported function GetImageURLAsBase64 should be of the form "GetImageURLAsBase64 ..."
pkg/utils/config.go:11:1: exported function SaveConfig should have comment or be unexported
pkg/utils/config.go:24:1: exported function LoadConfig should have comment or be unexported
pkg/utils/hash.go:8:1: exported function MD5 should have comment or be unexported
pkg/utils/json.go:9:1: exported function EscapeNewLines should have comment or be unexported
pkg/utils/logging.go:12:1: exported function ResetDownloadTimers should have comment or be unexported
pkg/utils/logging.go:17:1: exported function DisplayDownloadFunction should have comment or be unexported
pkg/utils/path.go:10:1: exported function ExistsInPath should have comment or be unexported
pkg/utils/path.go:15:1: exported function InTrustedRoot should have comment or be unexported
pkg/utils/strings.go:14:1: exported function RandString should have comment or be unexported
pkg/utils/untar.go:10:1: exported function IsArchive should have comment or be unexported
pkg/utils/untar.go:20:1: exported function ExtractArchive should have comment or be unexported
pkg/xsync/map.go:7:6: exported type SyncedMap should have comment or be unexported
pkg/xsync/map.go:12:1: exported function NewSyncedMap should have comment or be unexported
pkg/xsysinfo/cpu.go:10:1: exported function CPUCapabilities should have comment or be unexported
pkg/xsysinfo/cpu.go:36:1: exported function HasCPUCaps should have comment or be unexported
pkg/xsysinfo/cpu.go:40:1: exported function CPUPhysicalCores should have comment or be unexported
pkg/xsysinfo/gpu.go:8:1: exported function GPUs should have comment or be unexported

Copy link

⚠ goimports failed (.)

core/application.go
-package core
-
-import (
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/services"
-	"github.com/mudler/LocalAI/pkg/model"
-)
-
-// The purpose of this structure is to hold pointers to all initialized services, to make plumbing easy
-// Perhaps a proper DI system is worth it in the future, but for now keep things simple.
-type Application struct {
-
-	// Application-Level Config
-	ApplicationConfig *config.ApplicationConfig
-	// ApplicationState *ApplicationState
-
-	// Core Low-Level Services
-	BackendConfigLoader *config.BackendConfigLoader
-	ModelLoader         *model.ModelLoader
-
-	// Backend Services
-	// EmbeddingsBackendService      *backend.EmbeddingsBackendService
-	// ImageGenerationBackendService *backend.ImageGenerationBackendService
-	// LLMBackendService             *backend.LLMBackendService
-	// TranscriptionBackendService *backend.TranscriptionBackendService
-	// TextToSpeechBackendService  *backend.TextToSpeechBackendService
-
-	// LocalAI System Services
-	BackendMonitorService *services.BackendMonitorService
-	GalleryService        *services.GalleryService
-	LocalAIMetricsService *services.LocalAIMetricsService
-	// OpenAIService         *services.OpenAIService
-}
-
-// TODO [NEXT PR?]: Break up ApplicationConfig.
-// Migrate over stuff that is not set via config at all - especially runtime stuff
-type ApplicationState struct {
-}
+package core
+
+import (
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/services"
+	"github.com/mudler/LocalAI/pkg/model"
+)
+
+// The purpose of this structure is to hold pointers to all initialized services, to make plumbing easy
+// Perhaps a proper DI system is worth it in the future, but for now keep things simple.
+type Application struct {
+
+	// Application-Level Config
+	ApplicationConfig *config.ApplicationConfig
+	// ApplicationState *ApplicationState
+
+	// Core Low-Level Services
+	BackendConfigLoader *config.BackendConfigLoader
+	ModelLoader         *model.ModelLoader
+
+	// Backend Services
+	// EmbeddingsBackendService      *backend.EmbeddingsBackendService
+	// ImageGenerationBackendService *backend.ImageGenerationBackendService
+	// LLMBackendService             *backend.LLMBackendService
+	// TranscriptionBackendService *backend.TranscriptionBackendService
+	// TextToSpeechBackendService  *backend.TextToSpeechBackendService
+
+	// LocalAI System Services
+	BackendMonitorService *services.BackendMonitorService
+	GalleryService        *services.GalleryService
+	LocalAIMetricsService *services.LocalAIMetricsService
+	// OpenAIService         *services.OpenAIService
+}
+
+// TODO [NEXT PR?]: Break up ApplicationConfig.
+// Migrate over stuff that is not set via config at all - especially runtime stuff
+type ApplicationState struct {
+}
core/backend/stores.go
 )
 
 func StoreBackend(sl *model.ModelLoader, appConfig *config.ApplicationConfig, storeName string) (grpc.Backend, error) {
-    if storeName == "" {
-      storeName = "default"
-    }
+	if storeName == "" {
+		storeName = "default"
+	}
 
-    sc := []model.Option{
-      model.WithBackendString(model.LocalStoreBackend),
-      model.WithAssetDir(appConfig.AssetsDestination),
-      model.WithModel(storeName),
-    }
+	sc := []model.Option{
+		model.WithBackendString(model.LocalStoreBackend),
+		model.WithAssetDir(appConfig.AssetsDestination),
+		model.WithModel(storeName),
+	}
 
-    return sl.BackendLoader(sc...)
+	return sl.BackendLoader(sc...)
 }
-
core/backend/tts.go
 	backend,
 	text,
 	modelFile,
-	voice ,
+	voice,
 	language string,
 	loader *model.ModelLoader,
 	appConfig *config.ApplicationConfig,
core/config/backend_config_loader.go
-package config
-
-import (
-	"errors"
-	"fmt"
-	"io/fs"
-	"os"
-	"path/filepath"
-	"sort"
-	"strings"
-	"sync"
-
-	"github.com/charmbracelet/glamour"
-	"github.com/mudler/LocalAI/core/schema"
-	"github.com/mudler/LocalAI/pkg/downloader"
-	"github.com/mudler/LocalAI/pkg/utils"
-	"github.com/rs/zerolog/log"
-	"gopkg.in/yaml.v3"
-)
-
-type BackendConfigLoader struct {
-	configs   map[string]BackendConfig
-	modelPath string
-	sync.Mutex
-}
-
-func NewBackendConfigLoader(modelPath string) *BackendConfigLoader {
-	return &BackendConfigLoader{
-		configs:   make(map[string]BackendConfig),
-		modelPath: modelPath,
-	}
-}
-
-type LoadOptions struct {
-	modelPath        string
-	debug            bool
-	threads, ctxSize int
-	f16              bool
-}
-
-func LoadOptionDebug(debug bool) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.debug = debug
-	}
-}
-
-func LoadOptionThreads(threads int) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.threads = threads
-	}
-}
-
-func LoadOptionContextSize(ctxSize int) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.ctxSize = ctxSize
-	}
-}
-
-func ModelPath(modelPath string) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.modelPath = modelPath
-	}
-}
-
-func LoadOptionF16(f16 bool) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.f16 = f16
-	}
-}
-
-type ConfigLoaderOption func(*LoadOptions)
-
-func (lo *LoadOptions) Apply(options ...ConfigLoaderOption) {
-	for _, l := range options {
-		l(lo)
-	}
-}
-
-// TODO: either in the next PR or the next commit, I want to merge these down into a single function that looks at the first few characters of the file to determine if we need to deserialize to []BackendConfig or BackendConfig
-func readMultipleBackendConfigsFromFile(file string, opts ...ConfigLoaderOption) ([]*BackendConfig, error) {
-	c := &[]*BackendConfig{}
-	f, err := os.ReadFile(file)
-	if err != nil {
-		return nil, fmt.Errorf("cannot read config file: %w", err)
-	}
-	if err := yaml.Unmarshal(f, c); err != nil {
-		return nil, fmt.Errorf("cannot unmarshal config file: %w", err)
-	}
-
-	for _, cc := range *c {
-		cc.SetDefaults(opts...)
-	}
-
-	return *c, nil
-}
-
-func readBackendConfigFromFile(file string, opts ...ConfigLoaderOption) (*BackendConfig, error) {
-	lo := &LoadOptions{}
-	lo.Apply(opts...)
-
-	c := &BackendConfig{}
-	f, err := os.ReadFile(file)
-	if err != nil {
-		return nil, fmt.Errorf("cannot read config file: %w", err)
-	}
-	if err := yaml.Unmarshal(f, c); err != nil {
-		return nil, fmt.Errorf("cannot unmarshal config file: %w", err)
-	}
-
-	c.SetDefaults(opts...)
-	return c, nil
-}
-
-// Load a config file for a model
-func (bcl *BackendConfigLoader) LoadBackendConfigFileByName(modelName, modelPath string, opts ...ConfigLoaderOption) (*BackendConfig, error) {
-
-	// Load a config file if present after the model name
-	cfg := &BackendConfig{
-		PredictionOptions: schema.PredictionOptions{
-			Model: modelName,
-		},
-	}
-
-	cfgExisting, exists := bcl.GetBackendConfig(modelName)
-	if exists {
-		cfg = &cfgExisting
-	} else {
-		// Try loading a model config file
-		modelConfig := filepath.Join(modelPath, modelName+".yaml")
-		if _, err := os.Stat(modelConfig); err == nil {
-			if err := bcl.LoadBackendConfig(
-				modelConfig, opts...,
-			); err != nil {
-				return nil, fmt.Errorf("failed loading model config (%s) %s", modelConfig, err.Error())
-			}
-			cfgExisting, exists = bcl.GetBackendConfig(modelName)
-			if exists {
-				cfg = &cfgExisting
-			}
-		}
-	}
-
-	cfg.SetDefaults(opts...)
-
-	return cfg, nil
-}
-
-// This format is currently only used when reading a single file at startup, passed in via ApplicationConfig.ConfigFile
-func (bcl *BackendConfigLoader) LoadMultipleBackendConfigsSingleFile(file string, opts ...ConfigLoaderOption) error {
-	bcl.Lock()
-	defer bcl.Unlock()
-	c, err := readMultipleBackendConfigsFromFile(file, opts...)
-	if err != nil {
-		return fmt.Errorf("cannot load config file: %w", err)
-	}
-
-	for _, cc := range c {
-		if cc.Validate() {
-			bcl.configs[cc.Name] = *cc
-		}
-	}
-	return nil
-}
-
-func (bcl *BackendConfigLoader) LoadBackendConfig(file string, opts ...ConfigLoaderOption) error {
-	bcl.Lock()
-	defer bcl.Unlock()
-	c, err := readBackendConfigFromFile(file, opts...)
-	if err != nil {
-		return fmt.Errorf("cannot read config file: %w", err)
-	}
-
-	if c.Validate() {
-		bcl.configs[c.Name] = *c
-	} else {
-		return fmt.Errorf("config is not valid")
-	}
-
-	return nil
-}
-
-func (bcl *BackendConfigLoader) GetBackendConfig(m string) (BackendConfig, bool) {
-	bcl.Lock()
-	defer bcl.Unlock()
-	v, exists := bcl.configs[m]
-	return v, exists
-}
-
-func (bcl *BackendConfigLoader) GetAllBackendConfigs() []BackendConfig {
-	bcl.Lock()
-	defer bcl.Unlock()
-	var res []BackendConfig
-	for _, v := range bcl.configs {
-		res = append(res, v)
-	}
-
-	sort.SliceStable(res, func(i, j int) bool {
-		return res[i].Name < res[j].Name
-	})
-
-	return res
-}
-
-func (bcl *BackendConfigLoader) RemoveBackendConfig(m string) {
-	bcl.Lock()
-	defer bcl.Unlock()
-	delete(bcl.configs, m)
-}
-
-// Preload prepare models if they are not local but url or huggingface repositories
-func (bcl *BackendConfigLoader) Preload(modelPath string) error {
-	bcl.Lock()
-	defer bcl.Unlock()
-
-	status := func(fileName, current, total string, percent float64) {
-		utils.DisplayDownloadFunction(fileName, current, total, percent)
-	}
-
-	log.Info().Msgf("Preloading models from %s", modelPath)
-
-	renderMode := "dark"
-	if os.Getenv("COLOR") != "" {
-		renderMode = os.Getenv("COLOR")
-	}
-
-	glamText := func(t string) {
-		out, err := glamour.Render(t, renderMode)
-		if err == nil && os.Getenv("NO_COLOR") == "" {
-			fmt.Println(out)
-		} else {
-			fmt.Println(t)
-		}
-	}
-
-	for i, config := range bcl.configs {
-
-		// Download files and verify their SHA
-		for i, file := range config.DownloadFiles {
-			log.Debug().Msgf("Checking %q exists and matches SHA", file.Filename)
-
-			if err := utils.VerifyPath(file.Filename, modelPath); err != nil {
-				return err
-			}
-			// Create file path
-			filePath := filepath.Join(modelPath, file.Filename)
-
-			if err := downloader.DownloadFile(file.URI, filePath, file.SHA256, i, len(config.DownloadFiles), status); err != nil {
-				return err
-			}
-		}
-
-		// If the model is an URL, expand it, and download the file
-		if config.IsModelURL() {
-			modelFileName := config.ModelFileName()
-			modelURL := downloader.ConvertURL(config.Model)
-			// check if file exists
-			if _, err := os.Stat(filepath.Join(modelPath, modelFileName)); errors.Is(err, os.ErrNotExist) {
-				err := downloader.DownloadFile(modelURL, filepath.Join(modelPath, modelFileName), "", 0, 0, status)
-				if err != nil {
-					return err
-				}
-			}
-
-			cc := bcl.configs[i]
-			c := &cc
-			c.PredictionOptions.Model = modelFileName
-			bcl.configs[i] = *c
-		}
-
-		if config.IsMMProjURL() {
-			modelFileName := config.MMProjFileName()
-			modelURL := downloader.ConvertURL(config.MMProj)
-			// check if file exists
-			if _, err := os.Stat(filepath.Join(modelPath, modelFileName)); errors.Is(err, os.ErrNotExist) {
-				err := downloader.DownloadFile(modelURL, filepath.Join(modelPath, modelFileName), "", 0, 0, status)
-				if err != nil {
-					return err
-				}
-			}
-
-			cc := bcl.configs[i]
-			c := &cc
-			c.MMProj = modelFileName
-			bcl.configs[i] = *c
-		}
-
-		if bcl.configs[i].Name != "" {
-			glamText(fmt.Sprintf("**Model name**: _%s_", bcl.configs[i].Name))
-		}
-		if bcl.configs[i].Description != "" {
-			//glamText("**Description**")
-			glamText(bcl.configs[i].Description)
-		}
-		if bcl.configs[i].Usage != "" {
-			//glamText("**Usage**")
-			glamText(bcl.configs[i].Usage)
-		}
-	}
-	return nil
-}
-
-// LoadBackendConfigsFromPath reads all the configurations of the models from a path
-// (non-recursive)
-func (bcl *BackendConfigLoader) LoadBackendConfigsFromPath(path string, opts ...ConfigLoaderOption) error {
-	bcl.Lock()
-	defer bcl.Unlock()
-	entries, err := os.ReadDir(path)
-	if err != nil {
-		return fmt.Errorf("cannot read directory '%s': %w", path, err)
-	}
-	files := make([]fs.FileInfo, 0, len(entries))
-	for _, entry := range entries {
-		info, err := entry.Info()
-		if err != nil {
-			return err
-		}
-		files = append(files, info)
-	}
-	for _, file := range files {
-		// Skip templates, YAML and .keep files
-		if !strings.Contains(file.Name(), ".yaml") && !strings.Contains(file.Name(), ".yml") ||
-			strings.HasPrefix(file.Name(), ".") {
-			continue
-		}
-		c, err := readBackendConfigFromFile(filepath.Join(path, file.Name()), opts...)
-		if err != nil {
-			log.Error().Err(err).Msgf("cannot read config file: %s", file.Name())
-			continue
-		}
-		if c.Validate() {
-			bcl.configs[c.Name] = *c
-		} else {
-			log.Error().Err(err).Msgf("config is not valid")
-		}
-	}
-
-	return nil
-}
+package config
+
+import (
+	"errors"
+	"fmt"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+	"sync"
+
+	"github.com/charmbracelet/glamour"
+	"github.com/mudler/LocalAI/core/schema"
+	"github.com/mudler/LocalAI/pkg/downloader"
+	"github.com/mudler/LocalAI/pkg/utils"
+	"github.com/rs/zerolog/log"
+	"gopkg.in/yaml.v3"
+)
+
+type BackendConfigLoader struct {
+	configs   map[string]BackendConfig
+	modelPath string
+	sync.Mutex
+}
+
+func NewBackendConfigLoader(modelPath string) *BackendConfigLoader {
+	return &BackendConfigLoader{
+		configs:   make(map[string]BackendConfig),
+		modelPath: modelPath,
+	}
+}
+
+type LoadOptions struct {
+	modelPath        string
+	debug            bool
+	threads, ctxSize int
+	f16              bool
+}
+
+func LoadOptionDebug(debug bool) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.debug = debug
+	}
+}
+
+func LoadOptionThreads(threads int) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.threads = threads
+	}
+}
+
+func LoadOptionContextSize(ctxSize int) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.ctxSize = ctxSize
+	}
+}
+
+func ModelPath(modelPath string) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.modelPath = modelPath
+	}
+}
+
+func LoadOptionF16(f16 bool) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.f16 = f16
+	}
+}
+
+type ConfigLoaderOption func(*LoadOptions)
+
+func (lo *LoadOptions) Apply(options ...ConfigLoaderOption) {
+	for _, l := range options {
+		l(lo)
+	}
+}
+
+// TODO: either in the next PR or the next commit, I want to merge these down into a single function that looks at the first few characters of the file to determine if we need to deserialize to []BackendConfig or BackendConfig
+func readMultipleBackendConfigsFromFile(file string, opts ...ConfigLoaderOption) ([]*BackendConfig, error) {
+	c := &[]*BackendConfig{}
+	f, err := os.ReadFile(file)
+	if err != nil {
+		return nil, fmt.Errorf("cannot read config file: %w", err)
+	}
+	if err := yaml.Unmarshal(f, c); err != nil {
+		return nil, fmt.Errorf("cannot unmarshal config file: %w", err)
+	}
+
+	for _, cc := range *c {
+		cc.SetDefaults(opts...)
+	}
+
+	return *c, nil
+}
+
+func readBackendConfigFromFile(file string, opts ...ConfigLoaderOption) (*BackendConfig, error) {
+	lo := &LoadOptions{}
+	lo.Apply(opts...)
+
+	c := &BackendConfig{}
+	f, err := os.ReadFile(file)
+	if err != nil {
+		return nil, fmt.Errorf("cannot read config file: %w", err)
+	}
+	if err := yaml.Unmarshal(f, c); err != nil {
+		return nil, fmt.Errorf("cannot unmarshal config file: %w", err)
+	}
+
+	c.SetDefaults(opts...)
+	return c, nil
+}
+
+// Load a config file for a model
+func (bcl *BackendConfigLoader) LoadBackendConfigFileByName(modelName, modelPath string, opts ...ConfigLoaderOption) (*BackendConfig, error) {
+
+	// Load a config file if present after the model name
+	cfg := &BackendConfig{
+		PredictionOptions: schema.PredictionOptions{
+			Model: modelName,
+		},
+	}
+
+	cfgExisting, exists := bcl.GetBackendConfig(modelName)
+	if exists {
+		cfg = &cfgExisting
+	} else {
+		// Try loading a model config file
+		modelConfig := filepath.Join(modelPath, modelName+".yaml")
+		if _, err := os.Stat(modelConfig); err == nil {
+			if err := bcl.LoadBackendConfig(
+				modelConfig, opts...,
+			); err != nil {
+				return nil, fmt.Errorf("failed loading model config (%s) %s", modelConfig, err.Error())
+			}
+			cfgExisting, exists = bcl.GetBackendConfig(modelName)
+			if exists {
+				cfg = &cfgExisting
+			}
+		}
+	}
+
+	cfg.SetDefaults(opts...)
+
+	return cfg, nil
+}
+
+// This format is currently only used when reading a single file at startup, passed in via ApplicationConfig.ConfigFile
+func (bcl *BackendConfigLoader) LoadMultipleBackendConfigsSingleFile(file string, opts ...ConfigLoaderOption) error {
+	bcl.Lock()
+	defer bcl.Unlock()
+	c, err := readMultipleBackendConfigsFromFile(file, opts...)
+	if err != nil {
+		return fmt.Errorf("cannot load config file: %w", err)
+	}
+
+	for _, cc := range c {
+		if cc.Validate() {
+			bcl.configs[cc.Name] = *cc
+		}
+	}
+	return nil
+}
+
+func (bcl *BackendConfigLoader) LoadBackendConfig(file string, opts ...ConfigLoaderOption) error {
+	bcl.Lock()
+	defer bcl.Unlock()
+	c, err := readBackendConfigFromFile(file, opts...)
+	if err != nil {
+		return fmt.Errorf("cannot read config file: %w", err)
+	}
+
+	if c.Validate() {
+		bcl.configs[c.Name] = *c
+	} else {
+		return fmt.Errorf("config is not valid")
+	}
+
+	return nil
+}
+
+func (bcl *BackendConfigLoader) GetBackendConfig(m string) (BackendConfig, bool) {
+	bcl.Lock()
+	defer bcl.Unlock()
+	v, exists := bcl.configs[m]
+	return v, exists
+}
+
+func (bcl *BackendConfigLoader) GetAllBackendConfigs() []BackendConfig {
+	bcl.Lock()
+	defer bcl.Unlock()
+	var res []BackendConfig
+	for _, v := range bcl.configs {
+		res = append(res, v)
+	}
+
+	sort.SliceStable(res, func(i, j int) bool {
+		return res[i].Name < res[j].Name
+	})
+
+	return res
+}
+
+func (bcl *BackendConfigLoader) RemoveBackendConfig(m string) {
+	bcl.Lock()
+	defer bcl.Unlock()
+	delete(bcl.configs, m)
+}
+
+// Preload prepare models if they are not local but url or huggingface repositories
+func (bcl *BackendConfigLoader) Preload(modelPath string) error {
+	bcl.Lock()
+	defer bcl.Unlock()
+
+	status := func(fileName, current, total string, percent float64) {
+		utils.DisplayDownloadFunction(fileName, current, total, percent)
+	}
+
+	log.Info().Msgf("Preloading models from %s", modelPath)
+
+	renderMode := "dark"
+	if os.Getenv("COLOR") != "" {
+		renderMode = os.Getenv("COLOR")
+	}
+
+	glamText := func(t string) {
+		out, err := glamour.Render(t, renderMode)
+		if err == nil && os.Getenv("NO_COLOR") == "" {
+			fmt.Println(out)
+		} else {
+			fmt.Println(t)
+		}
+	}
+
+	for i, config := range bcl.configs {
+
+		// Download files and verify their SHA
+		for i, file := range config.DownloadFiles {
+			log.Debug().Msgf("Checking %q exists and matches SHA", file.Filename)
+
+			if err := utils.VerifyPath(file.Filename, modelPath); err != nil {
+				return err
+			}
+			// Create file path
+			filePath := filepath.Join(modelPath, file.Filename)
+
+			if err := downloader.DownloadFile(file.URI, filePath, file.SHA256, i, len(config.DownloadFiles), status); err != nil {
+				return err
+			}
+		}
+
+		// If the model is an URL, expand it, and download the file
+		if config.IsModelURL() {
+			modelFileName := config.ModelFileName()
+			modelURL := downloader.ConvertURL(config.Model)
+			// check if file exists
+			if _, err := os.Stat(filepath.Join(modelPath, modelFileName)); errors.Is(err, os.ErrNotExist) {
+				err := downloader.DownloadFile(modelURL, filepath.Join(modelPath, modelFileName), "", 0, 0, status)
+				if err != nil {
+					return err
+				}
+			}
+
+			cc := bcl.configs[i]
+			c := &cc
+			c.PredictionOptions.Model = modelFileName
+			bcl.configs[i] = *c
+		}
+
+		if config.IsMMProjURL() {
+			modelFileName := config.MMProjFileName()
+			modelURL := downloader.ConvertURL(config.MMProj)
+			// check if file exists
+			if _, err := os.Stat(filepath.Join(modelPath, modelFileName)); errors.Is(err, os.ErrNotExist) {
+				err := downloader.DownloadFile(modelURL, filepath.Join(modelPath, modelFileName), "", 0, 0, status)
+				if err != nil {
+					return err
+				}
+			}
+
+			cc := bcl.configs[i]
+			c := &cc
+			c.MMProj = modelFileName
+			bcl.configs[i] = *c
+		}
+
+		if bcl.configs[i].Name != "" {
+			glamText(fmt.Sprintf("**Model name**: _%s_", bcl.configs[i].Name))
+		}
+		if bcl.configs[i].Description != "" {
+			//glamText("**Description**")
+			glamText(bcl.configs[i].Description)
+		}
+		if bcl.configs[i].Usage != "" {
+			//glamText("**Usage**")
+			glamText(bcl.configs[i].Usage)
+		}
+	}
+	return nil
+}
+
+// LoadBackendConfigsFromPath reads all the configurations of the models from a path
+// (non-recursive)
+func (bcl *BackendConfigLoader) LoadBackendConfigsFromPath(path string, opts ...ConfigLoaderOption) error {
+	bcl.Lock()
+	defer bcl.Unlock()
+	entries, err := os.ReadDir(path)
+	if err != nil {
+		return fmt.Errorf("cannot read directory '%s': %w", path, err)
+	}
+	files := make([]fs.FileInfo, 0, len(entries))
+	for _, entry := range entries {
+		info, err := entry.Info()
+		if err != nil {
+			return err
+		}
+		files = append(files, info)
+	}
+	for _, file := range files {
+		// Skip templates, YAML and .keep files
+		if !strings.Contains(file.Name(), ".yaml") && !strings.Contains(file.Name(), ".yml") ||
+			strings.HasPrefix(file.Name(), ".") {
+			continue
+		}
+		c, err := readBackendConfigFromFile(filepath.Join(path, file.Name()), opts...)
+		if err != nil {
+			log.Error().Err(err).Msgf("cannot read config file: %s", file.Name())
+			continue
+		}
+		if c.Validate() {
+			bcl.configs[c.Name] = *c
+		} else {
+			log.Error().Err(err).Msgf("config is not valid")
+		}
+	}
+
+	return nil
+}
core/gallery/op.go
-package gallery
-
-import "github.com/mudler/LocalAI/core/config"
-
-type GalleryOp struct {
-	Id               string
-	GalleryModelName string
-	ConfigURL        string
-	Delete           bool
-
-	Req       GalleryModel
-	Galleries []config.Gallery
-}
-
-type GalleryOpStatus struct {
-	Deletion           bool    `json:"deletion"` // Deletion is true if the operation is a deletion
-	FileName           string  `json:"file_name"`
-	Error              error   `json:"error"`
-	Processed          bool    `json:"processed"`
-	Message            string  `json:"message"`
-	Progress           float64 `json:"progress"`
-	TotalFileSize      string  `json:"file_size"`
-	DownloadedFileSize string  `json:"downloaded_size"`
-	GalleryModelName   string  `json:"gallery_model_name"`
-}
+package gallery
+
+import "github.com/mudler/LocalAI/core/config"
+
+type GalleryOp struct {
+	Id               string
+	GalleryModelName string
+	ConfigURL        string
+	Delete           bool
+
+	Req       GalleryModel
+	Galleries []config.Gallery
+}
+
+type GalleryOpStatus struct {
+	Deletion           bool    `json:"deletion"` // Deletion is true if the operation is a deletion
+	FileName           string  `json:"file_name"`
+	Error              error   `json:"error"`
+	Processed          bool    `json:"processed"`
+	Message            string  `json:"message"`
+	Progress           float64 `json:"progress"`
+	TotalFileSize      string  `json:"file_size"`
+	DownloadedFileSize string  `json:"downloaded_size"`
+	GalleryModelName   string  `json:"gallery_model_name"`
+}
core/http/endpoints/localai/backend_monitor.go
-package localai
-
-import (
-	"github.com/gofiber/fiber/v2"
-	"github.com/mudler/LocalAI/core/schema"
-	"github.com/mudler/LocalAI/core/services"
-)
-
-func BackendMonitorEndpoint(bm *services.BackendMonitorService) func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-
-		input := new(schema.BackendMonitorRequest)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-
-		resp, err := bm.CheckAndSample(input.Model)
-		if err != nil {
-			return err
-		}
-		return c.JSON(resp)
-	}
-}
-
-func BackendShutdownEndpoint(bm *services.BackendMonitorService) func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		input := new(schema.BackendMonitorRequest)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-
-		return bm.ShutdownModel(input.Model)
-	}
-}
+package localai
+
+import (
+	"github.com/gofiber/fiber/v2"
+	"github.com/mudler/LocalAI/core/schema"
+	"github.com/mudler/LocalAI/core/services"
+)
+
+func BackendMonitorEndpoint(bm *services.BackendMonitorService) func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+
+		input := new(schema.BackendMonitorRequest)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+
+		resp, err := bm.CheckAndSample(input.Model)
+		if err != nil {
+			return err
+		}
+		return c.JSON(resp)
+	}
+}
+
+func BackendShutdownEndpoint(bm *services.BackendMonitorService) func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		input := new(schema.BackendMonitorRequest)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+
+		return bm.ShutdownModel(input.Model)
+	}
+}
core/http/endpoints/localai/gallery.go
-package localai
-
-import (
-	"encoding/json"
-	"fmt"
-	"slices"
-
-	"github.com/gofiber/fiber/v2"
-	"github.com/google/uuid"
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/gallery"
-	"github.com/mudler/LocalAI/core/services"
-	"github.com/rs/zerolog/log"
-)
-
-type ModelGalleryEndpointService struct {
-	galleries      []config.Gallery
-	modelPath      string
-	galleryApplier *services.GalleryService
-}
-
-type GalleryModel struct {
-	ID        string `json:"id"`
-	ConfigURL string `json:"config_url"`
-	gallery.GalleryModel
-}
-
-func CreateModelGalleryEndpointService(galleries []config.Gallery, modelPath string, galleryApplier *services.GalleryService) ModelGalleryEndpointService {
-	return ModelGalleryEndpointService{
-		galleries:      galleries,
-		modelPath:      modelPath,
-		galleryApplier: galleryApplier,
-	}
-}
-
-func (mgs *ModelGalleryEndpointService) GetOpStatusEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		status := mgs.galleryApplier.GetStatus(c.Params("uuid"))
-		if status == nil {
-			return fmt.Errorf("could not find any status for ID")
-		}
-		return c.JSON(status)
-	}
-}
-
-func (mgs *ModelGalleryEndpointService) GetAllStatusEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		return c.JSON(mgs.galleryApplier.GetAllStatus())
-	}
-}
-
-func (mgs *ModelGalleryEndpointService) ApplyModelGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		input := new(GalleryModel)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-
-		uuid, err := uuid.NewUUID()
-		if err != nil {
-			return err
-		}
-		mgs.galleryApplier.C <- gallery.GalleryOp{
-			Req:              input.GalleryModel,
-			Id:               uuid.String(),
-			GalleryModelName: input.ID,
-			Galleries:        mgs.galleries,
-			ConfigURL:        input.ConfigURL,
-		}
-		return c.JSON(struct {
-			ID        string `json:"uuid"`
-			StatusURL string `json:"status"`
-		}{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()})
-	}
-}
-
-func (mgs *ModelGalleryEndpointService) DeleteModelGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		modelName := c.Params("name")
-
-		mgs.galleryApplier.C <- gallery.GalleryOp{
-			Delete:           true,
-			GalleryModelName: modelName,
-		}
-
-		uuid, err := uuid.NewUUID()
-		if err != nil {
-			return err
-		}
-
-		return c.JSON(struct {
-			ID        string `json:"uuid"`
-			StatusURL string `json:"status"`
-		}{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()})
-	}
-}
-
-func (mgs *ModelGalleryEndpointService) ListModelFromGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		log.Debug().Msgf("Listing models from galleries: %+v", mgs.galleries)
-
-		models, err := gallery.AvailableGalleryModels(mgs.galleries, mgs.modelPath)
-		if err != nil {
-			return err
-		}
-		log.Debug().Msgf("Models found from galleries: %+v", models)
-		for _, m := range models {
-			log.Debug().Msgf("Model found from galleries: %+v", m)
-		}
-		dat, err := json.Marshal(models)
-		if err != nil {
-			return err
-		}
-		return c.Send(dat)
-	}
-}
-
-// NOTE: This is different (and much simpler!) than above! This JUST lists the model galleries that have been loaded, not their contents!
-func (mgs *ModelGalleryEndpointService) ListModelGalleriesEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		log.Debug().Msgf("Listing model galleries %+v", mgs.galleries)
-		dat, err := json.Marshal(mgs.galleries)
-		if err != nil {
-			return err
-		}
-		return c.Send(dat)
-	}
-}
-
-func (mgs *ModelGalleryEndpointService) AddModelGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		input := new(config.Gallery)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-		if slices.ContainsFunc(mgs.galleries, func(gallery config.Gallery) bool {
-			return gallery.Name == input.Name
-		}) {
-			return fmt.Errorf("%s already exists", input.Name)
-		}
-		dat, err := json.Marshal(mgs.galleries)
-		if err != nil {
-			return err
-		}
-		log.Debug().Msgf("Adding %+v to gallery list", *input)
-		mgs.galleries = append(mgs.galleries, *input)
-		return c.Send(dat)
-	}
-}
-
-func (mgs *ModelGalleryEndpointService) RemoveModelGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		input := new(config.Gallery)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-		if !slices.ContainsFunc(mgs.galleries, func(gallery config.Gallery) bool {
-			return gallery.Name == input.Name
-		}) {
-			return fmt.Errorf("%s is not currently registered", input.Name)
-		}
-		mgs.galleries = slices.DeleteFunc(mgs.galleries, func(gallery config.Gallery) bool {
-			return gallery.Name == input.Name
-		})
-		return c.Send(nil)
-	}
-}
+package localai
+
+import (
+	"encoding/json"
+	"fmt"
+	"slices"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/google/uuid"
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/gallery"
+	"github.com/mudler/LocalAI/core/services"
+	"github.com/rs/zerolog/log"
+)
+
+type ModelGalleryEndpointService struct {
+	galleries      []config.Gallery
+	modelPath      string
+	galleryApplier *services.GalleryService
+}
+
+type GalleryModel struct {
+	ID        string `json:"id"`
+	ConfigURL string `json:"config_url"`
+	gallery.GalleryModel
+}
+
+func CreateModelGalleryEndpointService(galleries []config.Gallery, modelPath string, galleryApplier *services.GalleryService) ModelGalleryEndpointService {
+	return ModelGalleryEndpointService{
+		galleries:      galleries,
+		modelPath:      modelPath,
+		galleryApplier: galleryApplier,
+	}
+}
+
+func (mgs *ModelGalleryEndpointService) GetOpStatusEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		status := mgs.galleryApplier.GetStatus(c.Params("uuid"))
+		if status == nil {
+			return fmt.Errorf("could not find any status for ID")
+		}
+		return c.JSON(status)
+	}
+}
+
+func (mgs *ModelGalleryEndpointService) GetAllStatusEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		return c.JSON(mgs.galleryApplier.GetAllStatus())
+	}
+}
+
+func (mgs *ModelGalleryEndpointService) ApplyModelGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		input := new(GalleryModel)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+
+		uuid, err := uuid.NewUUID()
+		if err != nil {
+			return err
+		}
+		mgs.galleryApplier.C <- gallery.GalleryOp{
+			Req:              input.GalleryModel,
+			Id:               uuid.String(),
+			GalleryModelName: input.ID,
+			Galleries:        mgs.galleries,
+			ConfigURL:        input.ConfigURL,
+		}
+		return c.JSON(struct {
+			ID        string `json:"uuid"`
+			StatusURL string `json:"status"`
+		}{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()})
+	}
+}
+
+func (mgs *ModelGalleryEndpointService) DeleteModelGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		modelName := c.Params("name")
+
+		mgs.galleryApplier.C <- gallery.GalleryOp{
+			Delete:           true,
+			GalleryModelName: modelName,
+		}
+
+		uuid, err := uuid.NewUUID()
+		if err != nil {
+			return err
+		}
+
+		return c.JSON(struct {
+			ID        string `json:"uuid"`
+			StatusURL string `json:"status"`
+		}{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()})
+	}
+}
+
+func (mgs *ModelGalleryEndpointService) ListModelFromGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		log.Debug().Msgf("Listing models from galleries: %+v", mgs.galleries)
+
+		models, err := gallery.AvailableGalleryModels(mgs.galleries, mgs.modelPath)
+		if err != nil {
+			return err
+		}
+		log.Debug().Msgf("Models found from galleries: %+v", models)
+		for _, m := range models {
+			log.Debug().Msgf("Model found from galleries: %+v", m)
+		}
+		dat, err := json.Marshal(models)
+		if err != nil {
+			return err
+		}
+		return c.Send(dat)
+	}
+}
+
+// NOTE: This is different (and much simpler!) than above! This JUST lists the model galleries that have been loaded, not their contents!
+func (mgs *ModelGalleryEndpointService) ListModelGalleriesEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		log.Debug().Msgf("Listing model galleries %+v", mgs.galleries)
+		dat, err := json.Marshal(mgs.galleries)
+		if err != nil {
+			return err
+		}
+		return c.Send(dat)
+	}
+}
+
+func (mgs *ModelGalleryEndpointService) AddModelGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		input := new(config.Gallery)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+		if slices.ContainsFunc(mgs.galleries, func(gallery config.Gallery) bool {
+			return gallery.Name == input.Name
+		}) {
+			return fmt.Errorf("%s already exists", input.Name)
+		}
+		dat, err := json.Marshal(mgs.galleries)
+		if err != nil {
+			return err
+		}
+		log.Debug().Msgf("Adding %+v to gallery list", *input)
+		mgs.galleries = append(mgs.galleries, *input)
+		return c.Send(dat)
+	}
+}
+
+func (mgs *ModelGalleryEndpointService) RemoveModelGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		input := new(config.Gallery)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+		if !slices.ContainsFunc(mgs.galleries, func(gallery config.Gallery) bool {
+			return gallery.Name == input.Name
+		}) {
+			return fmt.Errorf("%s is not currently registered", input.Name)
+		}
+		mgs.galleries = slices.DeleteFunc(mgs.galleries, func(gallery config.Gallery) bool {
+			return gallery.Name == input.Name
+		})
+		return c.Send(nil)
+	}
+}
core/http/endpoints/localai/metrics.go
-package localai
-
-import (
-	"time"
-
-	"github.com/gofiber/fiber/v2"
-	"github.com/gofiber/fiber/v2/middleware/adaptor"
-	"github.com/mudler/LocalAI/core/services"
-	"github.com/prometheus/client_golang/prometheus/promhttp"
-)
-
-func LocalAIMetricsEndpoint() fiber.Handler {
-
-	return adaptor.HTTPHandler(promhttp.Handler())
-}
-
-type apiMiddlewareConfig struct {
-	Filter         func(c *fiber.Ctx) bool
-	metricsService *services.LocalAIMetricsService
-}
-
-func LocalAIMetricsAPIMiddleware(metrics *services.LocalAIMetricsService) fiber.Handler {
-	cfg := apiMiddlewareConfig{
-		metricsService: metrics,
-		Filter: func(c *fiber.Ctx) bool {
-			return c.Path() == "/metrics"
-		},
-	}
-
-	return func(c *fiber.Ctx) error {
-		if cfg.Filter != nil && cfg.Filter(c) {
-			return c.Next()
-		}
-		path := c.Path()
-		method := c.Method()
-
-		start := time.Now()
-		err := c.Next()
-		elapsed := float64(time.Since(start)) / float64(time.Second)
-		cfg.metricsService.ObserveAPICall(method, path, elapsed)
-		return err
-	}
-}
+package localai
+
+import (
+	"time"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/gofiber/fiber/v2/middleware/adaptor"
+	"github.com/mudler/LocalAI/core/services"
+	"github.com/prometheus/client_golang/prometheus/promhttp"
+)
+
+func LocalAIMetricsEndpoint() fiber.Handler {
+
+	return adaptor.HTTPHandler(promhttp.Handler())
+}
+
+type apiMiddlewareConfig struct {
+	Filter         func(c *fiber.Ctx) bool
+	metricsService *services.LocalAIMetricsService
+}
+
+func LocalAIMetricsAPIMiddleware(metrics *services.LocalAIMetricsService) fiber.Handler {
+	cfg := apiMiddlewareConfig{
+		metricsService: metrics,
+		Filter: func(c *fiber.Ctx) bool {
+			return c.Path() == "/metrics"
+		},
+	}
+
+	return func(c *fiber.Ctx) error {
+		if cfg.Filter != nil && cfg.Filter(c) {
+			return c.Next()
+		}
+		path := c.Path()
+		method := c.Method()
+
+		start := time.Now()
+		err := c.Next()
+		elapsed := float64(time.Since(start)) / float64(time.Second)
+		cfg.metricsService.ObserveAPICall(method, path, elapsed)
+		return err
+	}
+}
core/http/endpoints/localai/tts.go
 )
 
 // TTSEndpoint is the OpenAI Speech API endpoint https://platform.openai.com/docs/api-reference/audio/createSpeech
-//	@Summary	Generates audio from the input text.
-//  @Accept json
-//  @Produce audio/x-wav
-//	@Param		request	body		schema.TTSRequest	true	"query params"
-//	@Success	200		{string}	binary				"generated audio/wav file"
-//	@Router		/v1/audio/speech [post]
-//	@Router		/tts [post]
+//
+//		@Summary	Generates audio from the input text.
+//	 @Accept json
+//	 @Produce audio/x-wav
+//		@Param		request	body		schema.TTSRequest	true	"query params"
+//		@Success	200		{string}	binary				"generated audio/wav file"
+//		@Router		/v1/audio/speech [post]
+//		@Router		/tts [post]
 func TTSEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
 	return func(c *fiber.Ctx) error {
 
core/schema/elevenlabs.go
-package schema
-
-type ElevenLabsTTSRequest struct {
-	Text    string `json:"text" yaml:"text"`
-	ModelID string `json:"model_id" yaml:"model_id"`
-}
+package schema
+
+type ElevenLabsTTSRequest struct {
+	Text    string `json:"text" yaml:"text"`
+	ModelID string `json:"model_id" yaml:"model_id"`
+}
core/services/backend_monitor.go
-package services
-
-import (
-	"context"
-	"fmt"
-	"strings"
-
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/schema"
-	"github.com/mudler/LocalAI/pkg/grpc/proto"
-	"github.com/mudler/LocalAI/pkg/model"
-
-	"github.com/rs/zerolog/log"
-
-	gopsutil "github.com/shirou/gopsutil/v3/process"
-)
-
-type BackendMonitorService struct {
-	backendConfigLoader *config.BackendConfigLoader
-	modelLoader         *model.ModelLoader
-	options             *config.ApplicationConfig // Taking options in case we need to inspect ExternalGRPCBackends, though that's out of scope for now, hence the name.
-}
-
-func NewBackendMonitorService(modelLoader *model.ModelLoader, configLoader *config.BackendConfigLoader, appConfig *config.ApplicationConfig) *BackendMonitorService {
-	return &BackendMonitorService{
-		modelLoader:         modelLoader,
-		backendConfigLoader: configLoader,
-		options:             appConfig,
-	}
-}
-
-func (bms BackendMonitorService) getModelLoaderIDFromModelName(modelName string) (string, error) {
-	config, exists := bms.backendConfigLoader.GetBackendConfig(modelName)
-	var backendId string
-	if exists {
-		backendId = config.Model
-	} else {
-		// Last ditch effort: use it raw, see if a backend happens to match.
-		backendId = modelName
-	}
-
-	if !strings.HasSuffix(backendId, ".bin") {
-		backendId = fmt.Sprintf("%s.bin", backendId)
-	}
-
-	return backendId, nil
-}
-
-func (bms *BackendMonitorService) SampleLocalBackendProcess(model string) (*schema.BackendMonitorResponse, error) {
-	config, exists := bms.backendConfigLoader.GetBackendConfig(model)
-	var backend string
-	if exists {
-		backend = config.Model
-	} else {
-		// Last ditch effort: use it raw, see if a backend happens to match.
-		backend = model
-	}
-
-	if !strings.HasSuffix(backend, ".bin") {
-		backend = fmt.Sprintf("%s.bin", backend)
-	}
-
-	pid, err := bms.modelLoader.GetGRPCPID(backend)
-
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Msg("failed to find GRPC pid")
-		return nil, err
-	}
-
-	// Name is slightly frightening but this does _not_ create a new process, rather it looks up an existing process by PID.
-	backendProcess, err := gopsutil.NewProcess(int32(pid))
-
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting process info")
-		return nil, err
-	}
-
-	memInfo, err := backendProcess.MemoryInfo()
-
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting memory info")
-		return nil, err
-	}
-
-	memPercent, err := backendProcess.MemoryPercent()
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting memory percent")
-		return nil, err
-	}
-
-	cpuPercent, err := backendProcess.CPUPercent()
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting cpu percent")
-		return nil, err
-	}
-
-	return &schema.BackendMonitorResponse{
-		MemoryInfo:    memInfo,
-		MemoryPercent: memPercent,
-		CPUPercent:    cpuPercent,
-	}, nil
-}
-
-func (bms BackendMonitorService) CheckAndSample(modelName string) (*proto.StatusResponse, error) {
-	backendId, err := bms.getModelLoaderIDFromModelName(modelName)
-	if err != nil {
-		return nil, err
-	}
-	modelAddr := bms.modelLoader.CheckIsLoaded(backendId)
-	if modelAddr == "" {
-		return nil, fmt.Errorf("backend %s is not currently loaded", backendId)
-	}
-
-	status, rpcErr := modelAddr.GRPC(false, nil).Status(context.TODO())
-	if rpcErr != nil {
-		log.Warn().Msgf("backend %s experienced an error retrieving status info: %s", backendId, rpcErr.Error())
-		val, slbErr := bms.SampleLocalBackendProcess(backendId)
-		if slbErr != nil {
-			return nil, fmt.Errorf("backend %s experienced an error retrieving status info via rpc: %s, then failed local node process sample: %s", backendId, rpcErr.Error(), slbErr.Error())
-		}
-		return &proto.StatusResponse{
-			State: proto.StatusResponse_ERROR,
-			Memory: &proto.MemoryUsageData{
-				Total: val.MemoryInfo.VMS,
-				Breakdown: map[string]uint64{
-					"gopsutil-RSS": val.MemoryInfo.RSS,
-				},
-			},
-		}, nil
-	}
-	return status, nil
-}
-
-func (bms BackendMonitorService) ShutdownModel(modelName string) error {
-	backendId, err := bms.getModelLoaderIDFromModelName(modelName)
-	if err != nil {
-		return err
-	}
-	return bms.modelLoader.ShutdownModel(backendId)
-}
+package services
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/schema"
+	"github.com/mudler/LocalAI/pkg/grpc/proto"
+	"github.com/mudler/LocalAI/pkg/model"
+
+	"github.com/rs/zerolog/log"
+
+	gopsutil "github.com/shirou/gopsutil/v3/process"
+)
+
+type BackendMonitorService struct {
+	backendConfigLoader *config.BackendConfigLoader
+	modelLoader         *model.ModelLoader
+	options             *config.ApplicationConfig // Taking options in case we need to inspect ExternalGRPCBackends, though that's out of scope for now, hence the name.
+}
+
+func NewBackendMonitorService(modelLoader *model.ModelLoader, configLoader *config.BackendConfigLoader, appConfig *config.ApplicationConfig) *BackendMonitorService {
+	return &BackendMonitorService{
+		modelLoader:         modelLoader,
+		backendConfigLoader: configLoader,
+		options:             appConfig,
+	}
+}
+
+func (bms BackendMonitorService) getModelLoaderIDFromModelName(modelName string) (string, error) {
+	config, exists := bms.backendConfigLoader.GetBackendConfig(modelName)
+	var backendId string
+	if exists {
+		backendId = config.Model
+	} else {
+		// Last ditch effort: use it raw, see if a backend happens to match.
+		backendId = modelName
+	}
+
+	if !strings.HasSuffix(backendId, ".bin") {
+		backendId = fmt.Sprintf("%s.bin", backendId)
+	}
+
+	return backendId, nil
+}
+
+func (bms *BackendMonitorService) SampleLocalBackendProcess(model string) (*schema.BackendMonitorResponse, error) {
+	config, exists := bms.backendConfigLoader.GetBackendConfig(model)
+	var backend string
+	if exists {
+		backend = config.Model
+	} else {
+		// Last ditch effort: use it raw, see if a backend happens to match.
+		backend = model
+	}
+
+	if !strings.HasSuffix(backend, ".bin") {
+		backend = fmt.Sprintf("%s.bin", backend)
+	}
+
+	pid, err := bms.modelLoader.GetGRPCPID(backend)
+
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Msg("failed to find GRPC pid")
+		return nil, err
+	}
+
+	// Name is slightly frightening but this does _not_ create a new process, rather it looks up an existing process by PID.
+	backendProcess, err := gopsutil.NewProcess(int32(pid))
+
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting process info")
+		return nil, err
+	}
+
+	memInfo, err := backendProcess.MemoryInfo()
+
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting memory info")
+		return nil, err
+	}
+
+	memPercent, err := backendProcess.MemoryPercent()
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting memory percent")
+		return nil, err
+	}
+
+	cpuPercent, err := backendProcess.CPUPercent()
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting cpu percent")
+		return nil, err
+	}
+
+	return &schema.BackendMonitorResponse{
+		MemoryInfo:    memInfo,
+		MemoryPercent: memPercent,
+		CPUPercent:    cpuPercent,
+	}, nil
+}
+
+func (bms BackendMonitorService) CheckAndSample(modelName string) (*proto.StatusResponse, error) {
+	backendId, err := bms.getModelLoaderIDFromModelName(modelName)
+	if err != nil {
+		return nil, err
+	}
+	modelAddr := bms.modelLoader.CheckIsLoaded(backendId)
+	if modelAddr == "" {
+		return nil, fmt.Errorf("backend %s is not currently loaded", backendId)
+	}
+
+	status, rpcErr := modelAddr.GRPC(false, nil).Status(context.TODO())
+	if rpcErr != nil {
+		log.Warn().Msgf("backend %s experienced an error retrieving status info: %s", backendId, rpcErr.Error())
+		val, slbErr := bms.SampleLocalBackendProcess(backendId)
+		if slbErr != nil {
+			return nil, fmt.Errorf("backend %s experienced an error retrieving status info via rpc: %s, then failed local node process sample: %s", backendId, rpcErr.Error(), slbErr.Error())
+		}
+		return &proto.StatusResponse{
+			State: proto.StatusResponse_ERROR,
+			Memory: &proto.MemoryUsageData{
+				Total: val.MemoryInfo.VMS,
+				Breakdown: map[string]uint64{
+					"gopsutil-RSS": val.MemoryInfo.RSS,
+				},
+			},
+		}, nil
+	}
+	return status, nil
+}
+
+func (bms BackendMonitorService) ShutdownModel(modelName string) error {
+	backendId, err := bms.getModelLoaderIDFromModelName(modelName)
+	if err != nil {
+		return err
+	}
+	return bms.modelLoader.ShutdownModel(backendId)
+}
core/services/gallery.go
-package services
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"os"
-	"path/filepath"
-	"sync"
-
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/gallery"
-	"github.com/mudler/LocalAI/pkg/startup"
-	"github.com/mudler/LocalAI/pkg/utils"
-	"gopkg.in/yaml.v2"
-)
-
-type GalleryService struct {
-	appConfig *config.ApplicationConfig
-	sync.Mutex
-	C        chan gallery.GalleryOp
-	statuses map[string]*gallery.GalleryOpStatus
-}
-
-func NewGalleryService(appConfig *config.ApplicationConfig) *GalleryService {
-	return &GalleryService{
-		appConfig: appConfig,
-		C:         make(chan gallery.GalleryOp),
-		statuses:  make(map[string]*gallery.GalleryOpStatus),
-	}
-}
-
-func prepareModel(modelPath string, req gallery.GalleryModel, downloadStatus func(string, string, string, float64), enforceScan bool) error {
-
-	config, err := gallery.GetGalleryConfigFromURL(req.URL, modelPath)
-	if err != nil {
-		return err
-	}
-
-	config.Files = append(config.Files, req.AdditionalFiles...)
-
-	return gallery.InstallModel(modelPath, req.Name, &config, req.Overrides, downloadStatus, enforceScan)
-}
-
-func (g *GalleryService) UpdateStatus(s string, op *gallery.GalleryOpStatus) {
-	g.Lock()
-	defer g.Unlock()
-	g.statuses[s] = op
-}
-
-func (g *GalleryService) GetStatus(s string) *gallery.GalleryOpStatus {
-	g.Lock()
-	defer g.Unlock()
-
-	return g.statuses[s]
-}
-
-func (g *GalleryService) GetAllStatus() map[string]*gallery.GalleryOpStatus {
-	g.Lock()
-	defer g.Unlock()
-
-	return g.statuses
-}
-
-func (g *GalleryService) Start(c context.Context, cl *config.BackendConfigLoader) {
-	go func() {
-		for {
-			select {
-			case <-c.Done():
-				return
-			case op := <-g.C:
-				utils.ResetDownloadTimers()
-
-				g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", Progress: 0})
-
-				// updates the status with an error
-				var updateError func(e error)
-				if !g.appConfig.OpaqueErrors {
-					updateError = func(e error) {
-						g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: e, Processed: true, Message: "error: " + e.Error()})
-					}
-				} else {
-					updateError = func(_ error) {
-						g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: fmt.Errorf("an error occurred"), Processed: true})
-					}
-				}
-
-				// displayDownload displays the download progress
-				progressCallback := func(fileName string, current string, total string, percentage float64) {
-					g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", FileName: fileName, Progress: percentage, TotalFileSize: total, DownloadedFileSize: current})
-					utils.DisplayDownloadFunction(fileName, current, total, percentage)
-				}
-
-				var err error
-
-				// delete a model
-				if op.Delete {
-					modelConfig := &config.BackendConfig{}
-
-					// Galleryname is the name of the model in this case
-					dat, err := os.ReadFile(filepath.Join(g.appConfig.ModelPath, op.GalleryModelName+".yaml"))
-					if err != nil {
-						updateError(err)
-						continue
-					}
-					err = yaml.Unmarshal(dat, modelConfig)
-					if err != nil {
-						updateError(err)
-						continue
-					}
-
-					files := []string{}
-					// Remove the model from the config
-					if modelConfig.Model != "" {
-						files = append(files, modelConfig.ModelFileName())
-					}
-
-					if modelConfig.MMProj != "" {
-						files = append(files, modelConfig.MMProjFileName())
-					}
-
-					err = gallery.DeleteModelFromSystem(g.appConfig.ModelPath, op.GalleryModelName, files)
-					if err != nil {
-						updateError(err)
-						continue
-					}
-				} else {
-					// if the request contains a gallery name, we apply the gallery from the gallery list
-					if op.GalleryModelName != "" {
-						err = gallery.InstallModelFromGallery(op.Galleries, op.GalleryModelName, g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans)
-					} else if op.ConfigURL != "" {
-						err = startup.InstallModels(op.Galleries, op.ConfigURL, g.appConfig.ModelPath, g.appConfig.EnforcePredownloadScans, progressCallback, op.ConfigURL)
-						if err != nil {
-							updateError(err)
-							continue
-						}
-						err = cl.Preload(g.appConfig.ModelPath)
-					} else {
-						err = prepareModel(g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans)
-					}
-				}
-
-				if err != nil {
-					updateError(err)
-					continue
-				}
-
-				// Reload models
-				err = cl.LoadBackendConfigsFromPath(g.appConfig.ModelPath)
-				if err != nil {
-					updateError(err)
-					continue
-				}
-
-				err = cl.Preload(g.appConfig.ModelPath)
-				if err != nil {
-					updateError(err)
-					continue
-				}
-
-				g.UpdateStatus(op.Id,
-					&gallery.GalleryOpStatus{
-						Deletion:         op.Delete,
-						Processed:        true,
-						GalleryModelName: op.GalleryModelName,
-						Message:          "completed",
-						Progress:         100})
-			}
-		}
-	}()
-}
-
-type galleryModel struct {
-	gallery.GalleryModel `yaml:",inline"` // https://github.com/go-yaml/yaml/issues/63
-	ID                   string           `json:"id"`
-}
-
-func processRequests(modelPath string, enforceScan bool, galleries []config.Gallery, requests []galleryModel) error {
-	var err error
-	for _, r := range requests {
-		utils.ResetDownloadTimers()
-		if r.ID == "" {
-			err = prepareModel(modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan)
-
-		} else {
-			err = gallery.InstallModelFromGallery(
-				galleries, r.ID, modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan)
-		}
-	}
-	return err
-}
-
-func ApplyGalleryFromFile(modelPath, s string, enforceScan bool, galleries []config.Gallery) error {
-	dat, err := os.ReadFile(s)
-	if err != nil {
-		return err
-	}
-	var requests []galleryModel
-
-	if err := yaml.Unmarshal(dat, &requests); err != nil {
-		return err
-	}
-
-	return processRequests(modelPath, enforceScan, galleries, requests)
-}
-
-func ApplyGalleryFromString(modelPath, s string, enforceScan bool, galleries []config.Gallery) error {
-	var requests []galleryModel
-	err := json.Unmarshal([]byte(s), &requests)
-	if err != nil {
-		return err
-	}
-
-	return processRequests(modelPath, enforceScan, galleries, requests)
-}
+package services
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"os"
+	"path/filepath"
+	"sync"
+
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/gallery"
+	"github.com/mudler/LocalAI/pkg/startup"
+	"github.com/mudler/LocalAI/pkg/utils"
+	"gopkg.in/yaml.v2"
+)
+
+type GalleryService struct {
+	appConfig *config.ApplicationConfig
+	sync.Mutex
+	C        chan gallery.GalleryOp
+	statuses map[string]*gallery.GalleryOpStatus
+}
+
+func NewGalleryService(appConfig *config.ApplicationConfig) *GalleryService {
+	return &GalleryService{
+		appConfig: appConfig,
+		C:         make(chan gallery.GalleryOp),
+		statuses:  make(map[string]*gallery.GalleryOpStatus),
+	}
+}
+
+func prepareModel(modelPath string, req gallery.GalleryModel, downloadStatus func(string, string, string, float64), enforceScan bool) error {
+
+	config, err := gallery.GetGalleryConfigFromURL(req.URL, modelPath)
+	if err != nil {
+		return err
+	}
+
+	config.Files = append(config.Files, req.AdditionalFiles...)
+
+	return gallery.InstallModel(modelPath, req.Name, &config, req.Overrides, downloadStatus, enforceScan)
+}
+
+func (g *GalleryService) UpdateStatus(s string, op *gallery.GalleryOpStatus) {
+	g.Lock()
+	defer g.Unlock()
+	g.statuses[s] = op
+}
+
+func (g *GalleryService) GetStatus(s string) *gallery.GalleryOpStatus {
+	g.Lock()
+	defer g.Unlock()
+
+	return g.statuses[s]
+}
+
+func (g *GalleryService) GetAllStatus() map[string]*gallery.GalleryOpStatus {
+	g.Lock()
+	defer g.Unlock()
+
+	return g.statuses
+}
+
+func (g *GalleryService) Start(c context.Context, cl *config.BackendConfigLoader) {
+	go func() {
+		for {
+			select {
+			case <-c.Done():
+				return
+			case op := <-g.C:
+				utils.ResetDownloadTimers()
+
+				g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", Progress: 0})
+
+				// updates the status with an error
+				var updateError func(e error)
+				if !g.appConfig.OpaqueErrors {
+					updateError = func(e error) {
+						g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: e, Processed: true, Message: "error: " + e.Error()})
+					}
+				} else {
+					updateError = func(_ error) {
+						g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: fmt.Errorf("an error occurred"), Processed: true})
+					}
+				}
+
+				// displayDownload displays the download progress
+				progressCallback := func(fileName string, current string, total string, percentage float64) {
+					g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", FileName: fileName, Progress: percentage, TotalFileSize: total, DownloadedFileSize: current})
+					utils.DisplayDownloadFunction(fileName, current, total, percentage)
+				}
+
+				var err error
+
+				// delete a model
+				if op.Delete {
+					modelConfig := &config.BackendConfig{}
+
+					// Galleryname is the name of the model in this case
+					dat, err := os.ReadFile(filepath.Join(g.appConfig.ModelPath, op.GalleryModelName+".yaml"))
+					if err != nil {
+						updateError(err)
+						continue
+					}
+					err = yaml.Unmarshal(dat, modelConfig)
+					if err != nil {
+						updateError(err)
+						continue
+					}
+
+					files := []string{}
+					// Remove the model from the config
+					if modelConfig.Model != "" {
+						files = append(files, modelConfig.ModelFileName())
+					}
+
+					if modelConfig.MMProj != "" {
+						files = append(files, modelConfig.MMProjFileName())
+					}
+
+					err = gallery.DeleteModelFromSystem(g.appConfig.ModelPath, op.GalleryModelName, files)
+					if err != nil {
+						updateError(err)
+						continue
+					}
+				} else {
+					// if the request contains a gallery name, we apply the gallery from the gallery list
+					if op.GalleryModelName != "" {
+						err = gallery.InstallModelFromGallery(op.Galleries, op.GalleryModelName, g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans)
+					} else if op.ConfigURL != "" {
+						err = startup.InstallModels(op.Galleries, op.ConfigURL, g.appConfig.ModelPath, g.appConfig.EnforcePredownloadScans, progressCallback, op.ConfigURL)
+						if err != nil {
+							updateError(err)
+							continue
+						}
+						err = cl.Preload(g.appConfig.ModelPath)
+					} else {
+						err = prepareModel(g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans)
+					}
+				}
+
+				if err != nil {
+					updateError(err)
+					continue
+				}
+
+				// Reload models
+				err = cl.LoadBackendConfigsFromPath(g.appConfig.ModelPath)
+				if err != nil {
+					updateError(err)
+					continue
+				}
+
+				err = cl.Preload(g.appConfig.ModelPath)
+				if err != nil {
+					updateError(err)
+					continue
+				}
+
+				g.UpdateStatus(op.Id,
+					&gallery.GalleryOpStatus{
+						Deletion:         op.Delete,
+						Processed:        true,
+						GalleryModelName: op.GalleryModelName,
+						Message:          "completed",
+						Progress:         100})
+			}
+		}
+	}()
+}
+
+type galleryModel struct {
+	gallery.GalleryModel `yaml:",inline"` // https://github.com/go-yaml/yaml/issues/63
+	ID                   string           `json:"id"`
+}
+
+func processRequests(modelPath string, enforceScan bool, galleries []config.Gallery, requests []galleryModel) error {
+	var err error
+	for _, r := range requests {
+		utils.ResetDownloadTimers()
+		if r.ID == "" {
+			err = prepareModel(modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan)
+
+		} else {
+			err = gallery.InstallModelFromGallery(
+				galleries, r.ID, modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan)
+		}
+	}
+	return err
+}
+
+func ApplyGalleryFromFile(modelPath, s string, enforceScan bool, galleries []config.Gallery) error {
+	dat, err := os.ReadFile(s)
+	if err != nil {
+		return err
+	}
+	var requests []galleryModel
+
+	if err := yaml.Unmarshal(dat, &requests); err != nil {
+		return err
+	}
+
+	return processRequests(modelPath, enforceScan, galleries, requests)
+}
+
+func ApplyGalleryFromString(modelPath, s string, enforceScan bool, galleries []config.Gallery) error {
+	var requests []galleryModel
+	err := json.Unmarshal([]byte(s), &requests)
+	if err != nil {
+		return err
+	}
+
+	return processRequests(modelPath, enforceScan, galleries, requests)
+}
core/services/list_models.go
-package services
-
-import (
-	"regexp"
-
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/pkg/model"
-)
-
-func ListModels(bcl *config.BackendConfigLoader, ml *model.ModelLoader, filter string, excludeConfigured bool) ([]string, error) {
-
-	models, err := ml.ListFilesInModelPath()
-	if err != nil {
-		return nil, err
-	}
-
-	var mm map[string]interface{} = map[string]interface{}{}
-
-	dataModels := []string{}
-
-	var filterFn func(name string) bool
-
-	// If filter is not specified, do not filter the list by model name
-	if filter == "" {
-		filterFn = func(_ string) bool { return true }
-	} else {
-		// If filter _IS_ specified, we compile it to a regex which is used to create the filterFn
-		rxp, err := regexp.Compile(filter)
-		if err != nil {
-			return nil, err
-		}
-		filterFn = func(name string) bool {
-			return rxp.MatchString(name)
-		}
-	}
-
-	// Start with the known configurations
-	for _, c := range bcl.GetAllBackendConfigs() {
-		if excludeConfigured {
-			mm[c.Model] = nil
-		}
-
-		if filterFn(c.Name) {
-			dataModels = append(dataModels, c.Name)
-		}
-	}
-
-	// Then iterate through the loose files:
-	for _, m := range models {
-		// And only adds them if they shouldn't be skipped.
-		if _, exists := mm[m]; !exists && filterFn(m) {
-			dataModels = append(dataModels, m)
-		}
-	}
-
-	return dataModels, nil
-}
+package services
+
+import (
+	"regexp"
+
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/pkg/model"
+)
+
+func ListModels(bcl *config.BackendConfigLoader, ml *model.ModelLoader, filter string, excludeConfigured bool) ([]string, error) {
+
+	models, err := ml.ListFilesInModelPath()
+	if err != nil {
+		return nil, err
+	}
+
+	var mm map[string]interface{} = map[string]interface{}{}
+
+	dataModels := []string{}
+
+	var filterFn func(name string) bool
+
+	// If filter is not specified, do not filter the list by model name
+	if filter == "" {
+		filterFn = func(_ string) bool { return true }
+	} else {
+		// If filter _IS_ specified, we compile it to a regex which is used to create the filterFn
+		rxp, err := regexp.Compile(filter)
+		if err != nil {
+			return nil, err
+		}
+		filterFn = func(name string) bool {
+			return rxp.MatchString(name)
+		}
+	}
+
+	// Start with the known configurations
+	for _, c := range bcl.GetAllBackendConfigs() {
+		if excludeConfigured {
+			mm[c.Model] = nil
+		}
+
+		if filterFn(c.Name) {
+			dataModels = append(dataModels, c.Name)
+		}
+	}
+
+	// Then iterate through the loose files:
+	for _, m := range models {
+		// And only adds them if they shouldn't be skipped.
+		if _, exists := mm[m]; !exists && filterFn(m) {
+			dataModels = append(dataModels, m)
+		}
+	}
+
+	return dataModels, nil
+}
core/startup/config_file_watcher.go
-package startup
-
-import (
-	"encoding/json"
-	"fmt"
-	"os"
-	"path"
-	"path/filepath"
-	"time"
-
-	"github.com/fsnotify/fsnotify"
-	"github.com/imdario/mergo"
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/rs/zerolog/log"
-)
-
-type fileHandler func(fileContent []byte, appConfig *config.ApplicationConfig) error
-
-type configFileHandler struct {
-	handlers map[string]fileHandler
-
-	watcher *fsnotify.Watcher
-
-	appConfig *config.ApplicationConfig
-}
-
-// TODO: This should be a singleton eventually so other parts of the code can register config file handlers,
-// then we can export it to other packages
-func newConfigFileHandler(appConfig *config.ApplicationConfig) configFileHandler {
-	c := configFileHandler{
-		handlers:  make(map[string]fileHandler),
-		appConfig: appConfig,
-	}
-	err := c.Register("api_keys.json", readApiKeysJson(*appConfig), true)
-	if err != nil {
-		log.Error().Err(err).Str("file", "api_keys.json").Msg("unable to register config file handler")
-	}
-	err = c.Register("external_backends.json", readExternalBackendsJson(*appConfig), true)
-	if err != nil {
-		log.Error().Err(err).Str("file", "external_backends.json").Msg("unable to register config file handler")
-	}
-	return c
-}
-
-func (c *configFileHandler) Register(filename string, handler fileHandler, runNow bool) error {
-	_, ok := c.handlers[filename]
-	if ok {
-		return fmt.Errorf("handler already registered for file %s", filename)
-	}
-	c.handlers[filename] = handler
-	if runNow {
-		c.callHandler(filename, handler)
-	}
-	return nil
-}
-
-func (c *configFileHandler) callHandler(filename string, handler fileHandler) {
-	rootedFilePath := filepath.Join(c.appConfig.DynamicConfigsDir, filepath.Clean(filename))
-	log.Trace().Str("filename", rootedFilePath).Msg("reading file for dynamic config update")
-	fileContent, err := os.ReadFile(rootedFilePath)
-	if err != nil && !os.IsNotExist(err) {
-		log.Error().Err(err).Str("filename", rootedFilePath).Msg("could not read file")
-	}
-
-	if err = handler(fileContent, c.appConfig); err != nil {
-		log.Error().Err(err).Msg("WatchConfigDirectory goroutine failed to update options")
-	}
-}
-
-func (c *configFileHandler) Watch() error {
-	configWatcher, err := fsnotify.NewWatcher()
-	c.watcher = configWatcher
-	if err != nil {
-		return err
-	}
-
-	if c.appConfig.DynamicConfigsDirPollInterval > 0 {
-		log.Debug().Msg("Poll interval set, falling back to polling for configuration changes")
-		ticker := time.NewTicker(c.appConfig.DynamicConfigsDirPollInterval)
-		go func() {
-			for {
-				<-ticker.C
-				for file, handler := range c.handlers {
-					log.Debug().Str("file", file).Msg("polling config file")
-					c.callHandler(file, handler)
-				}
-			}
-		}()
-	}
-
-	// Start listening for events.
-	go func() {
-		for {
-			select {
-			case event, ok := <-c.watcher.Events:
-				if !ok {
-					return
-				}
-				if event.Has(fsnotify.Write | fsnotify.Create | fsnotify.Remove) {
-					handler, ok := c.handlers[path.Base(event.Name)]
-					if !ok {
-						continue
-					}
-
-					c.callHandler(filepath.Base(event.Name), handler)
-				}
-			case err, ok := <-c.watcher.Errors:
-				log.Error().Err(err).Msg("config watcher error received")
-				if !ok {
-					return
-				}
-			}
-		}
-	}()
-
-	// Add a path.
-	err = c.watcher.Add(c.appConfig.DynamicConfigsDir)
-	if err != nil {
-		return fmt.Errorf("unable to create a watcher on the configuration directory: %+v", err)
-	}
-
-	return nil
-}
-
-// TODO: When we institute graceful shutdown, this should be called
-func (c *configFileHandler) Stop() error {
-	return c.watcher.Close()
-}
-
-func readApiKeysJson(startupAppConfig config.ApplicationConfig) fileHandler {
-	handler := func(fileContent []byte, appConfig *config.ApplicationConfig) error {
-		log.Debug().Msg("processing api keys runtime update")
-		log.Trace().Int("numKeys", len(startupAppConfig.ApiKeys)).Msg("api keys provided at startup")
-
-		if len(fileContent) > 0 {
-			// Parse JSON content from the file
-			var fileKeys []string
-			err := json.Unmarshal(fileContent, &fileKeys)
-			if err != nil {
-				return err
-			}
-
-			log.Trace().Int("numKeys", len(fileKeys)).Msg("discovered API keys from api keys dynamic config dile")
-
-			appConfig.ApiKeys = append(startupAppConfig.ApiKeys, fileKeys...)
-		} else {
-			log.Trace().Msg("no API keys discovered from dynamic config file")
-			appConfig.ApiKeys = startupAppConfig.ApiKeys
-		}
-		log.Trace().Int("numKeys", len(appConfig.ApiKeys)).Msg("total api keys after processing")
-		return nil
-	}
-
-	return handler
-}
-
-func readExternalBackendsJson(startupAppConfig config.ApplicationConfig) fileHandler {
-	handler := func(fileContent []byte, appConfig *config.ApplicationConfig) error {
-		log.Debug().Msg("processing external_backends.json")
-
-		if len(fileContent) > 0 {
-			// Parse JSON content from the file
-			var fileBackends map[string]string
-			err := json.Unmarshal(fileContent, &fileBackends)
-			if err != nil {
-				return err
-			}
-			appConfig.ExternalGRPCBackends = startupAppConfig.ExternalGRPCBackends
-			err = mergo.Merge(&appConfig.ExternalGRPCBackends, &fileBackends)
-			if err != nil {
-				return err
-			}
-		} else {
-			appConfig.ExternalGRPCBackends = startupAppConfig.ExternalGRPCBackends
-		}
-		log.Debug().Msg("external backends loaded from external_backends.json")
-		return nil
-	}
-	return handler
-}
+package startup
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+	"path"
+	"path/filepath"
+	"time"
+
+	"github.com/fsnotify/fsnotify"
+	"github.com/imdario/mergo"
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/rs/zerolog/log"
+)
+
+type fileHandler func(fileContent []byte, appConfig *config.ApplicationConfig) error
+
+type configFileHandler struct {
+	handlers map[string]fileHandler
+
+	watcher *fsnotify.Watcher
+
+	appConfig *config.ApplicationConfig
+}
+
+// TODO: This should be a singleton eventually so other parts of the code can register config file handlers,
+// then we can export it to other packages
+func newConfigFileHandler(appConfig *config.ApplicationConfig) configFileHandler {
+	c := configFileHandler{
+		handlers:  make(map[string]fileHandler),
+		appConfig: appConfig,
+	}
+	err := c.Register("api_keys.json", readApiKeysJson(*appConfig), true)
+	if err != nil {
+		log.Error().Err(err).Str("file", "api_keys.json").Msg("unable to register config file handler")
+	}
+	err = c.Register("external_backends.json", readExternalBackendsJson(*appConfig), true)
+	if err != nil {
+		log.Error().Err(err).Str("file", "external_backends.json").Msg("unable to register config file handler")
+	}
+	return c
+}
+
+func (c *configFileHandler) Register(filename string, handler fileHandler, runNow bool) error {
+	_, ok := c.handlers[filename]
+	if ok {
+		return fmt.Errorf("handler already registered for file %s", filename)
+	}
+	c.handlers[filename] = handler
+	if runNow {
+		c.callHandler(filename, handler)
+	}
+	return nil
+}
+
+func (c *configFileHandler) callHandler(filename string, handler fileHandler) {
+	rootedFilePath := filepath.Join(c.appConfig.DynamicConfigsDir, filepath.Clean(filename))
+	log.Trace().Str("filename", rootedFilePath).Msg("reading file for dynamic config update")
+	fileContent, err := os.ReadFile(rootedFilePath)
+	if err != nil && !os.IsNotExist(err) {
+		log.Error().Err(err).Str("filename", rootedFilePath).Msg("could not read file")
+	}
+
+	if err = handler(fileContent, c.appConfig); err != nil {
+		log.Error().Err(err).Msg("WatchConfigDirectory goroutine failed to update options")
+	}
+}
+
+func (c *configFileHandler) Watch() error {
+	configWatcher, err := fsnotify.NewWatcher()
+	c.watcher = configWatcher
+	if err != nil {
+		return err
+	}
+
+	if c.appConfig.DynamicConfigsDirPollInterval > 0 {
+		log.Debug().Msg("Poll interval set, falling back to polling for configuration changes")
+		ticker := time.NewTicker(c.appConfig.DynamicConfigsDirPollInterval)
+		go func() {
+			for {
+				<-ticker.C
+				for file, handler := range c.handlers {
+					log.Debug().Str("file", file).Msg("polling config file")
+					c.callHandler(file, handler)
+				}
+			}
+		}()
+	}
+
+	// Start listening for events.
+	go func() {
+		for {
+			select {
+			case event, ok := <-c.watcher.Events:
+				if !ok {
+					return
+				}
+				if event.Has(fsnotify.Write | fsnotify.Create | fsnotify.Remove) {
+					handler, ok := c.handlers[path.Base(event.Name)]
+					if !ok {
+						continue
+					}
+
+					c.callHandler(filepath.Base(event.Name), handler)
+				}
+			case err, ok := <-c.watcher.Errors:
+				log.Error().Err(err).Msg("config watcher error received")
+				if !ok {
+					return
+				}
+			}
+		}
+	}()
+
+	// Add a path.
+	err = c.watcher.Add(c.appConfig.DynamicConfigsDir)
+	if err != nil {
+		return fmt.Errorf("unable to create a watcher on the configuration directory: %+v", err)
+	}
+
+	return nil
+}
+
+// TODO: When we institute graceful shutdown, this should be called
+func (c *configFileHandler) Stop() error {
+	return c.watcher.Close()
+}
+
+func readApiKeysJson(startupAppConfig config.ApplicationConfig) fileHandler {
+	handler := func(fileContent []byte, appConfig *config.ApplicationConfig) error {
+		log.Debug().Msg("processing api keys runtime update")
+		log.Trace().Int("numKeys", len(startupAppConfig.ApiKeys)).Msg("api keys provided at startup")
+
+		if len(fileContent) > 0 {
+			// Parse JSON content from the file
+			var fileKeys []string
+			err := json.Unmarshal(fileContent, &fileKeys)
+			if err != nil {
+				return err
+			}
+
+			log.Trace().Int("numKeys", len(fileKeys)).Msg("discovered API keys from api keys dynamic config dile")
+
+			appConfig.ApiKeys = append(startupAppConfig.ApiKeys, fileKeys...)
+		} else {
+			log.Trace().Msg("no API keys discovered from dynamic config file")
+			appConfig.ApiKeys = startupAppConfig.ApiKeys
+		}
+		log.Trace().Int("numKeys", len(appConfig.ApiKeys)).Msg("total api keys after processing")
+		return nil
+	}
+
+	return handler
+}
+
+func readExternalBackendsJson(startupAppConfig config.ApplicationConfig) fileHandler {
+	handler := func(fileContent []byte, appConfig *config.ApplicationConfig) error {
+		log.Debug().Msg("processing external_backends.json")
+
+		if len(fileContent) > 0 {
+			// Parse JSON content from the file
+			var fileBackends map[string]string
+			err := json.Unmarshal(fileContent, &fileBackends)
+			if err != nil {
+				return err
+			}
+			appConfig.ExternalGRPCBackends = startupAppConfig.ExternalGRPCBackends
+			err = mergo.Merge(&appConfig.ExternalGRPCBackends, &fileBackends)
+			if err != nil {
+				return err
+			}
+		} else {
+			appConfig.ExternalGRPCBackends = startupAppConfig.ExternalGRPCBackends
+		}
+		log.Debug().Msg("external backends loaded from external_backends.json")
+		return nil
+	}
+	return handler
+}
core/startup/startup.go
-package startup
-
-import (
-	"fmt"
-	"os"
-
-	"github.com/mudler/LocalAI/core"
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/services"
-	"github.com/mudler/LocalAI/internal"
-	"github.com/mudler/LocalAI/pkg/assets"
-	"github.com/mudler/LocalAI/pkg/library"
-	"github.com/mudler/LocalAI/pkg/model"
-	pkgStartup "github.com/mudler/LocalAI/pkg/startup"
-	"github.com/mudler/LocalAI/pkg/xsysinfo"
-	"github.com/rs/zerolog/log"
-)
-
-func Startup(opts ...config.AppOption) (*config.BackendConfigLoader, *model.ModelLoader, *config.ApplicationConfig, error) {
-	options := config.NewApplicationConfig(opts...)
-
-	log.Info().Msgf("Starting LocalAI using %d threads, with models path: %s", options.Threads, options.ModelPath)
-	log.Info().Msgf("LocalAI version: %s", internal.PrintableVersion())
-	caps, err := xsysinfo.CPUCapabilities()
-	if err == nil {
-		log.Debug().Msgf("CPU capabilities: %v", caps)
-	}
-	gpus, err := xsysinfo.GPUs()
-	if err == nil {
-		log.Debug().Msgf("GPU count: %d", len(gpus))
-		for _, gpu := range gpus {
-			log.Debug().Msgf("GPU: %s", gpu.String())
-		}
-	}
-
-	// Make sure directories exists
-	if options.ModelPath == "" {
-		return nil, nil, nil, fmt.Errorf("options.ModelPath cannot be empty")
-	}
-	err = os.MkdirAll(options.ModelPath, 0750)
-	if err != nil {
-		return nil, nil, nil, fmt.Errorf("unable to create ModelPath: %q", err)
-	}
-	if options.ImageDir != "" {
-		err := os.MkdirAll(options.ImageDir, 0750)
-		if err != nil {
-			return nil, nil, nil, fmt.Errorf("unable to create ImageDir: %q", err)
-		}
-	}
-	if options.AudioDir != "" {
-		err := os.MkdirAll(options.AudioDir, 0750)
-		if err != nil {
-			return nil, nil, nil, fmt.Errorf("unable to create AudioDir: %q", err)
-		}
-	}
-	if options.UploadDir != "" {
-		err := os.MkdirAll(options.UploadDir, 0750)
-		if err != nil {
-			return nil, nil, nil, fmt.Errorf("unable to create UploadDir: %q", err)
-		}
-	}
-
-	if err := pkgStartup.InstallModels(options.Galleries, options.ModelLibraryURL, options.ModelPath, options.EnforcePredownloadScans, nil, options.ModelsURL...); err != nil {
-		log.Error().Err(err).Msg("error installing models")
-	}
-
-	cl := config.NewBackendConfigLoader(options.ModelPath)
-	ml := model.NewModelLoader(options.ModelPath)
-
-	configLoaderOpts := options.ToConfigLoaderOptions()
-
-	if err := cl.LoadBackendConfigsFromPath(options.ModelPath, configLoaderOpts...); err != nil {
-		log.Error().Err(err).Msg("error loading config files")
-	}
-
-	if options.ConfigFile != "" {
-		if err := cl.LoadMultipleBackendConfigsSingleFile(options.ConfigFile, configLoaderOpts...); err != nil {
-			log.Error().Err(err).Msg("error loading config file")
-		}
-	}
-
-	if err := cl.Preload(options.ModelPath); err != nil {
-		log.Error().Err(err).Msg("error downloading models")
-	}
-
-	if options.PreloadJSONModels != "" {
-		if err := services.ApplyGalleryFromString(options.ModelPath, options.PreloadJSONModels, options.EnforcePredownloadScans, options.Galleries); err != nil {
-			return nil, nil, nil, err
-		}
-	}
-
-	if options.PreloadModelsFromPath != "" {
-		if err := services.ApplyGalleryFromFile(options.ModelPath, options.PreloadModelsFromPath, options.EnforcePredownloadScans, options.Galleries); err != nil {
-			return nil, nil, nil, err
-		}
-	}
-
-	if options.Debug {
-		for _, v := range cl.GetAllBackendConfigs() {
-			log.Debug().Msgf("Model: %s (config: %+v)", v.Name, v)
-		}
-	}
-
-	if options.AssetsDestination != "" {
-		// Extract files from the embedded FS
-		err := assets.ExtractFiles(options.BackendAssets, options.AssetsDestination)
-		log.Debug().Msgf("Extracting backend assets files to %s", options.AssetsDestination)
-		if err != nil {
-			log.Warn().Msgf("Failed extracting backend assets files: %s (might be required for some backends to work properly, like gpt4all)", err)
-		}
-	}
-
-	if options.LibPath != "" {
-		// If there is a lib directory, set LD_LIBRARY_PATH to include it
-		err := library.LoadExternal(options.LibPath)
-		if err != nil {
-			log.Error().Err(err).Str("LibPath", options.LibPath).Msg("Error while loading external libraries")
-		}
-	}
-
-	// turn off any process that was started by GRPC if the context is canceled
-	go func() {
-		<-options.Context.Done()
-		log.Debug().Msgf("Context canceled, shutting down")
-		err := ml.StopAllGRPC()
-		if err != nil {
-			log.Error().Err(err).Msg("error while stopping all grpc backends")
-		}
-	}()
-
-	if options.WatchDog {
-		wd := model.NewWatchDog(
-			ml,
-			options.WatchDogBusyTimeout,
-			options.WatchDogIdleTimeout,
-			options.WatchDogBusy,
-			options.WatchDogIdle)
-		ml.SetWatchDog(wd)
-		go wd.Run()
-		go func() {
-			<-options.Context.Done()
-			log.Debug().Msgf("Context canceled, shutting down")
-			wd.Shutdown()
-		}()
-	}
-
-	// Watch the configuration directory
-	startWatcher(options)
-
-	log.Info().Msg("core/startup process completed!")
-	return cl, ml, options, nil
-}
-
-func startWatcher(options *config.ApplicationConfig) {
-	if options.DynamicConfigsDir == "" {
-		// No need to start the watcher if the directory is not set
-		return
-	}
-
-	if _, err := os.Stat(options.DynamicConfigsDir); err != nil {
-		if os.IsNotExist(err) {
-			// We try to create the directory if it does not exist and was specified
-			if err := os.MkdirAll(options.DynamicConfigsDir, 0700); err != nil {
-				log.Error().Err(err).Msg("failed creating DynamicConfigsDir")
-			}
-		} else {
-			// something else happened, we log the error and don't start the watcher
-			log.Error().Err(err).Msg("failed to read DynamicConfigsDir, watcher will not be started")
-			return
-		}
-	}
-
-	configHandler := newConfigFileHandler(options)
-	if err := configHandler.Watch(); err != nil {
-		log.Error().Err(err).Msg("failed creating watcher")
-	}
-}
-
-// In Lieu of a proper DI framework, this function wires up the Application manually.
-// This is in core/startup rather than core/state.go to keep package references clean!
-func createApplication(appConfig *config.ApplicationConfig) *core.Application {
-	app := &core.Application{
-		ApplicationConfig:   appConfig,
-		BackendConfigLoader: config.NewBackendConfigLoader(appConfig.ModelPath),
-		ModelLoader:         model.NewModelLoader(appConfig.ModelPath),
-	}
-
-	var err error
-
-	// app.EmbeddingsBackendService = backend.NewEmbeddingsBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	// app.ImageGenerationBackendService = backend.NewImageGenerationBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	// app.LLMBackendService = backend.NewLLMBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	// app.TranscriptionBackendService = backend.NewTranscriptionBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	// app.TextToSpeechBackendService = backend.NewTextToSpeechBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-
-	app.BackendMonitorService = services.NewBackendMonitorService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	app.GalleryService = services.NewGalleryService(app.ApplicationConfig)
-	// app.OpenAIService = services.NewOpenAIService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig, app.LLMBackendService)
-
-	app.LocalAIMetricsService, err = services.NewLocalAIMetricsService()
-	if err != nil {
-		log.Error().Err(err).Msg("encountered an error initializing metrics service, startup will continue but metrics will not be tracked.")
-	}
-
-	return app
-}
+package startup
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/mudler/LocalAI/core"
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/services"
+	"github.com/mudler/LocalAI/internal"
+	"github.com/mudler/LocalAI/pkg/assets"
+	"github.com/mudler/LocalAI/pkg/library"
+	"github.com/mudler/LocalAI/pkg/model"
+	pkgStartup "github.com/mudler/LocalAI/pkg/startup"
+	"github.com/mudler/LocalAI/pkg/xsysinfo"
+	"github.com/rs/zerolog/log"
+)
+
+func Startup(opts ...config.AppOption) (*config.BackendConfigLoader, *model.ModelLoader, *config.ApplicationConfig, error) {
+	options := config.NewApplicationConfig(opts...)
+
+	log.Info().Msgf("Starting LocalAI using %d threads, with models path: %s", options.Threads, options.ModelPath)
+	log.Info().Msgf("LocalAI version: %s", internal.PrintableVersion())
+	caps, err := xsysinfo.CPUCapabilities()
+	if err == nil {
+		log.Debug().Msgf("CPU capabilities: %v", caps)
+	}
+	gpus, err := xsysinfo.GPUs()
+	if err == nil {
+		log.Debug().Msgf("GPU count: %d", len(gpus))
+		for _, gpu := range gpus {
+			log.Debug().Msgf("GPU: %s", gpu.String())
+		}
+	}
+
+	// Make sure directories exists
+	if options.ModelPath == "" {
+		return nil, nil, nil, fmt.Errorf("options.ModelPath cannot be empty")
+	}
+	err = os.MkdirAll(options.ModelPath, 0750)
+	if err != nil {
+		return nil, nil, nil, fmt.Errorf("unable to create ModelPath: %q", err)
+	}
+	if options.ImageDir != "" {
+		err := os.MkdirAll(options.ImageDir, 0750)
+		if err != nil {
+			return nil, nil, nil, fmt.Errorf("unable to create ImageDir: %q", err)
+		}
+	}
+	if options.AudioDir != "" {
+		err := os.MkdirAll(options.AudioDir, 0750)
+		if err != nil {
+			return nil, nil, nil, fmt.Errorf("unable to create AudioDir: %q", err)
+		}
+	}
+	if options.UploadDir != "" {
+		err := os.MkdirAll(options.UploadDir, 0750)
+		if err != nil {
+			return nil, nil, nil, fmt.Errorf("unable to create UploadDir: %q", err)
+		}
+	}
+
+	if err := pkgStartup.InstallModels(options.Galleries, options.ModelLibraryURL, options.ModelPath, options.EnforcePredownloadScans, nil, options.ModelsURL...); err != nil {
+		log.Error().Err(err).Msg("error installing models")
+	}
+
+	cl := config.NewBackendConfigLoader(options.ModelPath)
+	ml := model.NewModelLoader(options.ModelPath)
+
+	configLoaderOpts := options.ToConfigLoaderOptions()
+
+	if err := cl.LoadBackendConfigsFromPath(options.ModelPath, configLoaderOpts...); err != nil {
+		log.Error().Err(err).Msg("error loading config files")
+	}
+
+	if options.ConfigFile != "" {
+		if err := cl.LoadMultipleBackendConfigsSingleFile(options.ConfigFile, configLoaderOpts...); err != nil {
+			log.Error().Err(err).Msg("error loading config file")
+		}
+	}
+
+	if err := cl.Preload(options.ModelPath); err != nil {
+		log.Error().Err(err).Msg("error downloading models")
+	}
+
+	if options.PreloadJSONModels != "" {
+		if err := services.ApplyGalleryFromString(options.ModelPath, options.PreloadJSONModels, options.EnforcePredownloadScans, options.Galleries); err != nil {
+			return nil, nil, nil, err
+		}
+	}
+
+	if options.PreloadModelsFromPath != "" {
+		if err := services.ApplyGalleryFromFile(options.ModelPath, options.PreloadModelsFromPath, options.EnforcePredownloadScans, options.Galleries); err != nil {
+			return nil, nil, nil, err
+		}
+	}
+
+	if options.Debug {
+		for _, v := range cl.GetAllBackendConfigs() {
+			log.Debug().Msgf("Model: %s (config: %+v)", v.Name, v)
+		}
+	}
+
+	if options.AssetsDestination != "" {
+		// Extract files from the embedded FS
+		err := assets.ExtractFiles(options.BackendAssets, options.AssetsDestination)
+		log.Debug().Msgf("Extracting backend assets files to %s", options.AssetsDestination)
+		if err != nil {
+			log.Warn().Msgf("Failed extracting backend assets files: %s (might be required for some backends to work properly, like gpt4all)", err)
+		}
+	}
+
+	if options.LibPath != "" {
+		// If there is a lib directory, set LD_LIBRARY_PATH to include it
+		err := library.LoadExternal(options.LibPath)
+		if err != nil {
+			log.Error().Err(err).Str("LibPath", options.LibPath).Msg("Error while loading external libraries")
+		}
+	}
+
+	// turn off any process that was started by GRPC if the context is canceled
+	go func() {
+		<-options.Context.Done()
+		log.Debug().Msgf("Context canceled, shutting down")
+		err := ml.StopAllGRPC()
+		if err != nil {
+			log.Error().Err(err).Msg("error while stopping all grpc backends")
+		}
+	}()
+
+	if options.WatchDog {
+		wd := model.NewWatchDog(
+			ml,
+			options.WatchDogBusyTimeout,
+			options.WatchDogIdleTimeout,
+			options.WatchDogBusy,
+			options.WatchDogIdle)
+		ml.SetWatchDog(wd)
+		go wd.Run()
+		go func() {
+			<-options.Context.Done()
+			log.Debug().Msgf("Context canceled, shutting down")
+			wd.Shutdown()
+		}()
+	}
+
+	// Watch the configuration directory
+	startWatcher(options)
+
+	log.Info().Msg("core/startup process completed!")
+	return cl, ml, options, nil
+}
+
+func startWatcher(options *config.ApplicationConfig) {
+	if options.DynamicConfigsDir == "" {
+		// No need to start the watcher if the directory is not set
+		return
+	}
+
+	if _, err := os.Stat(options.DynamicConfigsDir); err != nil {
+		if os.IsNotExist(err) {
+			// We try to create the directory if it does not exist and was specified
+			if err := os.MkdirAll(options.DynamicConfigsDir, 0700); err != nil {
+				log.Error().Err(err).Msg("failed creating DynamicConfigsDir")
+			}
+		} else {
+			// something else happened, we log the error and don't start the watcher
+			log.Error().Err(err).Msg("failed to read DynamicConfigsDir, watcher will not be started")
+			return
+		}
+	}
+
+	configHandler := newConfigFileHandler(options)
+	if err := configHandler.Watch(); err != nil {
+		log.Error().Err(err).Msg("failed creating watcher")
+	}
+}
+
+// In Lieu of a proper DI framework, this function wires up the Application manually.
+// This is in core/startup rather than core/state.go to keep package references clean!
+func createApplication(appConfig *config.ApplicationConfig) *core.Application {
+	app := &core.Application{
+		ApplicationConfig:   appConfig,
+		BackendConfigLoader: config.NewBackendConfigLoader(appConfig.ModelPath),
+		ModelLoader:         model.NewModelLoader(appConfig.ModelPath),
+	}
+
+	var err error
+
+	// app.EmbeddingsBackendService = backend.NewEmbeddingsBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	// app.ImageGenerationBackendService = backend.NewImageGenerationBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	// app.LLMBackendService = backend.NewLLMBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	// app.TranscriptionBackendService = backend.NewTranscriptionBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	// app.TextToSpeechBackendService = backend.NewTextToSpeechBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+
+	app.BackendMonitorService = services.NewBackendMonitorService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	app.GalleryService = services.NewGalleryService(app.ApplicationConfig)
+	// app.OpenAIService = services.NewOpenAIService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig, app.LLMBackendService)
+
+	app.LocalAIMetricsService, err = services.NewLocalAIMetricsService()
+	if err != nil {
+		log.Error().Err(err).Msg("encountered an error initializing metrics service, startup will continue but metrics will not be tracked.")
+	}
+
+	return app
+}
pkg/utils/base64.go
-package utils
-
-import (
-	"encoding/base64"
-	"fmt"
-	"io"
-	"net/http"
-	"strings"
-	"time"
-)
-
-var base64DownloadClient http.Client = http.Client{
-	Timeout: 30 * time.Second,
-}
-
-// this function check if the string is an URL, if it's an URL downloads the image in memory
-// encodes it in base64 and returns the base64 string
-
-// This may look weird down in pkg/utils while it is currently only used in core/config
-//
-//	but I believe it may be useful for MQTT as well in the near future, so I'm
-//	extracting it while I'm thinking of it.
-func GetImageURLAsBase64(s string) (string, error) {
-	if strings.HasPrefix(s, "http") {
-		// download the image
-		resp, err := base64DownloadClient.Get(s)
-		if err != nil {
-			return "", err
-		}
-		defer resp.Body.Close()
-
-		// read the image data into memory
-		data, err := io.ReadAll(resp.Body)
-		if err != nil {
-			return "", err
-		}
-
-		// encode the image data in base64
-		encoded := base64.StdEncoding.EncodeToString(data)
-
-		// return the base64 string
-		return encoded, nil
-	}
-
-	// if the string instead is prefixed with "data:image/...;base64,", drop it
-	dropPrefix := []string{"data:image/jpeg;base64,", "data:image/png;base64,"}
-	for _, prefix := range dropPrefix {
-		if strings.HasPrefix(s, prefix) {
-			return strings.ReplaceAll(s, prefix, ""), nil
-		}
-	}
-	return "", fmt.Errorf("not valid string")
-}
+package utils
+
+import (
+	"encoding/base64"
+	"fmt"
+	"io"
+	"net/http"
+	"strings"
+	"time"
+)
+
+var base64DownloadClient http.Client = http.Client{
+	Timeout: 30 * time.Second,
+}
+
+// this function check if the string is an URL, if it's an URL downloads the image in memory
+// encodes it in base64 and returns the base64 string
+
+// This may look weird down in pkg/utils while it is currently only used in core/config
+//
+//	but I believe it may be useful for MQTT as well in the near future, so I'm
+//	extracting it while I'm thinking of it.
+func GetImageURLAsBase64(s string) (string, error) {
+	if strings.HasPrefix(s, "http") {
+		// download the image
+		resp, err := base64DownloadClient.Get(s)
+		if err != nil {
+			return "", err
+		}
+		defer resp.Body.Close()
+
+		// read the image data into memory
+		data, err := io.ReadAll(resp.Body)
+		if err != nil {
+			return "", err
+		}
+
+		// encode the image data in base64
+		encoded := base64.StdEncoding.EncodeToString(data)
+
+		// return the base64 string
+		return encoded, nil
+	}
+
+	// if the string instead is prefixed with "data:image/...;base64,", drop it
+	dropPrefix := []string{"data:image/jpeg;base64,", "data:image/png;base64,"}
+	for _, prefix := range dropPrefix {
+		if strings.HasPrefix(s, prefix) {
+			return strings.ReplaceAll(s, prefix, ""), nil
+		}
+	}
+	return "", fmt.Errorf("not valid string")
+}
pkg/utils/base64_test.go
-package utils_test
-
-import (
-	. "github.com/mudler/LocalAI/pkg/utils"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-)
-
-var _ = Describe("utils/base64 tests", func() {
-	It("GetImageURLAsBase64 can strip jpeg data url prefixes", func() {
-		// This one doesn't actually _care_ that it's base64, so feed "bad" data in this test in order to catch a change in that behavior for informational purposes.
-		input := "data:image/jpeg;base64,FOO"
-		b64, err := GetImageURLAsBase64(input)
-		Expect(err).To(BeNil())
-		Expect(b64).To(Equal("FOO"))
-	})
-	It("GetImageURLAsBase64 can strip png data url prefixes", func() {
-		// This one doesn't actually _care_ that it's base64, so feed "bad" data in this test in order to catch a change in that behavior for informational purposes.
-		input := "data:image/png;base64,BAR"
-		b64, err := GetImageURLAsBase64(input)
-		Expect(err).To(BeNil())
-		Expect(b64).To(Equal("BAR"))
-	})
-	It("GetImageURLAsBase64 returns an error for bogus data", func() {
-		input := "FOO"
-		b64, err := GetImageURLAsBase64(input)
-		Expect(b64).To(Equal(""))
-		Expect(err).ToNot(BeNil())
-		Expect(err).To(MatchError("not valid string"))
-	})
-	It("GetImageURLAsBase64 can actually download images and calculates something", func() {
-		// This test doesn't actually _check_ the results at this time, which is bad, but there wasn't a test at all before...
-		input := "https://upload.wikimedia.org/wikipedia/en/2/29/Wargames.jpg"
-		b64, err := GetImageURLAsBase64(input)
-		Expect(err).To(BeNil())
-		Expect(b64).ToNot(BeNil())
-	})
-})
+package utils_test
+
+import (
+	. "github.com/mudler/LocalAI/pkg/utils"
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+)
+
+var _ = Describe("utils/base64 tests", func() {
+	It("GetImageURLAsBase64 can strip jpeg data url prefixes", func() {
+		// This one doesn't actually _care_ that it's base64, so feed "bad" data in this test in order to catch a change in that behavior for informational purposes.
+		input := "data:image/jpeg;base64,FOO"
+		b64, err := GetImageURLAsBase64(input)
+		Expect(err).To(BeNil())
+		Expect(b64).To(Equal("FOO"))
+	})
+	It("GetImageURLAsBase64 can strip png data url prefixes", func() {
+		// This one doesn't actually _care_ that it's base64, so feed "bad" data in this test in order to catch a change in that behavior for informational purposes.
+		input := "data:image/png;base64,BAR"
+		b64, err := GetImageURLAsBase64(input)
+		Expect(err).To(BeNil())
+		Expect(b64).To(Equal("BAR"))
+	})
+	It("GetImageURLAsBase64 returns an error for bogus data", func() {
+		input := "FOO"
+		b64, err := GetImageURLAsBase64(input)
+		Expect(b64).To(Equal(""))
+		Expect(err).ToNot(BeNil())
+		Expect(err).To(MatchError("not valid string"))
+	})
+	It("GetImageURLAsBase64 can actually download images and calculates something", func() {
+		// This test doesn't actually _check_ the results at this time, which is bad, but there wasn't a test at all before...
+		input := "https://upload.wikimedia.org/wikipedia/en/2/29/Wargames.jpg"
+		b64, err := GetImageURLAsBase64(input)
+		Expect(err).To(BeNil())
+		Expect(b64).ToNot(BeNil())
+	})
+})

Copy link

⚠ shadow failed (.)

pkg/grpc/backend.go:7:2: no required module provides package github.com/mudler/LocalAI/pkg/grpc/proto; to add it:
	go get github.com/mudler/LocalAI/pkg/grpc/proto
assets.go:5:12: pattern backend-assets/*: no matching files found

Copy link

⚠ gosec failed (.)

2024/07/12 08:30:11 internal error: package "fmt" without types was imported from "command-line-arguments"
Show Detail
2024/07/12 08:30:11 internal error: package "fmt" without types was imported from "command-line-arguments"

Code Reference

Copy link

PR description is too short and seems to not fulfill PR template, please fill in

Copy link

⚠ errcheck failed (.)

error: failed to check packages: errors while loading package github.com/mudler/LocalAI/pkg/grpc: [/github/workspace/pkg/grpc/backend.go:38:41: undefined: pb.PredictOptions /github/workspace/pkg/grpc/backend.go:38:87: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/backend.go:39:38: undefined: pb.PredictOptions /github/workspace/pkg/grpc/backend.go:39:84: undefined: pb.Reply /github/workspace/pkg/grpc/backend.go:40:40: undefined: pb.ModelOptions /github/workspace/pkg/grpc/backend.go:40:84: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:41:44: undefined: pb.PredictOptions /github/workspace/pkg/grpc/backend.go:42:44: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/backend.go:42:96: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:43:34: undefined: pb.TTSRequest /github/workspace/pkg/grpc/backend.go:43:76: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:44:49: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/backend.go:45:45: undefined: pb.PredictOptions /github/workspace/pkg/grpc/backend.go:45:91: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/backend.go:46:35: undefined: pb.StatusResponse /github/workspace/pkg/grpc/backend.go:48:40: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/backend.go:48:88: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:49:43: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/backend.go:49:94: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:50:40: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/backend.go:50:88: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/backend.go:51:41: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/backend.go:51:90: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/backend.go:53:37: undefined: pb.RerankRequest /github/workspace/pkg/grpc/backend.go:53:82: undefined: pb.RerankResult /github/workspace/pkg/grpc/server.go:24:5: undefined: pb.UnimplementedBackendServer /github/workspace/pkg/grpc/interface.go:13:14: undefined: pb.PredictOptions /github/workspace/pkg/grpc/interface.go:14:20: undefined: pb.PredictOptions /github/workspace/pkg/grpc/interface.go:15:11: undefined: pb.ModelOptions /github/workspace/pkg/grpc/interface.go:16:17: undefined: pb.PredictOptions /github/workspace/pkg/grpc/interface.go:17:20: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/interface.go:18:25: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/interface.go:19:10: undefined: pb.TTSRequest /github/workspace/pkg/grpc/interface.go:20:21: undefined: pb.PredictOptions /github/workspace/pkg/grpc/interface.go:20:41: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/interface.go:21:15: undefined: pb.StatusResponse /github/workspace/pkg/grpc/interface.go:23:16: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/interface.go:24:19: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/interface.go:25:16: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/interface.go:25:38: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/interface.go:26:17: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/interface.go:26:40: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/client.go:72:57: undefined: pb.PredictOptions /github/workspace/pkg/grpc/client.go:72:103: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/client.go:93:54: undefined: pb.PredictOptions /github/workspace/pkg/grpc/client.go:93:100: undefined: pb.Reply /github/workspace/pkg/grpc/client.go:114:56: undefined: pb.ModelOptions /github/workspace/pkg/grpc/client.go:114:100: undefined: pb.Result /github/workspace/pkg/grpc/client.go:134:60: undefined: pb.PredictOptions /github/workspace/pkg/grpc/client.go:173:60: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/client.go:173:112: undefined: pb.Result /github/workspace/pkg/grpc/client.go:193:50: undefined: pb.TTSRequest /github/workspace/pkg/grpc/client.go:193:92: undefined: pb.Result /github/workspace/pkg/grpc/client.go:213:65: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/client.go:253:61: undefined: pb.PredictOptions /github/workspace/pkg/grpc/client.go:253:107: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/client.go:279:51: undefined: pb.StatusResponse /github/workspace/pkg/grpc/client.go:295:56: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/client.go:295:104: undefined: pb.Result /github/workspace/pkg/grpc/client.go:311:59: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/client.go:311:110: undefined: pb.Result /github/workspace/pkg/grpc/client.go:327:56: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/client.go:327:104: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/client.go:343:57: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/client.go:343:106: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/client.go:359:53: undefined: pb.RerankRequest /github/workspace/pkg/grpc/client.go:359:98: undefined: pb.RerankResult /github/workspace/pkg/grpc/embed.go:56:71: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/embed.go:28:63: undefined: pb.PredictOptions /github/workspace/pkg/grpc/embed.go:28:109: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/embed.go:48:66: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/embed.go:48:118: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:36:62: undefined: pb.ModelOptions /github/workspace/pkg/grpc/embed.go:36:106: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:32:60: undefined: pb.PredictOptions /github/workspace/pkg/grpc/embed.go:32:106: undefined: pb.Reply /github/workspace/pkg/grpc/embed.go:40:66: undefined: pb.PredictOptions /github/workspace/pkg/grpc/embed.go:104:59: undefined: pb.RerankRequest /github/workspace/pkg/grpc/embed.go:104:104: undefined: pb.RerankResult /github/workspace/pkg/grpc/embed.go:84:57: undefined: pb.StatusResponse /github/workspace/pkg/grpc/embed.go:92:65: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/embed.go:92:116: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:100:63: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/embed.go:100:112: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/embed.go:96:62: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/embed.go:96:110: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/embed.go:88:62: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/embed.go:88:110: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:52:56: undefined: pb.TTSRequest /github/workspace/pkg/grpc/embed.go:52:98: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:80:67: undefined: pb.PredictOptions /github/workspace/pkg/grpc/embed.go:80:113: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/embed.go:14:10: undefined: pb.Backend_PredictStreamServer /github/workspace/pkg/grpc/embed.go:113:51: undefined: pb.Reply /github/workspace/pkg/grpc/interface.go:29:29: undefined: pb.Reply /github/workspace/pkg/grpc/server.go:28:53: undefined: pb.HealthMessage /github/workspace/pkg/grpc/server.go:28:73: undefined: pb.Reply /github/workspace/pkg/grpc/server.go:32:56: undefined: pb.PredictOptions /github/workspace/pkg/grpc/server.go:32:77: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/server.go:45:56: undefined: pb.ModelOptions /github/workspace/pkg/grpc/server.go:45:75: undefined: pb.Result /github/workspace/pkg/grpc/server.go:57:54: undefined: pb.PredictOptions /github/workspace/pkg/grpc/server.go:57:75: undefined: pb.Reply /github/workspace/pkg/grpc/server.go:66:60: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/server.go:66:87: undefined: pb.Result /github/workspace/pkg/grpc/server.go:78:50: undefined: pb.TTSRequest /github/workspace/pkg/grpc/server.go:78:67: undefined: pb.Result /github/workspace/pkg/grpc/server.go:90:65: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/server.go:90:89: undefined: pb.TranscriptResult /github/workspace/pkg/grpc/server.go:119:39: undefined: pb.PredictOptions /github/workspace/pkg/grpc/server.go:119:65: undefined: pb.Backend_PredictStreamServer /github/workspace/pkg/grpc/server.go:140:61: undefined: pb.PredictOptions /github/workspace/pkg/grpc/server.go:140:82: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/server.go:161:53: undefined: pb.HealthMessage /github/workspace/pkg/grpc/server.go:161:73: undefined: pb.StatusResponse /github/workspace/pkg/grpc/server.go:170:56: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/server.go:170:79: undefined: pb.Result /github/workspace/pkg/grpc/server.go:182:59: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/server.go:182:85: undefined: pb.Result /github/workspace/pkg/grpc/server.go:194:56: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/server.go:194:79: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/server.go:206:57: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/server.go:206:81: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/client.go:54:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:60:37: undefined: pb.HealthMessage /github/workspace/pkg/grpc/client.go:88:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:109:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:130:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:150:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:189:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:209:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:229:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:269:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:291:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:292:32: undefined: pb.HealthMessage /github/workspace/pkg/grpc/client.go:307:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:323:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:339:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:355:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:371:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/embed.go:105:13: e.s.Rerank undefined (type *server has no field or method Rerank) /github/workspace/pkg/grpc/embed.go:85:29: undefined: pb.HealthMessage /github/workspace/pkg/grpc/embed.go:134:21: undefined: pb.Reply /github/workspace/pkg/grpc/interface.go:30:13: undefined: pb.Reply /github/workspace/pkg/grpc/server.go:42:13: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/server.go:52:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:54:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:73:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:75:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:85:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:87:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:99:17: undefined: pb.TranscriptResult /github/workspace/pkg/grpc/server.go:106:8: undefined: pb.TranscriptSegment /github/workspace/pkg/grpc/server.go:155:13: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/server.go:177:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:179:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:189:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:191:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:224:5: undefined: pb.RegisterBackendServer /github/workspace/pkg/grpc/server.go:239:5: undefined: pb.RegisterBackendServer]

Copy link

⚠ staticcheck failed (.)

-: # github.com/donomii/go-rwkv.cpp
/go/pkg/mod/github.com/donomii/go-rwkv.cpp@v0.0.0-20240228065144-661e7ae26d44/wrapper.go:16:11: fatal error: rwkv.h: No such file or directory
   16 | //#cgo darwin LDFLAGS: -framework Accelerate -lcblas
      |           ^~~~~~~~
compilation terminated. (compile)
-: # github.com/ggerganov/whisper.cpp/bindings/go
/go/pkg/mod/github.com/ggerganov/whisper.cpp/bindings/go@v0.0.0-20230628193450-85ed71aaec8e/params.go:11:10: fatal error: whisper.h: No such file or directory
   11 | #include <whisper.h>
      |          ^~~~~~~~~~~
compilation terminated. (compile)
-: # github.com/go-skynet/go-bert.cpp
gobert.cpp:1:10: fatal error: ggml.h: No such file or directory
    1 | #include "ggml.h"
      |          ^~~~~~~~
compilation terminated. (compile)
-: # github.com/go-skynet/go-llama.cpp
binding.cpp:1:10: fatal error: common.h: No such file or directory
    1 | #include "common.h"
      |          ^~~~~~~~~~
compilation terminated. (compile)
-: # github.com/mudler/go-piper
gopiper.cpp:14:10: fatal error: spdlog/spdlog.h: No such file or directory
   14 | #include <spdlog/spdlog.h>
      |          ^~~~~~~~~~~~~~~~~
compilation terminated. (compile)
-: # github.com/nomic-ai/gpt4all/gpt4all-bindings/golang
binding.cpp:1:10: fatal error: ../../gpt4all-backend/llmodel_c.h: No such file or directory
    1 | #include "../../gpt4all-backend/llmodel_c.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated. (compile)
-: error obtaining VCS status: exit status 128
	Use -buildvcs=false to disable VCS stamping. (compile)
pkg/functions/grammar_json_schema.go:182:3: empty branch (SA9003)
pkg/functions/grammar_json_schema_test.go:6:2: package "github.com/mudler/LocalAI/pkg/functions" is being imported more than once (ST1019)
	pkg/functions/grammar_json_schema_test.go:7:2: other import of "github.com/mudler/LocalAI/pkg/functions"
pkg/stablediffusion/generate_unsupported.go:9:9: error strings should not be capitalized (ST1005)
pkg/tinydream/generate_unsupported.go:9:9: error strings should not be capitalized (ST1005)
pkg/utils/strings.go:11:2: rand.Seed has been deprecated since Go 1.20 and an alternative has been available since Go 1.0: As of Go 1.20 there is no reason to call Seed with a random value. Programs that call Seed with a known value to get a specific sequence of results should use New(NewSource(seed)) to obtain a local random generator.  (SA1019)
assets.go:5:12: pattern backend-assets/*: no matching files found (compile)
core/http/app_test.go:197:12: pattern backend-assets/*: no matching files found (compile)
pkg/grpc/backend.go:7:2: no required module provides package github.com/mudler/LocalAI/pkg/grpc/proto; to add it:
	go get github.com/mudler/LocalAI/pkg/grpc/proto (compile)
tests/integration/stores_test.go:22:12: pattern backend-assets/*: no matching files found (compile)

Checks Document

@dave-gray101
Copy link
Collaborator

dave-gray101 commented Jul 12, 2024

This is a good idea mudler... but it seems a bit overactive. Can we tune that at all before we set it loose?

Edit: I think I'm blaming the static checker for the description / title actions, which I didn't realize were distinct at first. Guess that's just going to take some getting used to on my part, ha

Copy link

⚠ golint failed (.)

Found 604 lint suggestions; failing.

Show Detail
backend/go/image/stablediffusion/stablediffusion.go:11:6: exported type Image should have comment or be unexported
backend/go/image/stablediffusion/stablediffusion.go:16:1: exported method Image.Load should have comment or be unexported
backend/go/image/stablediffusion/stablediffusion.go:23:1: exported method Image.GenerateImage should have comment or be unexported
backend/go/image/tinydream/tinydream.go:11:6: exported type Image should have comment or be unexported
backend/go/image/tinydream/tinydream.go:16:1: exported method Image.Load should have comment or be unexported
backend/go/image/tinydream/tinydream.go:23:1: exported method Image.GenerateImage should have comment or be unexported
backend/go/llm/bert/bert.go:12:6: exported type Embeddings should have comment or be unexported
backend/go/llm/bert/bert.go:17:1: exported method Embeddings.Load should have comment or be unexported
backend/go/llm/bert/bert.go:23:1: exported method Embeddings.Embeddings should have comment or be unexported
backend/go/llm/gpt4all/gpt4all.go:13:6: exported type LLM should have comment or be unexported
backend/go/llm/gpt4all/gpt4all.go:19:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/gpt4all/gpt4all.go:41:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/gpt4all/gpt4all.go:45:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/langchain/langchain.go:14:6: exported type LLM should have comment or be unexported
backend/go/llm/langchain/langchain.go:21:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/langchain/langchain.go:32:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/langchain/langchain.go:46:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/llama/llama.go:14:6: exported type LLM should have comment or be unexported
backend/go/llm/llama/llama.go:21:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/llama/llama.go:201:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/llama/llama.go:208:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/llama/llama.go:233:1: exported method LLM.Embeddings should have comment or be unexported
backend/go/llm/llama/llama.go:247:1: exported method LLM.TokenizeString should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:13:6: exported type LLM should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:19:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:169:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:173:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/llama-ggml/llama.go:192:1: exported method LLM.Embeddings should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:16:6: exported type LLM should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:22:1: exported method LLM.Load should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:40:1: exported method LLM.Predict should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:55:1: exported method LLM.PredictStream should have comment or be unexported
backend/go/llm/rwkv/rwkv.go:78:1: exported method LLM.TokenizeString should have comment or be unexported
backend/go/stores/store.go:17:6: exported type Store should have comment or be unexported
backend/go/stores/store.go:32:1: comment on exported type Pair should be of the form "Pair ..." (with optional leading article)
backend/go/stores/store.go:39:1: exported function NewStore should have comment or be unexported
backend/go/stores/store.go:101:1: exported method Store.Load should have comment or be unexported
backend/go/stores/store.go:105:1: comment on exported method Store.StoresSet should be of the form "StoresSet ..."
backend/go/stores/store.go:151:2: don't use underscores in Go names; var merge_ks should be mergeKs
backend/go/stores/store.go:152:2: don't use underscores in Go names; var merge_vs should be mergeVs
backend/go/stores/store.go:200:1: exported method Store.StoresDelete should have comment or be unexported
backend/go/stores/store.go:220:2: don't use underscores in Go names; var merge_ks should be mergeKs
backend/go/stores/store.go:221:2: don't use underscores in Go names; var merge_vs should be mergeVs
backend/go/stores/store.go:223:2: don't use underscores in Go names; var tail_ks should be tailKs
backend/go/stores/store.go:224:2: don't use underscores in Go names; var tail_vs should be tailVs
backend/go/stores/store.go:266:1: exported method Store.StoresGet should have comment or be unexported
backend/go/stores/store.go:283:2: don't use underscores in Go names; var tail_k should be tailK
backend/go/stores/store.go:284:2: don't use underscores in Go names; var tail_v should be tailV
backend/go/stores/store.go:337:6: exported type PriorityItem should have comment or be unexported
backend/go/stores/store.go:343:6: exported type PriorityQueue should have comment or be unexported
backend/go/stores/store.go:356:1: exported method PriorityQueue.Push should have comment or be unexported
backend/go/stores/store.go:361:1: exported method PriorityQueue.Pop should have comment or be unexported
backend/go/stores/store.go:369:1: exported method Store.StoresFindNormalized should have comment or be unexported
backend/go/stores/store.go:371:2: don't use underscores in Go names; var top_ks should be topKs
backend/go/stores/store.go:426:1: exported method Store.StoresFindFallback should have comment or be unexported
backend/go/stores/store.go:428:2: don't use underscores in Go names; var top_ks should be topKs
backend/go/stores/store.go:473:1: exported method Store.StoresFind should have comment or be unexported
backend/go/stores/store.go:494:9: if block ends with a return statement, so drop this else and outdent its block
backend/go/transcribe/transcript.go:32:1: exported function Transcript should have comment or be unexported
backend/go/transcribe/whisper.go:12:6: exported type Whisper should have comment or be unexported
backend/go/transcribe/whisper.go:17:1: exported method Whisper.Load should have comment or be unexported
backend/go/transcribe/whisper.go:24:1: exported method Whisper.AudioTranscription should have comment or be unexported
backend/go/tts/piper.go:15:6: exported type Piper should have comment or be unexported
backend/go/tts/piper.go:20:1: exported method Piper.Load should have comment or be unexported
backend/go/tts/piper.go:30:1: exported method Piper.TTS should have comment or be unexported
backend/go/tts/piper.go:34:6: exported type PiperB should have comment or be unexported
backend/go/tts/piper.go:38:1: exported function New should have comment or be unexported
backend/go/tts/piper.go:47:1: exported method PiperB.TTS should have comment or be unexported
core/application.go:9:1: comment on exported type Application should be of the form "Application ..." (with optional leading article)
core/application.go:35:1: comment on exported type ApplicationState should be of the form "ApplicationState ..." (with optional leading article)
core/backend/embeddings.go:12:1: exported function ModelEmbedding should have comment or be unexported
core/backend/image.go:10:1: exported function ImageGeneration should have comment or be unexported
core/backend/image.go:10:59: don't use underscores in Go names; func parameter positive_prompt should be positivePrompt
core/backend/image.go:10:76: don't use underscores in Go names; func parameter negative_prompt should be negativePrompt
core/backend/llm.go:22:6: exported type LLMResponse should have comment or be unexported
core/backend/llm.go:27:6: exported type TokenUsage should have comment or be unexported
core/backend/llm.go:32:1: exported function ModelInference should have comment or be unexported
core/backend/llm.go:150:10: if block ends with a return statement, so drop this else and outdent its block
core/backend/llm.go:175:1: exported function Finetune should have comment or be unexported
core/backend/rerank.go:12:1: exported function Rerank should have comment or be unexported
core/backend/stores.go:10:1: exported function StoreBackend should have comment or be unexported
core/backend/transcript.go:14:1: exported function ModelTranscription should have comment or be unexported
core/backend/tts.go:32:1: exported function ModelTTS should have comment or be unexported
core/cli/cli.go:8:5: exported var CLI should have comment or be unexported
core/cli/federated.go:10:6: exported type FederatedCLI should have comment or be unexported
core/cli/federated.go:15:1: exported method FederatedCLI.Run should have comment or be unexported
core/cli/models.go:18:6: exported type ModelsCMDFlags should have comment or be unexported
core/cli/models.go:23:6: exported type ModelsList should have comment or be unexported
core/cli/models.go:27:6: exported type ModelsInstall should have comment or be unexported
core/cli/models.go:34:6: exported type ModelsCMD should have comment or be unexported
core/cli/models.go:39:1: exported method ModelsList.Run should have comment or be unexported
core/cli/models.go:59:1: exported method ModelsInstall.Run should have comment or be unexported
core/cli/run.go:20:6: exported type RunCMD should have comment or be unexported
core/cli/run.go:68:1: exported method RunCMD.Run should have comment or be unexported
core/cli/transcript.go:15:6: exported type TranscriptCMD should have comment or be unexported
core/cli/transcript.go:27:1: exported method TranscriptCMD.Run should have comment or be unexported
core/cli/tts.go:17:6: exported type TTSCMD should have comment or be unexported
core/cli/tts.go:29:1: exported method TTSCMD.Run should have comment or be unexported
core/cli/util.go:17:6: exported type UtilCMD should have comment or be unexported
core/cli/util.go:22:6: exported type GGUFInfoCMD should have comment or be unexported
core/cli/util.go:27:6: exported type HFScanCMD should have comment or be unexported
core/cli/util.go:33:1: exported method GGUFInfoCMD.Run should have comment or be unexported
core/cli/util.go:69:1: exported method HFScanCMD.Run should have comment or be unexported
core/cli/util.go:85:9: if block ends with a return statement, so drop this else and outdent its block
core/cli/context/context.go:1:1: don't use MixedCaps in package name; cliContext should be clicontext
core/cli/context/context.go:5:6: exported type Context should have comment or be unexported
core/cli/worker/worker.go:3:6: exported type WorkerFlags should have comment or be unexported
core/cli/worker/worker.go:3:6: type name will be used as worker.WorkerFlags by other packages, and that stutters; consider calling this Flags
core/cli/worker/worker.go:7:6: exported type Worker should have comment or be unexported
core/cli/worker/worker_llamacpp.go:14:6: exported type LLamaCPP should have comment or be unexported
core/cli/worker/worker_llamacpp.go:19:1: exported method LLamaCPP.Run should have comment or be unexported
core/cli/worker/worker_nop2p.go:12:6: exported type P2P should have comment or be unexported
core/cli/worker/worker_nop2p.go:14:1: exported method P2P.Run should have comment or be unexported
core/clients/store.go:11:1: comment on exported type StoreClient should be of the form "StoreClient ..." (with optional leading article)
core/clients/store.go:17:6: exported type SetRequest should have comment or be unexported
core/clients/store.go:22:6: exported type GetRequest should have comment or be unexported
core/clients/store.go:26:6: exported type GetResponse should have comment or be unexported
core/clients/store.go:31:6: exported type DeleteRequest should have comment or be unexported
core/clients/store.go:35:6: exported type FindRequest should have comment or be unexported
core/clients/store.go:40:6: exported type FindResponse should have comment or be unexported
core/clients/store.go:46:1: comment on exported function NewStoreClient should be of the form "NewStoreClient ..."
core/clients/store.go:47:21: func parameter baseUrl should be baseURL
core/clients/store.go:54:1: comment on exported method StoreClient.Set should be of the form "Set ..."
core/clients/store.go:59:1: comment on exported method StoreClient.Get should be of the form "Get ..."
core/clients/store.go:75:1: comment on exported method StoreClient.Delete should be of the form "Delete ..."
core/clients/store.go:80:1: comment on exported method StoreClient.Find should be of the form "Find ..."
core/config/application_config.go:13:6: exported type ApplicationConfig should have comment or be unexported
core/config/application_config.go:33:2: struct field ApiKeys should be APIKeys
core/config/application_config.go:61:6: exported type AppOption should have comment or be unexported
core/config/application_config.go:63:1: exported function NewApplicationConfig should have comment or be unexported
core/config/application_config.go:76:1: exported function WithModelsURL should have comment or be unexported
core/config/application_config.go:82:1: exported function WithModelPath should have comment or be unexported
core/config/application_config.go:88:1: exported function WithCors should have comment or be unexported
core/config/application_config.go:94:1: exported function WithCsrf should have comment or be unexported
core/config/application_config.go:100:1: exported function WithP2PToken should have comment or be unexported
core/config/application_config.go:106:1: exported function WithModelLibraryURL should have comment or be unexported
core/config/application_config.go:112:1: exported function WithLibPath should have comment or be unexported
core/config/application_config.go:118:5: exported var EnableWatchDog should have comment or be unexported
core/config/application_config.go:122:5: exported var EnableWatchDogIdleCheck should have comment or be unexported
core/config/application_config.go:127:5: exported var EnableWatchDogBusyCheck should have comment or be unexported
core/config/application_config.go:132:5: exported var DisableWebUI should have comment or be unexported
core/config/application_config.go:136:1: exported function SetWatchDogBusyTimeout should have comment or be unexported
core/config/application_config.go:142:1: exported function SetWatchDogIdleTimeout should have comment or be unexported
core/config/application_config.go:148:5: exported var EnableSingleBackend should have comment or be unexported
core/config/application_config.go:152:5: exported var EnableParallelBackendRequests should have comment or be unexported
core/config/application_config.go:156:5: exported var EnableGalleriesAutoload should have comment or be unexported
core/config/application_config.go:160:1: exported function WithExternalBackend should have comment or be unexported
core/config/application_config.go:169:1: exported function WithCorsAllowOrigins should have comment or be unexported
core/config/application_config.go:175:1: exported function WithBackendAssetsOutput should have comment or be unexported
core/config/application_config.go:181:1: exported function WithBackendAssets should have comment or be unexported
core/config/application_config.go:187:1: exported function WithStringGalleries should have comment or be unexported
core/config/application_config.go:201:1: exported function WithGalleries should have comment or be unexported
core/config/application_config.go:207:1: exported function WithContext should have comment or be unexported
core/config/application_config.go:213:1: exported function WithYAMLConfigPreload should have comment or be unexported
core/config/application_config.go:219:1: exported function WithJSONStringPreload should have comment or be unexported
core/config/application_config.go:224:1: exported function WithConfigFile should have comment or be unexported
core/config/application_config.go:230:1: exported function WithUploadLimitMB should have comment or be unexported
core/config/application_config.go:236:1: exported function WithThreads should have comment or be unexported
core/config/application_config.go:245:1: exported function WithContextSize should have comment or be unexported
core/config/application_config.go:251:1: exported function WithF16 should have comment or be unexported
core/config/application_config.go:257:1: exported function WithDebug should have comment or be unexported
core/config/application_config.go:263:1: exported function WithAudioDir should have comment or be unexported
core/config/application_config.go:269:1: exported function WithImageDir should have comment or be unexported
core/config/application_config.go:275:1: exported function WithUploadDir should have comment or be unexported
core/config/application_config.go:281:1: exported function WithConfigsDir should have comment or be unexported
core/config/application_config.go:287:1: exported function WithDynamicConfigDir should have comment or be unexported
core/config/application_config.go:293:1: exported function WithDynamicConfigDirPollInterval should have comment or be unexported
core/config/application_config.go:299:1: exported function WithApiKeys should have comment or be unexported
core/config/application_config.go:299:6: func WithApiKeys should be WithAPIKeys
core/config/application_config.go:305:1: exported function WithEnforcedPredownloadScans should have comment or be unexported
core/config/application_config.go:311:1: exported function WithOpaqueErrors should have comment or be unexported
core/config/backend_config.go:15:2: don't use ALL_CAPS in Go names; use CamelCase
core/config/backend_config.go:15:2: exported const RAND_SEED should have comment (or a comment on this block) or be unexported
core/config/backend_config.go:18:6: exported type TTSConfig should have comment or be unexported
core/config/backend_config.go:27:6: exported type BackendConfig should have comment or be unexported
core/config/backend_config.go:74:6: exported type File should have comment or be unexported
core/config/backend_config.go:80:6: exported type VallE should have comment or be unexported
core/config/backend_config.go:84:6: exported type FeatureFlag should have comment or be unexported
core/config/backend_config.go:86:1: exported method FeatureFlag.Enabled should have comment or be unexported
core/config/backend_config.go:91:6: exported type GRPC should have comment or be unexported
core/config/backend_config.go:96:6: exported type Diffusers should have comment or be unexported
core/config/backend_config.go:197:1: exported method BackendConfig.SetFunctionCallString should have comment or be unexported
core/config/backend_config.go:201:1: exported method BackendConfig.SetFunctionCallNameString should have comment or be unexported
core/config/backend_config.go:205:1: exported method BackendConfig.ShouldUseFunctions should have comment or be unexported
core/config/backend_config.go:209:1: exported method BackendConfig.ShouldCallSpecificFunction should have comment or be unexported
core/config/backend_config.go:224:1: exported method BackendConfig.IsMMProjURL should have comment or be unexported
core/config/backend_config.go:228:1: exported method BackendConfig.IsModelURL should have comment or be unexported
core/config/backend_config.go:243:1: exported method BackendConfig.FunctionToCall should have comment or be unexported
core/config/backend_config.go:252:1: exported method BackendConfig.SetDefaults should have comment or be unexported
core/config/backend_config.go:252:1: receiver name cfg should be consistent with previous receiver name c for BackendConfig
core/config/backend_config.go:379:1: exported method BackendConfig.Validate should have comment or be unexported
core/config/backend_config.go:406:1: exported method BackendConfig.HasTemplate should have comment or be unexported
core/config/backend_config_loader.go:21:6: exported type BackendConfigLoader should have comment or be unexported
core/config/backend_config_loader.go:27:1: exported function NewBackendConfigLoader should have comment or be unexported
core/config/backend_config_loader.go:34:6: exported type LoadOptions should have comment or be unexported
core/config/backend_config_loader.go:41:1: exported function LoadOptionDebug should have comment or be unexported
core/config/backend_config_loader.go:47:1: exported function LoadOptionThreads should have comment or be unexported
core/config/backend_config_loader.go:53:1: exported function LoadOptionContextSize should have comment or be unexported
core/config/backend_config_loader.go:59:1: exported function ModelPath should have comment or be unexported
core/config/backend_config_loader.go:65:1: exported function LoadOptionF16 should have comment or be unexported
core/config/backend_config_loader.go:71:6: exported type ConfigLoaderOption should have comment or be unexported
core/config/backend_config_loader.go:71:6: type name will be used as config.ConfigLoaderOption by other packages, and that stutters; consider calling this LoaderOption
core/config/backend_config_loader.go:73:1: exported method LoadOptions.Apply should have comment or be unexported
core/config/backend_config_loader.go:114:1: comment on exported method BackendConfigLoader.LoadBackendConfigFileByName should be of the form "LoadBackendConfigFileByName ..."
core/config/backend_config_loader.go:148:1: comment on exported method BackendConfigLoader.LoadMultipleBackendConfigsSingleFile should be of the form "LoadMultipleBackendConfigsSingleFile ..."
core/config/backend_config_loader.go:165:1: exported method BackendConfigLoader.LoadBackendConfig should have comment or be unexported
core/config/backend_config_loader.go:182:1: exported method BackendConfigLoader.GetBackendConfig should have comment or be unexported
core/config/backend_config_loader.go:189:1: exported method BackendConfigLoader.GetAllBackendConfigs should have comment or be unexported
core/config/backend_config_loader.go:204:1: exported method BackendConfigLoader.RemoveBackendConfig should have comment or be unexported
core/config/gallery.go:3:6: exported type Gallery should have comment or be unexported
core/config/guesser.go:16:2: exported const Unknown should have comment (or a comment on this block) or be unexported
core/dependencies_manager/manager.go:13:6: exported type Asset should have comment or be unexported
core/gallery/gallery.go:18:1: comment on exported function InstallModelFromGallery should be of the form "InstallModelFromGallery ..."
core/gallery/gallery.go:87:1: exported function FindModel should have comment or be unexported
core/gallery/gallery.go:114:1: comment on exported function AvailableGalleryModels should be of the form "AvailableGalleryModels ..."
core/gallery/gallery.go:179:1: exported function GetLocalModelConfiguration should have comment or be unexported
core/gallery/gallery.go:185:1: exported function DeleteModelFromSystem should have comment or be unexported
core/gallery/gallery.go:239:1: comment on exported function SafetyScanGalleryModels should be of the form "SafetyScanGalleryModels ..."
core/gallery/gallery.go:254:1: exported function SafetyScanGalleryModel should have comment or be unexported
core/gallery/models.go:18:1: comment on exported type Config should be of the form "Config ..." (with optional leading article)
core/gallery/models.go:58:6: exported type File should have comment or be unexported
core/gallery/models.go:64:6: exported type PromptTemplate should have comment or be unexported
core/gallery/models.go:69:1: exported function GetGalleryConfigFromURL should have comment or be unexported
core/gallery/models.go:81:1: exported function ReadConfigFile should have comment or be unexported
core/gallery/models.go:98:1: exported function InstallModel should have comment or be unexported
core/gallery/op.go:5:6: exported type GalleryOp should have comment or be unexported
core/gallery/op.go:5:6: type name will be used as gallery.GalleryOp by other packages, and that stutters; consider calling this Op
core/gallery/op.go:6:2: struct field Id should be ID
core/gallery/op.go:15:6: exported type GalleryOpStatus should have comment or be unexported
core/gallery/op.go:15:6: type name will be used as gallery.GalleryOpStatus by other packages, and that stutters; consider calling this OpStatus
core/gallery/request.go:13:6: type name will be used as gallery.GalleryModel by other packages, and that stutters; consider calling this Model
core/gallery/request.go:33:1: exported method GalleryModel.ID should have comment or be unexported
core/gallery/request.go:37:6: exported type GalleryModels should have comment or be unexported
core/gallery/request.go:37:6: type name will be used as gallery.GalleryModels by other packages, and that stutters; consider calling this Models
core/gallery/request.go:39:1: exported method GalleryModels.Search should have comment or be unexported
core/gallery/request.go:53:1: exported method GalleryModels.FindByName should have comment or be unexported
core/http/app.go:36:2: var xApiKey should be xAPIKey
core/http/app.go:68:1: exported function App should have comment or be unexported
core/http/render.go:27:9: if block ends with a return statement, so drop this else and outdent its block
core/http/ctx/fiber.go:1:1: don't use MixedCaps in package name; fiberContext should be fibercontext
core/http/elements/gallery.go:27:1: exported function DoneProgress should have comment or be unexported
core/http/elements/gallery.go:51:1: exported function ErrorProgress should have comment or be unexported
core/http/elements/gallery.go:67:1: exported function ProgressBar should have comment or be unexported
core/http/elements/gallery.go:84:1: exported function P2PNodeStats should have comment or be unexported
core/http/elements/gallery.go:134:1: exported function P2PNodeBoxes should have comment or be unexported
core/http/elements/gallery.go:213:1: exported function StartProgressBar should have comment or be unexported
core/http/elements/gallery.go:375:1: exported function ListModels should have comment or be unexported
core/http/endpoints/jina/rerank.go:20:6: func name will be used as jina.JINARerankEndpoint by other packages, and that stutters; consider calling this RerankEndpoint
core/http/endpoints/localai/backend_monitor.go:31:1: comment on exported function BackendShutdownEndpoint should be of the form "BackendShutdownEndpoint ..."
core/http/endpoints/localai/gallery.go:17:6: exported type ModelGalleryEndpointService should have comment or be unexported
core/http/endpoints/localai/gallery.go:23:6: exported type GalleryModel should have comment or be unexported
core/http/endpoints/localai/gallery.go:29:1: exported function CreateModelGalleryEndpointService should have comment or be unexported
core/http/endpoints/localai/metrics.go:16:6: func name will be used as localai.LocalAIMetricsEndpoint by other packages, and that stutters; consider calling this MetricsEndpoint
core/http/endpoints/localai/metrics.go:25:1: exported function LocalAIMetricsAPIMiddleware should have comment or be unexported
core/http/endpoints/localai/metrics.go:25:6: func name will be used as localai.LocalAIMetricsAPIMiddleware by other packages, and that stutters; consider calling this MetricsAPIMiddleware
core/http/endpoints/localai/stores.go:12:1: exported function StoresSetEndpoint should have comment or be unexported
core/http/endpoints/localai/stores.go:39:1: exported function StoresDeleteEndpoint should have comment or be unexported
core/http/endpoints/localai/stores.go:60:1: exported function StoresGetEndpoint should have comment or be unexported
core/http/endpoints/localai/stores.go:91:1: exported function StoresFindEndpoint should have comment or be unexported
core/http/endpoints/localai/welcome.go:13:1: exported function WelcomeEndpoint should have comment or be unexported
core/http/endpoints/localai/welcome.go:55:10: if block ends with a return statement, so drop this else and outdent its block
core/http/endpoints/openai/assistant.go:25:2: exported const CodeInterpreter should have comment (or a comment on this block) or be unexported
core/http/endpoints/openai/assistant.go:33:2: const MaxFileIdSize should be MaxFileIDSize
core/http/endpoints/openai/assistant.go:38:6: exported type Tool should have comment or be unexported
core/http/endpoints/openai/assistant.go:57:2: exported var Assistants should have comment or be unexported
core/http/endpoints/openai/assistant.go:61:6: exported type AssistantRequest should have comment or be unexported
core/http/endpoints/openai/assistant.go:122:5: var currentId should be currentID
core/http/endpoints/openai/assistant.go:295:6: exported type AssistantFile should have comment or be unexported
core/http/endpoints/openai/assistant.go:303:2: exported var AssistantFiles should have comment or be unexported
core/http/endpoints/openai/assistant.go:307:1: exported function CreateAssistantFileEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:348:1: exported function ListAssistantFilesEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:410:1: exported function ModifyAssistantEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:449:1: exported function DeleteAssistantFileEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:452:3: var fileId should be fileID
core/http/endpoints/openai/assistant.go:459:12: range var fileId should be fileID
core/http/endpoints/openai/assistant.go:503:1: exported function GetAssistantFileEndpoint should have comment or be unexported
core/http/endpoints/openai/assistant.go:506:3: var fileId should be fileID
core/http/endpoints/openai/assistant_test.go:271:3: var modifiedArJson should be modifiedArJSON
core/http/endpoints/openai/assistant_test.go:378:75: func parameter assistantId should be assistantID
core/http/endpoints/openai/assistant_test.go:379:2: var afrJson should be afrJSON
core/http/endpoints/openai/assistant_test.go:445:57: func parameter fileId should be fileID
core/http/endpoints/openai/assistant_test.go:445:65: func parameter assistantId should be assistantID
core/http/endpoints/openai/files.go:18:5: exported var UploadedFiles should have comment or be unexported
core/http/endpoints/openai/files.go:20:7: exported const UploadedFilesFile should have comment or be unexported
core/http/endpoints/openai/files.go:70:5: var currentFileId should be currentFileID
core/http/endpoints/openai/files.go:72:6: func getNextFileId should be getNextFileID
core/http/endpoints/openai/files.go:131:6: exported type DeleteStatus should have comment or be unexported
core/http/endpoints/openai/files.go:132:2: struct field Id should be ID
core/http/endpoints/openai/files_test.go:181:61: func parameter fileId should be fileID
core/http/endpoints/openai/files_test.go:225:60: func parameter fileId should be fileID
core/http/endpoints/openai/image.go:49:1: comment on exported function ImageEndpoint should be of the form "ImageEndpoint ..."
core/http/endpoints/openai/image.go:163:5: don't use underscores in Go names; var positive_prompt should be positivePrompt
core/http/endpoints/openai/image.go:164:5: don't use underscores in Go names; var negative_prompt should be negativePrompt
core/http/endpoints/openai/inference.go:11:1: exported function ComputeChoices should have comment or be unexported
core/http/routes/elevenlabs.go:10:1: exported function RegisterElevenLabsRoutes should have comment or be unexported
core/http/routes/jina.go:11:1: exported function RegisterJINARoutes should have comment or be unexported
core/http/routes/localai.go:14:1: exported function RegisterLocalAIRoutes should have comment or be unexported
core/http/routes/openai.go:11:1: exported function RegisterOpenAIRoutes should have comment or be unexported
core/http/routes/ui.go:24:1: exported function RegisterUIRoutes should have comment or be unexported
core/p2p/federated.go:3:7: exported const FederatedID should have comment or be unexported
core/p2p/federated.go:5:6: exported type FederatedServer should have comment or be unexported
core/p2p/federated.go:9:1: exported function NewFederatedServer should have comment or be unexported
core/p2p/node.go:10:6: exported type NodeData should have comment or be unexported
core/p2p/node.go:17:1: exported method NodeData.IsOnline should have comment or be unexported
core/p2p/node.go:26:1: exported function GetAvailableNodes should have comment or be unexported
core/p2p/node.go:39:1: exported function AddNode should have comment or be unexported
core/p2p/p2p_disabled.go:13:1: exported function GenerateToken should have comment or be unexported
core/p2p/p2p_disabled.go:17:1: exported method FederatedServer.Start should have comment or be unexported
core/p2p/p2p_disabled.go:21:1: exported function ServiceDiscoverer should have comment or be unexported
core/p2p/p2p_disabled.go:25:1: exported function ExposeService should have comment or be unexported
core/p2p/p2p_disabled.go:29:1: exported function IsP2PEnabled should have comment or be unexported
core/p2p/p2p_disabled.go:33:1: exported function NewNode should have comment or be unexported
core/schema/elevenlabs.go:3:6: exported type ElevenLabsTTSRequest should have comment or be unexported
core/schema/jina.go:3:1: comment on exported type JINARerankRequest should be of the form "JINARerankRequest ..." (with optional leading article)
core/schema/jina.go:11:1: comment on exported type JINADocumentResult should be of the form "JINADocumentResult ..." (with optional leading article)
core/schema/jina.go:18:1: comment on exported type JINAText should be of the form "JINAText ..." (with optional leading article)
core/schema/jina.go:23:1: comment on exported type JINARerankResponse should be of the form "JINARerankResponse ..." (with optional leading article)
core/schema/jina.go:30:1: comment on exported type JINAUsageInfo should be of the form "JINAUsageInfo ..." (with optional leading article)
core/schema/localai.go:8:6: exported type BackendMonitorRequest should have comment or be unexported
core/schema/localai.go:12:6: exported type BackendMonitorResponse should have comment or be unexported
core/schema/localai.go:18:6: exported type GalleryResponse should have comment or be unexported
core/schema/localai.go:23:1: comment on exported type TTSRequest should be of the form "TTSRequest ..." (with optional leading article)
core/schema/localai.go:32:6: exported type StoresSet should have comment or be unexported
core/schema/localai.go:39:6: exported type StoresDelete should have comment or be unexported
core/schema/localai.go:45:6: exported type StoresGet should have comment or be unexported
core/schema/localai.go:51:6: exported type StoresGetResponse should have comment or be unexported
core/schema/localai.go:56:6: exported type StoresFind should have comment or be unexported
core/schema/localai.go:63:6: exported type StoresFindResponse should have comment or be unexported
core/schema/localai.go:69:6: exported type P2PNodesResponse should have comment or be unexported
core/schema/openai.go:18:6: exported type ErrorResponse should have comment or be unexported
core/schema/openai.go:22:6: exported type OpenAIUsage should have comment or be unexported
core/schema/openai.go:28:6: exported type Item should have comment or be unexported
core/schema/openai.go:38:6: exported type OpenAIResponse should have comment or be unexported
core/schema/openai.go:49:6: exported type Choice should have comment or be unexported
core/schema/openai.go:57:6: exported type Content should have comment or be unexported
core/schema/openai.go:63:6: exported type ContentURL should have comment or be unexported
core/schema/openai.go:67:6: exported type Message should have comment or be unexported
core/schema/openai.go:86:6: exported type ToolCall should have comment or be unexported
core/schema/openai.go:93:6: exported type FunctionCall should have comment or be unexported
core/schema/openai.go:98:6: exported type OpenAIModel should have comment or be unexported
core/schema/openai.go:103:6: exported type DeleteAssistantResponse should have comment or be unexported
core/schema/openai.go:119:6: exported type ListFiles should have comment or be unexported
core/schema/openai.go:124:6: exported type AssistantFileRequest should have comment or be unexported
core/schema/openai.go:128:6: exported type DeleteAssistantFileResponse should have comment or be unexported
core/schema/openai.go:134:6: exported type ImageGenerationResponseFormat should have comment or be unexported
core/schema/openai.go:136:6: exported type ChatCompletionResponseFormatType should have comment or be unexported
core/schema/openai.go:138:6: exported type ChatCompletionResponseFormat should have comment or be unexported
core/schema/openai.go:142:6: exported type OpenAIRequest should have comment or be unexported
core/schema/openai.go:190:6: exported type ModelsDataResponse should have comment or be unexported
core/schema/prediction.go:3:6: exported type PredictionOptions should have comment or be unexported
core/schema/transcription.go:5:6: exported type Segment should have comment or be unexported
core/schema/transcription.go:6:2: struct field Id should be ID
core/schema/transcription.go:13:6: exported type TranscriptionResult should have comment or be unexported
core/services/backend_monitor.go:18:6: exported type BackendMonitorService should have comment or be unexported
core/services/backend_monitor.go:24:1: exported function NewBackendMonitorService should have comment or be unexported
core/services/backend_monitor.go:34:6: var backendId should be backendID
core/services/backend_monitor.go:49:1: exported method BackendMonitorService.SampleLocalBackendProcess should have comment or be unexported
core/services/backend_monitor.go:104:1: exported method BackendMonitorService.CheckAndSample should have comment or be unexported
core/services/backend_monitor.go:105:2: var backendId should be backendID
core/services/backend_monitor.go:134:1: exported method BackendMonitorService.ShutdownModel should have comment or be unexported
core/services/backend_monitor.go:135:2: var backendId should be backendID
core/services/gallery.go:18:6: exported type GalleryService should have comment or be unexported
core/services/gallery.go:25:1: exported function NewGalleryService should have comment or be unexported
core/services/gallery.go:45:1: exported method GalleryService.UpdateStatus should have comment or be unexported
core/services/gallery.go:51:1: exported method GalleryService.GetStatus should have comment or be unexported
core/services/gallery.go:58:1: exported method GalleryService.GetAllStatus should have comment or be unexported
core/services/gallery.go:65:1: exported method GalleryService.Start should have comment or be unexported
core/services/gallery.go:193:1: exported function ApplyGalleryFromFile should have comment or be unexported
core/services/gallery.go:207:1: exported function ApplyGalleryFromString should have comment or be unexported
core/services/list_models.go:10:1: exported function ListModels should have comment or be unexported
core/services/metrics.go:13:6: exported type LocalAIMetricsService should have comment or be unexported
core/services/metrics.go:15:2: struct field ApiTimeMetric should be APITimeMetric
core/services/metrics.go:18:1: exported method LocalAIMetricsService.ObserveAPICall should have comment or be unexported
core/services/metrics.go:26:1: comment on exported function NewLocalAIMetricsService should be of the form "NewLocalAIMetricsService ..."
core/services/metrics.go:47:1: exported method LocalAIMetricsService.Shutdown should have comment or be unexported
core/services/metrics.go:47:1: receiver name lams should be consistent with previous receiver name m for LocalAIMetricsService
core/startup/config_file_watcher.go:130:6: func readApiKeysJson should be readAPIKeysJSON
core/startup/config_file_watcher.go:157:6: func readExternalBackendsJson should be readExternalBackendsJSON
core/startup/startup.go:19:1: exported function Startup should have comment or be unexported
embedded/embedded.go:24:1: exported function ModelShortURL should have comment or be unexported
embedded/embedded.go:39:1: exported function GetRemoteLibraryShorteners should have comment or be unexported
examples/semantic-todo/main.go:21:6: exported type Task should have comment or be unexported
examples/semantic-todo/main.go:26:6: exported type AppState should have comment or be unexported
examples/semantic-todo/main.go:29:2: exported const StateRoot should have comment (or a comment on this block) or be unexported
examples/semantic-todo/main.go:34:6: exported type App should have comment or be unexported
examples/semantic-todo/main.go:42:1: exported function NewApp should have comment or be unexported
examples/semantic-todo/main.go:95:6: exported type StoresSet should have comment or be unexported
examples/semantic-todo/main.go:151:6: exported type StoresFind should have comment or be unexported
examples/semantic-todo/main.go:158:6: exported type StoresFindResponse should have comment or be unexported
internal/version.go:5:5: exported var Version should have comment or be unexported
internal/version.go:6:5: exported var Commit should have comment or be unexported
internal/version.go:8:1: exported function PrintableVersion should have comment or be unexported
pkg/assets/extract.go:13:1: exported function ResolvePath should have comment or be unexported
pkg/assets/extract.go:17:1: exported function ExtractFiles should have comment or be unexported
pkg/assets/list.go:10:1: exported function ListFiles should have comment or be unexported
pkg/downloader/uri.go:24:2: exported const HuggingFacePrefix should have comment (or a comment on this block) or be unexported
pkg/downloader/uri.go:33:1: exported function DownloadAndUnmarshal should have comment or be unexported
pkg/downloader/uri.go:81:1: exported function LooksLikeURL should have comment or be unexported
pkg/downloader/uri.go:91:1: exported function LooksLikeOCI should have comment or be unexported
pkg/downloader/uri.go:95:1: exported function ConvertURL should have comment or be unexported
pkg/downloader/uri.go:164:1: exported function DownloadFile should have comment or be unexported
pkg/downloader/uri.go:301:1: comment on exported function GetBase64Image should be of the form "GetBase64Image ..."
pkg/downloader/uri.go:360:6: exported type HuggingFaceScanResult should have comment or be unexported
pkg/downloader/uri.go:361:2: struct field RepositoryId should be RepositoryID
pkg/downloader/uri.go:369:5: exported var ErrNonHuggingFaceFile should have comment or be unexported
pkg/downloader/uri.go:370:5: exported var ErrUnsafeFilesFound should have comment or be unexported
pkg/downloader/uri.go:372:1: exported function HuggingFaceScan should have comment or be unexported
pkg/functions/functions.go:14:6: exported type Function should have comment or be unexported
pkg/functions/functions.go:19:6: exported type Functions should have comment or be unexported
pkg/functions/functions.go:21:6: exported type Tool should have comment or be unexported
pkg/functions/functions.go:25:6: exported type Tools should have comment or be unexported
pkg/functions/functions.go:27:1: comment on exported method Functions.ToJSONStructure should be of the form "ToJSONStructure ..."
pkg/functions/grammar_json_schema.go:16:2: exported const JSONBNF should have comment (or a comment on this block) or be unexported
pkg/functions/grammar_json_schema.go:43:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:43:2: exported var SPACE_RULE should have comment or be unexported
pkg/functions/grammar_json_schema.go:45:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:63:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:64:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:65:2: don't use ALL_CAPS in Go names; use CamelCase
pkg/functions/grammar_json_schema.go:72:6: exported type JSONSchemaConverter should have comment or be unexported
pkg/functions/grammar_json_schema.go:77:1: exported function NewJSONSchemaConverter should have comment or be unexported
pkg/functions/grammar_json_schema.go:335:1: exported method JSONSchemaConverter.Grammar should have comment or be unexported
pkg/functions/grammar_json_schema.go:341:1: exported method JSONSchemaConverter.GrammarFromBytes should have comment or be unexported
pkg/functions/grammar_json_schema.go:352:6: exported type FunctionName should have comment or be unexported
pkg/functions/grammar_json_schema.go:356:6: exported type Argument should have comment or be unexported
pkg/functions/grammar_json_schema.go:361:6: exported type Item should have comment or be unexported
pkg/functions/grammar_json_schema.go:366:6: exported type JSONFunctionStructure should have comment or be unexported
pkg/functions/grammar_json_schema.go:372:1: exported method JSONFunctionStructure.Grammar should have comment or be unexported
pkg/functions/options.go:3:6: exported type GrammarOption should have comment or be unexported
pkg/functions/options.go:13:1: exported method GrammarOption.Apply should have comment or be unexported
pkg/functions/options.go:19:5: exported var EnableMaybeArray should have comment or be unexported
pkg/functions/options.go:23:5: exported var DisableParallelNewLines should have comment or be unexported
pkg/functions/options.go:27:5: exported var EnableMaybeString should have comment or be unexported
pkg/functions/options.go:31:5: exported var NoMixedFreeString should have comment or be unexported
pkg/functions/options.go:40:1: exported function SetPrefix should have comment or be unexported
pkg/functions/options.go:46:1: exported function SetPropOrder should have comment or be unexported
pkg/functions/parse.go:14:6: exported type GrammarConfig should have comment or be unexported
pkg/functions/parse.go:47:6: type name will be used as functions.FunctionsConfig by other packages, and that stutters; consider calling this Config
pkg/functions/parse.go:85:6: exported type ReplaceResult should have comment or be unexported
pkg/functions/parse.go:90:6: exported type FuncCallResults should have comment or be unexported
pkg/functions/parse.go:95:1: exported method GrammarConfig.Options should have comment or be unexported
pkg/functions/parse.go:120:1: exported function CleanupLLMResult should have comment or be unexported
pkg/functions/parse.go:134:1: exported function ParseTextContent should have comment or be unexported
pkg/functions/parse.go:192:1: exported function ParseFunctionCall should have comment or be unexported
pkg/functions/parse.go:234:5: don't use underscores in Go names; var func_name should be funcName
pkg/grpc/backend.go:13:1: exported function Provide should have comment or be unexported
pkg/grpc/backend.go:17:1: exported function NewClient should have comment or be unexported
pkg/grpc/backend.go:24:1: exported function NewGrpcClient should have comment or be unexported
pkg/grpc/backend.go:35:6: exported type Backend should have comment or be unexported
pkg/grpc/client.go:16:6: exported type Client should have comment or be unexported
pkg/grpc/client.go:25:6: exported type WatchDog should have comment or be unexported
pkg/grpc/client.go:30:1: exported method Client.IsBusy should have comment or be unexported
pkg/grpc/client.go:42:1: exported method Client.HealthCheck should have comment or be unexported
pkg/grpc/client.go:72:1: exported method Client.Embeddings should have comment or be unexported
pkg/grpc/client.go:93:1: exported method Client.Predict should have comment or be unexported
pkg/grpc/client.go:114:1: exported method Client.LoadModel should have comment or be unexported
pkg/grpc/client.go:134:1: exported method Client.PredictStream should have comment or be unexported
pkg/grpc/client.go:173:1: exported method Client.GenerateImage should have comment or be unexported
pkg/grpc/client.go:193:1: exported method Client.TTS should have comment or be unexported
pkg/grpc/client.go:213:1: exported method Client.AudioTranscription should have comment or be unexported
pkg/grpc/client.go:253:1: exported method Client.TokenizeString should have comment or be unexported
pkg/grpc/client.go:279:1: exported method Client.Status should have comment or be unexported
pkg/grpc/client.go:295:1: exported method Client.StoresSet should have comment or be unexported
pkg/grpc/client.go:311:1: exported method Client.StoresDelete should have comment or be unexported
pkg/grpc/client.go:327:1: exported method Client.StoresGet should have comment or be unexported
pkg/grpc/client.go:343:1: exported method Client.StoresFind should have comment or be unexported
pkg/grpc/client.go:359:1: exported method Client.Rerank should have comment or be unexported
pkg/grpc/interface.go:8:6: exported type LLM should have comment or be unexported
pkg/grpc/server.go:218:1: exported function StartServer should have comment or be unexported
pkg/grpc/server.go:233:1: exported function RunServer should have comment or be unexported
pkg/grpc/base/base.go:20:1: exported method Base.Locking should have comment or be unexported
pkg/grpc/base/base.go:24:1: exported method Base.Lock should have comment or be unexported
pkg/grpc/base/base.go:28:1: exported method Base.Unlock should have comment or be unexported
pkg/grpc/base/base.go:32:1: exported method Base.Busy should have comment or be unexported
pkg/grpc/base/base.go:36:1: exported method Base.Load should have comment or be unexported
pkg/grpc/base/base.go:40:1: exported method Base.Predict should have comment or be unexported
pkg/grpc/base/base.go:44:1: exported method Base.PredictStream should have comment or be unexported
pkg/grpc/base/base.go:48:1: exported method Base.Embeddings should have comment or be unexported
pkg/grpc/base/base.go:52:1: exported method Base.GenerateImage should have comment or be unexported
pkg/grpc/base/base.go:56:1: exported method Base.AudioTranscription should have comment or be unexported
pkg/grpc/base/base.go:60:1: exported method Base.TTS should have comment or be unexported
pkg/grpc/base/base.go:64:1: exported method Base.TokenizeString should have comment or be unexported
pkg/grpc/base/base.go:68:1: comment on exported method Base.Status should be of the form "Status ..."
pkg/grpc/base/base.go:75:1: exported method Base.StoresSet should have comment or be unexported
pkg/grpc/base/base.go:79:1: exported method Base.StoresGet should have comment or be unexported
pkg/grpc/base/base.go:83:1: exported method Base.StoresDelete should have comment or be unexported
pkg/grpc/base/base.go:87:1: exported method Base.StoresFind should have comment or be unexported
pkg/grpc/base/singlethread.go:23:1: exported method SingleThread.Lock should have comment or be unexported
pkg/grpc/base/singlethread.go:27:1: exported method SingleThread.Unlock should have comment or be unexported
pkg/grpc/base/singlethread.go:31:1: exported method SingleThread.Busy should have comment or be unexported
pkg/grpc/base/singlethread.go:39:1: comment on exported method SingleThread.Status should be of the form "Status ..."
pkg/langchain/huggingface.go:11:6: exported type HuggingFace should have comment or be unexported
pkg/langchain/huggingface.go:16:1: exported function NewHuggingFace should have comment or be unexported
pkg/langchain/huggingface.go:16:21: func parameter repoId should be repoID
pkg/langchain/huggingface.go:26:1: exported method HuggingFace.PredictHuggingFace should have comment or be unexported
pkg/langchain/langchain.go:3:6: exported type PredictOptions should have comment or be unexported
pkg/langchain/langchain.go:13:6: exported type PredictOption should have comment or be unexported
pkg/langchain/langchain.go:15:5: exported var DefaultOptions should have comment or be unexported
pkg/langchain/langchain.go:22:6: exported type Predict should have comment or be unexported
pkg/langchain/langchain.go:26:1: exported function SetModel should have comment or be unexported
pkg/langchain/langchain.go:32:1: exported function SetTemperature should have comment or be unexported
pkg/langchain/langchain.go:38:1: exported function SetMaxTokens should have comment or be unexported
pkg/langchain/langchain.go:44:1: exported function SetStopWords should have comment or be unexported
pkg/model/initializers.go:24:5: exported var Aliases should have comment or be unexported
pkg/model/initializers.go:34:2: exported const LlamaGGML should have comment (or a comment on this block) or be unexported
pkg/model/initializers.go:407:1: exported method ModelLoader.BackendLoader should have comment or be unexported
pkg/model/initializers.go:455:1: exported method ModelLoader.GreedyLoader should have comment or be unexported
pkg/model/initializers.go:549:11: if block ends with a return statement, so drop this else and outdent its block
pkg/model/loader.go:21:1: comment on exported type PromptTemplateData should be of the form "PromptTemplateData ..." (with optional leading article)
pkg/model/loader.go:33:6: exported type ChatMessageTemplateData should have comment or be unexported
pkg/model/loader.go:47:1: comment on exported type ModelLoader should be of the form "ModelLoader ..." (with optional leading article)
pkg/model/loader.go:48:6: type name will be used as model.ModelLoader by other packages, and that stutters; consider calling this Loader
pkg/model/loader.go:59:6: exported type ModelAddress should have comment or be unexported
pkg/model/loader.go:59:6: type name will be used as model.ModelAddress by other packages, and that stutters; consider calling this Address
pkg/model/loader.go:61:1: exported method ModelAddress.GRPC should have comment or be unexported
pkg/model/loader.go:69:1: exported function NewModelLoader should have comment or be unexported
pkg/model/loader.go:81:1: exported method ModelLoader.SetWatchDog should have comment or be unexported
pkg/model/loader.go:85:1: exported method ModelLoader.ExistsInModelPath should have comment or be unexported
pkg/model/loader.go:110:1: exported method ModelLoader.ListFilesInModelPath should have comment or be unexported
pkg/model/loader.go:144:1: exported method ModelLoader.LoadModel should have comment or be unexported
pkg/model/loader.go:174:1: exported method ModelLoader.ShutdownModel should have comment or be unexported
pkg/model/loader.go:190:1: exported method ModelLoader.CheckIsLoaded should have comment or be unexported
pkg/model/loader.go:221:2: exported const ChatPromptTemplate should have comment (or a comment on this block) or be unexported
pkg/model/loader.go:228:1: exported method ModelLoader.EvaluateTemplateForPrompt should have comment or be unexported
pkg/model/loader.go:236:1: exported method ModelLoader.EvaluateTemplateForChatMessage should have comment or be unexported
pkg/model/options.go:9:6: exported type Options should have comment or be unexported
pkg/model/options.go:26:6: exported type Option should have comment or be unexported
pkg/model/options.go:28:5: exported var EnableParallelRequests should have comment or be unexported
pkg/model/options.go:32:1: exported function WithExternalBackend should have comment or be unexported
pkg/model/options.go:41:1: exported function WithGRPCAttempts should have comment or be unexported
pkg/model/options.go:47:1: exported function WithGRPCAttemptsDelay should have comment or be unexported
pkg/model/options.go:53:1: exported function WithBackendString should have comment or be unexported
pkg/model/options.go:59:1: exported function WithModel should have comment or be unexported
pkg/model/options.go:65:1: exported function WithLoadGRPCLoadModelOpts should have comment or be unexported
pkg/model/options.go:71:1: exported function WithThreads should have comment or be unexported
pkg/model/options.go:77:1: exported function WithAssetDir should have comment or be unexported
pkg/model/options.go:83:1: exported function WithContext should have comment or be unexported
pkg/model/options.go:89:1: exported function WithSingleActiveBackend should have comment or be unexported
pkg/model/options.go:95:1: exported function NewOptions should have comment or be unexported
pkg/model/process.go:18:1: exported method ModelLoader.StopAllExcept should have comment or be unexported
pkg/model/process.go:43:6: exported type GRPCProcessFilter should have comment or be unexported
pkg/model/process.go:49:1: exported method ModelLoader.StopGRPC should have comment or be unexported
pkg/model/process.go:60:1: exported method ModelLoader.StopAllGRPC should have comment or be unexported
pkg/model/process.go:64:1: exported method ModelLoader.GetGRPCPID should have comment or be unexported
pkg/model/watchdog.go:19:6: exported type WatchDog should have comment or be unexported
pkg/model/watchdog.go:32:6: exported type ProcessManager should have comment or be unexported
pkg/model/watchdog.go:36:1: exported function NewWatchDog should have comment or be unexported
pkg/model/watchdog.go:50:1: exported method WatchDog.Shutdown should have comment or be unexported
pkg/model/watchdog.go:56:1: exported method WatchDog.AddAddressModelMap should have comment or be unexported
pkg/model/watchdog.go:62:1: exported method WatchDog.Add should have comment or be unexported
pkg/model/watchdog.go:68:1: exported method WatchDog.Mark should have comment or be unexported
pkg/model/watchdog.go:75:1: exported method WatchDog.UnMark should have comment or be unexported
pkg/model/watchdog.go:82:1: exported method WatchDog.Run should have comment or be unexported
pkg/oci/blob.go:15:1: exported function FetchImageBlob should have comment or be unexported
pkg/oci/image.go:71:1: exported function ParseImageParts should have comment or be unexported
pkg/oci/image.go:137:1: exported function GetOCIImageSize should have comment or be unexported
pkg/oci/ollama.go:12:1: comment on exported type Manifest should be of the form "Manifest ..." (with optional leading article)
pkg/oci/ollama.go:20:1: comment on exported type Config should be of the form "Config ..." (with optional leading article)
pkg/oci/ollama.go:27:1: comment on exported type LayerDetail should be of the form "LayerDetail ..." (with optional leading article)
pkg/oci/ollama.go:34:1: exported function OllamaModelManifest should have comment or be unexported
pkg/oci/ollama.go:63:1: exported function OllamaModelBlob should have comment or be unexported
pkg/oci/ollama.go:79:1: exported function OllamaFetchModel should have comment or be unexported
pkg/stablediffusion/generate_unsupported.go:8:1: exported function GenerateImage should have comment or be unexported
pkg/stablediffusion/generate_unsupported.go:8:57: don't use underscores in Go names; func parameter positive_prompt should be positivePrompt
pkg/stablediffusion/generate_unsupported.go:8:74: don't use underscores in Go names; func parameter negative_prompt should be negativePrompt
pkg/stablediffusion/generate_unsupported.go:8:96: don't use underscores in Go names; func parameter asset_dir should be assetDir
pkg/stablediffusion/stablediffusion.go:5:6: exported type StableDiffusion should have comment or be unexported
pkg/stablediffusion/stablediffusion.go:9:1: exported function New should have comment or be unexported
pkg/stablediffusion/stablediffusion.go:18:1: exported method StableDiffusion.GenerateImage should have comment or be unexported
pkg/stablediffusion/stablediffusion.go:18:78: don't use underscores in Go names; method parameter positive_prompt should be positivePrompt
pkg/stablediffusion/stablediffusion.go:18:95: don't use underscores in Go names; method parameter negative_prompt should be negativePrompt
pkg/startup/model_preload.go:147:1: error should be the last type when returning multiple items
pkg/startup/model_preload.go:171:6: func filenameFromUrl should be filenameFromURL
pkg/templates/cache.go:16:1: comment on exported type TemplateType should be of the form "TemplateType ..." (with optional leading article)
pkg/templates/cache.go:20:6: exported type TemplateCache should have comment or be unexported
pkg/templates/cache.go:26:1: exported function NewTemplateCache should have comment or be unexported
pkg/templates/cache.go:40:1: exported method TemplateCache.EvaluateTemplate should have comment or be unexported
pkg/tinydream/generate_unsupported.go:8:1: exported function GenerateImage should have comment or be unexported
pkg/tinydream/generate_unsupported.go:8:51: don't use underscores in Go names; func parameter positive_prompt should be positivePrompt
pkg/tinydream/generate_unsupported.go:8:68: don't use underscores in Go names; func parameter negative_prompt should be negativePrompt
pkg/tinydream/generate_unsupported.go:8:90: don't use underscores in Go names; func parameter asset_dir should be assetDir
pkg/tinydream/tinydream.go:5:6: exported type TinyDream should have comment or be unexported
pkg/tinydream/tinydream.go:9:1: exported function New should have comment or be unexported
pkg/tinydream/tinydream.go:18:1: exported method TinyDream.GenerateImage should have comment or be unexported
pkg/tinydream/tinydream.go:18:67: don't use underscores in Go names; method parameter positive_prompt should be positivePrompt
pkg/tinydream/tinydream.go:18:84: don't use underscores in Go names; method parameter negative_prompt should be negativePrompt
pkg/utils/base64.go:19:1: comment on exported function GetImageURLAsBase64 should be of the form "GetImageURLAsBase64 ..."
pkg/utils/config.go:11:1: exported function SaveConfig should have comment or be unexported
pkg/utils/config.go:24:1: exported function LoadConfig should have comment or be unexported
pkg/utils/hash.go:8:1: exported function MD5 should have comment or be unexported
pkg/utils/json.go:9:1: exported function EscapeNewLines should have comment or be unexported
pkg/utils/logging.go:12:1: exported function ResetDownloadTimers should have comment or be unexported
pkg/utils/logging.go:17:1: exported function DisplayDownloadFunction should have comment or be unexported
pkg/utils/path.go:10:1: exported function ExistsInPath should have comment or be unexported
pkg/utils/path.go:15:1: exported function InTrustedRoot should have comment or be unexported
pkg/utils/strings.go:14:1: exported function RandString should have comment or be unexported
pkg/utils/untar.go:10:1: exported function IsArchive should have comment or be unexported
pkg/utils/untar.go:20:1: exported function ExtractArchive should have comment or be unexported
pkg/xsync/map.go:7:6: exported type SyncedMap should have comment or be unexported
pkg/xsync/map.go:12:1: exported function NewSyncedMap should have comment or be unexported
pkg/xsysinfo/cpu.go:10:1: exported function CPUCapabilities should have comment or be unexported
pkg/xsysinfo/cpu.go:36:1: exported function HasCPUCaps should have comment or be unexported
pkg/xsysinfo/cpu.go:40:1: exported function CPUPhysicalCores should have comment or be unexported
pkg/xsysinfo/gpu.go:8:1: exported function GPUs should have comment or be unexported

Copy link

⚠ goimports failed (.)

core/application.go
-package core
-
-import (
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/services"
-	"github.com/mudler/LocalAI/pkg/model"
-)
-
-// The purpose of this structure is to hold pointers to all initialized services, to make plumbing easy
-// Perhaps a proper DI system is worth it in the future, but for now keep things simple.
-type Application struct {
-
-	// Application-Level Config
-	ApplicationConfig *config.ApplicationConfig
-	// ApplicationState *ApplicationState
-
-	// Core Low-Level Services
-	BackendConfigLoader *config.BackendConfigLoader
-	ModelLoader         *model.ModelLoader
-
-	// Backend Services
-	// EmbeddingsBackendService      *backend.EmbeddingsBackendService
-	// ImageGenerationBackendService *backend.ImageGenerationBackendService
-	// LLMBackendService             *backend.LLMBackendService
-	// TranscriptionBackendService *backend.TranscriptionBackendService
-	// TextToSpeechBackendService  *backend.TextToSpeechBackendService
-
-	// LocalAI System Services
-	BackendMonitorService *services.BackendMonitorService
-	GalleryService        *services.GalleryService
-	LocalAIMetricsService *services.LocalAIMetricsService
-	// OpenAIService         *services.OpenAIService
-}
-
-// TODO [NEXT PR?]: Break up ApplicationConfig.
-// Migrate over stuff that is not set via config at all - especially runtime stuff
-type ApplicationState struct {
-}
+package core
+
+import (
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/services"
+	"github.com/mudler/LocalAI/pkg/model"
+)
+
+// The purpose of this structure is to hold pointers to all initialized services, to make plumbing easy
+// Perhaps a proper DI system is worth it in the future, but for now keep things simple.
+type Application struct {
+
+	// Application-Level Config
+	ApplicationConfig *config.ApplicationConfig
+	// ApplicationState *ApplicationState
+
+	// Core Low-Level Services
+	BackendConfigLoader *config.BackendConfigLoader
+	ModelLoader         *model.ModelLoader
+
+	// Backend Services
+	// EmbeddingsBackendService      *backend.EmbeddingsBackendService
+	// ImageGenerationBackendService *backend.ImageGenerationBackendService
+	// LLMBackendService             *backend.LLMBackendService
+	// TranscriptionBackendService *backend.TranscriptionBackendService
+	// TextToSpeechBackendService  *backend.TextToSpeechBackendService
+
+	// LocalAI System Services
+	BackendMonitorService *services.BackendMonitorService
+	GalleryService        *services.GalleryService
+	LocalAIMetricsService *services.LocalAIMetricsService
+	// OpenAIService         *services.OpenAIService
+}
+
+// TODO [NEXT PR?]: Break up ApplicationConfig.
+// Migrate over stuff that is not set via config at all - especially runtime stuff
+type ApplicationState struct {
+}
core/backend/stores.go
 )
 
 func StoreBackend(sl *model.ModelLoader, appConfig *config.ApplicationConfig, storeName string) (grpc.Backend, error) {
-    if storeName == "" {
-      storeName = "default"
-    }
+	if storeName == "" {
+		storeName = "default"
+	}
 
-    sc := []model.Option{
-      model.WithBackendString(model.LocalStoreBackend),
-      model.WithAssetDir(appConfig.AssetsDestination),
-      model.WithModel(storeName),
-    }
+	sc := []model.Option{
+		model.WithBackendString(model.LocalStoreBackend),
+		model.WithAssetDir(appConfig.AssetsDestination),
+		model.WithModel(storeName),
+	}
 
-    return sl.BackendLoader(sc...)
+	return sl.BackendLoader(sc...)
 }
-
core/backend/tts.go
 	backend,
 	text,
 	modelFile,
-	voice ,
+	voice,
 	language string,
 	loader *model.ModelLoader,
 	appConfig *config.ApplicationConfig,
core/config/backend_config_loader.go
-package config
-
-import (
-	"errors"
-	"fmt"
-	"io/fs"
-	"os"
-	"path/filepath"
-	"sort"
-	"strings"
-	"sync"
-
-	"github.com/charmbracelet/glamour"
-	"github.com/mudler/LocalAI/core/schema"
-	"github.com/mudler/LocalAI/pkg/downloader"
-	"github.com/mudler/LocalAI/pkg/utils"
-	"github.com/rs/zerolog/log"
-	"gopkg.in/yaml.v3"
-)
-
-type BackendConfigLoader struct {
-	configs   map[string]BackendConfig
-	modelPath string
-	sync.Mutex
-}
-
-func NewBackendConfigLoader(modelPath string) *BackendConfigLoader {
-	return &BackendConfigLoader{
-		configs:   make(map[string]BackendConfig),
-		modelPath: modelPath,
-	}
-}
-
-type LoadOptions struct {
-	modelPath        string
-	debug            bool
-	threads, ctxSize int
-	f16              bool
-}
-
-func LoadOptionDebug(debug bool) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.debug = debug
-	}
-}
-
-func LoadOptionThreads(threads int) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.threads = threads
-	}
-}
-
-func LoadOptionContextSize(ctxSize int) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.ctxSize = ctxSize
-	}
-}
-
-func ModelPath(modelPath string) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.modelPath = modelPath
-	}
-}
-
-func LoadOptionF16(f16 bool) ConfigLoaderOption {
-	return func(o *LoadOptions) {
-		o.f16 = f16
-	}
-}
-
-type ConfigLoaderOption func(*LoadOptions)
-
-func (lo *LoadOptions) Apply(options ...ConfigLoaderOption) {
-	for _, l := range options {
-		l(lo)
-	}
-}
-
-// TODO: either in the next PR or the next commit, I want to merge these down into a single function that looks at the first few characters of the file to determine if we need to deserialize to []BackendConfig or BackendConfig
-func readMultipleBackendConfigsFromFile(file string, opts ...ConfigLoaderOption) ([]*BackendConfig, error) {
-	c := &[]*BackendConfig{}
-	f, err := os.ReadFile(file)
-	if err != nil {
-		return nil, fmt.Errorf("cannot read config file: %w", err)
-	}
-	if err := yaml.Unmarshal(f, c); err != nil {
-		return nil, fmt.Errorf("cannot unmarshal config file: %w", err)
-	}
-
-	for _, cc := range *c {
-		cc.SetDefaults(opts...)
-	}
-
-	return *c, nil
-}
-
-func readBackendConfigFromFile(file string, opts ...ConfigLoaderOption) (*BackendConfig, error) {
-	lo := &LoadOptions{}
-	lo.Apply(opts...)
-
-	c := &BackendConfig{}
-	f, err := os.ReadFile(file)
-	if err != nil {
-		return nil, fmt.Errorf("cannot read config file: %w", err)
-	}
-	if err := yaml.Unmarshal(f, c); err != nil {
-		return nil, fmt.Errorf("cannot unmarshal config file: %w", err)
-	}
-
-	c.SetDefaults(opts...)
-	return c, nil
-}
-
-// Load a config file for a model
-func (bcl *BackendConfigLoader) LoadBackendConfigFileByName(modelName, modelPath string, opts ...ConfigLoaderOption) (*BackendConfig, error) {
-
-	// Load a config file if present after the model name
-	cfg := &BackendConfig{
-		PredictionOptions: schema.PredictionOptions{
-			Model: modelName,
-		},
-	}
-
-	cfgExisting, exists := bcl.GetBackendConfig(modelName)
-	if exists {
-		cfg = &cfgExisting
-	} else {
-		// Try loading a model config file
-		modelConfig := filepath.Join(modelPath, modelName+".yaml")
-		if _, err := os.Stat(modelConfig); err == nil {
-			if err := bcl.LoadBackendConfig(
-				modelConfig, opts...,
-			); err != nil {
-				return nil, fmt.Errorf("failed loading model config (%s) %s", modelConfig, err.Error())
-			}
-			cfgExisting, exists = bcl.GetBackendConfig(modelName)
-			if exists {
-				cfg = &cfgExisting
-			}
-		}
-	}
-
-	cfg.SetDefaults(opts...)
-
-	return cfg, nil
-}
-
-// This format is currently only used when reading a single file at startup, passed in via ApplicationConfig.ConfigFile
-func (bcl *BackendConfigLoader) LoadMultipleBackendConfigsSingleFile(file string, opts ...ConfigLoaderOption) error {
-	bcl.Lock()
-	defer bcl.Unlock()
-	c, err := readMultipleBackendConfigsFromFile(file, opts...)
-	if err != nil {
-		return fmt.Errorf("cannot load config file: %w", err)
-	}
-
-	for _, cc := range c {
-		if cc.Validate() {
-			bcl.configs[cc.Name] = *cc
-		}
-	}
-	return nil
-}
-
-func (bcl *BackendConfigLoader) LoadBackendConfig(file string, opts ...ConfigLoaderOption) error {
-	bcl.Lock()
-	defer bcl.Unlock()
-	c, err := readBackendConfigFromFile(file, opts...)
-	if err != nil {
-		return fmt.Errorf("cannot read config file: %w", err)
-	}
-
-	if c.Validate() {
-		bcl.configs[c.Name] = *c
-	} else {
-		return fmt.Errorf("config is not valid")
-	}
-
-	return nil
-}
-
-func (bcl *BackendConfigLoader) GetBackendConfig(m string) (BackendConfig, bool) {
-	bcl.Lock()
-	defer bcl.Unlock()
-	v, exists := bcl.configs[m]
-	return v, exists
-}
-
-func (bcl *BackendConfigLoader) GetAllBackendConfigs() []BackendConfig {
-	bcl.Lock()
-	defer bcl.Unlock()
-	var res []BackendConfig
-	for _, v := range bcl.configs {
-		res = append(res, v)
-	}
-
-	sort.SliceStable(res, func(i, j int) bool {
-		return res[i].Name < res[j].Name
-	})
-
-	return res
-}
-
-func (bcl *BackendConfigLoader) RemoveBackendConfig(m string) {
-	bcl.Lock()
-	defer bcl.Unlock()
-	delete(bcl.configs, m)
-}
-
-// Preload prepare models if they are not local but url or huggingface repositories
-func (bcl *BackendConfigLoader) Preload(modelPath string) error {
-	bcl.Lock()
-	defer bcl.Unlock()
-
-	status := func(fileName, current, total string, percent float64) {
-		utils.DisplayDownloadFunction(fileName, current, total, percent)
-	}
-
-	log.Info().Msgf("Preloading models from %s", modelPath)
-
-	renderMode := "dark"
-	if os.Getenv("COLOR") != "" {
-		renderMode = os.Getenv("COLOR")
-	}
-
-	glamText := func(t string) {
-		out, err := glamour.Render(t, renderMode)
-		if err == nil && os.Getenv("NO_COLOR") == "" {
-			fmt.Println(out)
-		} else {
-			fmt.Println(t)
-		}
-	}
-
-	for i, config := range bcl.configs {
-
-		// Download files and verify their SHA
-		for i, file := range config.DownloadFiles {
-			log.Debug().Msgf("Checking %q exists and matches SHA", file.Filename)
-
-			if err := utils.VerifyPath(file.Filename, modelPath); err != nil {
-				return err
-			}
-			// Create file path
-			filePath := filepath.Join(modelPath, file.Filename)
-
-			if err := downloader.DownloadFile(file.URI, filePath, file.SHA256, i, len(config.DownloadFiles), status); err != nil {
-				return err
-			}
-		}
-
-		// If the model is an URL, expand it, and download the file
-		if config.IsModelURL() {
-			modelFileName := config.ModelFileName()
-			modelURL := downloader.ConvertURL(config.Model)
-			// check if file exists
-			if _, err := os.Stat(filepath.Join(modelPath, modelFileName)); errors.Is(err, os.ErrNotExist) {
-				err := downloader.DownloadFile(modelURL, filepath.Join(modelPath, modelFileName), "", 0, 0, status)
-				if err != nil {
-					return err
-				}
-			}
-
-			cc := bcl.configs[i]
-			c := &cc
-			c.PredictionOptions.Model = modelFileName
-			bcl.configs[i] = *c
-		}
-
-		if config.IsMMProjURL() {
-			modelFileName := config.MMProjFileName()
-			modelURL := downloader.ConvertURL(config.MMProj)
-			// check if file exists
-			if _, err := os.Stat(filepath.Join(modelPath, modelFileName)); errors.Is(err, os.ErrNotExist) {
-				err := downloader.DownloadFile(modelURL, filepath.Join(modelPath, modelFileName), "", 0, 0, status)
-				if err != nil {
-					return err
-				}
-			}
-
-			cc := bcl.configs[i]
-			c := &cc
-			c.MMProj = modelFileName
-			bcl.configs[i] = *c
-		}
-
-		if bcl.configs[i].Name != "" {
-			glamText(fmt.Sprintf("**Model name**: _%s_", bcl.configs[i].Name))
-		}
-		if bcl.configs[i].Description != "" {
-			//glamText("**Description**")
-			glamText(bcl.configs[i].Description)
-		}
-		if bcl.configs[i].Usage != "" {
-			//glamText("**Usage**")
-			glamText(bcl.configs[i].Usage)
-		}
-	}
-	return nil
-}
-
-// LoadBackendConfigsFromPath reads all the configurations of the models from a path
-// (non-recursive)
-func (bcl *BackendConfigLoader) LoadBackendConfigsFromPath(path string, opts ...ConfigLoaderOption) error {
-	bcl.Lock()
-	defer bcl.Unlock()
-	entries, err := os.ReadDir(path)
-	if err != nil {
-		return fmt.Errorf("cannot read directory '%s': %w", path, err)
-	}
-	files := make([]fs.FileInfo, 0, len(entries))
-	for _, entry := range entries {
-		info, err := entry.Info()
-		if err != nil {
-			return err
-		}
-		files = append(files, info)
-	}
-	for _, file := range files {
-		// Skip templates, YAML and .keep files
-		if !strings.Contains(file.Name(), ".yaml") && !strings.Contains(file.Name(), ".yml") ||
-			strings.HasPrefix(file.Name(), ".") {
-			continue
-		}
-		c, err := readBackendConfigFromFile(filepath.Join(path, file.Name()), opts...)
-		if err != nil {
-			log.Error().Err(err).Msgf("cannot read config file: %s", file.Name())
-			continue
-		}
-		if c.Validate() {
-			bcl.configs[c.Name] = *c
-		} else {
-			log.Error().Err(err).Msgf("config is not valid")
-		}
-	}
-
-	return nil
-}
+package config
+
+import (
+	"errors"
+	"fmt"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+	"sync"
+
+	"github.com/charmbracelet/glamour"
+	"github.com/mudler/LocalAI/core/schema"
+	"github.com/mudler/LocalAI/pkg/downloader"
+	"github.com/mudler/LocalAI/pkg/utils"
+	"github.com/rs/zerolog/log"
+	"gopkg.in/yaml.v3"
+)
+
+type BackendConfigLoader struct {
+	configs   map[string]BackendConfig
+	modelPath string
+	sync.Mutex
+}
+
+func NewBackendConfigLoader(modelPath string) *BackendConfigLoader {
+	return &BackendConfigLoader{
+		configs:   make(map[string]BackendConfig),
+		modelPath: modelPath,
+	}
+}
+
+type LoadOptions struct {
+	modelPath        string
+	debug            bool
+	threads, ctxSize int
+	f16              bool
+}
+
+func LoadOptionDebug(debug bool) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.debug = debug
+	}
+}
+
+func LoadOptionThreads(threads int) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.threads = threads
+	}
+}
+
+func LoadOptionContextSize(ctxSize int) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.ctxSize = ctxSize
+	}
+}
+
+func ModelPath(modelPath string) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.modelPath = modelPath
+	}
+}
+
+func LoadOptionF16(f16 bool) ConfigLoaderOption {
+	return func(o *LoadOptions) {
+		o.f16 = f16
+	}
+}
+
+type ConfigLoaderOption func(*LoadOptions)
+
+func (lo *LoadOptions) Apply(options ...ConfigLoaderOption) {
+	for _, l := range options {
+		l(lo)
+	}
+}
+
+// TODO: either in the next PR or the next commit, I want to merge these down into a single function that looks at the first few characters of the file to determine if we need to deserialize to []BackendConfig or BackendConfig
+func readMultipleBackendConfigsFromFile(file string, opts ...ConfigLoaderOption) ([]*BackendConfig, error) {
+	c := &[]*BackendConfig{}
+	f, err := os.ReadFile(file)
+	if err != nil {
+		return nil, fmt.Errorf("cannot read config file: %w", err)
+	}
+	if err := yaml.Unmarshal(f, c); err != nil {
+		return nil, fmt.Errorf("cannot unmarshal config file: %w", err)
+	}
+
+	for _, cc := range *c {
+		cc.SetDefaults(opts...)
+	}
+
+	return *c, nil
+}
+
+func readBackendConfigFromFile(file string, opts ...ConfigLoaderOption) (*BackendConfig, error) {
+	lo := &LoadOptions{}
+	lo.Apply(opts...)
+
+	c := &BackendConfig{}
+	f, err := os.ReadFile(file)
+	if err != nil {
+		return nil, fmt.Errorf("cannot read config file: %w", err)
+	}
+	if err := yaml.Unmarshal(f, c); err != nil {
+		return nil, fmt.Errorf("cannot unmarshal config file: %w", err)
+	}
+
+	c.SetDefaults(opts...)
+	return c, nil
+}
+
+// Load a config file for a model
+func (bcl *BackendConfigLoader) LoadBackendConfigFileByName(modelName, modelPath string, opts ...ConfigLoaderOption) (*BackendConfig, error) {
+
+	// Load a config file if present after the model name
+	cfg := &BackendConfig{
+		PredictionOptions: schema.PredictionOptions{
+			Model: modelName,
+		},
+	}
+
+	cfgExisting, exists := bcl.GetBackendConfig(modelName)
+	if exists {
+		cfg = &cfgExisting
+	} else {
+		// Try loading a model config file
+		modelConfig := filepath.Join(modelPath, modelName+".yaml")
+		if _, err := os.Stat(modelConfig); err == nil {
+			if err := bcl.LoadBackendConfig(
+				modelConfig, opts...,
+			); err != nil {
+				return nil, fmt.Errorf("failed loading model config (%s) %s", modelConfig, err.Error())
+			}
+			cfgExisting, exists = bcl.GetBackendConfig(modelName)
+			if exists {
+				cfg = &cfgExisting
+			}
+		}
+	}
+
+	cfg.SetDefaults(opts...)
+
+	return cfg, nil
+}
+
+// This format is currently only used when reading a single file at startup, passed in via ApplicationConfig.ConfigFile
+func (bcl *BackendConfigLoader) LoadMultipleBackendConfigsSingleFile(file string, opts ...ConfigLoaderOption) error {
+	bcl.Lock()
+	defer bcl.Unlock()
+	c, err := readMultipleBackendConfigsFromFile(file, opts...)
+	if err != nil {
+		return fmt.Errorf("cannot load config file: %w", err)
+	}
+
+	for _, cc := range c {
+		if cc.Validate() {
+			bcl.configs[cc.Name] = *cc
+		}
+	}
+	return nil
+}
+
+func (bcl *BackendConfigLoader) LoadBackendConfig(file string, opts ...ConfigLoaderOption) error {
+	bcl.Lock()
+	defer bcl.Unlock()
+	c, err := readBackendConfigFromFile(file, opts...)
+	if err != nil {
+		return fmt.Errorf("cannot read config file: %w", err)
+	}
+
+	if c.Validate() {
+		bcl.configs[c.Name] = *c
+	} else {
+		return fmt.Errorf("config is not valid")
+	}
+
+	return nil
+}
+
+func (bcl *BackendConfigLoader) GetBackendConfig(m string) (BackendConfig, bool) {
+	bcl.Lock()
+	defer bcl.Unlock()
+	v, exists := bcl.configs[m]
+	return v, exists
+}
+
+func (bcl *BackendConfigLoader) GetAllBackendConfigs() []BackendConfig {
+	bcl.Lock()
+	defer bcl.Unlock()
+	var res []BackendConfig
+	for _, v := range bcl.configs {
+		res = append(res, v)
+	}
+
+	sort.SliceStable(res, func(i, j int) bool {
+		return res[i].Name < res[j].Name
+	})
+
+	return res
+}
+
+func (bcl *BackendConfigLoader) RemoveBackendConfig(m string) {
+	bcl.Lock()
+	defer bcl.Unlock()
+	delete(bcl.configs, m)
+}
+
+// Preload prepare models if they are not local but url or huggingface repositories
+func (bcl *BackendConfigLoader) Preload(modelPath string) error {
+	bcl.Lock()
+	defer bcl.Unlock()
+
+	status := func(fileName, current, total string, percent float64) {
+		utils.DisplayDownloadFunction(fileName, current, total, percent)
+	}
+
+	log.Info().Msgf("Preloading models from %s", modelPath)
+
+	renderMode := "dark"
+	if os.Getenv("COLOR") != "" {
+		renderMode = os.Getenv("COLOR")
+	}
+
+	glamText := func(t string) {
+		out, err := glamour.Render(t, renderMode)
+		if err == nil && os.Getenv("NO_COLOR") == "" {
+			fmt.Println(out)
+		} else {
+			fmt.Println(t)
+		}
+	}
+
+	for i, config := range bcl.configs {
+
+		// Download files and verify their SHA
+		for i, file := range config.DownloadFiles {
+			log.Debug().Msgf("Checking %q exists and matches SHA", file.Filename)
+
+			if err := utils.VerifyPath(file.Filename, modelPath); err != nil {
+				return err
+			}
+			// Create file path
+			filePath := filepath.Join(modelPath, file.Filename)
+
+			if err := downloader.DownloadFile(file.URI, filePath, file.SHA256, i, len(config.DownloadFiles), status); err != nil {
+				return err
+			}
+		}
+
+		// If the model is an URL, expand it, and download the file
+		if config.IsModelURL() {
+			modelFileName := config.ModelFileName()
+			modelURL := downloader.ConvertURL(config.Model)
+			// check if file exists
+			if _, err := os.Stat(filepath.Join(modelPath, modelFileName)); errors.Is(err, os.ErrNotExist) {
+				err := downloader.DownloadFile(modelURL, filepath.Join(modelPath, modelFileName), "", 0, 0, status)
+				if err != nil {
+					return err
+				}
+			}
+
+			cc := bcl.configs[i]
+			c := &cc
+			c.PredictionOptions.Model = modelFileName
+			bcl.configs[i] = *c
+		}
+
+		if config.IsMMProjURL() {
+			modelFileName := config.MMProjFileName()
+			modelURL := downloader.ConvertURL(config.MMProj)
+			// check if file exists
+			if _, err := os.Stat(filepath.Join(modelPath, modelFileName)); errors.Is(err, os.ErrNotExist) {
+				err := downloader.DownloadFile(modelURL, filepath.Join(modelPath, modelFileName), "", 0, 0, status)
+				if err != nil {
+					return err
+				}
+			}
+
+			cc := bcl.configs[i]
+			c := &cc
+			c.MMProj = modelFileName
+			bcl.configs[i] = *c
+		}
+
+		if bcl.configs[i].Name != "" {
+			glamText(fmt.Sprintf("**Model name**: _%s_", bcl.configs[i].Name))
+		}
+		if bcl.configs[i].Description != "" {
+			//glamText("**Description**")
+			glamText(bcl.configs[i].Description)
+		}
+		if bcl.configs[i].Usage != "" {
+			//glamText("**Usage**")
+			glamText(bcl.configs[i].Usage)
+		}
+	}
+	return nil
+}
+
+// LoadBackendConfigsFromPath reads all the configurations of the models from a path
+// (non-recursive)
+func (bcl *BackendConfigLoader) LoadBackendConfigsFromPath(path string, opts ...ConfigLoaderOption) error {
+	bcl.Lock()
+	defer bcl.Unlock()
+	entries, err := os.ReadDir(path)
+	if err != nil {
+		return fmt.Errorf("cannot read directory '%s': %w", path, err)
+	}
+	files := make([]fs.FileInfo, 0, len(entries))
+	for _, entry := range entries {
+		info, err := entry.Info()
+		if err != nil {
+			return err
+		}
+		files = append(files, info)
+	}
+	for _, file := range files {
+		// Skip templates, YAML and .keep files
+		if !strings.Contains(file.Name(), ".yaml") && !strings.Contains(file.Name(), ".yml") ||
+			strings.HasPrefix(file.Name(), ".") {
+			continue
+		}
+		c, err := readBackendConfigFromFile(filepath.Join(path, file.Name()), opts...)
+		if err != nil {
+			log.Error().Err(err).Msgf("cannot read config file: %s", file.Name())
+			continue
+		}
+		if c.Validate() {
+			bcl.configs[c.Name] = *c
+		} else {
+			log.Error().Err(err).Msgf("config is not valid")
+		}
+	}
+
+	return nil
+}
core/gallery/op.go
-package gallery
-
-import "github.com/mudler/LocalAI/core/config"
-
-type GalleryOp struct {
-	Id               string
-	GalleryModelName string
-	ConfigURL        string
-	Delete           bool
-
-	Req       GalleryModel
-	Galleries []config.Gallery
-}
-
-type GalleryOpStatus struct {
-	Deletion           bool    `json:"deletion"` // Deletion is true if the operation is a deletion
-	FileName           string  `json:"file_name"`
-	Error              error   `json:"error"`
-	Processed          bool    `json:"processed"`
-	Message            string  `json:"message"`
-	Progress           float64 `json:"progress"`
-	TotalFileSize      string  `json:"file_size"`
-	DownloadedFileSize string  `json:"downloaded_size"`
-	GalleryModelName   string  `json:"gallery_model_name"`
-}
+package gallery
+
+import "github.com/mudler/LocalAI/core/config"
+
+type GalleryOp struct {
+	Id               string
+	GalleryModelName string
+	ConfigURL        string
+	Delete           bool
+
+	Req       GalleryModel
+	Galleries []config.Gallery
+}
+
+type GalleryOpStatus struct {
+	Deletion           bool    `json:"deletion"` // Deletion is true if the operation is a deletion
+	FileName           string  `json:"file_name"`
+	Error              error   `json:"error"`
+	Processed          bool    `json:"processed"`
+	Message            string  `json:"message"`
+	Progress           float64 `json:"progress"`
+	TotalFileSize      string  `json:"file_size"`
+	DownloadedFileSize string  `json:"downloaded_size"`
+	GalleryModelName   string  `json:"gallery_model_name"`
+}
core/http/endpoints/localai/backend_monitor.go
-package localai
-
-import (
-	"github.com/gofiber/fiber/v2"
-	"github.com/mudler/LocalAI/core/schema"
-	"github.com/mudler/LocalAI/core/services"
-)
-
-// BackendMonitorEndpoint returns the status of the specified backend
-// @Summary Backend monitor endpoint
-// @Param request body schema.BackendMonitorRequest true "Backend statistics request"
-// @Success 200 {object} proto.StatusResponse "Response"
-// @Router /backend/monitor [get]
-func BackendMonitorEndpoint(bm *services.BackendMonitorService) func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-
-		input := new(schema.BackendMonitorRequest)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-
-		resp, err := bm.CheckAndSample(input.Model)
-		if err != nil {
-			return err
-		}
-		return c.JSON(resp)
-	}
-}
-
-// BackendMonitorEndpoint shuts down the specified backend
-// @Summary Backend monitor endpoint
-// @Param request body schema.BackendMonitorRequest true "Backend statistics request"
-// @Router /backend/shutdown [post]
-func BackendShutdownEndpoint(bm *services.BackendMonitorService) func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		input := new(schema.BackendMonitorRequest)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-
-		return bm.ShutdownModel(input.Model)
-	}
-}
+package localai
+
+import (
+	"github.com/gofiber/fiber/v2"
+	"github.com/mudler/LocalAI/core/schema"
+	"github.com/mudler/LocalAI/core/services"
+)
+
+// BackendMonitorEndpoint returns the status of the specified backend
+// @Summary Backend monitor endpoint
+// @Param request body schema.BackendMonitorRequest true "Backend statistics request"
+// @Success 200 {object} proto.StatusResponse "Response"
+// @Router /backend/monitor [get]
+func BackendMonitorEndpoint(bm *services.BackendMonitorService) func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+
+		input := new(schema.BackendMonitorRequest)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+
+		resp, err := bm.CheckAndSample(input.Model)
+		if err != nil {
+			return err
+		}
+		return c.JSON(resp)
+	}
+}
+
+// BackendMonitorEndpoint shuts down the specified backend
+// @Summary Backend monitor endpoint
+// @Param request body schema.BackendMonitorRequest true "Backend statistics request"
+// @Router /backend/shutdown [post]
+func BackendShutdownEndpoint(bm *services.BackendMonitorService) func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		input := new(schema.BackendMonitorRequest)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+
+		return bm.ShutdownModel(input.Model)
+	}
+}
core/http/endpoints/localai/gallery.go
-package localai
-
-import (
-	"encoding/json"
-	"fmt"
-	"slices"
-
-	"github.com/gofiber/fiber/v2"
-	"github.com/google/uuid"
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/gallery"
-	"github.com/mudler/LocalAI/core/schema"
-	"github.com/mudler/LocalAI/core/services"
-	"github.com/rs/zerolog/log"
-)
-
-type ModelGalleryEndpointService struct {
-	galleries      []config.Gallery
-	modelPath      string
-	galleryApplier *services.GalleryService
-}
-
-type GalleryModel struct {
-	ID        string `json:"id"`
-	ConfigURL string `json:"config_url"`
-	gallery.GalleryModel
-}
-
-func CreateModelGalleryEndpointService(galleries []config.Gallery, modelPath string, galleryApplier *services.GalleryService) ModelGalleryEndpointService {
-	return ModelGalleryEndpointService{
-		galleries:      galleries,
-		modelPath:      modelPath,
-		galleryApplier: galleryApplier,
-	}
-}
-
-// GetOpStatusEndpoint returns the job status
-// @Summary Returns the job status
-// @Success 200 {object} gallery.GalleryOpStatus "Response"
-// @Router /models/jobs/{uuid} [get]
-func (mgs *ModelGalleryEndpointService) GetOpStatusEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		status := mgs.galleryApplier.GetStatus(c.Params("uuid"))
-		if status == nil {
-			return fmt.Errorf("could not find any status for ID")
-		}
-		return c.JSON(status)
-	}
-}
-
-// GetAllStatusEndpoint returns all the jobs status progress
-// @Summary Returns all the jobs status progress
-// @Success 200 {object} map[string]gallery.GalleryOpStatus "Response"
-// @Router /models/jobs [get]
-func (mgs *ModelGalleryEndpointService) GetAllStatusEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		return c.JSON(mgs.galleryApplier.GetAllStatus())
-	}
-}
-
-// ApplyModelGalleryEndpoint installs a new model to a LocalAI instance from the model gallery
-// @Summary Install models to LocalAI.
-// @Param request body GalleryModel true "query params"
-// @Success 200 {object} schema.GalleryResponse "Response"
-// @Router /models/apply [post]
-func (mgs *ModelGalleryEndpointService) ApplyModelGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		input := new(GalleryModel)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-
-		uuid, err := uuid.NewUUID()
-		if err != nil {
-			return err
-		}
-		mgs.galleryApplier.C <- gallery.GalleryOp{
-			Req:              input.GalleryModel,
-			Id:               uuid.String(),
-			GalleryModelName: input.ID,
-			Galleries:        mgs.galleries,
-			ConfigURL:        input.ConfigURL,
-		}
-		return c.JSON(schema.GalleryResponse{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()})
-	}
-}
-
-// DeleteModelGalleryEndpoint lets delete models from a LocalAI instance
-// @Summary delete models to LocalAI.
-// @Param name	path string	true	"Model name"
-// @Success 200 {object} schema.GalleryResponse "Response"
-// @Router /models/delete/{name} [post]
-func (mgs *ModelGalleryEndpointService) DeleteModelGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		modelName := c.Params("name")
-
-		mgs.galleryApplier.C <- gallery.GalleryOp{
-			Delete:           true,
-			GalleryModelName: modelName,
-		}
-
-		uuid, err := uuid.NewUUID()
-		if err != nil {
-			return err
-		}
-
-		return c.JSON(schema.GalleryResponse{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()})
-	}
-}
-
-// ListModelFromGalleryEndpoint list the available models for installation from the active galleries
-// @Summary List installable models.
-// @Success 200 {object} []gallery.GalleryModel "Response"
-// @Router /models/available [get]
-func (mgs *ModelGalleryEndpointService) ListModelFromGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		log.Debug().Msgf("Listing models from galleries: %+v", mgs.galleries)
-
-		models, err := gallery.AvailableGalleryModels(mgs.galleries, mgs.modelPath)
-		if err != nil {
-			return err
-		}
-		log.Debug().Msgf("Models found from galleries: %+v", models)
-		for _, m := range models {
-			log.Debug().Msgf("Model found from galleries: %+v", m)
-		}
-		dat, err := json.Marshal(models)
-		if err != nil {
-			return err
-		}
-		return c.Send(dat)
-	}
-}
-
-// ListModelGalleriesEndpoint list the available galleries configured in LocalAI
-// @Summary List all Galleries
-// @Success 200 {object} []config.Gallery "Response"
-// @Router /models/galleries [get]
-// NOTE: This is different (and much simpler!) than above! This JUST lists the model galleries that have been loaded, not their contents!
-func (mgs *ModelGalleryEndpointService) ListModelGalleriesEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		log.Debug().Msgf("Listing model galleries %+v", mgs.galleries)
-		dat, err := json.Marshal(mgs.galleries)
-		if err != nil {
-			return err
-		}
-		return c.Send(dat)
-	}
-}
-
-// AddModelGalleryEndpoint adds a gallery in LocalAI
-// @Summary Adds a gallery in LocalAI
-// @Param request body config.Gallery true "Gallery details"
-// @Success 200 {object} []config.Gallery "Response"
-// @Router /models/galleries [post]
-func (mgs *ModelGalleryEndpointService) AddModelGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		input := new(config.Gallery)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-		if slices.ContainsFunc(mgs.galleries, func(gallery config.Gallery) bool {
-			return gallery.Name == input.Name
-		}) {
-			return fmt.Errorf("%s already exists", input.Name)
-		}
-		dat, err := json.Marshal(mgs.galleries)
-		if err != nil {
-			return err
-		}
-		log.Debug().Msgf("Adding %+v to gallery list", *input)
-		mgs.galleries = append(mgs.galleries, *input)
-		return c.Send(dat)
-	}
-}
-
-// RemoveModelGalleryEndpoint remove a gallery in LocalAI
-// @Summary removes a gallery from LocalAI
-// @Param request body config.Gallery true "Gallery details"
-// @Success 200 {object} []config.Gallery "Response"
-// @Router /models/galleries [delete]
-func (mgs *ModelGalleryEndpointService) RemoveModelGalleryEndpoint() func(c *fiber.Ctx) error {
-	return func(c *fiber.Ctx) error {
-		input := new(config.Gallery)
-		// Get input data from the request body
-		if err := c.BodyParser(input); err != nil {
-			return err
-		}
-		if !slices.ContainsFunc(mgs.galleries, func(gallery config.Gallery) bool {
-			return gallery.Name == input.Name
-		}) {
-			return fmt.Errorf("%s is not currently registered", input.Name)
-		}
-		mgs.galleries = slices.DeleteFunc(mgs.galleries, func(gallery config.Gallery) bool {
-			return gallery.Name == input.Name
-		})
-		dat, err := json.Marshal(mgs.galleries)
-		if err != nil {
-			return err
-		}
-		return c.Send(dat)
-	}
-}
+package localai
+
+import (
+	"encoding/json"
+	"fmt"
+	"slices"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/google/uuid"
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/gallery"
+	"github.com/mudler/LocalAI/core/schema"
+	"github.com/mudler/LocalAI/core/services"
+	"github.com/rs/zerolog/log"
+)
+
+type ModelGalleryEndpointService struct {
+	galleries      []config.Gallery
+	modelPath      string
+	galleryApplier *services.GalleryService
+}
+
+type GalleryModel struct {
+	ID        string `json:"id"`
+	ConfigURL string `json:"config_url"`
+	gallery.GalleryModel
+}
+
+func CreateModelGalleryEndpointService(galleries []config.Gallery, modelPath string, galleryApplier *services.GalleryService) ModelGalleryEndpointService {
+	return ModelGalleryEndpointService{
+		galleries:      galleries,
+		modelPath:      modelPath,
+		galleryApplier: galleryApplier,
+	}
+}
+
+// GetOpStatusEndpoint returns the job status
+// @Summary Returns the job status
+// @Success 200 {object} gallery.GalleryOpStatus "Response"
+// @Router /models/jobs/{uuid} [get]
+func (mgs *ModelGalleryEndpointService) GetOpStatusEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		status := mgs.galleryApplier.GetStatus(c.Params("uuid"))
+		if status == nil {
+			return fmt.Errorf("could not find any status for ID")
+		}
+		return c.JSON(status)
+	}
+}
+
+// GetAllStatusEndpoint returns all the jobs status progress
+// @Summary Returns all the jobs status progress
+// @Success 200 {object} map[string]gallery.GalleryOpStatus "Response"
+// @Router /models/jobs [get]
+func (mgs *ModelGalleryEndpointService) GetAllStatusEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		return c.JSON(mgs.galleryApplier.GetAllStatus())
+	}
+}
+
+// ApplyModelGalleryEndpoint installs a new model to a LocalAI instance from the model gallery
+// @Summary Install models to LocalAI.
+// @Param request body GalleryModel true "query params"
+// @Success 200 {object} schema.GalleryResponse "Response"
+// @Router /models/apply [post]
+func (mgs *ModelGalleryEndpointService) ApplyModelGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		input := new(GalleryModel)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+
+		uuid, err := uuid.NewUUID()
+		if err != nil {
+			return err
+		}
+		mgs.galleryApplier.C <- gallery.GalleryOp{
+			Req:              input.GalleryModel,
+			Id:               uuid.String(),
+			GalleryModelName: input.ID,
+			Galleries:        mgs.galleries,
+			ConfigURL:        input.ConfigURL,
+		}
+		return c.JSON(schema.GalleryResponse{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()})
+	}
+}
+
+// DeleteModelGalleryEndpoint lets delete models from a LocalAI instance
+// @Summary delete models to LocalAI.
+// @Param name	path string	true	"Model name"
+// @Success 200 {object} schema.GalleryResponse "Response"
+// @Router /models/delete/{name} [post]
+func (mgs *ModelGalleryEndpointService) DeleteModelGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		modelName := c.Params("name")
+
+		mgs.galleryApplier.C <- gallery.GalleryOp{
+			Delete:           true,
+			GalleryModelName: modelName,
+		}
+
+		uuid, err := uuid.NewUUID()
+		if err != nil {
+			return err
+		}
+
+		return c.JSON(schema.GalleryResponse{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()})
+	}
+}
+
+// ListModelFromGalleryEndpoint list the available models for installation from the active galleries
+// @Summary List installable models.
+// @Success 200 {object} []gallery.GalleryModel "Response"
+// @Router /models/available [get]
+func (mgs *ModelGalleryEndpointService) ListModelFromGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		log.Debug().Msgf("Listing models from galleries: %+v", mgs.galleries)
+
+		models, err := gallery.AvailableGalleryModels(mgs.galleries, mgs.modelPath)
+		if err != nil {
+			return err
+		}
+		log.Debug().Msgf("Models found from galleries: %+v", models)
+		for _, m := range models {
+			log.Debug().Msgf("Model found from galleries: %+v", m)
+		}
+		dat, err := json.Marshal(models)
+		if err != nil {
+			return err
+		}
+		return c.Send(dat)
+	}
+}
+
+// ListModelGalleriesEndpoint list the available galleries configured in LocalAI
+// @Summary List all Galleries
+// @Success 200 {object} []config.Gallery "Response"
+// @Router /models/galleries [get]
+// NOTE: This is different (and much simpler!) than above! This JUST lists the model galleries that have been loaded, not their contents!
+func (mgs *ModelGalleryEndpointService) ListModelGalleriesEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		log.Debug().Msgf("Listing model galleries %+v", mgs.galleries)
+		dat, err := json.Marshal(mgs.galleries)
+		if err != nil {
+			return err
+		}
+		return c.Send(dat)
+	}
+}
+
+// AddModelGalleryEndpoint adds a gallery in LocalAI
+// @Summary Adds a gallery in LocalAI
+// @Param request body config.Gallery true "Gallery details"
+// @Success 200 {object} []config.Gallery "Response"
+// @Router /models/galleries [post]
+func (mgs *ModelGalleryEndpointService) AddModelGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		input := new(config.Gallery)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+		if slices.ContainsFunc(mgs.galleries, func(gallery config.Gallery) bool {
+			return gallery.Name == input.Name
+		}) {
+			return fmt.Errorf("%s already exists", input.Name)
+		}
+		dat, err := json.Marshal(mgs.galleries)
+		if err != nil {
+			return err
+		}
+		log.Debug().Msgf("Adding %+v to gallery list", *input)
+		mgs.galleries = append(mgs.galleries, *input)
+		return c.Send(dat)
+	}
+}
+
+// RemoveModelGalleryEndpoint remove a gallery in LocalAI
+// @Summary removes a gallery from LocalAI
+// @Param request body config.Gallery true "Gallery details"
+// @Success 200 {object} []config.Gallery "Response"
+// @Router /models/galleries [delete]
+func (mgs *ModelGalleryEndpointService) RemoveModelGalleryEndpoint() func(c *fiber.Ctx) error {
+	return func(c *fiber.Ctx) error {
+		input := new(config.Gallery)
+		// Get input data from the request body
+		if err := c.BodyParser(input); err != nil {
+			return err
+		}
+		if !slices.ContainsFunc(mgs.galleries, func(gallery config.Gallery) bool {
+			return gallery.Name == input.Name
+		}) {
+			return fmt.Errorf("%s is not currently registered", input.Name)
+		}
+		mgs.galleries = slices.DeleteFunc(mgs.galleries, func(gallery config.Gallery) bool {
+			return gallery.Name == input.Name
+		})
+		dat, err := json.Marshal(mgs.galleries)
+		if err != nil {
+			return err
+		}
+		return c.Send(dat)
+	}
+}
core/http/endpoints/localai/metrics.go
-package localai
-
-import (
-	"time"
-
-	"github.com/gofiber/fiber/v2"
-	"github.com/gofiber/fiber/v2/middleware/adaptor"
-	"github.com/mudler/LocalAI/core/services"
-	"github.com/prometheus/client_golang/prometheus/promhttp"
-)
-
-// LocalAIMetricsEndpoint returns the metrics endpoint for LocalAI
-// @Summary Prometheus metrics endpoint
-// @Param request body config.Gallery true "Gallery details"
-// @Router /metrics [get]
-func LocalAIMetricsEndpoint() fiber.Handler {
-	return adaptor.HTTPHandler(promhttp.Handler())
-}
-
-type apiMiddlewareConfig struct {
-	Filter         func(c *fiber.Ctx) bool
-	metricsService *services.LocalAIMetricsService
-}
-
-func LocalAIMetricsAPIMiddleware(metrics *services.LocalAIMetricsService) fiber.Handler {
-	cfg := apiMiddlewareConfig{
-		metricsService: metrics,
-		Filter: func(c *fiber.Ctx) bool {
-			return c.Path() == "/metrics"
-		},
-	}
-
-	return func(c *fiber.Ctx) error {
-		if cfg.Filter != nil && cfg.Filter(c) {
-			return c.Next()
-		}
-		path := c.Path()
-		method := c.Method()
-
-		start := time.Now()
-		err := c.Next()
-		elapsed := float64(time.Since(start)) / float64(time.Second)
-		cfg.metricsService.ObserveAPICall(method, path, elapsed)
-		return err
-	}
-}
+package localai
+
+import (
+	"time"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/gofiber/fiber/v2/middleware/adaptor"
+	"github.com/mudler/LocalAI/core/services"
+	"github.com/prometheus/client_golang/prometheus/promhttp"
+)
+
+// LocalAIMetricsEndpoint returns the metrics endpoint for LocalAI
+// @Summary Prometheus metrics endpoint
+// @Param request body config.Gallery true "Gallery details"
+// @Router /metrics [get]
+func LocalAIMetricsEndpoint() fiber.Handler {
+	return adaptor.HTTPHandler(promhttp.Handler())
+}
+
+type apiMiddlewareConfig struct {
+	Filter         func(c *fiber.Ctx) bool
+	metricsService *services.LocalAIMetricsService
+}
+
+func LocalAIMetricsAPIMiddleware(metrics *services.LocalAIMetricsService) fiber.Handler {
+	cfg := apiMiddlewareConfig{
+		metricsService: metrics,
+		Filter: func(c *fiber.Ctx) bool {
+			return c.Path() == "/metrics"
+		},
+	}
+
+	return func(c *fiber.Ctx) error {
+		if cfg.Filter != nil && cfg.Filter(c) {
+			return c.Next()
+		}
+		path := c.Path()
+		method := c.Method()
+
+		start := time.Now()
+		err := c.Next()
+		elapsed := float64(time.Since(start)) / float64(time.Second)
+		cfg.metricsService.ObserveAPICall(method, path, elapsed)
+		return err
+	}
+}
core/http/endpoints/localai/tts.go
 )
 
 // TTSEndpoint is the OpenAI Speech API endpoint https://platform.openai.com/docs/api-reference/audio/createSpeech
-//	@Summary	Generates audio from the input text.
-//  @Accept json
-//  @Produce audio/x-wav
-//	@Param		request	body		schema.TTSRequest	true	"query params"
-//	@Success	200		{string}	binary				"generated audio/wav file"
-//	@Router		/v1/audio/speech [post]
-//	@Router		/tts [post]
+//
+//		@Summary	Generates audio from the input text.
+//	 @Accept json
+//	 @Produce audio/x-wav
+//		@Param		request	body		schema.TTSRequest	true	"query params"
+//		@Success	200		{string}	binary				"generated audio/wav file"
+//		@Router		/v1/audio/speech [post]
+//		@Router		/tts [post]
 func TTSEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
 	return func(c *fiber.Ctx) error {
 
core/schema/elevenlabs.go
-package schema
-
-type ElevenLabsTTSRequest struct {
-	Text    string `json:"text" yaml:"text"`
-	ModelID string `json:"model_id" yaml:"model_id"`
-}
+package schema
+
+type ElevenLabsTTSRequest struct {
+	Text    string `json:"text" yaml:"text"`
+	ModelID string `json:"model_id" yaml:"model_id"`
+}
core/services/backend_monitor.go
-package services
-
-import (
-	"context"
-	"fmt"
-	"strings"
-
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/schema"
-	"github.com/mudler/LocalAI/pkg/grpc/proto"
-	"github.com/mudler/LocalAI/pkg/model"
-
-	"github.com/rs/zerolog/log"
-
-	gopsutil "github.com/shirou/gopsutil/v3/process"
-)
-
-type BackendMonitorService struct {
-	backendConfigLoader *config.BackendConfigLoader
-	modelLoader         *model.ModelLoader
-	options             *config.ApplicationConfig // Taking options in case we need to inspect ExternalGRPCBackends, though that's out of scope for now, hence the name.
-}
-
-func NewBackendMonitorService(modelLoader *model.ModelLoader, configLoader *config.BackendConfigLoader, appConfig *config.ApplicationConfig) *BackendMonitorService {
-	return &BackendMonitorService{
-		modelLoader:         modelLoader,
-		backendConfigLoader: configLoader,
-		options:             appConfig,
-	}
-}
-
-func (bms BackendMonitorService) getModelLoaderIDFromModelName(modelName string) (string, error) {
-	config, exists := bms.backendConfigLoader.GetBackendConfig(modelName)
-	var backendId string
-	if exists {
-		backendId = config.Model
-	} else {
-		// Last ditch effort: use it raw, see if a backend happens to match.
-		backendId = modelName
-	}
-
-	if !strings.HasSuffix(backendId, ".bin") {
-		backendId = fmt.Sprintf("%s.bin", backendId)
-	}
-
-	return backendId, nil
-}
-
-func (bms *BackendMonitorService) SampleLocalBackendProcess(model string) (*schema.BackendMonitorResponse, error) {
-	config, exists := bms.backendConfigLoader.GetBackendConfig(model)
-	var backend string
-	if exists {
-		backend = config.Model
-	} else {
-		// Last ditch effort: use it raw, see if a backend happens to match.
-		backend = model
-	}
-
-	if !strings.HasSuffix(backend, ".bin") {
-		backend = fmt.Sprintf("%s.bin", backend)
-	}
-
-	pid, err := bms.modelLoader.GetGRPCPID(backend)
-
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Msg("failed to find GRPC pid")
-		return nil, err
-	}
-
-	// Name is slightly frightening but this does _not_ create a new process, rather it looks up an existing process by PID.
-	backendProcess, err := gopsutil.NewProcess(int32(pid))
-
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting process info")
-		return nil, err
-	}
-
-	memInfo, err := backendProcess.MemoryInfo()
-
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting memory info")
-		return nil, err
-	}
-
-	memPercent, err := backendProcess.MemoryPercent()
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting memory percent")
-		return nil, err
-	}
-
-	cpuPercent, err := backendProcess.CPUPercent()
-	if err != nil {
-		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting cpu percent")
-		return nil, err
-	}
-
-	return &schema.BackendMonitorResponse{
-		MemoryInfo:    memInfo,
-		MemoryPercent: memPercent,
-		CPUPercent:    cpuPercent,
-	}, nil
-}
-
-func (bms BackendMonitorService) CheckAndSample(modelName string) (*proto.StatusResponse, error) {
-	backendId, err := bms.getModelLoaderIDFromModelName(modelName)
-	if err != nil {
-		return nil, err
-	}
-	modelAddr := bms.modelLoader.CheckIsLoaded(backendId)
-	if modelAddr == "" {
-		return nil, fmt.Errorf("backend %s is not currently loaded", backendId)
-	}
-
-	status, rpcErr := modelAddr.GRPC(false, nil).Status(context.TODO())
-	if rpcErr != nil {
-		log.Warn().Msgf("backend %s experienced an error retrieving status info: %s", backendId, rpcErr.Error())
-		val, slbErr := bms.SampleLocalBackendProcess(backendId)
-		if slbErr != nil {
-			return nil, fmt.Errorf("backend %s experienced an error retrieving status info via rpc: %s, then failed local node process sample: %s", backendId, rpcErr.Error(), slbErr.Error())
-		}
-		return &proto.StatusResponse{
-			State: proto.StatusResponse_ERROR,
-			Memory: &proto.MemoryUsageData{
-				Total: val.MemoryInfo.VMS,
-				Breakdown: map[string]uint64{
-					"gopsutil-RSS": val.MemoryInfo.RSS,
-				},
-			},
-		}, nil
-	}
-	return status, nil
-}
-
-func (bms BackendMonitorService) ShutdownModel(modelName string) error {
-	backendId, err := bms.getModelLoaderIDFromModelName(modelName)
-	if err != nil {
-		return err
-	}
-	return bms.modelLoader.ShutdownModel(backendId)
-}
+package services
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/schema"
+	"github.com/mudler/LocalAI/pkg/grpc/proto"
+	"github.com/mudler/LocalAI/pkg/model"
+
+	"github.com/rs/zerolog/log"
+
+	gopsutil "github.com/shirou/gopsutil/v3/process"
+)
+
+type BackendMonitorService struct {
+	backendConfigLoader *config.BackendConfigLoader
+	modelLoader         *model.ModelLoader
+	options             *config.ApplicationConfig // Taking options in case we need to inspect ExternalGRPCBackends, though that's out of scope for now, hence the name.
+}
+
+func NewBackendMonitorService(modelLoader *model.ModelLoader, configLoader *config.BackendConfigLoader, appConfig *config.ApplicationConfig) *BackendMonitorService {
+	return &BackendMonitorService{
+		modelLoader:         modelLoader,
+		backendConfigLoader: configLoader,
+		options:             appConfig,
+	}
+}
+
+func (bms BackendMonitorService) getModelLoaderIDFromModelName(modelName string) (string, error) {
+	config, exists := bms.backendConfigLoader.GetBackendConfig(modelName)
+	var backendId string
+	if exists {
+		backendId = config.Model
+	} else {
+		// Last ditch effort: use it raw, see if a backend happens to match.
+		backendId = modelName
+	}
+
+	if !strings.HasSuffix(backendId, ".bin") {
+		backendId = fmt.Sprintf("%s.bin", backendId)
+	}
+
+	return backendId, nil
+}
+
+func (bms *BackendMonitorService) SampleLocalBackendProcess(model string) (*schema.BackendMonitorResponse, error) {
+	config, exists := bms.backendConfigLoader.GetBackendConfig(model)
+	var backend string
+	if exists {
+		backend = config.Model
+	} else {
+		// Last ditch effort: use it raw, see if a backend happens to match.
+		backend = model
+	}
+
+	if !strings.HasSuffix(backend, ".bin") {
+		backend = fmt.Sprintf("%s.bin", backend)
+	}
+
+	pid, err := bms.modelLoader.GetGRPCPID(backend)
+
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Msg("failed to find GRPC pid")
+		return nil, err
+	}
+
+	// Name is slightly frightening but this does _not_ create a new process, rather it looks up an existing process by PID.
+	backendProcess, err := gopsutil.NewProcess(int32(pid))
+
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting process info")
+		return nil, err
+	}
+
+	memInfo, err := backendProcess.MemoryInfo()
+
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting memory info")
+		return nil, err
+	}
+
+	memPercent, err := backendProcess.MemoryPercent()
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting memory percent")
+		return nil, err
+	}
+
+	cpuPercent, err := backendProcess.CPUPercent()
+	if err != nil {
+		log.Error().Err(err).Str("model", model).Int("pid", pid).Msg("error getting cpu percent")
+		return nil, err
+	}
+
+	return &schema.BackendMonitorResponse{
+		MemoryInfo:    memInfo,
+		MemoryPercent: memPercent,
+		CPUPercent:    cpuPercent,
+	}, nil
+}
+
+func (bms BackendMonitorService) CheckAndSample(modelName string) (*proto.StatusResponse, error) {
+	backendId, err := bms.getModelLoaderIDFromModelName(modelName)
+	if err != nil {
+		return nil, err
+	}
+	modelAddr := bms.modelLoader.CheckIsLoaded(backendId)
+	if modelAddr == "" {
+		return nil, fmt.Errorf("backend %s is not currently loaded", backendId)
+	}
+
+	status, rpcErr := modelAddr.GRPC(false, nil).Status(context.TODO())
+	if rpcErr != nil {
+		log.Warn().Msgf("backend %s experienced an error retrieving status info: %s", backendId, rpcErr.Error())
+		val, slbErr := bms.SampleLocalBackendProcess(backendId)
+		if slbErr != nil {
+			return nil, fmt.Errorf("backend %s experienced an error retrieving status info via rpc: %s, then failed local node process sample: %s", backendId, rpcErr.Error(), slbErr.Error())
+		}
+		return &proto.StatusResponse{
+			State: proto.StatusResponse_ERROR,
+			Memory: &proto.MemoryUsageData{
+				Total: val.MemoryInfo.VMS,
+				Breakdown: map[string]uint64{
+					"gopsutil-RSS": val.MemoryInfo.RSS,
+				},
+			},
+		}, nil
+	}
+	return status, nil
+}
+
+func (bms BackendMonitorService) ShutdownModel(modelName string) error {
+	backendId, err := bms.getModelLoaderIDFromModelName(modelName)
+	if err != nil {
+		return err
+	}
+	return bms.modelLoader.ShutdownModel(backendId)
+}
core/services/gallery.go
-package services
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"os"
-	"path/filepath"
-	"sync"
-
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/gallery"
-	"github.com/mudler/LocalAI/pkg/startup"
-	"github.com/mudler/LocalAI/pkg/utils"
-	"gopkg.in/yaml.v2"
-)
-
-type GalleryService struct {
-	appConfig *config.ApplicationConfig
-	sync.Mutex
-	C        chan gallery.GalleryOp
-	statuses map[string]*gallery.GalleryOpStatus
-}
-
-func NewGalleryService(appConfig *config.ApplicationConfig) *GalleryService {
-	return &GalleryService{
-		appConfig: appConfig,
-		C:         make(chan gallery.GalleryOp),
-		statuses:  make(map[string]*gallery.GalleryOpStatus),
-	}
-}
-
-func prepareModel(modelPath string, req gallery.GalleryModel, downloadStatus func(string, string, string, float64), enforceScan bool) error {
-
-	config, err := gallery.GetGalleryConfigFromURL(req.URL, modelPath)
-	if err != nil {
-		return err
-	}
-
-	config.Files = append(config.Files, req.AdditionalFiles...)
-
-	return gallery.InstallModel(modelPath, req.Name, &config, req.Overrides, downloadStatus, enforceScan)
-}
-
-func (g *GalleryService) UpdateStatus(s string, op *gallery.GalleryOpStatus) {
-	g.Lock()
-	defer g.Unlock()
-	g.statuses[s] = op
-}
-
-func (g *GalleryService) GetStatus(s string) *gallery.GalleryOpStatus {
-	g.Lock()
-	defer g.Unlock()
-
-	return g.statuses[s]
-}
-
-func (g *GalleryService) GetAllStatus() map[string]*gallery.GalleryOpStatus {
-	g.Lock()
-	defer g.Unlock()
-
-	return g.statuses
-}
-
-func (g *GalleryService) Start(c context.Context, cl *config.BackendConfigLoader) {
-	go func() {
-		for {
-			select {
-			case <-c.Done():
-				return
-			case op := <-g.C:
-				utils.ResetDownloadTimers()
-
-				g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", Progress: 0})
-
-				// updates the status with an error
-				var updateError func(e error)
-				if !g.appConfig.OpaqueErrors {
-					updateError = func(e error) {
-						g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: e, Processed: true, Message: "error: " + e.Error()})
-					}
-				} else {
-					updateError = func(_ error) {
-						g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: fmt.Errorf("an error occurred"), Processed: true})
-					}
-				}
-
-				// displayDownload displays the download progress
-				progressCallback := func(fileName string, current string, total string, percentage float64) {
-					g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", FileName: fileName, Progress: percentage, TotalFileSize: total, DownloadedFileSize: current})
-					utils.DisplayDownloadFunction(fileName, current, total, percentage)
-				}
-
-				var err error
-
-				// delete a model
-				if op.Delete {
-					modelConfig := &config.BackendConfig{}
-
-					// Galleryname is the name of the model in this case
-					dat, err := os.ReadFile(filepath.Join(g.appConfig.ModelPath, op.GalleryModelName+".yaml"))
-					if err != nil {
-						updateError(err)
-						continue
-					}
-					err = yaml.Unmarshal(dat, modelConfig)
-					if err != nil {
-						updateError(err)
-						continue
-					}
-
-					files := []string{}
-					// Remove the model from the config
-					if modelConfig.Model != "" {
-						files = append(files, modelConfig.ModelFileName())
-					}
-
-					if modelConfig.MMProj != "" {
-						files = append(files, modelConfig.MMProjFileName())
-					}
-
-					err = gallery.DeleteModelFromSystem(g.appConfig.ModelPath, op.GalleryModelName, files)
-					if err != nil {
-						updateError(err)
-						continue
-					}
-				} else {
-					// if the request contains a gallery name, we apply the gallery from the gallery list
-					if op.GalleryModelName != "" {
-						err = gallery.InstallModelFromGallery(op.Galleries, op.GalleryModelName, g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans)
-					} else if op.ConfigURL != "" {
-						err = startup.InstallModels(op.Galleries, op.ConfigURL, g.appConfig.ModelPath, g.appConfig.EnforcePredownloadScans, progressCallback, op.ConfigURL)
-						if err != nil {
-							updateError(err)
-							continue
-						}
-						err = cl.Preload(g.appConfig.ModelPath)
-					} else {
-						err = prepareModel(g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans)
-					}
-				}
-
-				if err != nil {
-					updateError(err)
-					continue
-				}
-
-				// Reload models
-				err = cl.LoadBackendConfigsFromPath(g.appConfig.ModelPath)
-				if err != nil {
-					updateError(err)
-					continue
-				}
-
-				err = cl.Preload(g.appConfig.ModelPath)
-				if err != nil {
-					updateError(err)
-					continue
-				}
-
-				g.UpdateStatus(op.Id,
-					&gallery.GalleryOpStatus{
-						Deletion:         op.Delete,
-						Processed:        true,
-						GalleryModelName: op.GalleryModelName,
-						Message:          "completed",
-						Progress:         100})
-			}
-		}
-	}()
-}
-
-type galleryModel struct {
-	gallery.GalleryModel `yaml:",inline"` // https://github.com/go-yaml/yaml/issues/63
-	ID                   string           `json:"id"`
-}
-
-func processRequests(modelPath string, enforceScan bool, galleries []config.Gallery, requests []galleryModel) error {
-	var err error
-	for _, r := range requests {
-		utils.ResetDownloadTimers()
-		if r.ID == "" {
-			err = prepareModel(modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan)
-
-		} else {
-			err = gallery.InstallModelFromGallery(
-				galleries, r.ID, modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan)
-		}
-	}
-	return err
-}
-
-func ApplyGalleryFromFile(modelPath, s string, enforceScan bool, galleries []config.Gallery) error {
-	dat, err := os.ReadFile(s)
-	if err != nil {
-		return err
-	}
-	var requests []galleryModel
-
-	if err := yaml.Unmarshal(dat, &requests); err != nil {
-		return err
-	}
-
-	return processRequests(modelPath, enforceScan, galleries, requests)
-}
-
-func ApplyGalleryFromString(modelPath, s string, enforceScan bool, galleries []config.Gallery) error {
-	var requests []galleryModel
-	err := json.Unmarshal([]byte(s), &requests)
-	if err != nil {
-		return err
-	}
-
-	return processRequests(modelPath, enforceScan, galleries, requests)
-}
+package services
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"os"
+	"path/filepath"
+	"sync"
+
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/gallery"
+	"github.com/mudler/LocalAI/pkg/startup"
+	"github.com/mudler/LocalAI/pkg/utils"
+	"gopkg.in/yaml.v2"
+)
+
+type GalleryService struct {
+	appConfig *config.ApplicationConfig
+	sync.Mutex
+	C        chan gallery.GalleryOp
+	statuses map[string]*gallery.GalleryOpStatus
+}
+
+func NewGalleryService(appConfig *config.ApplicationConfig) *GalleryService {
+	return &GalleryService{
+		appConfig: appConfig,
+		C:         make(chan gallery.GalleryOp),
+		statuses:  make(map[string]*gallery.GalleryOpStatus),
+	}
+}
+
+func prepareModel(modelPath string, req gallery.GalleryModel, downloadStatus func(string, string, string, float64), enforceScan bool) error {
+
+	config, err := gallery.GetGalleryConfigFromURL(req.URL, modelPath)
+	if err != nil {
+		return err
+	}
+
+	config.Files = append(config.Files, req.AdditionalFiles...)
+
+	return gallery.InstallModel(modelPath, req.Name, &config, req.Overrides, downloadStatus, enforceScan)
+}
+
+func (g *GalleryService) UpdateStatus(s string, op *gallery.GalleryOpStatus) {
+	g.Lock()
+	defer g.Unlock()
+	g.statuses[s] = op
+}
+
+func (g *GalleryService) GetStatus(s string) *gallery.GalleryOpStatus {
+	g.Lock()
+	defer g.Unlock()
+
+	return g.statuses[s]
+}
+
+func (g *GalleryService) GetAllStatus() map[string]*gallery.GalleryOpStatus {
+	g.Lock()
+	defer g.Unlock()
+
+	return g.statuses
+}
+
+func (g *GalleryService) Start(c context.Context, cl *config.BackendConfigLoader) {
+	go func() {
+		for {
+			select {
+			case <-c.Done():
+				return
+			case op := <-g.C:
+				utils.ResetDownloadTimers()
+
+				g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", Progress: 0})
+
+				// updates the status with an error
+				var updateError func(e error)
+				if !g.appConfig.OpaqueErrors {
+					updateError = func(e error) {
+						g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: e, Processed: true, Message: "error: " + e.Error()})
+					}
+				} else {
+					updateError = func(_ error) {
+						g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: fmt.Errorf("an error occurred"), Processed: true})
+					}
+				}
+
+				// displayDownload displays the download progress
+				progressCallback := func(fileName string, current string, total string, percentage float64) {
+					g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", FileName: fileName, Progress: percentage, TotalFileSize: total, DownloadedFileSize: current})
+					utils.DisplayDownloadFunction(fileName, current, total, percentage)
+				}
+
+				var err error
+
+				// delete a model
+				if op.Delete {
+					modelConfig := &config.BackendConfig{}
+
+					// Galleryname is the name of the model in this case
+					dat, err := os.ReadFile(filepath.Join(g.appConfig.ModelPath, op.GalleryModelName+".yaml"))
+					if err != nil {
+						updateError(err)
+						continue
+					}
+					err = yaml.Unmarshal(dat, modelConfig)
+					if err != nil {
+						updateError(err)
+						continue
+					}
+
+					files := []string{}
+					// Remove the model from the config
+					if modelConfig.Model != "" {
+						files = append(files, modelConfig.ModelFileName())
+					}
+
+					if modelConfig.MMProj != "" {
+						files = append(files, modelConfig.MMProjFileName())
+					}
+
+					err = gallery.DeleteModelFromSystem(g.appConfig.ModelPath, op.GalleryModelName, files)
+					if err != nil {
+						updateError(err)
+						continue
+					}
+				} else {
+					// if the request contains a gallery name, we apply the gallery from the gallery list
+					if op.GalleryModelName != "" {
+						err = gallery.InstallModelFromGallery(op.Galleries, op.GalleryModelName, g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans)
+					} else if op.ConfigURL != "" {
+						err = startup.InstallModels(op.Galleries, op.ConfigURL, g.appConfig.ModelPath, g.appConfig.EnforcePredownloadScans, progressCallback, op.ConfigURL)
+						if err != nil {
+							updateError(err)
+							continue
+						}
+						err = cl.Preload(g.appConfig.ModelPath)
+					} else {
+						err = prepareModel(g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans)
+					}
+				}
+
+				if err != nil {
+					updateError(err)
+					continue
+				}
+
+				// Reload models
+				err = cl.LoadBackendConfigsFromPath(g.appConfig.ModelPath)
+				if err != nil {
+					updateError(err)
+					continue
+				}
+
+				err = cl.Preload(g.appConfig.ModelPath)
+				if err != nil {
+					updateError(err)
+					continue
+				}
+
+				g.UpdateStatus(op.Id,
+					&gallery.GalleryOpStatus{
+						Deletion:         op.Delete,
+						Processed:        true,
+						GalleryModelName: op.GalleryModelName,
+						Message:          "completed",
+						Progress:         100})
+			}
+		}
+	}()
+}
+
+type galleryModel struct {
+	gallery.GalleryModel `yaml:",inline"` // https://github.com/go-yaml/yaml/issues/63
+	ID                   string           `json:"id"`
+}
+
+func processRequests(modelPath string, enforceScan bool, galleries []config.Gallery, requests []galleryModel) error {
+	var err error
+	for _, r := range requests {
+		utils.ResetDownloadTimers()
+		if r.ID == "" {
+			err = prepareModel(modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan)
+
+		} else {
+			err = gallery.InstallModelFromGallery(
+				galleries, r.ID, modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan)
+		}
+	}
+	return err
+}
+
+func ApplyGalleryFromFile(modelPath, s string, enforceScan bool, galleries []config.Gallery) error {
+	dat, err := os.ReadFile(s)
+	if err != nil {
+		return err
+	}
+	var requests []galleryModel
+
+	if err := yaml.Unmarshal(dat, &requests); err != nil {
+		return err
+	}
+
+	return processRequests(modelPath, enforceScan, galleries, requests)
+}
+
+func ApplyGalleryFromString(modelPath, s string, enforceScan bool, galleries []config.Gallery) error {
+	var requests []galleryModel
+	err := json.Unmarshal([]byte(s), &requests)
+	if err != nil {
+		return err
+	}
+
+	return processRequests(modelPath, enforceScan, galleries, requests)
+}
core/services/list_models.go
-package services
-
-import (
-	"regexp"
-
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/pkg/model"
-)
-
-func ListModels(bcl *config.BackendConfigLoader, ml *model.ModelLoader, filter string, excludeConfigured bool) ([]string, error) {
-
-	models, err := ml.ListFilesInModelPath()
-	if err != nil {
-		return nil, err
-	}
-
-	var mm map[string]interface{} = map[string]interface{}{}
-
-	dataModels := []string{}
-
-	var filterFn func(name string) bool
-
-	// If filter is not specified, do not filter the list by model name
-	if filter == "" {
-		filterFn = func(_ string) bool { return true }
-	} else {
-		// If filter _IS_ specified, we compile it to a regex which is used to create the filterFn
-		rxp, err := regexp.Compile(filter)
-		if err != nil {
-			return nil, err
-		}
-		filterFn = func(name string) bool {
-			return rxp.MatchString(name)
-		}
-	}
-
-	// Start with the known configurations
-	for _, c := range bcl.GetAllBackendConfigs() {
-		if excludeConfigured {
-			mm[c.Model] = nil
-		}
-
-		if filterFn(c.Name) {
-			dataModels = append(dataModels, c.Name)
-		}
-	}
-
-	// Then iterate through the loose files:
-	for _, m := range models {
-		// And only adds them if they shouldn't be skipped.
-		if _, exists := mm[m]; !exists && filterFn(m) {
-			dataModels = append(dataModels, m)
-		}
-	}
-
-	return dataModels, nil
-}
+package services
+
+import (
+	"regexp"
+
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/pkg/model"
+)
+
+func ListModels(bcl *config.BackendConfigLoader, ml *model.ModelLoader, filter string, excludeConfigured bool) ([]string, error) {
+
+	models, err := ml.ListFilesInModelPath()
+	if err != nil {
+		return nil, err
+	}
+
+	var mm map[string]interface{} = map[string]interface{}{}
+
+	dataModels := []string{}
+
+	var filterFn func(name string) bool
+
+	// If filter is not specified, do not filter the list by model name
+	if filter == "" {
+		filterFn = func(_ string) bool { return true }
+	} else {
+		// If filter _IS_ specified, we compile it to a regex which is used to create the filterFn
+		rxp, err := regexp.Compile(filter)
+		if err != nil {
+			return nil, err
+		}
+		filterFn = func(name string) bool {
+			return rxp.MatchString(name)
+		}
+	}
+
+	// Start with the known configurations
+	for _, c := range bcl.GetAllBackendConfigs() {
+		if excludeConfigured {
+			mm[c.Model] = nil
+		}
+
+		if filterFn(c.Name) {
+			dataModels = append(dataModels, c.Name)
+		}
+	}
+
+	// Then iterate through the loose files:
+	for _, m := range models {
+		// And only adds them if they shouldn't be skipped.
+		if _, exists := mm[m]; !exists && filterFn(m) {
+			dataModels = append(dataModels, m)
+		}
+	}
+
+	return dataModels, nil
+}
core/startup/config_file_watcher.go
-package startup
-
-import (
-	"encoding/json"
-	"fmt"
-	"os"
-	"path"
-	"path/filepath"
-	"time"
-
-	"github.com/fsnotify/fsnotify"
-	"dario.cat/mergo"
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/rs/zerolog/log"
-)
-
-type fileHandler func(fileContent []byte, appConfig *config.ApplicationConfig) error
-
-type configFileHandler struct {
-	handlers map[string]fileHandler
-
-	watcher *fsnotify.Watcher
-
-	appConfig *config.ApplicationConfig
-}
-
-// TODO: This should be a singleton eventually so other parts of the code can register config file handlers,
-// then we can export it to other packages
-func newConfigFileHandler(appConfig *config.ApplicationConfig) configFileHandler {
-	c := configFileHandler{
-		handlers:  make(map[string]fileHandler),
-		appConfig: appConfig,
-	}
-	err := c.Register("api_keys.json", readApiKeysJson(*appConfig), true)
-	if err != nil {
-		log.Error().Err(err).Str("file", "api_keys.json").Msg("unable to register config file handler")
-	}
-	err = c.Register("external_backends.json", readExternalBackendsJson(*appConfig), true)
-	if err != nil {
-		log.Error().Err(err).Str("file", "external_backends.json").Msg("unable to register config file handler")
-	}
-	return c
-}
-
-func (c *configFileHandler) Register(filename string, handler fileHandler, runNow bool) error {
-	_, ok := c.handlers[filename]
-	if ok {
-		return fmt.Errorf("handler already registered for file %s", filename)
-	}
-	c.handlers[filename] = handler
-	if runNow {
-		c.callHandler(filename, handler)
-	}
-	return nil
-}
-
-func (c *configFileHandler) callHandler(filename string, handler fileHandler) {
-	rootedFilePath := filepath.Join(c.appConfig.DynamicConfigsDir, filepath.Clean(filename))
-	log.Trace().Str("filename", rootedFilePath).Msg("reading file for dynamic config update")
-	fileContent, err := os.ReadFile(rootedFilePath)
-	if err != nil && !os.IsNotExist(err) {
-		log.Error().Err(err).Str("filename", rootedFilePath).Msg("could not read file")
-	}
-
-	if err = handler(fileContent, c.appConfig); err != nil {
-		log.Error().Err(err).Msg("WatchConfigDirectory goroutine failed to update options")
-	}
-}
-
-func (c *configFileHandler) Watch() error {
-	configWatcher, err := fsnotify.NewWatcher()
-	c.watcher = configWatcher
-	if err != nil {
-		return err
-	}
-
-	if c.appConfig.DynamicConfigsDirPollInterval > 0 {
-		log.Debug().Msg("Poll interval set, falling back to polling for configuration changes")
-		ticker := time.NewTicker(c.appConfig.DynamicConfigsDirPollInterval)
-		go func() {
-			for {
-				<-ticker.C
-				for file, handler := range c.handlers {
-					log.Debug().Str("file", file).Msg("polling config file")
-					c.callHandler(file, handler)
-				}
-			}
-		}()
-	}
-
-	// Start listening for events.
-	go func() {
-		for {
-			select {
-			case event, ok := <-c.watcher.Events:
-				if !ok {
-					return
-				}
-				if event.Has(fsnotify.Write | fsnotify.Create | fsnotify.Remove) {
-					handler, ok := c.handlers[path.Base(event.Name)]
-					if !ok {
-						continue
-					}
-
-					c.callHandler(filepath.Base(event.Name), handler)
-				}
-			case err, ok := <-c.watcher.Errors:
-				log.Error().Err(err).Msg("config watcher error received")
-				if !ok {
-					return
-				}
-			}
-		}
-	}()
-
-	// Add a path.
-	err = c.watcher.Add(c.appConfig.DynamicConfigsDir)
-	if err != nil {
-		return fmt.Errorf("unable to create a watcher on the configuration directory: %+v", err)
-	}
-
-	return nil
-}
-
-// TODO: When we institute graceful shutdown, this should be called
-func (c *configFileHandler) Stop() error {
-	return c.watcher.Close()
-}
-
-func readApiKeysJson(startupAppConfig config.ApplicationConfig) fileHandler {
-	handler := func(fileContent []byte, appConfig *config.ApplicationConfig) error {
-		log.Debug().Msg("processing api keys runtime update")
-		log.Trace().Int("numKeys", len(startupAppConfig.ApiKeys)).Msg("api keys provided at startup")
-
-		if len(fileContent) > 0 {
-			// Parse JSON content from the file
-			var fileKeys []string
-			err := json.Unmarshal(fileContent, &fileKeys)
-			if err != nil {
-				return err
-			}
-
-			log.Trace().Int("numKeys", len(fileKeys)).Msg("discovered API keys from api keys dynamic config dile")
-
-			appConfig.ApiKeys = append(startupAppConfig.ApiKeys, fileKeys...)
-		} else {
-			log.Trace().Msg("no API keys discovered from dynamic config file")
-			appConfig.ApiKeys = startupAppConfig.ApiKeys
-		}
-		log.Trace().Int("numKeys", len(appConfig.ApiKeys)).Msg("total api keys after processing")
-		return nil
-	}
-
-	return handler
-}
-
-func readExternalBackendsJson(startupAppConfig config.ApplicationConfig) fileHandler {
-	handler := func(fileContent []byte, appConfig *config.ApplicationConfig) error {
-		log.Debug().Msg("processing external_backends.json")
-
-		if len(fileContent) > 0 {
-			// Parse JSON content from the file
-			var fileBackends map[string]string
-			err := json.Unmarshal(fileContent, &fileBackends)
-			if err != nil {
-				return err
-			}
-			appConfig.ExternalGRPCBackends = startupAppConfig.ExternalGRPCBackends
-			err = mergo.Merge(&appConfig.ExternalGRPCBackends, &fileBackends)
-			if err != nil {
-				return err
-			}
-		} else {
-			appConfig.ExternalGRPCBackends = startupAppConfig.ExternalGRPCBackends
-		}
-		log.Debug().Msg("external backends loaded from external_backends.json")
-		return nil
-	}
-	return handler
-}
+package startup
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+	"path"
+	"path/filepath"
+	"time"
+
+	"dario.cat/mergo"
+	"github.com/fsnotify/fsnotify"
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/rs/zerolog/log"
+)
+
+type fileHandler func(fileContent []byte, appConfig *config.ApplicationConfig) error
+
+type configFileHandler struct {
+	handlers map[string]fileHandler
+
+	watcher *fsnotify.Watcher
+
+	appConfig *config.ApplicationConfig
+}
+
+// TODO: This should be a singleton eventually so other parts of the code can register config file handlers,
+// then we can export it to other packages
+func newConfigFileHandler(appConfig *config.ApplicationConfig) configFileHandler {
+	c := configFileHandler{
+		handlers:  make(map[string]fileHandler),
+		appConfig: appConfig,
+	}
+	err := c.Register("api_keys.json", readApiKeysJson(*appConfig), true)
+	if err != nil {
+		log.Error().Err(err).Str("file", "api_keys.json").Msg("unable to register config file handler")
+	}
+	err = c.Register("external_backends.json", readExternalBackendsJson(*appConfig), true)
+	if err != nil {
+		log.Error().Err(err).Str("file", "external_backends.json").Msg("unable to register config file handler")
+	}
+	return c
+}
+
+func (c *configFileHandler) Register(filename string, handler fileHandler, runNow bool) error {
+	_, ok := c.handlers[filename]
+	if ok {
+		return fmt.Errorf("handler already registered for file %s", filename)
+	}
+	c.handlers[filename] = handler
+	if runNow {
+		c.callHandler(filename, handler)
+	}
+	return nil
+}
+
+func (c *configFileHandler) callHandler(filename string, handler fileHandler) {
+	rootedFilePath := filepath.Join(c.appConfig.DynamicConfigsDir, filepath.Clean(filename))
+	log.Trace().Str("filename", rootedFilePath).Msg("reading file for dynamic config update")
+	fileContent, err := os.ReadFile(rootedFilePath)
+	if err != nil && !os.IsNotExist(err) {
+		log.Error().Err(err).Str("filename", rootedFilePath).Msg("could not read file")
+	}
+
+	if err = handler(fileContent, c.appConfig); err != nil {
+		log.Error().Err(err).Msg("WatchConfigDirectory goroutine failed to update options")
+	}
+}
+
+func (c *configFileHandler) Watch() error {
+	configWatcher, err := fsnotify.NewWatcher()
+	c.watcher = configWatcher
+	if err != nil {
+		return err
+	}
+
+	if c.appConfig.DynamicConfigsDirPollInterval > 0 {
+		log.Debug().Msg("Poll interval set, falling back to polling for configuration changes")
+		ticker := time.NewTicker(c.appConfig.DynamicConfigsDirPollInterval)
+		go func() {
+			for {
+				<-ticker.C
+				for file, handler := range c.handlers {
+					log.Debug().Str("file", file).Msg("polling config file")
+					c.callHandler(file, handler)
+				}
+			}
+		}()
+	}
+
+	// Start listening for events.
+	go func() {
+		for {
+			select {
+			case event, ok := <-c.watcher.Events:
+				if !ok {
+					return
+				}
+				if event.Has(fsnotify.Write | fsnotify.Create | fsnotify.Remove) {
+					handler, ok := c.handlers[path.Base(event.Name)]
+					if !ok {
+						continue
+					}
+
+					c.callHandler(filepath.Base(event.Name), handler)
+				}
+			case err, ok := <-c.watcher.Errors:
+				log.Error().Err(err).Msg("config watcher error received")
+				if !ok {
+					return
+				}
+			}
+		}
+	}()
+
+	// Add a path.
+	err = c.watcher.Add(c.appConfig.DynamicConfigsDir)
+	if err != nil {
+		return fmt.Errorf("unable to create a watcher on the configuration directory: %+v", err)
+	}
+
+	return nil
+}
+
+// TODO: When we institute graceful shutdown, this should be called
+func (c *configFileHandler) Stop() error {
+	return c.watcher.Close()
+}
+
+func readApiKeysJson(startupAppConfig config.ApplicationConfig) fileHandler {
+	handler := func(fileContent []byte, appConfig *config.ApplicationConfig) error {
+		log.Debug().Msg("processing api keys runtime update")
+		log.Trace().Int("numKeys", len(startupAppConfig.ApiKeys)).Msg("api keys provided at startup")
+
+		if len(fileContent) > 0 {
+			// Parse JSON content from the file
+			var fileKeys []string
+			err := json.Unmarshal(fileContent, &fileKeys)
+			if err != nil {
+				return err
+			}
+
+			log.Trace().Int("numKeys", len(fileKeys)).Msg("discovered API keys from api keys dynamic config dile")
+
+			appConfig.ApiKeys = append(startupAppConfig.ApiKeys, fileKeys...)
+		} else {
+			log.Trace().Msg("no API keys discovered from dynamic config file")
+			appConfig.ApiKeys = startupAppConfig.ApiKeys
+		}
+		log.Trace().Int("numKeys", len(appConfig.ApiKeys)).Msg("total api keys after processing")
+		return nil
+	}
+
+	return handler
+}
+
+func readExternalBackendsJson(startupAppConfig config.ApplicationConfig) fileHandler {
+	handler := func(fileContent []byte, appConfig *config.ApplicationConfig) error {
+		log.Debug().Msg("processing external_backends.json")
+
+		if len(fileContent) > 0 {
+			// Parse JSON content from the file
+			var fileBackends map[string]string
+			err := json.Unmarshal(fileContent, &fileBackends)
+			if err != nil {
+				return err
+			}
+			appConfig.ExternalGRPCBackends = startupAppConfig.ExternalGRPCBackends
+			err = mergo.Merge(&appConfig.ExternalGRPCBackends, &fileBackends)
+			if err != nil {
+				return err
+			}
+		} else {
+			appConfig.ExternalGRPCBackends = startupAppConfig.ExternalGRPCBackends
+		}
+		log.Debug().Msg("external backends loaded from external_backends.json")
+		return nil
+	}
+	return handler
+}
core/startup/startup.go
-package startup
-
-import (
-	"fmt"
-	"os"
-
-	"github.com/mudler/LocalAI/core"
-	"github.com/mudler/LocalAI/core/config"
-	"github.com/mudler/LocalAI/core/services"
-	"github.com/mudler/LocalAI/internal"
-	"github.com/mudler/LocalAI/pkg/assets"
-	"github.com/mudler/LocalAI/pkg/library"
-	"github.com/mudler/LocalAI/pkg/model"
-	pkgStartup "github.com/mudler/LocalAI/pkg/startup"
-	"github.com/mudler/LocalAI/pkg/xsysinfo"
-	"github.com/rs/zerolog/log"
-)
-
-func Startup(opts ...config.AppOption) (*config.BackendConfigLoader, *model.ModelLoader, *config.ApplicationConfig, error) {
-	options := config.NewApplicationConfig(opts...)
-
-	log.Info().Msgf("Starting LocalAI using %d threads, with models path: %s", options.Threads, options.ModelPath)
-	log.Info().Msgf("LocalAI version: %s", internal.PrintableVersion())
-	caps, err := xsysinfo.CPUCapabilities()
-	if err == nil {
-		log.Debug().Msgf("CPU capabilities: %v", caps)
-	}
-	gpus, err := xsysinfo.GPUs()
-	if err == nil {
-		log.Debug().Msgf("GPU count: %d", len(gpus))
-		for _, gpu := range gpus {
-			log.Debug().Msgf("GPU: %s", gpu.String())
-		}
-	}
-
-	// Make sure directories exists
-	if options.ModelPath == "" {
-		return nil, nil, nil, fmt.Errorf("options.ModelPath cannot be empty")
-	}
-	err = os.MkdirAll(options.ModelPath, 0750)
-	if err != nil {
-		return nil, nil, nil, fmt.Errorf("unable to create ModelPath: %q", err)
-	}
-	if options.ImageDir != "" {
-		err := os.MkdirAll(options.ImageDir, 0750)
-		if err != nil {
-			return nil, nil, nil, fmt.Errorf("unable to create ImageDir: %q", err)
-		}
-	}
-	if options.AudioDir != "" {
-		err := os.MkdirAll(options.AudioDir, 0750)
-		if err != nil {
-			return nil, nil, nil, fmt.Errorf("unable to create AudioDir: %q", err)
-		}
-	}
-	if options.UploadDir != "" {
-		err := os.MkdirAll(options.UploadDir, 0750)
-		if err != nil {
-			return nil, nil, nil, fmt.Errorf("unable to create UploadDir: %q", err)
-		}
-	}
-
-	if err := pkgStartup.InstallModels(options.Galleries, options.ModelLibraryURL, options.ModelPath, options.EnforcePredownloadScans, nil, options.ModelsURL...); err != nil {
-		log.Error().Err(err).Msg("error installing models")
-	}
-
-	cl := config.NewBackendConfigLoader(options.ModelPath)
-	ml := model.NewModelLoader(options.ModelPath)
-
-	configLoaderOpts := options.ToConfigLoaderOptions()
-
-	if err := cl.LoadBackendConfigsFromPath(options.ModelPath, configLoaderOpts...); err != nil {
-		log.Error().Err(err).Msg("error loading config files")
-	}
-
-	if options.ConfigFile != "" {
-		if err := cl.LoadMultipleBackendConfigsSingleFile(options.ConfigFile, configLoaderOpts...); err != nil {
-			log.Error().Err(err).Msg("error loading config file")
-		}
-	}
-
-	if err := cl.Preload(options.ModelPath); err != nil {
-		log.Error().Err(err).Msg("error downloading models")
-	}
-
-	if options.PreloadJSONModels != "" {
-		if err := services.ApplyGalleryFromString(options.ModelPath, options.PreloadJSONModels, options.EnforcePredownloadScans, options.Galleries); err != nil {
-			return nil, nil, nil, err
-		}
-	}
-
-	if options.PreloadModelsFromPath != "" {
-		if err := services.ApplyGalleryFromFile(options.ModelPath, options.PreloadModelsFromPath, options.EnforcePredownloadScans, options.Galleries); err != nil {
-			return nil, nil, nil, err
-		}
-	}
-
-	if options.Debug {
-		for _, v := range cl.GetAllBackendConfigs() {
-			log.Debug().Msgf("Model: %s (config: %+v)", v.Name, v)
-		}
-	}
-
-	if options.AssetsDestination != "" {
-		// Extract files from the embedded FS
-		err := assets.ExtractFiles(options.BackendAssets, options.AssetsDestination)
-		log.Debug().Msgf("Extracting backend assets files to %s", options.AssetsDestination)
-		if err != nil {
-			log.Warn().Msgf("Failed extracting backend assets files: %s (might be required for some backends to work properly, like gpt4all)", err)
-		}
-	}
-
-	if options.LibPath != "" {
-		// If there is a lib directory, set LD_LIBRARY_PATH to include it
-		err := library.LoadExternal(options.LibPath)
-		if err != nil {
-			log.Error().Err(err).Str("LibPath", options.LibPath).Msg("Error while loading external libraries")
-		}
-	}
-
-	// turn off any process that was started by GRPC if the context is canceled
-	go func() {
-		<-options.Context.Done()
-		log.Debug().Msgf("Context canceled, shutting down")
-		err := ml.StopAllGRPC()
-		if err != nil {
-			log.Error().Err(err).Msg("error while stopping all grpc backends")
-		}
-	}()
-
-	if options.WatchDog {
-		wd := model.NewWatchDog(
-			ml,
-			options.WatchDogBusyTimeout,
-			options.WatchDogIdleTimeout,
-			options.WatchDogBusy,
-			options.WatchDogIdle)
-		ml.SetWatchDog(wd)
-		go wd.Run()
-		go func() {
-			<-options.Context.Done()
-			log.Debug().Msgf("Context canceled, shutting down")
-			wd.Shutdown()
-		}()
-	}
-
-	// Watch the configuration directory
-	startWatcher(options)
-
-	log.Info().Msg("core/startup process completed!")
-	return cl, ml, options, nil
-}
-
-func startWatcher(options *config.ApplicationConfig) {
-	if options.DynamicConfigsDir == "" {
-		// No need to start the watcher if the directory is not set
-		return
-	}
-
-	if _, err := os.Stat(options.DynamicConfigsDir); err != nil {
-		if os.IsNotExist(err) {
-			// We try to create the directory if it does not exist and was specified
-			if err := os.MkdirAll(options.DynamicConfigsDir, 0700); err != nil {
-				log.Error().Err(err).Msg("failed creating DynamicConfigsDir")
-			}
-		} else {
-			// something else happened, we log the error and don't start the watcher
-			log.Error().Err(err).Msg("failed to read DynamicConfigsDir, watcher will not be started")
-			return
-		}
-	}
-
-	configHandler := newConfigFileHandler(options)
-	if err := configHandler.Watch(); err != nil {
-		log.Error().Err(err).Msg("failed creating watcher")
-	}
-}
-
-// In Lieu of a proper DI framework, this function wires up the Application manually.
-// This is in core/startup rather than core/state.go to keep package references clean!
-func createApplication(appConfig *config.ApplicationConfig) *core.Application {
-	app := &core.Application{
-		ApplicationConfig:   appConfig,
-		BackendConfigLoader: config.NewBackendConfigLoader(appConfig.ModelPath),
-		ModelLoader:         model.NewModelLoader(appConfig.ModelPath),
-	}
-
-	var err error
-
-	// app.EmbeddingsBackendService = backend.NewEmbeddingsBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	// app.ImageGenerationBackendService = backend.NewImageGenerationBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	// app.LLMBackendService = backend.NewLLMBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	// app.TranscriptionBackendService = backend.NewTranscriptionBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	// app.TextToSpeechBackendService = backend.NewTextToSpeechBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-
-	app.BackendMonitorService = services.NewBackendMonitorService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
-	app.GalleryService = services.NewGalleryService(app.ApplicationConfig)
-	// app.OpenAIService = services.NewOpenAIService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig, app.LLMBackendService)
-
-	app.LocalAIMetricsService, err = services.NewLocalAIMetricsService()
-	if err != nil {
-		log.Error().Err(err).Msg("encountered an error initializing metrics service, startup will continue but metrics will not be tracked.")
-	}
-
-	return app
-}
+package startup
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/mudler/LocalAI/core"
+	"github.com/mudler/LocalAI/core/config"
+	"github.com/mudler/LocalAI/core/services"
+	"github.com/mudler/LocalAI/internal"
+	"github.com/mudler/LocalAI/pkg/assets"
+	"github.com/mudler/LocalAI/pkg/library"
+	"github.com/mudler/LocalAI/pkg/model"
+	pkgStartup "github.com/mudler/LocalAI/pkg/startup"
+	"github.com/mudler/LocalAI/pkg/xsysinfo"
+	"github.com/rs/zerolog/log"
+)
+
+func Startup(opts ...config.AppOption) (*config.BackendConfigLoader, *model.ModelLoader, *config.ApplicationConfig, error) {
+	options := config.NewApplicationConfig(opts...)
+
+	log.Info().Msgf("Starting LocalAI using %d threads, with models path: %s", options.Threads, options.ModelPath)
+	log.Info().Msgf("LocalAI version: %s", internal.PrintableVersion())
+	caps, err := xsysinfo.CPUCapabilities()
+	if err == nil {
+		log.Debug().Msgf("CPU capabilities: %v", caps)
+	}
+	gpus, err := xsysinfo.GPUs()
+	if err == nil {
+		log.Debug().Msgf("GPU count: %d", len(gpus))
+		for _, gpu := range gpus {
+			log.Debug().Msgf("GPU: %s", gpu.String())
+		}
+	}
+
+	// Make sure directories exists
+	if options.ModelPath == "" {
+		return nil, nil, nil, fmt.Errorf("options.ModelPath cannot be empty")
+	}
+	err = os.MkdirAll(options.ModelPath, 0750)
+	if err != nil {
+		return nil, nil, nil, fmt.Errorf("unable to create ModelPath: %q", err)
+	}
+	if options.ImageDir != "" {
+		err := os.MkdirAll(options.ImageDir, 0750)
+		if err != nil {
+			return nil, nil, nil, fmt.Errorf("unable to create ImageDir: %q", err)
+		}
+	}
+	if options.AudioDir != "" {
+		err := os.MkdirAll(options.AudioDir, 0750)
+		if err != nil {
+			return nil, nil, nil, fmt.Errorf("unable to create AudioDir: %q", err)
+		}
+	}
+	if options.UploadDir != "" {
+		err := os.MkdirAll(options.UploadDir, 0750)
+		if err != nil {
+			return nil, nil, nil, fmt.Errorf("unable to create UploadDir: %q", err)
+		}
+	}
+
+	if err := pkgStartup.InstallModels(options.Galleries, options.ModelLibraryURL, options.ModelPath, options.EnforcePredownloadScans, nil, options.ModelsURL...); err != nil {
+		log.Error().Err(err).Msg("error installing models")
+	}
+
+	cl := config.NewBackendConfigLoader(options.ModelPath)
+	ml := model.NewModelLoader(options.ModelPath)
+
+	configLoaderOpts := options.ToConfigLoaderOptions()
+
+	if err := cl.LoadBackendConfigsFromPath(options.ModelPath, configLoaderOpts...); err != nil {
+		log.Error().Err(err).Msg("error loading config files")
+	}
+
+	if options.ConfigFile != "" {
+		if err := cl.LoadMultipleBackendConfigsSingleFile(options.ConfigFile, configLoaderOpts...); err != nil {
+			log.Error().Err(err).Msg("error loading config file")
+		}
+	}
+
+	if err := cl.Preload(options.ModelPath); err != nil {
+		log.Error().Err(err).Msg("error downloading models")
+	}
+
+	if options.PreloadJSONModels != "" {
+		if err := services.ApplyGalleryFromString(options.ModelPath, options.PreloadJSONModels, options.EnforcePredownloadScans, options.Galleries); err != nil {
+			return nil, nil, nil, err
+		}
+	}
+
+	if options.PreloadModelsFromPath != "" {
+		if err := services.ApplyGalleryFromFile(options.ModelPath, options.PreloadModelsFromPath, options.EnforcePredownloadScans, options.Galleries); err != nil {
+			return nil, nil, nil, err
+		}
+	}
+
+	if options.Debug {
+		for _, v := range cl.GetAllBackendConfigs() {
+			log.Debug().Msgf("Model: %s (config: %+v)", v.Name, v)
+		}
+	}
+
+	if options.AssetsDestination != "" {
+		// Extract files from the embedded FS
+		err := assets.ExtractFiles(options.BackendAssets, options.AssetsDestination)
+		log.Debug().Msgf("Extracting backend assets files to %s", options.AssetsDestination)
+		if err != nil {
+			log.Warn().Msgf("Failed extracting backend assets files: %s (might be required for some backends to work properly, like gpt4all)", err)
+		}
+	}
+
+	if options.LibPath != "" {
+		// If there is a lib directory, set LD_LIBRARY_PATH to include it
+		err := library.LoadExternal(options.LibPath)
+		if err != nil {
+			log.Error().Err(err).Str("LibPath", options.LibPath).Msg("Error while loading external libraries")
+		}
+	}
+
+	// turn off any process that was started by GRPC if the context is canceled
+	go func() {
+		<-options.Context.Done()
+		log.Debug().Msgf("Context canceled, shutting down")
+		err := ml.StopAllGRPC()
+		if err != nil {
+			log.Error().Err(err).Msg("error while stopping all grpc backends")
+		}
+	}()
+
+	if options.WatchDog {
+		wd := model.NewWatchDog(
+			ml,
+			options.WatchDogBusyTimeout,
+			options.WatchDogIdleTimeout,
+			options.WatchDogBusy,
+			options.WatchDogIdle)
+		ml.SetWatchDog(wd)
+		go wd.Run()
+		go func() {
+			<-options.Context.Done()
+			log.Debug().Msgf("Context canceled, shutting down")
+			wd.Shutdown()
+		}()
+	}
+
+	// Watch the configuration directory
+	startWatcher(options)
+
+	log.Info().Msg("core/startup process completed!")
+	return cl, ml, options, nil
+}
+
+func startWatcher(options *config.ApplicationConfig) {
+	if options.DynamicConfigsDir == "" {
+		// No need to start the watcher if the directory is not set
+		return
+	}
+
+	if _, err := os.Stat(options.DynamicConfigsDir); err != nil {
+		if os.IsNotExist(err) {
+			// We try to create the directory if it does not exist and was specified
+			if err := os.MkdirAll(options.DynamicConfigsDir, 0700); err != nil {
+				log.Error().Err(err).Msg("failed creating DynamicConfigsDir")
+			}
+		} else {
+			// something else happened, we log the error and don't start the watcher
+			log.Error().Err(err).Msg("failed to read DynamicConfigsDir, watcher will not be started")
+			return
+		}
+	}
+
+	configHandler := newConfigFileHandler(options)
+	if err := configHandler.Watch(); err != nil {
+		log.Error().Err(err).Msg("failed creating watcher")
+	}
+}
+
+// In Lieu of a proper DI framework, this function wires up the Application manually.
+// This is in core/startup rather than core/state.go to keep package references clean!
+func createApplication(appConfig *config.ApplicationConfig) *core.Application {
+	app := &core.Application{
+		ApplicationConfig:   appConfig,
+		BackendConfigLoader: config.NewBackendConfigLoader(appConfig.ModelPath),
+		ModelLoader:         model.NewModelLoader(appConfig.ModelPath),
+	}
+
+	var err error
+
+	// app.EmbeddingsBackendService = backend.NewEmbeddingsBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	// app.ImageGenerationBackendService = backend.NewImageGenerationBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	// app.LLMBackendService = backend.NewLLMBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	// app.TranscriptionBackendService = backend.NewTranscriptionBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	// app.TextToSpeechBackendService = backend.NewTextToSpeechBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+
+	app.BackendMonitorService = services.NewBackendMonitorService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig)
+	app.GalleryService = services.NewGalleryService(app.ApplicationConfig)
+	// app.OpenAIService = services.NewOpenAIService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig, app.LLMBackendService)
+
+	app.LocalAIMetricsService, err = services.NewLocalAIMetricsService()
+	if err != nil {
+		log.Error().Err(err).Msg("encountered an error initializing metrics service, startup will continue but metrics will not be tracked.")
+	}
+
+	return app
+}
pkg/utils/base64.go
-package utils
-
-import (
-	"encoding/base64"
-	"fmt"
-	"io"
-	"net/http"
-	"strings"
-	"time"
-)
-
-var base64DownloadClient http.Client = http.Client{
-	Timeout: 30 * time.Second,
-}
-
-// this function check if the string is an URL, if it's an URL downloads the image in memory
-// encodes it in base64 and returns the base64 string
-
-// This may look weird down in pkg/utils while it is currently only used in core/config
-//
-//	but I believe it may be useful for MQTT as well in the near future, so I'm
-//	extracting it while I'm thinking of it.
-func GetImageURLAsBase64(s string) (string, error) {
-	if strings.HasPrefix(s, "http") {
-		// download the image
-		resp, err := base64DownloadClient.Get(s)
-		if err != nil {
-			return "", err
-		}
-		defer resp.Body.Close()
-
-		// read the image data into memory
-		data, err := io.ReadAll(resp.Body)
-		if err != nil {
-			return "", err
-		}
-
-		// encode the image data in base64
-		encoded := base64.StdEncoding.EncodeToString(data)
-
-		// return the base64 string
-		return encoded, nil
-	}
-
-	// if the string instead is prefixed with "data:image/...;base64,", drop it
-	dropPrefix := []string{"data:image/jpeg;base64,", "data:image/png;base64,"}
-	for _, prefix := range dropPrefix {
-		if strings.HasPrefix(s, prefix) {
-			return strings.ReplaceAll(s, prefix, ""), nil
-		}
-	}
-	return "", fmt.Errorf("not valid string")
-}
+package utils
+
+import (
+	"encoding/base64"
+	"fmt"
+	"io"
+	"net/http"
+	"strings"
+	"time"
+)
+
+var base64DownloadClient http.Client = http.Client{
+	Timeout: 30 * time.Second,
+}
+
+// this function check if the string is an URL, if it's an URL downloads the image in memory
+// encodes it in base64 and returns the base64 string
+
+// This may look weird down in pkg/utils while it is currently only used in core/config
+//
+//	but I believe it may be useful for MQTT as well in the near future, so I'm
+//	extracting it while I'm thinking of it.
+func GetImageURLAsBase64(s string) (string, error) {
+	if strings.HasPrefix(s, "http") {
+		// download the image
+		resp, err := base64DownloadClient.Get(s)
+		if err != nil {
+			return "", err
+		}
+		defer resp.Body.Close()
+
+		// read the image data into memory
+		data, err := io.ReadAll(resp.Body)
+		if err != nil {
+			return "", err
+		}
+
+		// encode the image data in base64
+		encoded := base64.StdEncoding.EncodeToString(data)
+
+		// return the base64 string
+		return encoded, nil
+	}
+
+	// if the string instead is prefixed with "data:image/...;base64,", drop it
+	dropPrefix := []string{"data:image/jpeg;base64,", "data:image/png;base64,"}
+	for _, prefix := range dropPrefix {
+		if strings.HasPrefix(s, prefix) {
+			return strings.ReplaceAll(s, prefix, ""), nil
+		}
+	}
+	return "", fmt.Errorf("not valid string")
+}
pkg/utils/base64_test.go
-package utils_test
-
-import (
-	. "github.com/mudler/LocalAI/pkg/utils"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-)
-
-var _ = Describe("utils/base64 tests", func() {
-	It("GetImageURLAsBase64 can strip jpeg data url prefixes", func() {
-		// This one doesn't actually _care_ that it's base64, so feed "bad" data in this test in order to catch a change in that behavior for informational purposes.
-		input := "data:image/jpeg;base64,FOO"
-		b64, err := GetImageURLAsBase64(input)
-		Expect(err).To(BeNil())
-		Expect(b64).To(Equal("FOO"))
-	})
-	It("GetImageURLAsBase64 can strip png data url prefixes", func() {
-		// This one doesn't actually _care_ that it's base64, so feed "bad" data in this test in order to catch a change in that behavior for informational purposes.
-		input := "data:image/png;base64,BAR"
-		b64, err := GetImageURLAsBase64(input)
-		Expect(err).To(BeNil())
-		Expect(b64).To(Equal("BAR"))
-	})
-	It("GetImageURLAsBase64 returns an error for bogus data", func() {
-		input := "FOO"
-		b64, err := GetImageURLAsBase64(input)
-		Expect(b64).To(Equal(""))
-		Expect(err).ToNot(BeNil())
-		Expect(err).To(MatchError("not valid string"))
-	})
-	It("GetImageURLAsBase64 can actually download images and calculates something", func() {
-		// This test doesn't actually _check_ the results at this time, which is bad, but there wasn't a test at all before...
-		input := "https://upload.wikimedia.org/wikipedia/en/2/29/Wargames.jpg"
-		b64, err := GetImageURLAsBase64(input)
-		Expect(err).To(BeNil())
-		Expect(b64).ToNot(BeNil())
-	})
-})
+package utils_test
+
+import (
+	. "github.com/mudler/LocalAI/pkg/utils"
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+)
+
+var _ = Describe("utils/base64 tests", func() {
+	It("GetImageURLAsBase64 can strip jpeg data url prefixes", func() {
+		// This one doesn't actually _care_ that it's base64, so feed "bad" data in this test in order to catch a change in that behavior for informational purposes.
+		input := "data:image/jpeg;base64,FOO"
+		b64, err := GetImageURLAsBase64(input)
+		Expect(err).To(BeNil())
+		Expect(b64).To(Equal("FOO"))
+	})
+	It("GetImageURLAsBase64 can strip png data url prefixes", func() {
+		// This one doesn't actually _care_ that it's base64, so feed "bad" data in this test in order to catch a change in that behavior for informational purposes.
+		input := "data:image/png;base64,BAR"
+		b64, err := GetImageURLAsBase64(input)
+		Expect(err).To(BeNil())
+		Expect(b64).To(Equal("BAR"))
+	})
+	It("GetImageURLAsBase64 returns an error for bogus data", func() {
+		input := "FOO"
+		b64, err := GetImageURLAsBase64(input)
+		Expect(b64).To(Equal(""))
+		Expect(err).ToNot(BeNil())
+		Expect(err).To(MatchError("not valid string"))
+	})
+	It("GetImageURLAsBase64 can actually download images and calculates something", func() {
+		// This test doesn't actually _check_ the results at this time, which is bad, but there wasn't a test at all before...
+		input := "https://upload.wikimedia.org/wikipedia/en/2/29/Wargames.jpg"
+		b64, err := GetImageURLAsBase64(input)
+		Expect(err).To(BeNil())
+		Expect(b64).ToNot(BeNil())
+	})
+})

Copy link

⚠ shadow failed (.)

pkg/grpc/backend.go:7:2: no required module provides package github.com/mudler/LocalAI/pkg/grpc/proto; to add it:
	go get github.com/mudler/LocalAI/pkg/grpc/proto
assets.go:5:12: pattern backend-assets/*: no matching files found

Copy link

⚠ gosec failed (.)

2024/07/18 17:46:48 internal error: package "context" without types was imported from "github.com/mudler/LocalAI/pkg/grpc"
Show Detail
2024/07/18 17:46:48 internal error: package "context" without types was imported from "github.com/mudler/LocalAI/pkg/grpc"

Code Reference

Copy link

⚠ errcheck failed (.)

error: failed to check packages: errors while loading package github.com/mudler/LocalAI/pkg/grpc: [/github/workspace/pkg/grpc/backend.go:38:41: undefined: pb.PredictOptions /github/workspace/pkg/grpc/backend.go:38:87: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/backend.go:39:38: undefined: pb.PredictOptions /github/workspace/pkg/grpc/backend.go:39:84: undefined: pb.Reply /github/workspace/pkg/grpc/backend.go:40:40: undefined: pb.ModelOptions /github/workspace/pkg/grpc/backend.go:40:84: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:41:44: undefined: pb.PredictOptions /github/workspace/pkg/grpc/backend.go:42:44: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/backend.go:42:96: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:43:34: undefined: pb.TTSRequest /github/workspace/pkg/grpc/backend.go:43:76: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:44:49: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/backend.go:45:45: undefined: pb.PredictOptions /github/workspace/pkg/grpc/backend.go:45:91: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/backend.go:46:35: undefined: pb.StatusResponse /github/workspace/pkg/grpc/backend.go:48:40: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/backend.go:48:88: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:49:43: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/backend.go:49:94: undefined: pb.Result /github/workspace/pkg/grpc/backend.go:50:40: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/backend.go:50:88: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/backend.go:51:41: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/backend.go:51:90: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/backend.go:53:37: undefined: pb.RerankRequest /github/workspace/pkg/grpc/backend.go:53:82: undefined: pb.RerankResult /github/workspace/pkg/grpc/server.go:24:5: undefined: pb.UnimplementedBackendServer /github/workspace/pkg/grpc/interface.go:13:14: undefined: pb.PredictOptions /github/workspace/pkg/grpc/interface.go:14:20: undefined: pb.PredictOptions /github/workspace/pkg/grpc/interface.go:15:11: undefined: pb.ModelOptions /github/workspace/pkg/grpc/interface.go:16:17: undefined: pb.PredictOptions /github/workspace/pkg/grpc/interface.go:17:20: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/interface.go:18:25: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/interface.go:19:10: undefined: pb.TTSRequest /github/workspace/pkg/grpc/interface.go:20:21: undefined: pb.PredictOptions /github/workspace/pkg/grpc/interface.go:20:41: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/interface.go:21:15: undefined: pb.StatusResponse /github/workspace/pkg/grpc/interface.go:23:16: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/interface.go:24:19: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/interface.go:25:16: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/interface.go:25:38: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/interface.go:26:17: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/interface.go:26:40: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/client.go:72:57: undefined: pb.PredictOptions /github/workspace/pkg/grpc/client.go:72:103: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/client.go:93:54: undefined: pb.PredictOptions /github/workspace/pkg/grpc/client.go:93:100: undefined: pb.Reply /github/workspace/pkg/grpc/client.go:114:56: undefined: pb.ModelOptions /github/workspace/pkg/grpc/client.go:114:100: undefined: pb.Result /github/workspace/pkg/grpc/client.go:134:60: undefined: pb.PredictOptions /github/workspace/pkg/grpc/client.go:173:60: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/client.go:173:112: undefined: pb.Result /github/workspace/pkg/grpc/client.go:193:50: undefined: pb.TTSRequest /github/workspace/pkg/grpc/client.go:193:92: undefined: pb.Result /github/workspace/pkg/grpc/client.go:213:65: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/client.go:253:61: undefined: pb.PredictOptions /github/workspace/pkg/grpc/client.go:253:107: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/client.go:279:51: undefined: pb.StatusResponse /github/workspace/pkg/grpc/client.go:295:56: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/client.go:295:104: undefined: pb.Result /github/workspace/pkg/grpc/client.go:311:59: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/client.go:311:110: undefined: pb.Result /github/workspace/pkg/grpc/client.go:327:56: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/client.go:327:104: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/client.go:343:57: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/client.go:343:106: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/client.go:359:53: undefined: pb.RerankRequest /github/workspace/pkg/grpc/client.go:359:98: undefined: pb.RerankResult /github/workspace/pkg/grpc/embed.go:56:71: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/embed.go:28:63: undefined: pb.PredictOptions /github/workspace/pkg/grpc/embed.go:28:109: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/embed.go:48:66: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/embed.go:48:118: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:36:62: undefined: pb.ModelOptions /github/workspace/pkg/grpc/embed.go:36:106: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:32:60: undefined: pb.PredictOptions /github/workspace/pkg/grpc/embed.go:32:106: undefined: pb.Reply /github/workspace/pkg/grpc/embed.go:40:66: undefined: pb.PredictOptions /github/workspace/pkg/grpc/embed.go:104:59: undefined: pb.RerankRequest /github/workspace/pkg/grpc/embed.go:104:104: undefined: pb.RerankResult /github/workspace/pkg/grpc/embed.go:84:57: undefined: pb.StatusResponse /github/workspace/pkg/grpc/embed.go:92:65: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/embed.go:92:116: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:100:63: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/embed.go:100:112: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/embed.go:96:62: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/embed.go:96:110: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/embed.go:88:62: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/embed.go:88:110: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:52:56: undefined: pb.TTSRequest /github/workspace/pkg/grpc/embed.go:52:98: undefined: pb.Result /github/workspace/pkg/grpc/embed.go:80:67: undefined: pb.PredictOptions /github/workspace/pkg/grpc/embed.go:80:113: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/embed.go:14:10: undefined: pb.Backend_PredictStreamServer /github/workspace/pkg/grpc/embed.go:113:51: undefined: pb.Reply /github/workspace/pkg/grpc/interface.go:29:29: undefined: pb.Reply /github/workspace/pkg/grpc/server.go:28:53: undefined: pb.HealthMessage /github/workspace/pkg/grpc/server.go:28:73: undefined: pb.Reply /github/workspace/pkg/grpc/server.go:32:56: undefined: pb.PredictOptions /github/workspace/pkg/grpc/server.go:32:77: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/server.go:45:56: undefined: pb.ModelOptions /github/workspace/pkg/grpc/server.go:45:75: undefined: pb.Result /github/workspace/pkg/grpc/server.go:57:54: undefined: pb.PredictOptions /github/workspace/pkg/grpc/server.go:57:75: undefined: pb.Reply /github/workspace/pkg/grpc/server.go:66:60: undefined: pb.GenerateImageRequest /github/workspace/pkg/grpc/server.go:66:87: undefined: pb.Result /github/workspace/pkg/grpc/server.go:78:50: undefined: pb.TTSRequest /github/workspace/pkg/grpc/server.go:78:67: undefined: pb.Result /github/workspace/pkg/grpc/server.go:90:65: undefined: pb.TranscriptRequest /github/workspace/pkg/grpc/server.go:90:89: undefined: pb.TranscriptResult /github/workspace/pkg/grpc/server.go:119:39: undefined: pb.PredictOptions /github/workspace/pkg/grpc/server.go:119:65: undefined: pb.Backend_PredictStreamServer /github/workspace/pkg/grpc/server.go:140:61: undefined: pb.PredictOptions /github/workspace/pkg/grpc/server.go:140:82: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/server.go:161:53: undefined: pb.HealthMessage /github/workspace/pkg/grpc/server.go:161:73: undefined: pb.StatusResponse /github/workspace/pkg/grpc/server.go:170:56: undefined: pb.StoresSetOptions /github/workspace/pkg/grpc/server.go:170:79: undefined: pb.Result /github/workspace/pkg/grpc/server.go:182:59: undefined: pb.StoresDeleteOptions /github/workspace/pkg/grpc/server.go:182:85: undefined: pb.Result /github/workspace/pkg/grpc/server.go:194:56: undefined: pb.StoresGetOptions /github/workspace/pkg/grpc/server.go:194:79: undefined: pb.StoresGetResult /github/workspace/pkg/grpc/server.go:206:57: undefined: pb.StoresFindOptions /github/workspace/pkg/grpc/server.go:206:81: undefined: pb.StoresFindResult /github/workspace/pkg/grpc/client.go:54:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:60:37: undefined: pb.HealthMessage /github/workspace/pkg/grpc/client.go:88:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:109:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:130:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:150:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:189:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:209:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:229:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:269:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:291:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:292:32: undefined: pb.HealthMessage /github/workspace/pkg/grpc/client.go:307:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:323:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:339:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:355:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/client.go:371:15: undefined: pb.NewBackendClient /github/workspace/pkg/grpc/embed.go:105:13: e.s.Rerank undefined (type *server has no field or method Rerank) /github/workspace/pkg/grpc/embed.go:85:29: undefined: pb.HealthMessage /github/workspace/pkg/grpc/embed.go:134:21: undefined: pb.Reply /github/workspace/pkg/grpc/interface.go:30:13: undefined: pb.Reply /github/workspace/pkg/grpc/server.go:42:13: undefined: pb.EmbeddingResult /github/workspace/pkg/grpc/server.go:52:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:54:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:73:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:75:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:85:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:87:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:99:17: undefined: pb.TranscriptResult /github/workspace/pkg/grpc/server.go:106:8: undefined: pb.TranscriptSegment /github/workspace/pkg/grpc/server.go:155:13: undefined: pb.TokenizationResponse /github/workspace/pkg/grpc/server.go:177:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:179:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:189:14: undefined: pb.Result /github/workspace/pkg/grpc/server.go:191:13: undefined: pb.Result /github/workspace/pkg/grpc/server.go:224:5: undefined: pb.RegisterBackendServer /github/workspace/pkg/grpc/server.go:239:5: undefined: pb.RegisterBackendServer]

Copy link

⚠ staticcheck failed (.)

-: # github.com/donomii/go-rwkv.cpp
/go/pkg/mod/github.com/donomii/go-rwkv.cpp@v0.0.0-20240228065144-661e7ae26d44/wrapper.go:16:11: fatal error: rwkv.h: No such file or directory
   16 | //#cgo darwin LDFLAGS: -framework Accelerate -lcblas
      |           ^~~~~~~~
compilation terminated. (compile)
-: # github.com/ggerganov/whisper.cpp/bindings/go
/go/pkg/mod/github.com/ggerganov/whisper.cpp/bindings/go@v0.0.0-20240626202019-c118733a29ad/params.go:11:10: fatal error: whisper.h: No such file or directory
   11 | #include <whisper.h>
      |          ^~~~~~~~~~~
compilation terminated. (compile)
-: # github.com/go-skynet/go-bert.cpp
gobert.cpp:1:10: fatal error: ggml.h: No such file or directory
    1 | #include "ggml.h"
      |          ^~~~~~~~
compilation terminated. (compile)
-: # github.com/go-skynet/go-llama.cpp
binding.cpp:1:10: fatal error: common.h: No such file or directory
    1 | #include "common.h"
      |          ^~~~~~~~~~
compilation terminated. (compile)
-: # github.com/mudler/go-piper
gopiper.cpp:14:10: fatal error: spdlog/spdlog.h: No such file or directory
   14 | #include <spdlog/spdlog.h>
      |          ^~~~~~~~~~~~~~~~~
compilation terminated. (compile)
-: # github.com/nomic-ai/gpt4all/gpt4all-bindings/golang
binding.cpp:1:10: fatal error: ../../gpt4all-backend/llmodel_c.h: No such file or directory
    1 | #include "../../gpt4all-backend/llmodel_c.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated. (compile)
-: error obtaining VCS status: exit status 128
	Use -buildvcs=false to disable VCS stamping. (compile)
pkg/functions/grammar_json_schema.go:182:3: empty branch (SA9003)
pkg/functions/grammar_json_schema_test.go:6:2: package "github.com/mudler/LocalAI/pkg/functions" is being imported more than once (ST1019)
	pkg/functions/grammar_json_schema_test.go:7:2: other import of "github.com/mudler/LocalAI/pkg/functions"
pkg/stablediffusion/generate_unsupported.go:9:9: error strings should not be capitalized (ST1005)
pkg/tinydream/generate_unsupported.go:9:9: error strings should not be capitalized (ST1005)
pkg/utils/strings.go:11:2: rand.Seed has been deprecated since Go 1.20 and an alternative has been available since Go 1.0: As of Go 1.20 there is no reason to call Seed with a random value. Programs that call Seed with a known value to get a specific sequence of results should use New(NewSource(seed)) to obtain a local random generator.  (SA1019)
assets.go:5:12: pattern backend-assets/*: no matching files found (compile)
core/http/app_test.go:197:12: pattern backend-assets/*: no matching files found (compile)
pkg/grpc/backend.go:7:2: no required module provides package github.com/mudler/LocalAI/pkg/grpc/proto; to add it:
	go get github.com/mudler/LocalAI/pkg/grpc/proto (compile)
tests/integration/stores_test.go:22:12: pattern backend-assets/*: no matching files found (compile)

Checks Document

@localai-bot
Copy link
Contributor

Uh oh! Could not analyze this PR, maybe it's too big?

@mudler
Copy link
Owner Author

mudler commented Jul 18, 2024

This is a good idea mudler... but it seems a bit overactive. Can we tune that at all before we set it loose?

Yes definitely, I've been opening this PR to see what should be addressed, not going to enable it until the warnings/errors are fixed. Let's use this PR for reference

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants