News Tab with Markdown
This commit is contained in:
@@ -24,3 +24,4 @@ serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
easy-nostr = { path = "./easy-nostr" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
mod chat;
|
||||
mod home;
|
||||
mod news;
|
||||
|
||||
use tokio::sync::Mutex; // Wichtig für den State
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
// DIESE ZEILE HINZUGEFÜGT: Registriert den State für alle Commands
|
||||
// Registriert den Nostr-State
|
||||
.manage(chat::NostrState(Mutex::new(None)))
|
||||
// HINZUGEFÜGT: Registriert den News-State für den API-Key
|
||||
.manage(news::NewsState::default())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
home::fetch_nostr_posts,
|
||||
chat::send_nostr_message,
|
||||
chat::get_nostr_messages
|
||||
chat::get_nostr_messages,
|
||||
news::save_openrouter_key,
|
||||
news::fetch_ai_news,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
76
src-tauri/src/news.rs
Normal file
76
src-tauri/src/news.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Mutex;
|
||||
use tauri::State;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct NewsState {
|
||||
pub openrouter_key: Mutex<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct NewsArticle {
|
||||
pub content: String,
|
||||
pub author: String,
|
||||
pub created_at: u64,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn save_openrouter_key(key: String, state: State<'_, NewsState>) -> Result<(), String> {
|
||||
let mut lock = state
|
||||
.openrouter_key
|
||||
.lock()
|
||||
.map_err(|_| "Lock failed".to_string())?;
|
||||
*lock = key.trim().to_string();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn fetch_ai_news(state: State<'_, NewsState>) -> Result<Vec<NewsArticle>, String> {
|
||||
let key = {
|
||||
let lock = state
|
||||
.openrouter_key
|
||||
.lock()
|
||||
.map_err(|_| "Lock failed".to_string())?;
|
||||
lock.clone()
|
||||
};
|
||||
|
||||
if key.is_empty() {
|
||||
return Err("API Key fehlt.".to_string());
|
||||
}
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let body = serde_json::json!({
|
||||
"model": "minimax/minimax-m2.1",
|
||||
"messages": [
|
||||
{"role": "system", "content": "Kurze News, 1-2 Sätze, Deutsch."},
|
||||
{"role": "user", "content": "Tech-News."}
|
||||
]
|
||||
});
|
||||
|
||||
let response = client
|
||||
.post("https://openrouter.ai/api/v1/chat/completions")
|
||||
.header("Authorization", format!("Bearer {}", key))
|
||||
.header("HTTP-Referer", "http://localhost:1420")
|
||||
.json(&body)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
return Err(format!("API Fehler: {}", response.status()));
|
||||
}
|
||||
|
||||
let json_res: serde_json::Value = response.json().await.map_err(|e| e.to_string())?;
|
||||
|
||||
let content = json_res["choices"][0]["message"]["content"]
|
||||
.as_str()
|
||||
.ok_or_else(|| "Kein Content im JSON".to_string())?
|
||||
.to_string();
|
||||
|
||||
Ok(vec![NewsArticle {
|
||||
content,
|
||||
author: "OpenRouter AI".to_string(),
|
||||
created_at: 0,
|
||||
}])
|
||||
}
|
||||
Reference in New Issue
Block a user