chat()->ask('How do I scaffold a module?'); * * // Multi-turn: * $chat = $ai->chat(); * $chat->user('How do I scaffold a module?'); * $chat->user('And add Graylog hooks?'); * echo $chat->complete(); * * // Custom system + model: * echo $ai->chat() * ->system('Answer in German.') * ->user('Explain MMVC.') * ->model('qwen2.5-coder:14b') * ->complete(); */ class Chat { protected \stdClass $cfg; protected Ollama $ollama; /** @var array */ protected array $messages = []; protected ?string $modelOverride = null; protected ?float $temperature = null; protected ?int $maxTokens = null; protected ?string $systemPrompt = null; public function __construct(\stdClass $cfg) { $this->cfg = $cfg; $this->ollama = new Ollama($cfg); $this->systemPrompt = $cfg->chat_system_prompt ?? null; } public function system(string $prompt): self { $this->systemPrompt = $prompt; return $this; } public function model(string $name): self { $this->modelOverride = $name; return $this; } public function temperature(float $t): self { $this->temperature = $t; return $this; } public function maxTokens(int $n): self { $this->maxTokens = $n; return $this; } public function user(string $content): self { $this->messages[] = ['role' => 'user', 'content' => $content]; return $this; } public function assistant(string $content): self { $this->messages[] = ['role' => 'assistant', 'content' => $content]; return $this; } /** * Execute the chat call and return the assistant's reply text. * Appends the reply to the message history. */ public function complete(): string { $apiMessages = []; if ($this->systemPrompt) { $apiMessages[] = ['role' => 'system', 'content' => $this->systemPrompt]; } foreach ($this->messages as $m) { $apiMessages[] = $m; } $model = $this->modelOverride ?? ($this->cfg->chat_model ?? 'qwen2.5-coder:14b'); $fallback = $this->cfg->chat_fallback_model ?? null; $opts = [ 'temperature' => $this->temperature ?? (float) ($this->cfg->chat_temperature ?? 0.4), 'num_predict' => $this->maxTokens ?? (int) ($this->cfg->chat_max_tokens ?? 1024), ]; try { $res = $this->ollama->chat($model, $apiMessages, $opts); } catch (\RuntimeException $e) { if ($fallback && $fallback !== $model) { $res = $this->ollama->chat($fallback, $apiMessages, $opts); } else { throw $e; } } $text = $res['message']['content'] ?? ''; $this->assistant($text); return $text; } /** * One-shot helper — append a user message, complete, return reply. */ public function ask(string $question): string { $this->user($question); return $this->complete(); } /** * Reset the conversation (keeps system prompt + model override). */ public function reset(): self { $this->messages = []; return $this; } /** * @return array the conversation */ public function history(): array { return $this->messages; } }