mirror of
https://github.com/kristoferssolo/yoda-web.git
synced 2025-10-21 20:10:36 +00:00
feat: add translator
This commit is contained in:
parent
6373738bda
commit
e85cec1a7e
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -60,6 +60,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assert-json-diff"
|
name = "assert-json-diff"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
@ -2856,6 +2862,7 @@ dependencies = [
|
|||||||
name = "yoda-web"
|
name = "yoda-web"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"axum",
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
"config",
|
"config",
|
||||||
|
|||||||
@ -43,6 +43,8 @@ reqwest = { version = "0.12", default-features = false, features = [
|
|||||||
"json",
|
"json",
|
||||||
"rustls-tls",
|
"rustls-tls",
|
||||||
] }
|
] }
|
||||||
|
serde_json = "1"
|
||||||
|
anyhow = "1"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod domain;
|
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
|
pub mod speak;
|
||||||
|
pub mod state;
|
||||||
pub mod telemetry;
|
pub mod telemetry;
|
||||||
|
|||||||
10
src/main.rs
10
src/main.rs
@ -1,21 +1,23 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use tokio::net::TcpListener;
|
||||||
use yoda_web::{
|
use yoda_web::{
|
||||||
config::get_config,
|
config::get_config,
|
||||||
routes::route,
|
routes::route,
|
||||||
|
state::AppState,
|
||||||
telemetry::{get_subscriber, init_subscriber},
|
telemetry::{get_subscriber, init_subscriber},
|
||||||
};
|
};
|
||||||
use sqlx::postgres::PgPoolOptions;
|
|
||||||
use tokio::net::TcpListener;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), std::io::Error> {
|
async fn main() -> Result<(), std::io::Error> {
|
||||||
let subscriber = get_subscriber("yoda-web", "info", std::io::stdout);
|
let subscriber = get_subscriber("yoda-web", "info", std::io::stdout);
|
||||||
init_subscriber(subscriber);
|
init_subscriber(subscriber);
|
||||||
let config = get_config().expect("Failed to read configuation.");
|
let config = get_config().expect("Failed to read configuation.");
|
||||||
let pool = PgPoolOptions::new().connect_lazy_with(config.database.with_db());
|
let state = Arc::new(AppState::default());
|
||||||
let addr = format!("{}:{}", config.application.host, config.application.port);
|
let addr = format!("{}:{}", config.application.host, config.application.port);
|
||||||
let listener = TcpListener::bind(addr)
|
let listener = TcpListener::bind(addr)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to bind port 8000.");
|
.expect("Failed to bind port 8000.");
|
||||||
|
|
||||||
axum::serve(listener, route(pool)).await
|
axum::serve(listener, route(state)).await
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
mod health_check;
|
mod health_check;
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::{sync::Arc, time::Duration};
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
body::Bytes,
|
body::Bytes,
|
||||||
extract::MatchedPath,
|
extract::MatchedPath,
|
||||||
http::{HeaderMap, Request},
|
http::{HeaderMap, Request},
|
||||||
response::Response,
|
response::Response,
|
||||||
routing::get,
|
routing::{get, post},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -17,10 +17,13 @@ use tower_http::{classify::ServerErrorsFailureClass, trace::TraceLayer};
|
|||||||
use tracing::{info_span, Span};
|
use tracing::{info_span, Span};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub fn route(pool: PgPool) -> Router {
|
use crate::{speak::yoda_speak, state::AppState};
|
||||||
|
|
||||||
|
pub fn route(state: Arc<AppState>) -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/health_check", get(health_check))
|
.route("/health_check", get(health_check))
|
||||||
.with_state(pool)
|
.route("/yoda", post(yoda_speak))
|
||||||
|
.with_state(state)
|
||||||
.layer(
|
.layer(
|
||||||
TraceLayer::new_for_http()
|
TraceLayer::new_for_http()
|
||||||
.make_span_with(|request: &Request<_>| {
|
.make_span_with(|request: &Request<_>| {
|
||||||
|
|||||||
66
src/speak.rs
Normal file
66
src/speak.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
|
use axum::{extract::State, response::IntoResponse, Json};
|
||||||
|
use reqwest::{Client, StatusCode};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tracing_log::log::error;
|
||||||
|
|
||||||
|
use crate::state::AppState;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct InputText {
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct OutputText {
|
||||||
|
pub yoda_text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn yoda_speak(
|
||||||
|
State(state): State<Arc<AppState>>,
|
||||||
|
Json(input): Json<InputText>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
match convert_to_yoda_speak(&state.client, &input.text).await {
|
||||||
|
Ok(yoda_text) => {
|
||||||
|
let output = OutputText { yoda_text };
|
||||||
|
(StatusCode::OK, Json(output)).into_response()
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error converting to Yoda speak: {}", e);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
Json(json!({"error":"Failed to convert text"})),
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn convert_to_yoda_speak(client: &Client, text: &str) -> Result<String> {
|
||||||
|
let url = "https://api.funtranslations.com/translate/yoda.json";
|
||||||
|
let params = [("text", text)];
|
||||||
|
let response = client
|
||||||
|
.post(url)
|
||||||
|
.form(¶ms)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.context("Failed to send request to Yoda translation API")?;
|
||||||
|
let json: Value = response
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.context("Failed to parse JSON response")?;
|
||||||
|
|
||||||
|
let translated_text = json
|
||||||
|
.get("contents")
|
||||||
|
.context("Missing 'contents' key in JSON response")?
|
||||||
|
.get("translated")
|
||||||
|
.context("Missing 'translated' key in 'contents' object")?
|
||||||
|
.as_str()
|
||||||
|
.context("Failed to extract translated text from JSON")?
|
||||||
|
.to_owned();
|
||||||
|
Ok(translated_text)
|
||||||
|
}
|
||||||
20
src/state.rs
Normal file
20
src/state.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use reqwest::Client;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AppState {
|
||||||
|
pub client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AppState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
client: Client::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user