This commit is contained in:
王一嘉
2025-07-29 13:19:29 +08:00
parent 0e6011727b
commit 47cde47444
8 changed files with 891 additions and 79 deletions

818
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,6 +26,8 @@ serde_json = "1"
futures = "0.3.31"
tokio = "1.46.1"
clipboard = "0.5.0"
screenshots = "0.8.10"
minifb = "0.28.0"
[target."cfg(target_os = \"macos\")".dependencies]
cocoa = "0.26.1"

View File

@@ -0,0 +1,8 @@
use clipboard::{ClipboardContext, ClipboardProvider};
#[tauri::command]
pub fn copy(content: &str) {
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
ctx.set_contents(content.to_string()).unwrap();
}

View File

@@ -0,0 +1,3 @@
pub mod translate_steam;
pub mod copy;
pub mod screenshot;

View File

@@ -0,0 +1,43 @@
use minifb::{MouseButton, MouseMode, Window, WindowOptions};
use screenshots::Screen;
use std::cmp::min;
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn screenshot() {
let screens = Screen::all().unwrap();
let primary_screen = screens.first().unwrap();
let screen_width = primary_screen.display_info.width;
let screen_height = primary_screen.display_info.height;
// 创建透明窗口用于区域选择
let mut window = Window::new(
"选择截图区域 - 按住鼠标左键拖动",
screen_width as usize,
screen_height as usize,
WindowOptions {
borderless: true,
transparency: true,
topmost: true,
..WindowOptions::default()
},
)
.unwrap();
println!("成功");
}
fn capture_area(x: i32, y: i32, width: u32, height: u32) {
let screens = Screen::all().unwrap();
if let Some(screen) = screens.first() {
let image = screen.capture_area(x, y, width, height).unwrap();
let filename = format!("area_{}x{}_{}x{}.png", x, y, width, height);
image.save(&filename).unwrap();
println!("区域截图已保存为 {}", filename);
}
}
}

View File

@@ -0,0 +1,36 @@
use ollama_rs::generation::completion::{request::GenerationRequest};
use ollama_rs::Ollama;
use futures::StreamExt;
use tauri::{AppHandle, Emitter};
#[tauri::command]
pub async fn translate_steam(content: &str, app_handle: AppHandle) -> Result<String, ()> {
let model = "gemma2:2b".to_string();
let prompt = format!(
"你是一个专业翻译模型,任务是将给定的文本翻译成目标语言。请严格遵循以下规则:\n\
只返回翻译结果,不要解释、不要问候、不要添加任何额外内容。\n\
如果输入是英文,翻译成中文;如果是中文,翻译成英文。\n\
示例1\n\
输入: 'Good morning.'\n\
输出: '早上好。'\n\
示例2\n\
输入: '这本书很有趣。'\n\
输出: 'This book is very interesting.'\n\
现在请翻译:\n\
输入: '{}'\n\
输出:",
content
);
let ollama = Ollama::new("http://localhost".to_string(), 11434);
let mut stream = ollama.generate_stream(GenerationRequest::new(model, prompt)).await.unwrap();
while let Some(res) = stream.next().await {
let responses = res.unwrap();
for resp in responses {
app_handle.emit("translate_steam" ,resp.response).unwrap();
}
}
Ok("完成".to_string())
}

View File

@@ -1,47 +1,6 @@
use futures::StreamExt;
use ollama_rs::generation::completion::{request::GenerationRequest};
use ollama_rs::Ollama;
use tauri::{AppHandle, TitleBarStyle, WebviewUrl, WebviewWindowBuilder, Emitter};
use clipboard::{ClipboardContext, ClipboardProvider};
use tauri::{TitleBarStyle, WebviewUrl, WebviewWindowBuilder, Emitter};
#[tauri::command]
async fn translate_steam(content: &str, app_handle: AppHandle) -> Result<String, ()> {
let model = "gemma2:2b".to_string();
let prompt = format!(
"你是一个专业翻译模型,任务是将给定的文本翻译成目标语言。请严格遵循以下规则:\n\
只返回翻译结果,不要解释、不要问候、不要添加任何额外内容。\n\
如果输入是英文,翻译成中文;如果是中文,翻译成英文。\n\
示例1\n\
输入: 'Good morning.'\n\
输出: '早上好。'\n\
示例2\n\
输入: '这本书很有趣。'\n\
输出: 'This book is very interesting.'\n\
现在请翻译:\n\
输入: '{}'\n\
输出:",
content
);
let ollama = Ollama::new("http://localhost".to_string(), 11434);
let mut stream = ollama.generate_stream(GenerationRequest::new(model, prompt)).await.unwrap();
while let Some(res) = stream.next().await {
let responses = res.unwrap();
for resp in responses {
app_handle.emit("translate_steam" ,resp.response).unwrap();
}
}
Ok("完成".to_string())
}
#[tauri::command]
fn copy(content: &str) {
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
ctx.set_contents(content.to_string()).unwrap();
}
mod commands;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
@@ -80,7 +39,10 @@ pub fn run() {
Ok(())
})
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![translate_steam, copy])
.invoke_handler(tauri::generate_handler![
commands::translate_steam::translate_steam,
commands::copy::copy
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@@ -53,9 +53,9 @@ onUnmounted(() => {
div.content-header 中文
div.content-hr
div.content-body
textarea(v-model="form.in" @input="changeIn").content-body-textarea
a-textarea(v-model="form.in" @input="changeIn").content-body-textarea
div.content-item
div.content-header.flex.items-center.justify-between
div.content-header
div 英文
div.flex.items-center.gap-2
div.text-info 自动复制
@@ -63,7 +63,7 @@ onUnmounted(() => {
div.content-hr
div.content-body
view(v-if="loading") 加载中...
textarea(v-model="form.out" v-else).content-body-textarea
a-textarea(v-model="form.out" v-else).content-body-textarea
a-button.content-body-copy-btn(@click="copy()") 复制
</template>
@@ -76,7 +76,7 @@ onUnmounted(() => {
@apply w-full bg-white rounded-xl overflow-hidden flex flex-col;
}
&-header {
@apply p-3;
@apply p-3 h-[50px] flex items-center justify-between;
}
&-hr {
@apply h-[1px] bg-[#ddd] w-full;
@@ -84,7 +84,7 @@ onUnmounted(() => {
&-body {
@apply p-3 flex flex-grow relative;
&-textarea {
@apply flex-grow min-h-[150px] p-3;
@apply flex-grow min-h-[150px];
}
&-copy-btn {
@apply absolute right-[24px] bottom-[24px];