forked from erp-dev/erp
feat: big
This commit is contained in:
@@ -5,8 +5,8 @@ from mission.models import Mission, MissionCategory, MissionParticipant, Mission
|
||||
|
||||
@admin.register(MissionCategory)
|
||||
class MissionCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ["id", "merchant", "name", "payload_processor", "created_at"]
|
||||
list_filter = ["merchant", "payload_processor", "created_at"]
|
||||
list_display = ["id", "merchant", "name", "payload_processor", "speech_enabled", "created_at"]
|
||||
list_filter = ["merchant", "payload_processor", "speech_enabled", "created_at"]
|
||||
search_fields = ["name"]
|
||||
readonly_fields = ["created_at", "updated_at"]
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import logging
|
||||
|
||||
from mission.notifications import enqueue_mission_created_speech
|
||||
from mission.payload_processors import apply_mission_payload_processor
|
||||
from notifier.models import NotificationEventKeyEnum
|
||||
from notifier.services import enqueue_notification_event
|
||||
@@ -74,6 +75,7 @@ def on_mission_created(sender, instance, created_by=None, **kwargs):
|
||||
merchant_id=instance.merchant_id,
|
||||
payload=payload,
|
||||
)
|
||||
enqueue_mission_created_speech(mission=instance)
|
||||
|
||||
|
||||
def on_mission_replied(sender, instance, mission=None, responder=None, **kwargs):
|
||||
|
||||
16
mission/migrations/0008_missioncategory_speech_enabled.py
Normal file
16
mission/migrations/0008_missioncategory_speech_enabled.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("mission", "0007_missioncategory_payload_processor"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="missioncategory",
|
||||
name="speech_enabled",
|
||||
field=models.BooleanField(default=False, verbose_name="是否播报"),
|
||||
),
|
||||
]
|
||||
@@ -28,6 +28,7 @@ class MissionCategory(ModelBase):
|
||||
choices=MissionPayloadProcessorEnum.choices,
|
||||
verbose_name="payload 增强器",
|
||||
)
|
||||
speech_enabled = models.BooleanField(default=False, verbose_name="是否播报")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
36
mission/notifications.py
Normal file
36
mission/notifications.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def enqueue_mission_created_speech(*, mission) -> None:
|
||||
if not getattr(settings, "SPEECH_ENABLED", True):
|
||||
return
|
||||
if not getattr(settings, "MISSION_SPEECH_NOTIFY_ENABLED", True):
|
||||
return
|
||||
|
||||
category = getattr(mission, "category", None)
|
||||
if not getattr(category, "speech_enabled", False):
|
||||
return
|
||||
|
||||
text = _build_mission_created_speech_text(mission=mission)
|
||||
try:
|
||||
from mission.tasks import notify_mission_speech
|
||||
|
||||
notify_mission_speech.delay(text=text)
|
||||
except Exception:
|
||||
logger.exception("[mission.notifications] 投递任务语音播报任务失败(已忽略)")
|
||||
|
||||
|
||||
def _build_mission_created_speech_text(*, mission) -> str:
|
||||
category_name = getattr(getattr(mission, "category", None), "name", "任务") or "任务"
|
||||
creator_name = getattr(getattr(mission, "creator", None), "name", "") or ""
|
||||
prefix = f"{creator_name}创建了" if creator_name else "创建了"
|
||||
description = (getattr(mission, "description", "") or "").strip()
|
||||
if len(description) > 60:
|
||||
description = f"{description[:60]}..."
|
||||
if description:
|
||||
return f"{prefix}{category_name}任务,{description}"
|
||||
return f"{prefix}{category_name}任务"
|
||||
27
mission/tasks.py
Normal file
27
mission/tasks.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import logging
|
||||
from typing import Any, Dict
|
||||
|
||||
from celery import shared_task
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@shared_task(bind=True)
|
||||
def notify_mission_speech(self, *, text: str) -> Dict[str, Any]:
|
||||
try:
|
||||
from flower.utils import play_speech
|
||||
|
||||
response = play_speech(text=text, timeout_seconds=3.0)
|
||||
return {
|
||||
"status": "sent",
|
||||
"task_id": self.request.id,
|
||||
"status_code": response.status_code,
|
||||
"raw": response.raw,
|
||||
}
|
||||
except Exception as exc:
|
||||
logger.exception("[mission.tasks] 任务语音播报失败(已忽略)")
|
||||
return {
|
||||
"status": "error",
|
||||
"task_id": self.request.id,
|
||||
"error": str(exc),
|
||||
}
|
||||
@@ -580,6 +580,28 @@ class MissionModelTestCase(TestCase):
|
||||
self.assertEqual(mock_enqueue.call_args.kwargs["merchant_id"], self.merchant.id)
|
||||
self.assertEqual(mock_enqueue.call_args.kwargs["payload"]["mission_id"], mission.id)
|
||||
|
||||
@patch("mission.tasks.notify_mission_speech.delay")
|
||||
@patch("mission.handlers.enqueue_notification_event")
|
||||
def test_mission_created_speech_requires_category_enabled(self, mock_enqueue, mock_speech_delay):
|
||||
with self.captureOnCommitCallbacks(execute=True):
|
||||
create_mission(creator=self.creator, description="不播报任务")
|
||||
|
||||
mock_enqueue.assert_called_once()
|
||||
mock_speech_delay.assert_not_called()
|
||||
|
||||
@patch("mission.tasks.notify_mission_speech.delay")
|
||||
@patch("mission.handlers.enqueue_notification_event")
|
||||
def test_mission_created_speech_enqueues_when_category_enabled(self, mock_enqueue, mock_speech_delay):
|
||||
self.default_category.speech_enabled = True
|
||||
self.default_category.save(update_fields=["speech_enabled", "updated_at"])
|
||||
|
||||
with self.captureOnCommitCallbacks(execute=True):
|
||||
mission = create_mission(creator=self.creator, description="需要播报任务")
|
||||
|
||||
mock_enqueue.assert_called_once()
|
||||
mock_speech_delay.assert_called_once()
|
||||
self.assertIn(str(mission.description), mock_speech_delay.call_args.kwargs["text"])
|
||||
|
||||
@patch("mission.handlers.enqueue_notification_event")
|
||||
def test_mission_created_handler_applies_category_payload_processor(self, mock_enqueue):
|
||||
self.default_category.payload_processor = "structured_description_v1"
|
||||
|
||||
Reference in New Issue
Block a user