AIdetector / core /aggregator.py
mokshad
Initial deploy — AI text detector API
e945892
Raw
History Blame
1.8 kB
# core/aggregator.py
# Combines BERT score + stylometric score into a final probability.
from core.stylometrics import compute_stylometric_score
from core.explainer import find_ai_phrases, generate_explanation
from config.settings import settings
def aggregate_scores(
bert_result: dict,
text: str,
sentence_scores: list[dict],
) -> dict:
"""
Two-signal hybrid:
- BERT (70%): neural, trained on Wikipedia pairs
- Stylometrics (30%): model-agnostic structural features
"""
stylo_result = compute_stylometric_score(text)
stylo_score = stylo_result["stylometric_ai_score"]
bert_prob = bert_result["ai_probability"]
bert_weight = 0.70
stylo_weight = 0.30
final_probability = (
bert_prob * bert_weight +
stylo_score * stylo_weight
)
final_probability = round(max(0.0, min(1.0, final_probability)), 4)
ai_phrases = find_ai_phrases(text)
explanation = generate_explanation(
ai_probability=final_probability,
stylometric_data=stylo_result,
sentence_scores=sentence_scores,
ai_phrases=ai_phrases,
)
is_ai = final_probability >= settings.CONFIDENCE_THRESHOLD
return {
"ai_probability": final_probability,
"is_ai": is_ai,
"verdict": explanation["verdict"],
"confidence_threshold": settings.CONFIDENCE_THRESHOLD,
"scores": {
"bert_score": bert_prob,
"stylometric_score": round(stylo_score, 4),
"bert_weight": bert_weight,
"stylometric_weight": stylo_weight,
},
"stylometric_features": stylo_result["features"],
"sentence_scores": sentence_scores,
"explanation": explanation,
"chunks_analyzed": bert_result.get("chunks_analyzed", 1),
}