News Tab with Markdown

This commit is contained in:
2025-12-30 18:11:41 +01:00
parent cfd3f68077
commit d4fb4701c3
6 changed files with 346 additions and 6 deletions

View File

@@ -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"] }

View File

@@ -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
View 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,
}])
}