fix: backend improvements (customer health, tests, middleware, corpus)

This commit is contained in:
wlt
2026-06-24 10:38:26 +08:00
parent eb39cc1baa
commit ad329815fa
11 changed files with 122 additions and 77 deletions
+4 -4
View File
@@ -1,5 +1,5 @@
from typing import Dict, Any, Optional, List
from sqlalchemy import select, func, and_
from sqlalchemy import select, func, and_, String
from sqlalchemy.ext.asyncio import AsyncSession
from datetime import datetime, timedelta
import logging
@@ -58,7 +58,7 @@ class CorpusTrainer:
select(
CorpusEntry.source_text,
CorpusEntry.task_type,
func.min(CorpusEntry.id).label("keep_id"),
func.min(CorpusEntry.id.cast(String)).label("keep_id"),
)
.group_by(CorpusEntry.source_text, CorpusEntry.task_type)
.having(func.count(CorpusEntry.id) > 1)
@@ -70,7 +70,7 @@ class CorpusTrainer:
and_(
CorpusEntry.source_text == subquery.c.source_text,
CorpusEntry.task_type == subquery.c.task_type,
CorpusEntry.id != subquery.c.keep_id,
CorpusEntry.id.cast(String) != subquery.c.keep_id,
)
)
)
@@ -170,7 +170,7 @@ class CorpusTrainer:
from app.config import settings
import httpx
if settings.OPENAI_API_KEY:
if getattr(settings, 'OPENAI_API_KEY', None):
async with httpx.AsyncClient() as client:
resp = await client.post(
"https://api.openai.com/v1/embeddings",
+40 -5
View File
@@ -233,6 +233,12 @@ class CustomerHealthService:
score = max(0, min(100, 80 - recent_hours * 3))
return {"score": round(score), "recent_avg_hours": round(recent_hours, 1), "trend": "declining"}
@staticmethod
def _words_in_text(words, text_words):
"""Check if all words in the phrase appear in the text word set.
Handles multi-word phrases where word order differs."""
return all(w in text_words for w in words)
@staticmethod
def calc_sentiment_score(messages: List[str]) -> Dict[str, Any]:
if not messages:
@@ -240,11 +246,22 @@ class CustomerHealthService:
positive = 0
negative = 0
for msg in messages:
lower = msg.lower()
if any(w in lower for w in POSITIVE_WORDS):
positive += 1
if any(w in lower for w in NEGATIVE_WORDS):
negative += 1
words = msg.lower().split()
words_set = set(words)
for w in POSITIVE_WORDS:
parts = w.split()
if len(parts) > 1:
if CustomerHealthService._words_in_text(parts, words_set):
positive += 1
elif w in words_set:
positive += 1
for w in NEGATIVE_WORDS:
parts = w.split()
if len(parts) > 1:
if CustomerHealthService._words_in_text(parts, words_set):
negative += 1
elif w in words_set:
negative += 1
if positive > negative:
return {"score": 80, "label": "positive", "last_messages": messages}
elif negative > positive:
@@ -311,6 +328,24 @@ class CustomerHealthService:
return f"客户已沉默{silence_days}天,建议立即跟进,提供优惠或新产品信息"
return f"客户已沉默{silence_days}天,建议重新激活"
@staticmethod
def _calculate_overview_static(rows) -> Dict[str, Any]:
total = len(rows)
active = 0
watch = 0
critical = 0
for row in rows:
score = CustomerHealthService.calculate_silence_score(row.last_contact_at)
status_weight = CustomerHealthService.status_weight(row.status)
combined = score * 0.7 + status_weight * 0.3
if combined >= 70:
active += 1
elif combined >= 40:
watch += 1
else:
critical += 1
return {"total": total, "active": active, "watch": watch, "critical": critical}
def _calculate_silence_score(self, last_contact_at: Optional[datetime]) -> float:
return self.calculate_silence_score(last_contact_at)