Freeze mixed-file retrieval diagnostic and shared-engine evaluator
This commit is contained in:
1 parent
bba34de7aa
commit
6a5a2dc40d
20 files changed
+7597
No files matched your search
@@ -0,0 +1,218 @@
|
||||
use super::*;
|
||||
|
||||
/// Explicit semantic source channel, independent of filename/type filters.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SemanticOrigin {
|
||||
All,
|
||||
Text,
|
||||
Image,
|
||||
Video,
|
||||
Audio,
|
||||
}
|
||||
impl SemanticOrigin {
|
||||
fn source_type(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::All => None,
|
||||
Self::Text => Some("text"),
|
||||
Self::Image => Some("image"),
|
||||
Self::Video => Some("video"),
|
||||
Self::Audio => Some("audio"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A conservative intent hint, not a language understanding model. Explicit
|
||||
/// document/visual cues veto it; ordinary topic and instrument queries do not
|
||||
/// silently restrict modality. Word boundaries avoid filename substrings.
|
||||
fn preferred_origin(query: &str) -> Option<SemanticOrigin> {
|
||||
if query.split_whitespace().count() == 1 && Path::new(query).extension().is_some() {
|
||||
return None;
|
||||
}
|
||||
let lower = query.to_lowercase();
|
||||
let words: Vec<_> = lower
|
||||
.split(|c: char| !c.is_alphanumeric())
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect();
|
||||
let has = |values: &[&str]| words.iter().any(|word| values.contains(word));
|
||||
if has(&[
|
||||
"image",
|
||||
"photo",
|
||||
"picture",
|
||||
"screenshot",
|
||||
"diagram",
|
||||
"document",
|
||||
"pdf",
|
||||
"text",
|
||||
"paper",
|
||||
"bild",
|
||||
"foto",
|
||||
"screenshot",
|
||||
"dokument",
|
||||
"textdatei",
|
||||
]) {
|
||||
return None;
|
||||
}
|
||||
if has(&[
|
||||
"audio",
|
||||
"spoken",
|
||||
"speech",
|
||||
"recording",
|
||||
"conversation",
|
||||
"interview",
|
||||
"podcast",
|
||||
"sound",
|
||||
"music",
|
||||
"gesprochen",
|
||||
"gespräch",
|
||||
"gespraech",
|
||||
"geräusch",
|
||||
"geraeusch",
|
||||
"musik",
|
||||
"hörbar",
|
||||
"hörbarer",
|
||||
"hörbare",
|
||||
"hoerbar",
|
||||
"hoerbarer",
|
||||
"hoerbare",
|
||||
"tonaufnahme",
|
||||
]) {
|
||||
return Some(SemanticOrigin::Audio);
|
||||
}
|
||||
if (has(&["someone", "speaker"])
|
||||
&& has(&[
|
||||
"mentions",
|
||||
"mentioned",
|
||||
"says",
|
||||
"said",
|
||||
"speaks",
|
||||
"speaking",
|
||||
]))
|
||||
|| (has(&["jemand", "sprecher", "sprecherin"])
|
||||
&& has(&["erwähnt", "erwaehnt", "sagt", "gesagt", "spricht"]))
|
||||
{
|
||||
return Some(SemanticOrigin::Audio);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
impl HybridSearch {
|
||||
pub(super) fn routed_semantic(
|
||||
&mut self,
|
||||
query: &str,
|
||||
vector: &[f32],
|
||||
limit: usize,
|
||||
options: &SearchOptions,
|
||||
) -> Result<Vec<SearchResult>> {
|
||||
let mut trace = TraceCollector::new(MetricsMode::Basic);
|
||||
self.routed_semantic_traced(query, vector, limit, options, &mut trace, None)
|
||||
}
|
||||
pub(super) fn routed_semantic_traced(
|
||||
&mut self,
|
||||
query: &str,
|
||||
vector: &[f32],
|
||||
limit: usize,
|
||||
options: &SearchOptions,
|
||||
trace: &mut TraceCollector,
|
||||
parent: Option<SpanToken>,
|
||||
) -> Result<Vec<SearchResult>> {
|
||||
trace.timed("semantic.routing", parent, |trace, parent| {
|
||||
if let Some(origin) = if options.code_only {
|
||||
None
|
||||
} else {
|
||||
preferred_origin(query)
|
||||
} {
|
||||
trace.counter(parent, "audio_preference", 1);
|
||||
let preferred = self.store.search_origin_traced(
|
||||
vector,
|
||||
&self.generation_fingerprint,
|
||||
limit,
|
||||
options,
|
||||
origin.source_type(),
|
||||
trace,
|
||||
parent,
|
||||
)?;
|
||||
if !preferred.is_empty() {
|
||||
return Ok(preferred);
|
||||
}
|
||||
}
|
||||
trace.counter(parent, "general_lane", 1);
|
||||
self.store.search_origin_traced(
|
||||
vector,
|
||||
&self.generation_fingerprint,
|
||||
limit,
|
||||
options,
|
||||
None,
|
||||
trace,
|
||||
parent,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Query one actual source channel, or All to bypass automatic spoken/audio
|
||||
/// preference. This never embeds files again or changes an active policy.
|
||||
pub fn search_semantic_with_origin(
|
||||
&mut self,
|
||||
query: &str,
|
||||
limit: usize,
|
||||
options: &SearchOptions,
|
||||
origin: SemanticOrigin,
|
||||
) -> Result<Vec<SearchResult>> {
|
||||
let _ = self.lexical.search_with_options(query, 0, options)?;
|
||||
if query.trim().is_empty() || limit == 0 {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
let mut trace = TraceCollector::new(MetricsMode::Basic);
|
||||
let vector = self.query_vector(query, options.code_only, &mut trace, None)?;
|
||||
self.store.search_origin(
|
||||
&vector,
|
||||
&self.generation_fingerprint,
|
||||
limit.min(1000),
|
||||
options,
|
||||
origin.source_type(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn persisted_custom_limits_require_identical_model_and_preprocessing() {
|
||||
let expected = "pinned-model:pinned-media:preprocessing-v1";
|
||||
assert!(reusable_policy(
|
||||
expected,
|
||||
&format!("{expected}:custom-240-2000-120-10000-2000-1800-14400000-17179869184")
|
||||
));
|
||||
for active in ["other-model:pinned-media:preprocessing-v1:custom-240-2000-120-10000-2000-1800-14400000-17179869184","pinned-model:pinned-media:preprocessing-v2:custom-240-2000-120-10000-2000-1800-14400000-17179869184","pinned-model:pinned-media:preprocessing-v1:custom-unknown"] {assert!(!reusable_policy(expected,active));}
|
||||
}
|
||||
#[test]
|
||||
fn explicit_spoken_intent_is_conservative_and_bilingual() {
|
||||
for query in [
|
||||
"where someone mentions a contract",
|
||||
"a speaker says the date",
|
||||
"spoken discussion of ecology",
|
||||
"audio of a waterfall",
|
||||
"jemand erwähnt das Budget",
|
||||
"Wo spricht jemand über Kündigung?",
|
||||
"Gespräch über die neue Wohnung",
|
||||
"hörbarer Regen",
|
||||
] {
|
||||
assert_eq!(
|
||||
preferred_origin(query),
|
||||
Some(SemanticOrigin::Audio),
|
||||
"{query}"
|
||||
);
|
||||
}
|
||||
for query in [
|
||||
"contract deadline",
|
||||
"violin solo",
|
||||
"photo of someone speaking",
|
||||
"Bild von einem Sprecher",
|
||||
"a document that someone mentioned",
|
||||
"speech.png",
|
||||
"a screenshot of an audio waveform",
|
||||
] {
|
||||
assert_eq!(preferred_origin(query), None, "{query}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user