Enhance Ollama integration via API and update settings UI
This commit is contained in:
@@ -264,7 +264,7 @@
|
|||||||
if (res.status === 'no-cli') {
|
if (res.status === 'no-cli') {
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<div style="color:red;font-weight:bold;margin:1em 0;">
|
<div style="color:red;font-weight:bold;margin:1em 0;">
|
||||||
You need to install Ollama to use the cool stuff !!
|
Ollama is not reachable. Start Ollama or install it to use the cool stuff !!
|
||||||
</div>`;
|
</div>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ use std::{
|
|||||||
use tauri::{
|
use tauri::{
|
||||||
menu::{Menu, MenuItem, PredefinedMenuItem, Submenu},
|
menu::{Menu, MenuItem, PredefinedMenuItem, Submenu},
|
||||||
tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconBuilder, TrayIconEvent},
|
tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconBuilder, TrayIconEvent},
|
||||||
AppHandle, Emitter, Manager, WebviewUrl, WebviewWindow, WebviewWindowBuilder, WindowEvent,
|
utils::config::Color,
|
||||||
|
AppHandle, Emitter, Manager, TitleBarStyle, WebviewUrl, WebviewWindow, WebviewWindowBuilder,
|
||||||
|
WindowEvent,
|
||||||
};
|
};
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
@@ -38,6 +40,8 @@ const MAX_SQUASH_PROMPT_MESSAGE_CHARS: usize = 400;
|
|||||||
const MAX_SQUASH_NAME_STATUS_CHARS: usize = 6_000;
|
const MAX_SQUASH_NAME_STATUS_CHARS: usize = 6_000;
|
||||||
const MAX_SQUASH_DIFFSTAT_CHARS: usize = 4_000;
|
const MAX_SQUASH_DIFFSTAT_CHARS: usize = 4_000;
|
||||||
const MAX_SQUASH_COMMIT_MESSAGE_CHARS: usize = 160;
|
const MAX_SQUASH_COMMIT_MESSAGE_CHARS: usize = 160;
|
||||||
|
const OLLAMA_BASE_URL: &str = "http://127.0.0.1:11434";
|
||||||
|
const ROSE_TITLEBAR_COLOR: Color = Color(255, 241, 242, 255);
|
||||||
|
|
||||||
const TAURI_BUILD_IGNORES: &[&str] = &["dist-tauri", "src-tauri/target", "src-tauri/gen"];
|
const TAURI_BUILD_IGNORES: &[&str] = &["dist-tauri", "src-tauri/target", "src-tauri/gen"];
|
||||||
|
|
||||||
@@ -680,7 +684,7 @@ fn ensure_ollama_running() -> CommandResult<()> {
|
|||||||
.timeout(Duration::from_millis(700))
|
.timeout(Duration::from_millis(700))
|
||||||
.build()
|
.build()
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
if client.get("http://127.0.0.1:11434/").send().is_ok() {
|
if client.get(OLLAMA_BASE_URL).send().is_ok() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,7 +713,7 @@ fn ensure_ollama_running() -> CommandResult<()> {
|
|||||||
|
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
thread::sleep(Duration::from_millis(500));
|
thread::sleep(Duration::from_millis(500));
|
||||||
if client.get("http://127.0.0.1:11434/").send().is_ok() {
|
if client.get(OLLAMA_BASE_URL).send().is_ok() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -730,7 +734,7 @@ fn stream_ollama(
|
|||||||
.build()
|
.build()
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
let mut response = client
|
let mut response = client
|
||||||
.post("http://127.0.0.1:11434/api/generate")
|
.post(format!("{OLLAMA_BASE_URL}/api/generate"))
|
||||||
.json(&json!({
|
.json(&json!({
|
||||||
"model": model,
|
"model": model,
|
||||||
"prompt": prompt,
|
"prompt": prompt,
|
||||||
@@ -1800,12 +1804,17 @@ fn open_settings_window(app: &AppHandle) -> CommandResult<()> {
|
|||||||
win.set_focus().map_err(|e| e.to_string())?;
|
win.set_focus().map_err(|e| e.to_string())?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
WebviewWindowBuilder::new(app, "settings", WebviewUrl::App("settings.html".into()))
|
let builder =
|
||||||
.title("Einstellungen")
|
WebviewWindowBuilder::new(app, "settings", WebviewUrl::App("settings.html".into()))
|
||||||
.inner_size(600.0, 500.0)
|
.title("Einstellungen")
|
||||||
.resizable(false)
|
.inner_size(600.0, 500.0)
|
||||||
.build()
|
.resizable(false)
|
||||||
.map_err(|e| e.to_string())?;
|
.background_color(ROSE_TITLEBAR_COLOR);
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let builder = builder
|
||||||
|
.title_bar_style(TitleBarStyle::Transparent)
|
||||||
|
.hidden_title(true);
|
||||||
|
builder.build().map_err(|e| e.to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2263,6 +2272,10 @@ fn set_monitoring(
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn ollama_list() -> CommandResult<Value> {
|
fn ollama_list() -> CommandResult<Value> {
|
||||||
|
if let Ok(models) = ollama_list_from_api() {
|
||||||
|
return Ok(json!({ "status": "ok", "models": models }));
|
||||||
|
}
|
||||||
|
|
||||||
let output = run_process(
|
let output = run_process(
|
||||||
"ollama",
|
"ollama",
|
||||||
&["list".into(), "--json".into()],
|
&["list".into(), "--json".into()],
|
||||||
@@ -2287,6 +2300,27 @@ fn ollama_list() -> CommandResult<Value> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ollama_list_from_api() -> CommandResult<Vec<Value>> {
|
||||||
|
let client = Client::builder()
|
||||||
|
.timeout(Duration::from_secs(2))
|
||||||
|
.build()
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
let response = client
|
||||||
|
.get(format!("{OLLAMA_BASE_URL}/api/tags"))
|
||||||
|
.send()
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
let status = response.status();
|
||||||
|
if !status.is_success() {
|
||||||
|
return Err(format!("Ollama tags request failed: {status}"));
|
||||||
|
}
|
||||||
|
let payload: Value = response.json().map_err(|e| e.to_string())?;
|
||||||
|
Ok(payload
|
||||||
|
.get("models")
|
||||||
|
.and_then(Value::as_array)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default())
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_ollama_list_plain() -> CommandResult<Value> {
|
fn parse_ollama_list_plain() -> CommandResult<Value> {
|
||||||
match run_process("ollama", &["list".into()], None, None, None) {
|
match run_process("ollama", &["list".into()], None, None, None) {
|
||||||
Ok(out) => {
|
Ok(out) => {
|
||||||
@@ -2310,12 +2344,37 @@ fn parse_ollama_list_plain() -> CommandResult<Value> {
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn ollama_pull(model: String) -> CommandResult<Value> {
|
fn ollama_pull(model: String) -> CommandResult<Value> {
|
||||||
|
if let Ok(value) = ollama_pull_from_api(&model) {
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
|
||||||
match run_process("ollama", &["pull".into(), model], None, None, None) {
|
match run_process("ollama", &["pull".into(), model], None, None, None) {
|
||||||
Ok(out) => Ok(json!({ "status": "ok", "msg": out.stdout })),
|
Ok(out) => Ok(json!({ "status": "ok", "msg": out.stdout })),
|
||||||
Err(err) => Ok(json!({ "status": "error", "msg": err })),
|
Err(err) => Ok(json!({ "status": "error", "msg": err })),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ollama_pull_from_api(model: &str) -> CommandResult<Value> {
|
||||||
|
let client = Client::builder()
|
||||||
|
.timeout(Duration::from_secs(30 * 60))
|
||||||
|
.build()
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
let response = client
|
||||||
|
.post(format!("{OLLAMA_BASE_URL}/api/pull"))
|
||||||
|
.json(&json!({ "name": model, "stream": false }))
|
||||||
|
.send()
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
let status = response.status();
|
||||||
|
if !status.is_success() {
|
||||||
|
return Err(format!("Ollama pull request failed: {status}"));
|
||||||
|
}
|
||||||
|
let payload: Value = response.json().unwrap_or_else(|_| json!({}));
|
||||||
|
Ok(json!({
|
||||||
|
"status": "ok",
|
||||||
|
"msg": payload.get("status").and_then(Value::as_str).unwrap_or("model pulled")
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn get_commit_model(state: tauri::State<'_, AppState>) -> CommandResult<String> {
|
fn get_commit_model(state: tauri::State<'_, AppState>) -> CommandResult<String> {
|
||||||
Ok(state
|
Ok(state
|
||||||
|
|||||||
@@ -15,7 +15,10 @@
|
|||||||
"width": 900,
|
"width": 900,
|
||||||
"height": 600,
|
"height": 600,
|
||||||
"minWidth": 800,
|
"minWidth": 800,
|
||||||
"minHeight": 500
|
"minHeight": 500,
|
||||||
|
"titleBarStyle": "Transparent",
|
||||||
|
"hiddenTitle": true,
|
||||||
|
"backgroundColor": "#fff1f2"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"security": {
|
"security": {
|
||||||
|
|||||||
Reference in New Issue
Block a user