71 lines
1.9 KiB
Rust
71 lines
1.9 KiB
Rust
use tauri::{AppHandle, Emitter};
|
|
use serde::{Deserialize, Serialize};
|
|
use futures_util::StreamExt;
|
|
use reqwest::Client;
|
|
|
|
#[derive(Serialize, Deserialize, Clone)]
|
|
struct TranslationPayload {
|
|
model: String,
|
|
prompt: String,
|
|
stream: bool,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct OllamaResponse {
|
|
response: Option<String>,
|
|
// done: bool,
|
|
}
|
|
|
|
#[tauri::command]
|
|
async fn translate(
|
|
app: AppHandle,
|
|
api_address: String,
|
|
payload: TranslationPayload,
|
|
) -> Result<String, String> {
|
|
let client = Client::new();
|
|
let url = format!("{}/api/generate", api_address);
|
|
|
|
let res = client
|
|
.post(&url)
|
|
.json(&payload)
|
|
.send()
|
|
.await
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
if !payload.stream {
|
|
let data = res.json::<OllamaResponse>().await.map_err(|e| e.to_string())?;
|
|
return Ok(data.response.unwrap_or_default());
|
|
}
|
|
|
|
let mut stream = res.bytes_stream();
|
|
let mut full_response = String::new();
|
|
|
|
while let Some(item) = stream.next().await {
|
|
let chunk = item.map_err(|e| e.to_string())?;
|
|
let text = String::from_utf8_lossy(&chunk);
|
|
|
|
// Handle potential multiple JSON objects in one chunk
|
|
for line in text.lines() {
|
|
if line.trim().is_empty() { continue; }
|
|
if let Ok(json) = serde_json::from_str::<OllamaResponse>(line) {
|
|
if let Some(token) = json.response {
|
|
full_response.push_str(&token);
|
|
app.emit("translation-chunk", token).map_err(|e| e.to_string())?;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(full_response)
|
|
}
|
|
|
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
pub fn run() {
|
|
tauri::Builder::default()
|
|
.plugin(tauri_plugin_opener::init())
|
|
.plugin(tauri_plugin_http::init())
|
|
.invoke_handler(tauri::generate_handler![translate])
|
|
.run(tauri::generate_context!())
|
|
.expect("error while running tauri application");
|
|
}
|