feat: Build complete POC for Butler model (client, matrix, daemon)
This commit is contained in:
128
connector-superoffice/webhook_server.py
Normal file
128
connector-superoffice/webhook_server.py
Normal file
@@ -0,0 +1,128 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import os
|
||||
import sqlite3
|
||||
import hashlib
|
||||
from superoffice_client import SuperOfficeClient # Our new shiny client class
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
DB_FILE = "marketing_matrix.db"
|
||||
|
||||
# UDF ProgIds (from our plan)
|
||||
PROG_ID_CONTACT_VERTICAL = "SuperOffice:5"
|
||||
PROG_ID_PERSON_ROLE = "SuperOffice:3"
|
||||
PROG_ID_CONTACT_CHALLENGE = "SuperOffice:6"
|
||||
PROG_ID_PERSON_SUBJECT = "SuperOffice:5"
|
||||
PROG_ID_PERSON_INTRO = "SuperOffice:6"
|
||||
PROG_ID_PERSON_PROOF = "SuperOffice:7"
|
||||
PROG_ID_PERSON_HASH = "SuperOffice:8"
|
||||
|
||||
# --- CORE LOGIC ---
|
||||
def get_text_from_matrix(vertical_id, role_id):
|
||||
"""Fetches the pre-generated text block from the local SQLite DB."""
|
||||
conn = sqlite3.connect(DB_FILE)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT subject, intro, social_proof FROM text_blocks WHERE vertical_id = ? AND role_id = ?", (vertical_id, role_id))
|
||||
row = c.fetchone()
|
||||
conn.close()
|
||||
return row if row else (None, None, None)
|
||||
|
||||
def process_single_person(client: SuperOfficeClient, person_id: int):
|
||||
"""Central logic to update marketing copy for a single person."""
|
||||
print(f"Processing Person ID: {person_id}")
|
||||
|
||||
person_data = client.get_person(person_id)
|
||||
if not person_data:
|
||||
raise ValueError(f"Person {person_id} not found")
|
||||
|
||||
contact_id = person_data.get('contact', {}).get('contactId')
|
||||
if not contact_id:
|
||||
raise ValueError("Person is not linked to a Contact")
|
||||
|
||||
contact_data = client.get_contact(contact_id)
|
||||
if not contact_data:
|
||||
raise ValueError(f"Contact {contact_id} not found")
|
||||
|
||||
# Extract and clean Vertical and Role IDs
|
||||
vertical_id_raw = contact_data["UserDefinedFields"].get(PROG_ID_CONTACT_VERTICAL, "")
|
||||
role_id_raw = person_data["UserDefinedFields"].get(PROG_ID_PERSON_ROLE, "")
|
||||
|
||||
if not vertical_id_raw or not role_id_raw:
|
||||
raise ValueError("Vertical or Role ID is not set.")
|
||||
|
||||
vertical_id = int(vertical_id_raw.replace("[I:", "").replace("]", ""))
|
||||
role_id = int(role_id_raw.replace("[I:", "").replace("]", ""))
|
||||
|
||||
# Get text from matrix
|
||||
subject, intro, proof = get_text_from_matrix(vertical_id, role_id)
|
||||
if not subject:
|
||||
raise ValueError(f"No text found in matrix for V:{vertical_id}, R:{role_id}")
|
||||
|
||||
# Generate Hash
|
||||
text_concat = f"{subject}{intro}{proof}"
|
||||
copy_hash = hashlib.md5(text_concat.encode()).hexdigest()
|
||||
|
||||
# Prepare payloads
|
||||
contact_payload = {PROG_ID_CONTACT_CHALLENGE: intro}
|
||||
person_payload = {
|
||||
PROG_ID_PERSON_SUBJECT: subject,
|
||||
PROG_ID_PERSON_INTRO: intro,
|
||||
PROG_ID_PERSON_PROOF: proof,
|
||||
PROG_ID_PERSON_HASH: copy_hash
|
||||
}
|
||||
|
||||
# Inject data
|
||||
client.update_udfs("Contact", contact_id, contact_payload)
|
||||
client.update_udfs("Person", person_id, person_payload)
|
||||
|
||||
return f"Updated Person {person_id} with texts for V:{vertical_id}/R:{role_id}"
|
||||
|
||||
# --- WEBHOOK ENDPOINTS ---
|
||||
@app.route('/regenerate_for_person', methods=['POST'])
|
||||
def webhook_person():
|
||||
data = request.get_json()
|
||||
if not data or "person_id" not in data:
|
||||
return jsonify({"error": "Missing person_id"}), 400
|
||||
|
||||
try:
|
||||
client = SuperOfficeClient()
|
||||
message = process_single_person(client, data['person_id'])
|
||||
return jsonify({"status": "success", "message": message}), 200
|
||||
except Exception as e:
|
||||
print(f"❌ Error processing person: {e}")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.route('/regenerate_for_contact', methods=['POST'])
|
||||
def webhook_contact():
|
||||
data = request.get_json()
|
||||
if not data or "contact_id" not in data:
|
||||
return jsonify({"error": "Missing contact_id"}), 400
|
||||
|
||||
contact_id = data['contact_id']
|
||||
print(f"Received request to regenerate for all persons in Contact ID: {contact_id}")
|
||||
|
||||
try:
|
||||
client = SuperOfficeClient()
|
||||
contact = client.get_contact(contact_id)
|
||||
if not contact or not contact.get('persons'):
|
||||
return jsonify({"status": "success", "message": "No persons found for this contact."}), 200
|
||||
|
||||
updated_count = 0
|
||||
for person_summary in contact['persons']:
|
||||
try:
|
||||
process_single_person(client, person_summary['personId'])
|
||||
updated_count += 1
|
||||
except Exception as e:
|
||||
print(f" - Skipping Person {person_summary.get('personId')}: {e}")
|
||||
|
||||
return jsonify({"status": "success", "message": f"Processed {updated_count} persons for Contact {contact_id}"}), 200
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error processing contact: {e}")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
if __name__ == '__main__':
|
||||
# For local dev. Use a proper WSGI server (Gunicorn) for production.
|
||||
# Needs pip install Flask
|
||||
app.run(host='0.0.0.0', port=5001, debug=True)
|
||||
Reference in New Issue
Block a user