From 5d14c8a28b6d37856034e2c9e18aa2ce2886f87d Mon Sep 17 00:00:00 2001 From: centdix Date: Thu, 29 May 2025 17:21:55 +0200 Subject: [PATCH] draft working stuff --- backend/windmill-api/src/inkeep.rs | 117 ++++++++++++++++++++--- frontend/src/lib/components/chat/core.ts | 5 +- 2 files changed, 106 insertions(+), 16 deletions(-) diff --git a/backend/windmill-api/src/inkeep.rs b/backend/windmill-api/src/inkeep.rs index b80444ec77..7773110279 100644 --- a/backend/windmill-api/src/inkeep.rs +++ b/backend/windmill-api/src/inkeep.rs @@ -1,25 +1,116 @@ -use axum::body::Bytes; +use axum::{ + body::Bytes, + response::{IntoResponse, Response}, + routing::post, + Router, +}; +use http::{HeaderMap, StatusCode}; use reqwest::Client; -use windmill_common::ee::{EEServiceError, WINDMILL_CUSTOMER_SERVICE_BASE_URL}; +use tracing::{error, info, warn}; +use windmill_common::ee::WINDMILL_CUSTOMER_SERVICE_BASE_URL; +use windmill_common::error::{to_anyhow, Error, Result}; lazy_static::lazy_static! { static ref HTTP_CLIENT: Client = reqwest::ClientBuilder::new() .timeout(std::time::Duration::from_secs(60 * 5)) .user_agent("windmill/beta") .build().unwrap(); - - static ref OPENAI_AZURE_BASE_PATH: Option = std::env::var("OPENAI_AZURE_BASE_PATH").ok(); - - pub static ref AI_REQUEST_CACHE: Cache<(String, AIProvider), ExpiringAIRequestConfig> = Cache::new(500); } -pub async fn send_inkeep_request(body: Bytes) -> Result<()> { - let request_url = format!("{}/inkeep", WINDMILL_CUSTOMER_SERVICE_BASE_URL.as_str()); - let response = http_client.post(request_url).body(body).send().await?; +pub fn global_service() -> Router { + Router::new().route("/", post(send_inkeep_request)) +} - if response.status().is_success() { - Ok(()) - } else { - Err(EEServiceError::new("Failed to send inkeep request")) +pub async fn send_inkeep_request(headers: HeaderMap, body: Bytes) -> impl IntoResponse { + let request_url = format!("{}/inkeep", WINDMILL_CUSTOMER_SERVICE_BASE_URL.as_str()); + + // Ensure Content-Type is set to application/json + let mut forwarded_headers = headers.clone(); + forwarded_headers.insert( + http::header::CONTENT_TYPE, + "application/json".parse().unwrap(), + ); + + match HTTP_CLIENT + .post(&request_url) + .headers(forwarded_headers) + .body(body) + .send() + .await + { + Ok(response) => { + let status = response.status(); + let response_headers = response.headers().clone(); + + match response.bytes().await { + Ok(response_body) => { + info!("Response body size: {} bytes", response_body.len()); + + // Build proper axum Response + let mut response_builder = Response::builder().status(status); + + // Filter out hop-by-hop headers that shouldn't be forwarded + let skip_headers = [ + "connection", + "keep-alive", + "proxy-authenticate", + "proxy-authorization", + "te", + "trailers", + "transfer-encoding", + "upgrade", + "content-length", // Let axum handle this + ]; + + // Add safe headers from the upstream response + for (key, value) in response_headers.iter() { + let key_str = key.as_str().to_lowercase(); + if !skip_headers.contains(&key_str.as_str()) { + response_builder = response_builder.header(key, value); + } + } + + // Ensure we have content-type for JSON responses + response_builder = response_builder.header("content-type", "application/json"); + + match response_builder.body(axum::body::Body::from(response_body)) { + Ok(response) => { + info!("Successfully built response"); + response + } + Err(e) => { + error!("Failed to build response: {}", e); + Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .header("content-type", "application/json") + .body(axum::body::Body::from( + r#"{"error": "Failed to build response"}"#, + )) + .unwrap() + } + } + } + Err(e) => { + error!("Failed to read response body: {}", e); + Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .header("content-type", "application/json") + .body(axum::body::Body::from( + r#"{"error": "Failed to read response body"}"#, + )) + .unwrap() + } + } + } + Err(e) => { + error!("Failed to send request to inkeep service: {}", e); + Response::builder() + .status(StatusCode::BAD_GATEWAY) + .header("content-type", "application/json") + .body(axum::body::Body::from( + r#"{"error": "Failed to connect to inkeep service"}"#, + )) + .unwrap() + } } } diff --git a/frontend/src/lib/components/chat/core.ts b/frontend/src/lib/components/chat/core.ts index edb4fdfa88..b109ee06f9 100644 --- a/frontend/src/lib/components/chat/core.ts +++ b/frontend/src/lib/components/chat/core.ts @@ -151,11 +151,10 @@ function triggerComponent(args: { id: string; value: string }): string { } async function getDocumentation(args: { request: string }): Promise { - const retrieval = await fetch('https://api.inkeep.com/v1/chat/completions', { + const retrieval = await fetch('/api/inkeep', { method: 'POST', headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${import.meta.env.VITE_INKEEP_API_KEY}` + 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'inkeep-rag',