Skip to content

Commit

Permalink
implemented supported languages endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
KaiErikNiermann committed Sep 8, 2023
1 parent 4eb5054 commit 4e4ac6a
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 50 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/target
libs/**/target
.env

# compilation testing
gtkapp
Expand Down
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ lib_translator = { path = "./libs/lib_translator" }
glib = "0.18.1"
image = "0.24.6"
futures = "0.3"
tokio = { version = "1.32.0", features = ["full"] }
tokio = { version = "1.32.0", features = ["full"] }
dotenv = "0.15.0"
79 changes: 47 additions & 32 deletions libs/lib_gui/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use gtk::prelude::*;
use gtk::{glib, Application, ApplicationWindow, Button, Menu, MenuBar, MenuItem};
use lib_ocr::win_sc::*;
use lib_translator;
use std::collections::HashMap;
use std::env;
use std::thread;
use tokio::runtime;
use tokio::runtime::Runtime;
Expand Down Expand Up @@ -39,7 +41,7 @@ fn get_runtime() -> Runtime {

#[cfg(target_os = "linux")]
fn take_sc() {
println!("No support on linux yet");
println!("No support on linux yet, coming soon hopefully");
}

#[cfg(target_os = "windows")]
Expand All @@ -57,23 +59,23 @@ fn take_sc() {
}

#[derive(Clone)]
enum UpdateMessage {
enum UpdateText {
UpdateLabel(String),
}

fn get_lang_dropdown(
onclick: impl Fn(&MenuItem) + Clone + 'static
) -> Menu {
let language_choices: Vec<MenuItem> = vec![
MenuItem::with_label("jp"),
MenuItem::with_label("eng"),
MenuItem::with_label("de"),
];
fn get_lang_dropdown() -> Menu {
let lang_choices: HashMap<String, MenuItem> = HashMap::from([
(String::from("jp"), MenuItem::with_label("jp")),
(String::from("eng"), MenuItem::with_label("eng")),
(String::from("de"), MenuItem::with_label("de")),
]);

let lang_menu = Menu::new();
for lang in language_choices {
lang_menu.append(&lang);
lang.connect_activate(onclick.clone());
for (lang_str, lang_choice_item) in lang_choices {
lang_menu.append(&lang_choice_item);
lang_choice_item.connect_activate(glib::clone!(@strong lang_str => move |_| {
println!("You chose {}", lang_str);
}));
}
lang_menu
}
Expand All @@ -96,13 +98,8 @@ pub fn build_ui(
let source = MenuItem::with_label("Source");
let target = MenuItem::with_label("Target");

source.set_submenu(Some(&get_lang_dropdown(
move |_: &MenuItem| println!("clicked in source"),
)));

target.set_submenu(Some(&get_lang_dropdown(
move |_: &MenuItem| println!("clicked in target"),
)));
source.set_submenu(Some(&get_lang_dropdown()));
target.set_submenu(Some(&get_lang_dropdown()));

menu.append(&source);
menu.append(&target);
Expand All @@ -111,44 +108,62 @@ pub fn build_ui(
vbox.pack_start(&button, false, false, 10);
vbox.pack_start(&label, false, false, 10);

// set padding around vbox
vbox.set_margin(25);


let rt = get_runtime();

#[cfg(target_os = "linux")]
let fp = "./placeholder.png";

#[cfg(target_os = "windows")]
let fp = "./screenshot.png";

button.connect_clicked(glib::clone!(@weak label, @weak tbox => move |_| {
// Set translation window opacity to 0
tbox.set_opacity(0.0);

take_sc();

let tokio_handle = rt.handle();

tokio_handle.spawn(async move {
let res: Vec<lib_translator::Language> = match lib_translator::get_supported().await {
Ok(res) => {
println!("{:?}", res);
res
},
Err(_) => panic!("Whoop")
};

println!("{:?}", res);
});

let (sender, receiver): (
gtk::glib::Sender<UpdateMessage>,
gtk::glib::Receiver<UpdateMessage>,
gtk::glib::Sender<UpdateText>,
gtk::glib::Receiver<UpdateText>,
) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);

let tokio_handle = rt.handle();

/*
* Because reqwuest is async this is the only somewhat sane approach I found for
* being able to get the translated text and then update the label. Credit to slomo and their
* blog here : https://coaxion.net/blog/2019/02/mpsc-channel-api-for-painless-usage-of-threads-with-gtk-in-rust/
*/
tokio_handle.spawn(async move {
let text = lib_ocr::run_ocr("./screenshot.png", "eng");
let text = lib_ocr::run_ocr(fp, "eng");

let translated_text = match lib_translator::translate_text(&text, "f191652f-38ee-caed-ab30-f20a9a0cc21e:fx").await {
tokio_handle.spawn(async move {
let translated_text = match lib_translator::translate_text(&text).await {
Ok(text) => text,
Err(error_text) => panic!("{:?}", error_text)
Err(_) => String::from("Could not translate")
};

let _ = sender.send(UpdateMessage::UpdateLabel(translated_text));
let _ = sender.send(UpdateText::UpdateLabel(translated_text));
});

let label_clone = label.clone();
receiver.attach(None, move |msg| {
match msg {
UpdateMessage::UpdateLabel(text) => label_clone.set_text(text.as_str()),
UpdateText::UpdateLabel(text) => label_clone.set_text(text.as_str()),
}

glib::Continue(true)
Expand Down
6 changes: 4 additions & 2 deletions libs/lib_ocr/src/image.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use image::io::Reader as ImageReader;
use rusty_tesseract::{Args, Image};
use std::env;
use std::fs;

pub fn get_image(path: &str) -> Image {
// print cwd
Expand All @@ -27,5 +26,8 @@ pub fn get_image(path: &str) -> Image {
}

pub fn text_from_image(img: &Image, args: &Args) -> String {
rusty_tesseract::image_to_string(img, args).unwrap()
return match rusty_tesseract::image_to_string(img, args) {
Ok(res) => res,
Err(_) => String::from("OCR failed"),
};
}
1 change: 1 addition & 0 deletions libs/lib_ocr/src/text.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub fn clean_text(text: &str) -> String {
return text
.replace("\n", " ")
.replace("\"", "\\\"")
.split_whitespace()
.collect::<Vec<_>>()
.join(" ");
Expand Down
59 changes: 44 additions & 15 deletions libs/lib_translator/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
use reqwest::{Client, Request, Response};
use serde::{Deserialize, Serialize};
use std::env;

#[derive(Serialize, Deserialize, Debug)]
struct translations {
struct TransResponseBody {
detected_source_language: String,
text: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct APIResponse {
translations: Vec<translations>,
struct TranslationResponse {
translations: Vec<TransResponseBody>,
}

pub async fn translate_text(text: &str, auth_key: &str) -> Result<String, String> {
#[derive(Serialize, Deserialize, Debug)]
pub struct Language {
language: String,
name: String,
supports_formality: bool
}

pub async fn translate_text(text: &str) -> Result<String, reqwest::Error> {
let auth_key = env::var("DEEPL_API_KEY").expect("DEEPL_API_KEY key is not set, set it in a .env file in the root dir of the project");
let client = Client::new();
let url = "https://api-free.deepl.com/v2/translate";

// Create the JSON data payload.
let json_data = format!(
r#"{{
"text": ["{}"],
"target_lang": "EN"
"target_lang": "DE"
}}"#,
text
);
Expand All @@ -35,21 +44,41 @@ pub async fn translate_text(text: &str, auth_key: &str) -> Result<String, String
.await
.unwrap();

match response.status() {
reqwest::StatusCode::OK => {
let string_res = response.text().await.unwrap();
let api_res: APIResponse = serde_json::from_str(&string_res).unwrap();
match response.error_for_status() {
Ok(res) => {
let string_res = res.text().await.unwrap();
let api_res: TranslationResponse = serde_json::from_str(&string_res).unwrap();

println!("{:?}", api_res.translations[0].text);
println!("Ok!");
Ok(String::from(api_res.translations[0].text.clone()))
}
reqwest::StatusCode::BAD_REQUEST => {
println!("Bad request");
Err(String::from("Error"))
}
_ => {
panic!("Something unexpected");
Err(e) => {
println!("{:?}", e);
Err(e)
}
}
}

pub async fn get_supported() -> Result<Vec<Language>, reqwest::Error> {
let auth_key = env::var("DEEPL_API_KEY").expect("DEEPL_API_KEY key is not set, set it in a .env file in the root dir of the project");
let client = Client::new();
let url = "https://api-free.deepl.com/v2/languages?type=target";

let response = client
.get(url)
.header("Authorization", format!("DeepL-Auth-Key {}", auth_key))
.send()
.await
.unwrap();

match response.error_for_status() {
Ok(res) => {
let string_res = res.text().await.unwrap();
let api_res: Vec<Language> = serde_json::from_str(&string_res).unwrap();

Ok(api_res)
},
Err(e) => Err(e)
}
}
Binary file added placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use dotenv::dotenv;
use lib_gui;

fn main() {
dotenv().ok();

let app = lib_gui::init_app();
lib_gui::run_app(&app);
}

0 comments on commit 4e4ac6a

Please sign in to comment.