109 lines
5.1 KiB
C#
109 lines
5.1 KiB
C#
using Journal.Core.Models;
|
|
|
|
namespace Journal.Core.Services.Config;
|
|
|
|
public sealed class JournalConfigService : IJournalConfigService
|
|
{
|
|
public JournalConfig Current => BuildConfig();
|
|
|
|
private static JournalConfig BuildConfig()
|
|
{
|
|
var projectRoot = ResolveProjectRoot();
|
|
var appDirectory = ResolvePath("JOURNAL_APP_DIR", Path.Combine(projectRoot, "journal"));
|
|
|
|
var dataDirectory = ResolvePath("JOURNAL_DATA_DIR", Path.Combine(appDirectory, "data"));
|
|
var vaultDirectory = ResolvePath("JOURNAL_VAULT_DIR", Path.Combine(appDirectory, "vault"));
|
|
var logDirectory = ResolvePath("JOURNAL_LOG_DIR", Path.Combine(projectRoot, "logs"));
|
|
|
|
var pidFile = ResolvePath("JOURNAL_PID_FILE", Path.Combine(logDirectory, "nicegui_server.pid"));
|
|
var serverControlFile = ResolvePath("JOURNAL_SERVER_CONTROL_FILE", Path.Combine(logDirectory, "server_control.action"));
|
|
|
|
var nlpBackend = (Environment.GetEnvironmentVariable("JOURNAL_NLP_BACKEND") ?? "auto").Trim().ToLowerInvariant();
|
|
if (nlpBackend is not ("auto" or "spacy" or "fallback"))
|
|
nlpBackend = "auto";
|
|
|
|
var aiProvider = (Environment.GetEnvironmentVariable("JOURNAL_AI_PROVIDER") ?? "none").Trim().ToLowerInvariant();
|
|
if (aiProvider is not ("none" or "python-sidecar"))
|
|
aiProvider = "none";
|
|
|
|
var pythonExecutable = Environment.GetEnvironmentVariable("JOURNAL_PYTHON_EXE");
|
|
if (string.IsNullOrWhiteSpace(pythonExecutable))
|
|
pythonExecutable = "python";
|
|
|
|
var defaultAiSidecarPath = Path.Combine(projectRoot, "journal", "ai", "sidecar.py");
|
|
var pythonAiSidecarPath = ResolvePath("JOURNAL_AI_SIDECAR_PATH", defaultAiSidecarPath);
|
|
var aiSidecarTimeoutMs = ParseInt("JOURNAL_AI_TIMEOUT_MS", 45000);
|
|
|
|
return new JournalConfig(
|
|
ProjectRoot: projectRoot,
|
|
AppDirectory: appDirectory,
|
|
DataDirectory: dataDirectory,
|
|
VaultDirectory: vaultDirectory,
|
|
LogDirectory: logDirectory,
|
|
PidFile: pidFile,
|
|
ServerControlFile: serverControlFile,
|
|
DatabaseFilename: Environment.GetEnvironmentVariable("JOURNAL_DATABASE_FILENAME") ?? "journal_cache.db",
|
|
MonthlyVaultFormat: Environment.GetEnvironmentVariable("JOURNAL_MONTHLY_VAULT_FORMAT") ?? "%Y-%m.vault",
|
|
CloudAiApiKey: Environment.GetEnvironmentVariable("CLOUDAI_API_KEY") ?? "",
|
|
CloudAiApiUrl: Environment.GetEnvironmentVariable("CLOUDAI_API_URL") ?? "",
|
|
LlamaCppUrl: Environment.GetEnvironmentVariable("LLAMA_CPP_URL") ?? "http://127.0.0.1:8085/v1/completions",
|
|
LlamaCppModel: Environment.GetEnvironmentVariable("LLAMA_CPP_MODEL") ?? "qwen/qwen3-4b",
|
|
LlamaCppTimeout: ParseInt("LLAMA_CPP_TIMEOUT", 6000),
|
|
EmbeddingApiUrl: Environment.GetEnvironmentVariable("EMBEDDING_API_URL") ?? "http://127.0.0.1:8086/v1/embeddings",
|
|
EmbeddingModelName: Environment.GetEnvironmentVariable("EMBEDDING_MODEL_NAME") ?? "text-embedding-nomic-embed-text-v2-moe",
|
|
ModelContextTokens: ParseInt("MODEL_CONTEXT_TOKENS", 131072),
|
|
ChunkTokenBudget: ParseInt("CHUNK_TOKEN_BUDGET", 120000),
|
|
MicrophoneDeviceIndex: ParseNullableInt("MICROPHONE_DEVICE_INDEX"),
|
|
SpeechRecognitionEngine: Environment.GetEnvironmentVariable("SPEECH_RECOGNITION_ENGINE") ?? "whisper",
|
|
WhisperModelSize: Environment.GetEnvironmentVariable("WHISPER_MODEL_SIZE") ?? "base",
|
|
NlpBackend: nlpBackend,
|
|
AiProvider: aiProvider,
|
|
PythonExecutable: pythonExecutable,
|
|
PythonAiSidecarPath: pythonAiSidecarPath,
|
|
AiSidecarTimeoutMs: aiSidecarTimeoutMs);
|
|
}
|
|
|
|
private static string ResolveProjectRoot()
|
|
{
|
|
var envRoot = Environment.GetEnvironmentVariable("JOURNAL_PROJECT_ROOT");
|
|
if (!string.IsNullOrWhiteSpace(envRoot))
|
|
return Path.GetFullPath(envRoot);
|
|
|
|
var cwd = Directory.GetCurrentDirectory();
|
|
if (Directory.Exists(Path.Combine(cwd, "journal")))
|
|
return Path.GetFullPath(cwd);
|
|
|
|
var upOne = Path.GetFullPath(Path.Combine(cwd, ".."));
|
|
if (Directory.Exists(Path.Combine(upOne, "journal")))
|
|
return upOne;
|
|
|
|
var upTwo = Path.GetFullPath(Path.Combine(cwd, "..", ".."));
|
|
if (Directory.Exists(Path.Combine(upTwo, "journal")))
|
|
return upTwo;
|
|
|
|
return Path.GetFullPath(cwd);
|
|
}
|
|
|
|
private static string ResolvePath(string envVar, string defaultPath)
|
|
{
|
|
var value = Environment.GetEnvironmentVariable(envVar);
|
|
var raw = string.IsNullOrWhiteSpace(value) ? defaultPath : value;
|
|
return Path.GetFullPath(raw);
|
|
}
|
|
|
|
private static int ParseInt(string envVar, int defaultValue)
|
|
{
|
|
var value = Environment.GetEnvironmentVariable(envVar);
|
|
return int.TryParse(value, out var parsed) ? parsed : defaultValue;
|
|
}
|
|
|
|
private static int? ParseNullableInt(string envVar)
|
|
{
|
|
var value = Environment.GetEnvironmentVariable(envVar);
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
return null;
|
|
return int.TryParse(value, out var parsed) ? parsed : null;
|
|
}
|
|
}
|
|
|