Markdown-wrapper strippaus LLM-vastauksista + hub-status tooltip

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaakko Vanhala
2026-04-05 08:41:23 +03:00
parent 88fd31ca8c
commit 949f34833f
3 changed files with 67 additions and 3 deletions

View File

@@ -225,7 +225,7 @@ impl LlmEngine {
} else { 0.0 }; } else { 0.0 };
Ok(GenerateResult { Ok(GenerateResult {
text: generated_text, text: strip_markdown_wrapper(&generated_text),
tokens_generated, tokens_generated,
duration_ms: gen_time.as_millis() as f64, duration_ms: gen_time.as_millis() as f64,
tokens_per_sec, tokens_per_sec,
@@ -233,6 +233,31 @@ impl LlmEngine {
} }
} }
/// Poistaa mallin tuottaman markdown-wrapperin ja johdantotekstin.
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.to_string();
let lower = result.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();
}
break;
}
}
result.trim().to_string()
}
pub struct GenerateResult { pub struct GenerateResult {
pub text: String, pub text: String,
pub tokens_generated: usize, pub tokens_generated: usize,

View File

@@ -27,6 +27,37 @@ struct CachedModel {
is_3b: bool, is_3b: bool,
} }
/// Poistaa mallin tuottaman markdown-wrapperin ja johdantotekstin.
/// "Sure! Here is...\n```python\nprint('hi')\n```" → "print('hi')"
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();
}
// Ei sulkevaa ``` — ota kaikki loput
return code.trim().to_string();
}
// Ei koodiblokkia — poista yleiset johdantolauseet alusta
let mut result = text.to_string();
let lower = result.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') {
result = result[newline + 1..].to_string();
}
break;
}
}
result.trim().to_string()
}
thread_local! { thread_local! {
static RAM_CACHE: RefCell<std::collections::HashMap<String, Rc<Vec<u8>>>> = RefCell::new(std::collections::HashMap::new()); static RAM_CACHE: RefCell<std::collections::HashMap<String, Rc<Vec<u8>>>> = RefCell::new(std::collections::HashMap::new());
static MODEL_CACHE: RefCell<Option<CachedModel>> = RefCell::new(None); static MODEL_CACHE: RefCell<Option<CachedModel>> = RefCell::new(None);
@@ -295,7 +326,11 @@ pub async fn run_coder_inference(prompt: String, ws: Rc<RefCell<WebSocket>>, use
} }
let gen_time = perf.now() - start_gen; let gen_time = perf.now() - start_gen;
(generated_text, tokens_generated, gen_time)
// Siivotaan vastaus: poista markdown-koodiblokit ja johdantotekstit
let cleaned = strip_markdown_wrapper(&generated_text);
(cleaned, tokens_generated, gen_time)
}); });
let tokens_per_sec = if gen_time > 0.0 { (tokens_generated as f64 / gen_time) * 1000.0 } else { 0.0 }; let tokens_per_sec = if gen_time > 0.0 { (tokens_generated as f64 / gen_time) * 1000.0 } else { 0.0 };

View File

@@ -1090,7 +1090,7 @@
</div> </div>
</div> </div>
<div id="agent-hub-status" style="margin-top:20px;padding:8px 14px;background:#0d1117;border:1px solid var(--border-color);border-radius:6px 6px 0 0;font-family:'Courier New',monospace;font-size:13px;display:flex;align-items:center;gap:8px"> <div id="agent-hub-status" title="WebSocket-yhteys Kipinä Hubiin — hallitsee tehtävien jakelun ja solmujen koordinoinnin" style="margin-top:20px;padding:8px 14px;background:#0d1117;border:1px solid var(--border-color);border-radius:6px 6px 0 0;font-family:'Courier New',monospace;font-size:13px;display:flex;align-items:center;gap:8px;cursor:help">
<span id="agent-hub-dot" style="width:8px;height:8px;border-radius:50%;background:#d29922;display:inline-block"></span> <span id="agent-hub-dot" style="width:8px;height:8px;border-radius:50%;background:#d29922;display:inline-block"></span>
<span style="color:#8b949e">Hub:</span> <span style="color:#8b949e">Hub:</span>
<span id="agent-hub-label" style="color:#d29922">Yhdistetään...</span> <span id="agent-hub-label" style="color:#d29922">Yhdistetään...</span>
@@ -1640,8 +1640,10 @@
// Päivitetään agents-näkymän hub-status // Päivitetään agents-näkymän hub-status
const hubDot = document.getElementById('agent-hub-dot'); const hubDot = document.getElementById('agent-hub-dot');
const hubLabel = document.getElementById('agent-hub-label'); const hubLabel = document.getElementById('agent-hub-label');
const hubStatus = document.getElementById('agent-hub-status');
if (hubDot) hubDot.style.background = '#3fb950'; if (hubDot) hubDot.style.background = '#3fb950';
if (hubLabel) { hubLabel.textContent = 'Yhdistetty'; hubLabel.style.color = '#3fb950'; } if (hubLabel) { hubLabel.textContent = 'Yhdistetty'; hubLabel.style.color = '#3fb950'; }
if (hubStatus) hubStatus.title = 'Yhdistetty Kipinä Hubiin — tehtävien jakelu ja solmujen koordinointi aktiivinen';
// Päivitetään molemmat statukset // Päivitetään molemmat statukset
const el = document.getElementById('node-status'); const el = document.getElementById('node-status');
@@ -1692,8 +1694,10 @@
uiSocket.onclose = () => { uiSocket.onclose = () => {
const hubDot = document.getElementById('agent-hub-dot'); const hubDot = document.getElementById('agent-hub-dot');
const hubLabel = document.getElementById('agent-hub-label'); const hubLabel = document.getElementById('agent-hub-label');
const hubStatus2 = document.getElementById('agent-hub-status');
if (hubDot) hubDot.style.background = '#f85149'; if (hubDot) hubDot.style.background = '#f85149';
if (hubLabel) { hubLabel.textContent = 'Yhteys katkennut'; hubLabel.style.color = '#f85149'; } if (hubLabel) { hubLabel.textContent = 'Yhteys katkennut'; hubLabel.style.color = '#f85149'; }
if (hubStatus2) hubStatus2.title = 'WebSocket-yhteys hubiin katkesi — tarkista verkkoyhteytesi tai hubin tila. Lataa sivu uudelleen yhdistääksesi.';
const el = document.getElementById('node-status'); const el = document.getElementById('node-status');
el.textContent = 'Disconnected'; el.textContent = 'Disconnected';