mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-18 23:39:34 +00:00
Phase 1 - Repo Hardening: - README.md, LICENSE, SECURITY.md, CONTRIBUTING.md - GitHub Actions repo-hygiene workflow - docs/: ARCHITECTURE, DATA-MODEL, API-MAP, AGENT-MAP, DEPLOYMENT-NOTES Phase 2 - Database Models (7 new): - Company, Contact, Call, Commission, Payout, Dispute, GuaranteeClaim - Consent, Complaint, Policy, KnowledgeArticle, SectorAsset - Updated models/__init__.py with all 32+ models Phase 3 - API Surfaces (16 new route files): - companies, contacts, calls, meetings, commissions, payouts - disputes, guarantees, consents, complaints, knowledge - sectors, presentations, supervisor, admin, health - Updated router.py with all 24 route groups Phase 4 - AI Prompt Registry (18 agent contracts): - Lead Qualification, Affiliate Recruitment Evaluator, Onboarding Coach - Outreach Writer, Arabic WhatsApp, English Conversation, Voice Call - Meeting Booking, Sector Strategist, Objection Handler - Proposal Drafter, QA Reviewer, Compliance Reviewer - Knowledge Retrieval, Revenue Attribution, Fraud Reviewer - Guarantee Claim Reviewer, Management Summary Phase 5 - Communication Templates: - 15 production templates (WhatsApp, email, voice, internal) - Arabic + English variants with variable interpolation Phase 6 - Compliance Center (7 legal docs): - Privacy policy, Terms of service, Refund policy - Commission policy, Affiliate rules, Consent policy, Data protection - All PDPL-compliant, Arabic Phase 7 - Celery Workers (fully implemented): - follow_up_tasks: automated lead follow-ups with workflow execution - message_tasks: WhatsApp/email/SMS with retry logic - notification_tasks: daily reports, meeting reminders, in-app notifications - affiliate_tasks: target checking, commission calculation, weekly reports, AI outreach Phase 8 - Knowledge Base OS (8 files): - Services overview, Pricing policy, Channel policy, Meeting policy - Identity rules, Escalation rules, Hiring path, Internal SOPs https://claude.ai/code/session_01KnJgK7RwyeCvRZTRThHtfU
192 lines
6.3 KiB
Python
192 lines
6.3 KiB
Python
from app.workers.celery_app import celery_app
|
|
from app.config import get_settings
|
|
from app.database import SessionLocal
|
|
from datetime import datetime, timezone
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
settings = get_settings()
|
|
|
|
|
|
@celery_app.task(name="app.workers.message_tasks.send_scheduled_messages")
|
|
def send_scheduled_messages():
|
|
"""Send messages that are scheduled for delivery."""
|
|
from app.models.message import Message
|
|
from sqlalchemy import select, and_
|
|
|
|
logger.info("Processing scheduled messages...")
|
|
|
|
with SessionLocal() as db:
|
|
now = datetime.now(timezone.utc)
|
|
|
|
pending_messages = db.execute(
|
|
select(Message).where(
|
|
and_(
|
|
Message.status == "pending",
|
|
Message.scheduled_at <= now if hasattr(Message, 'scheduled_at') else True,
|
|
)
|
|
).limit(50)
|
|
).scalars().all()
|
|
|
|
sent_count = 0
|
|
failed_count = 0
|
|
|
|
for msg in pending_messages:
|
|
try:
|
|
if msg.channel == "whatsapp":
|
|
result = _send_whatsapp_message(msg.lead_id, msg.content, str(msg.tenant_id))
|
|
elif msg.channel == "email":
|
|
result = _send_email_message(msg)
|
|
elif msg.channel == "sms":
|
|
result = _send_sms_message(msg)
|
|
else:
|
|
logger.warning(f"Unknown channel: {msg.channel}")
|
|
continue
|
|
|
|
msg.status = "sent"
|
|
msg.sent_at = now
|
|
sent_count += 1
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to send message {msg.id}: {e}")
|
|
msg.status = "failed"
|
|
failed_count += 1
|
|
|
|
db.commit()
|
|
logger.info(f"Sent {sent_count}, failed {failed_count} of {len(pending_messages)} messages")
|
|
|
|
return {"sent": sent_count, "failed": failed_count}
|
|
|
|
|
|
@celery_app.task(name="app.workers.message_tasks.send_whatsapp", bind=True, max_retries=3)
|
|
def send_whatsapp(self, phone: str, message: str, tenant_id: str):
|
|
"""Send a WhatsApp message via Business API."""
|
|
from app.integrations.whatsapp import send_whatsapp_message
|
|
from app.models.message import Message
|
|
|
|
logger.info(f"Sending WhatsApp to {phone}")
|
|
|
|
try:
|
|
result = send_whatsapp_message(phone, message)
|
|
|
|
# Store message record
|
|
with SessionLocal() as db:
|
|
msg = Message(
|
|
tenant_id=tenant_id,
|
|
channel="whatsapp",
|
|
direction="outbound",
|
|
content=message,
|
|
status="sent",
|
|
sent_at=datetime.now(timezone.utc),
|
|
metadata={"phone": phone, "wa_message_id": result.get("messages", [{}])[0].get("id", "")},
|
|
)
|
|
db.add(msg)
|
|
db.commit()
|
|
|
|
logger.info(f"WhatsApp sent successfully to {phone}")
|
|
return {"status": "sent", "phone": phone}
|
|
|
|
except Exception as e:
|
|
logger.error(f"WhatsApp send failed to {phone}: {e}")
|
|
raise self.retry(exc=e, countdown=60 * (self.request.retries + 1))
|
|
|
|
|
|
@celery_app.task(name="app.workers.message_tasks.send_email", bind=True, max_retries=3)
|
|
def send_email(self, to_email: str, subject: str, body: str, tenant_id: str):
|
|
"""Send an email via configured provider."""
|
|
from app.integrations.email_sender import send_email as smtp_send
|
|
from app.models.message import Message
|
|
|
|
logger.info(f"Sending email to {to_email}")
|
|
|
|
try:
|
|
smtp_send(to_email, subject, body)
|
|
|
|
with SessionLocal() as db:
|
|
msg = Message(
|
|
tenant_id=tenant_id,
|
|
channel="email",
|
|
direction="outbound",
|
|
content=body,
|
|
status="sent",
|
|
sent_at=datetime.now(timezone.utc),
|
|
metadata={"to": to_email, "subject": subject},
|
|
)
|
|
db.add(msg)
|
|
db.commit()
|
|
|
|
logger.info(f"Email sent successfully to {to_email}")
|
|
return {"status": "sent", "email": to_email}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Email send failed to {to_email}: {e}")
|
|
raise self.retry(exc=e, countdown=60 * (self.request.retries + 1))
|
|
|
|
|
|
@celery_app.task(name="app.workers.message_tasks.send_sms", bind=True, max_retries=3)
|
|
def send_sms(self, phone: str, message: str, tenant_id: str):
|
|
"""Send SMS via Unifonic."""
|
|
from app.integrations.sms import send_sms as unifonic_send
|
|
from app.models.message import Message
|
|
|
|
logger.info(f"Sending SMS to {phone}")
|
|
|
|
try:
|
|
unifonic_send(phone, message)
|
|
|
|
with SessionLocal() as db:
|
|
msg = Message(
|
|
tenant_id=tenant_id,
|
|
channel="sms",
|
|
direction="outbound",
|
|
content=message,
|
|
status="sent",
|
|
sent_at=datetime.now(timezone.utc),
|
|
metadata={"phone": phone},
|
|
)
|
|
db.add(msg)
|
|
db.commit()
|
|
|
|
logger.info(f"SMS sent successfully to {phone}")
|
|
return {"status": "sent", "phone": phone}
|
|
|
|
except Exception as e:
|
|
logger.error(f"SMS send failed to {phone}: {e}")
|
|
raise self.retry(exc=e, countdown=60 * (self.request.retries + 1))
|
|
|
|
|
|
def _send_whatsapp_message(lead_id, content, tenant_id):
|
|
"""Helper to send WhatsApp from message record."""
|
|
from app.integrations.whatsapp import send_whatsapp_message
|
|
from app.models.lead import Lead
|
|
|
|
with SessionLocal() as db:
|
|
lead = db.get(Lead, lead_id)
|
|
if lead and lead.phone:
|
|
return send_whatsapp_message(lead.phone, content)
|
|
return None
|
|
|
|
|
|
def _send_email_message(msg):
|
|
"""Helper to send email from message record."""
|
|
from app.integrations.email_sender import send_email as smtp_send
|
|
from app.models.lead import Lead
|
|
|
|
with SessionLocal() as db:
|
|
lead = db.get(Lead, msg.lead_id) if msg.lead_id else None
|
|
if lead and lead.email:
|
|
smtp_send(lead.email, "Dealix - متابعة", msg.content)
|
|
return None
|
|
|
|
|
|
def _send_sms_message(msg):
|
|
"""Helper to send SMS from message record."""
|
|
from app.integrations.sms import send_sms as unifonic_send
|
|
from app.models.lead import Lead
|
|
|
|
with SessionLocal() as db:
|
|
lead = db.get(Lead, msg.lead_id) if msg.lead_id else None
|
|
if lead and lead.phone:
|
|
unifonic_send(lead.phone, msg.content)
|
|
return None
|