From 7a1352ead7ba1f3e06d01274cf1a8703cbd13e2f Mon Sep 17 00:00:00 2001 From: Jaakko Vanhala Date: Sun, 5 Apr 2026 10:07:19 +0300 Subject: [PATCH] Korjattu strip_markdown_wrapper yhteensopivaksi prefill-tekniikan kanssa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefill lisää ``` prompttiin jolloin malli tuottaa: "rust\nfn main()...\n```" Vanha stripperi etsi aloittavaa ```-blokkia ja palautti tyhjän. Uusi logiikka: 1. Poistaa kielitunnisteen ensimmäiseltä riviltä (rust, python jne.) 2. Poistaa sulkevan ``` lopusta (rfind, varmistaa ettei ole koodin sisällä) 3. Poistaa johdantolauseet ja selityskommentit kuten ennenkin Co-Authored-By: Claude Opus 4.6 (1M context) --- network-poc/native-node/src/inference.rs | 41 ++++++++++------- network-poc/node/src/qwen_coder.rs | 56 +++++++++++++----------- 2 files changed, 55 insertions(+), 42 deletions(-) diff --git a/network-poc/native-node/src/inference.rs b/network-poc/native-node/src/inference.rs index 608ccf2..5ef2599 100644 --- a/network-poc/native-node/src/inference.rs +++ b/network-poc/native-node/src/inference.rs @@ -234,33 +234,40 @@ impl LlmEngine { } } -/// Poistaa mallin tuottaman markdown-wrapperin ja johdantotekstin. +/// Siivoa mallin tuottama vastaus (prefill-yhteensopiva). fn strip_markdown_wrapper(text: &str) -> String { - let text = text.trim(); - if let Some(start) = text.find("```") { - let after = &text[start + 3..]; - let code_start = after.find('\n').map(|i| i + 1).unwrap_or(0); - let code = &after[code_start..]; - if let Some(end) = code.find("```") { - return code[..end].trim().to_string(); - } - return code.trim().to_string(); + let mut result = text.trim().to_string(); + + // Poistetaan kielitunniste ensimmäiseltä riviltä + if let Some(nl) = result.find('\n') { + let first = result[..nl].trim(); + let is_lang = !first.is_empty() + && first.len() <= 20 + && first.chars().all(|c| c.is_alphanumeric() || c == '+' || c == '#'); + if is_lang { result = result[nl + 1..].to_string(); } } - let mut result = text.to_string(); - let lower = result.to_lowercase(); + + // Poistetaan sulkeva ``` lopusta + if let Some(pos) = result.rfind("```") { + if result[pos + 3..].trim().is_empty() { + result = result[..pos].to_string(); + } + } + + // Poistetaan johdantolauseet + let lower = result.trim().to_lowercase(); for prefix in &["sure!", "here is", "here's", "certainly!", "below is"] { if lower.starts_with(prefix) { - if let Some(nl) = result.find('\n') { - result = result[nl + 1..].to_string(); - } + if let Some(nl) = result.find('\n') { result = result[nl + 1..].to_string(); } break; } } + + // Poistetaan selityskommentit alusta let mut lines: Vec<&str> = result.trim().lines().collect(); while !lines.is_empty() { let first = lines[0].trim(); - let is_preamble = first.starts_with("# ") - && !first.starts_with("#!") + let is_preamble = first.starts_with("# ") && !first.starts_with("#!") && (first.to_lowercase().contains("this is") || first.to_lowercase().contains("simple") || first.to_lowercase().contains("program that") diff --git a/network-poc/node/src/qwen_coder.rs b/network-poc/node/src/qwen_coder.rs index 470dabc..61d3f05 100644 --- a/network-poc/node/src/qwen_coder.rs +++ b/network-poc/node/src/qwen_coder.rs @@ -27,26 +27,35 @@ struct CachedModel { is_3b: bool, } -/// Poistaa mallin tuottaman markdown-wrapperin ja johdantotekstin. -/// "Sure! Here is...\n```python\nprint('hi')\n```" → "print('hi')" +/// Siivoa mallin tuottama vastaus. +/// Prefill-tekniikan vuoksi malli tuottaa: "rust\nfn main() {...}\n```" +/// eli kielitunniste alussa + sulkeva ``` lopussa. Molemmat poistetaan. fn strip_markdown_wrapper(text: &str) -> String { - let text = text.trim(); - // Jos vastaus sisältää ```-koodiblokin, ota vain sen sisältö - if let Some(start) = text.find("```") { - let after_backticks = &text[start + 3..]; - // Ohita mahdollinen kielitunniste (```python, ```rust jne.) - let code_start = after_backticks.find('\n').map(|i| i + 1).unwrap_or(0); - let code = &after_backticks[code_start..]; - // Etsi sulkeva ``` - if let Some(end) = code.find("```") { - return code[..end].trim().to_string(); + let mut result = text.trim().to_string(); + + // 1. Poistetaan kielitunniste ensimmäiseltä riviltä (rust, python, javascript jne.) + // Tunnistetaan: rivi jossa vain yksi lyhyt sana ilman välilyöntejä tai erikoismerkkejä + if let Some(first_newline) = result.find('\n') { + let first_line = result[..first_newline].trim(); + let is_lang_tag = !first_line.is_empty() + && first_line.len() <= 20 + && first_line.chars().all(|c| c.is_alphanumeric() || c == '+' || c == '#'); + if is_lang_tag { + result = result[first_newline + 1..].to_string(); } - // Ei sulkevaa ``` — ota kaikki loput - return code.trim().to_string(); } - // Ei koodiblokkia — poista yleiset johdantolauseet ja selityskommentit alusta - let mut result = text.to_string(); - let lower = result.to_lowercase(); + + // 2. Poistetaan sulkeva ``` lopusta + if let Some(pos) = result.rfind("```") { + // Varmistetaan ettei poisteta koodin sisällä olevaa ``` + let after = result[pos + 3..].trim(); + if after.is_empty() { + result = result[..pos].to_string(); + } + } + + // 3. Poistetaan johdantolauseet: "Sure! Here is...", "Certainly!" jne. + let lower = result.trim().to_lowercase(); for prefix in &["sure!", "here is", "here's", "certainly!", "below is"] { if lower.starts_with(prefix) { if let Some(newline) = result.find('\n') { @@ -55,12 +64,12 @@ fn strip_markdown_wrapper(text: &str) -> String { break; } } - // Poistetaan alun selityskommentit: "# This is a simple..." -tyyppiset rivit - // jotka eivät ole osa varsinaista koodia (esim. shebangia #! pidetään) + + // 4. Poistetaan selityskommentit alusta: "# This is a simple program..." let mut lines: Vec<&str> = result.trim().lines().collect(); while !lines.is_empty() { let first = lines[0].trim(); - let is_preamble_comment = first.starts_with("# ") + let is_preamble = first.starts_with("# ") && !first.starts_with("#!") && (first.to_lowercase().contains("this is") || first.to_lowercase().contains("simple") @@ -68,12 +77,9 @@ fn strip_markdown_wrapper(text: &str) -> String { || first.to_lowercase().contains("here is") || first.to_lowercase().contains("the following") || first.to_lowercase().contains("below")); - if is_preamble_comment { - lines.remove(0); - } else { - break; - } + if is_preamble { lines.remove(0); } else { break; } } + lines.join("\n").trim().to_string() }