WIP Rework markdown parsing

This commit is contained in:
Tristan D. 2025-02-10 17:12:00 +01:00
parent 604410ef61
commit d39459f2a9
Signed by: tristan
SSH key fingerprint: SHA256:9oFM1J63hYWJjCnLG6C0fxBS15rwNcWwdQNMOHYKJ/4
11 changed files with 109 additions and 42 deletions

38
Cargo.lock generated
View file

@ -1730,6 +1730,15 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@ -2869,7 +2878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets 0.48.5",
"windows-targets 0.52.6",
]
[[package]]
@ -2955,6 +2964,7 @@ dependencies = [
"mime_guess",
"once_cell",
"pin-project-lite",
"pulldown-cmark",
"rand 0.8.5",
"regex",
"reqwest",
@ -4039,6 +4049,26 @@ dependencies = [
"psl-types",
]
[[package]]
name = "pulldown-cmark"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14"
dependencies = [
"bitflags 2.8.0",
"getopts",
"memchr",
"pulldown-cmark-escape",
"serde",
"unicase",
]
[[package]]
name = "pulldown-cmark-escape"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
[[package]]
name = "quick-xml"
version = "0.37.2"
@ -6166,6 +6196,12 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-xid"
version = "0.2.6"

View file

@ -83,6 +83,7 @@ tracing-test = "0.2.4"
sysinfo = { version = "0.30.11", optional = true }
derive_more = { version = "0.99.17", features = ["nightly"] }
sqlx-macros = { version = "0.7.4", optional = true, features = ["chrono", "json", "migrate", "sqlite", "uuid"] }
pulldown-cmark = { version = "0.12.2", features = ["serde"] }
# qdrant-client = "1.11.2"
# swiftide = "0.9.1"

View file

@ -48,11 +48,15 @@ pub async fn run_starter_task(pool: sqlx::SqlitePool) {
use crate::server::backends::BackendService;
let _ = tracing::debug_span!("starter_task");
tracing::debug!("AAAAAAAAAAAAAAA");
return; // TODO ????
tracing::debug!("Starter task started");
let service_handle = BackendService::new();
let mut stream = IntervalStream::new(time::interval(Duration::from_millis(1000)));
while let Some(instant) = stream.next().await {
break; // TODO integrate proxy man ?
tracing::debug!("fire; instant={:?}", instant);
let waiting_to_start: Vec<BackendProcess> = sqlx::query_as(

View file

@ -41,7 +41,8 @@ pub fn App() -> impl IntoView {
<Routes>
<Route path="" view=MainPage>
<Route path="/chat" view=ChatPage/>
<SettingsRoutes/>
// TODO make settings page for proxy-man
// <SettingsRoutes/>
</Route>
</Routes>
</main>

View file

@ -12,7 +12,7 @@ use crate::{
app::components::{svgs::*, Card},
};
#[component]
#[island]
fn ChatMessageBubble(
msg: RwSignal<ChatMessage>,
history: RwSignal<Vec<RwSignal<ChatMessage>>>,
@ -33,12 +33,37 @@ fn ChatMessageBubble(
let textarea_ref = NodeRef::<html::P>::new();
use pulldown_cmark;
let editable_p = move || {
// TODO Convert back to raw str when editable
let mode = if edit_mode.get() { "true" } else { "false" };
let msg_str = move || msg.get().content.clone();
let md_str = move || {
let owned_str = msg_str();
let parser = pulldown_cmark::Parser::new(&owned_str);
let mut md_output = String::new();
pulldown_cmark::html::push_html(&mut md_output, parser);
md_output
};
let inner_p = move || {
if edit_mode.get() {
view! {
<p inner_html=move || { msg_str() }></p>
}
} else {
view! {
<p inner_html=move || { md_str() }></p>
}
}
};
view! {
<p node_ref=textarea_ref contenteditable=move || { mode }>
<span inner_html=msg.get().content.clone()></span>
{inner_p}
</p>
}
};

View file

@ -68,9 +68,7 @@ pub struct LlamaService {
impl LlamaService {
pub fn new(id: Uuid) -> Self {
Self {
id,
}
Self { id }
}
}
@ -80,7 +78,8 @@ async fn do_chat_request(chat: Chat, sender: mpsc::Sender<ChannelMessage>) -> an
let request_body: LlamaChatCompletionRequest = chat.into();
let request_builder = client
.post("http://localhost:8080/v1/chat/completions")
// # .post("http://localhost:8080/v1/chat/completions")
.post("http://100.64.0.3:18080/v1/chat/completions")
.header("Content-Type", "application/json")
.json(&request_body);
@ -92,7 +91,19 @@ async fn do_chat_request(chat: Chat, sender: mpsc::Sender<ChannelMessage>) -> an
Ok(Event::Message(event)) => match event.event.as_str() {
"message" => {
let data = event.data;
let response: LlamaChatResponse = serde_json::from_str(&data).unwrap();
tracing::debug!(?data);
if data == "[DONE]" {
sender
.send(ChannelMessage::Stop)
.await
.expect("channel fail");
es.close();
break;
}
let response: LlamaChatResponse = serde_json::from_str(&data).expect("no json");
for choice in response.choices.into_iter() {
if let Some(delta) = choice.delta {

View file

@ -112,7 +112,7 @@ pub async fn do_completion_request() -> Result<(), Box<dyn std::error::Error>> {
let request_body = CompletionRequest::default();
let request_builder = client
.post("http://localhost:8080/completion")
.post("http://100.64.0.3:18080/completion")
.header("Accept", "text/event-stream")
.header("Content-Type", "application/json")
.header("User-Agent", "llama_forge_rs")

View file

@ -177,10 +177,7 @@ mod tests {
use crate::{
api::{ChannelMessage, ChatMessage, ChatRole},
server::backends::{
llama_chat::LlamaService,
BackendService,
BackendServiceStatus,
ChatService,
llama_chat::LlamaService, BackendService, BackendServiceStatus, ChatService,
},
};

View file

@ -18,9 +18,7 @@ impl<S> Layer<S> for LoggingLayer {
type Service = LoggingService<S>;
fn layer(&self, inner: S) -> Self::Service {
LoggingService {
inner,
}
LoggingService { inner }
}
}

View file

@ -6,26 +6,20 @@ use axum::{
http::Request,
response::IntoResponse,
routing::get,
Extension,
Router,
Extension, Router,
};
use leptos::*;
use leptos_axum::{generate_route_list, handle_server_fns_with_context, LeptosRoutes};
use leptos_router::RouteListing;
use sqlx::{
sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions, SqliteSynchronous},
ConnectOptions,
SqlitePool,
ConnectOptions, SqlitePool,
};
use tower::Layer;
use tower_http::{
compression::CompressionLayer,
trace::{
DefaultMakeSpan,
DefaultOnEos,
DefaultOnFailure,
DefaultOnRequest,
DefaultOnResponse,
DefaultMakeSpan, DefaultOnEos, DefaultOnFailure, DefaultOnRequest, DefaultOnResponse,
TraceLayer,
},
CompressionLevel,
@ -122,7 +116,7 @@ pub async fn app(leptos_options: LeptosOptions) -> Router {
let pool = new_pool().await.expect("pool err");
// TODO move this out of server(pool has to be moved out too)
// // TODO move this out of server(pool has to be moved out too)
let task = run_starter_task(pool.clone());
tokio::task::spawn(task);