ethiotech4848 commited on
Commit
4b3f578
·
verified ·
1 Parent(s): 0463b13

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -87
app.py CHANGED
@@ -28,79 +28,6 @@ CHATWOOT_ACCOUNT_ID = os.getenv("CHATWOOT_ACCOUNT_ID") # Account ID (integ
28
  # Add at the top after imports:
29
  stop_reply_conversations = set()
30
 
31
- # @app.post("/ask")
32
- # async def ask(request: Request):
33
- # payload = await request.json()
34
- # print("📥 Incoming payload:", json.dumps(payload, indent=2))
35
-
36
- # message_type = payload.get("message_type", "").lower()
37
- # account_id = payload.get("account", {}).get("id") # bot's account id
38
- # sender_id = payload.get("sender", {}).get("id") # sender id of this message
39
-
40
- # # Only respond to incoming messages
41
- # if message_type != "incoming":
42
- # print("⚠️ Ignoring non-incoming messages")
43
- # return {"status": "ignored"}
44
-
45
- # # Ignore messages sent by bot itself (to avoid loops)
46
- # if sender_id == account_id:
47
- # print("⚠️ Ignoring message from bot itself to prevent loop.")
48
- # return {"status": "ignored"}
49
-
50
- # # Extract user question and conversation id
51
- # user_question = payload.get("content", "")
52
- # conversation_id = payload.get("conversation", {}).get("id")
53
- # if not user_question or not conversation_id or not CHATWOOT_ACCOUNT_ID:
54
- # print("❌ Missing message, conversation ID, or account ID")
55
- # return {"status": "invalid payload"}
56
-
57
- # messages = [
58
- # {"role": "system", "content": system_prompt},
59
- # {"role": "user", "content": user_question},
60
- # ]
61
-
62
- # try:
63
- # response = client.chat.completions.create(
64
- # model="gpt-4o-mini",
65
- # messages=messages,
66
- # temperature=0,
67
- # max_tokens=200,
68
- # )
69
- # answer = response.choices[0].message.content.strip()
70
- # print("✅ OpenAI Answer:", answer)
71
- # except Exception as e:
72
- # print("❌ OpenAI Error:", e)
73
- # answer = "Sorry, I'm having trouble answering right now."
74
-
75
- # message_payload = {
76
- # "content": answer,
77
- # "message_type": "outgoing",
78
- # "private": False,
79
- # "content_type": "text",
80
- # "content_attributes": {}
81
- # }
82
-
83
- # try:
84
- # async with httpx.AsyncClient() as http:
85
- # chatwoot_url = f"{CHATWOOT_BASE_URL}/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{conversation_id}/messages"
86
- # print("📤 Sending to Chatwoot:", chatwoot_url)
87
- # print("📦 Payload to Chatwoot:", json.dumps(message_payload, indent=2))
88
-
89
- # resp = await http.post(
90
- # chatwoot_url,
91
- # headers={
92
- # "Content-Type": "application/json",
93
- # "api_access_token": CHATWOOT_API_KEY,
94
- # },
95
- # json=message_payload,
96
- # )
97
- # print("📬 Chatwoot Response:", resp.status_code, resp.text)
98
-
99
- # except Exception as e:
100
- # print("❌ Chatwoot Send Error:", e)
101
-
102
- # return {"status": "ok"}
103
-
104
  @app.post("/ask")
105
  async def ask(request: Request):
106
  payload = await request.json()
@@ -110,6 +37,8 @@ async def ask(request: Request):
110
  account_id = payload.get("account", {}).get("id")
111
  sender_id = payload.get("sender", {}).get("id")
112
  conversation_id = payload.get("conversation", {}).get("id")
 
 
113
 
114
  # Only respond to incoming messages
115
  if message_type != "incoming":
@@ -121,19 +50,35 @@ async def ask(request: Request):
121
  print("⚠️ Ignoring message from bot itself")
122
  return {"status": "ignored"}
123
 
124
- # If conversation is blacklisted (bot should stop replying)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  if conversation_id in stop_reply_conversations:
126
- print(f"⚠️ Conversation {conversation_id} is blacklisted, no reply sent.")
127
- return {"status": "ignored"}
128
 
129
- user_question = payload.get("content", "")
130
- if not user_question or not conversation_id or not CHATWOOT_ACCOUNT_ID:
131
- print("❌ Missing message, conversation ID, or account ID")
132
  return {"status": "invalid payload"}
133
 
 
134
  messages = [
135
  {"role": "system", "content": system_prompt},
136
- {"role": "user", "content": user_question},
137
  ]
138
 
139
  try:
@@ -149,19 +94,26 @@ async def ask(request: Request):
149
  print("❌ OpenAI Error:", e)
150
  answer = "Sorry, I'm having trouble answering right now."
151
 
152
- # If answer is "I'm not sure about that..." message, blacklist this conversation
153
- if answer == "I'm not sure about that. Let me connect you with a human agent.":
 
154
  stop_reply_conversations.add(conversation_id)
155
- print(f"⚠️ Added conversation {conversation_id} to stop reply blacklist.")
 
 
 
156
 
 
 
 
 
157
  message_payload = {
158
- "content": answer,
159
  "message_type": "outgoing",
160
  "private": False,
161
  "content_type": "text",
162
  "content_attributes": {}
163
  }
164
-
165
  try:
166
  async with httpx.AsyncClient() as http:
167
  chatwoot_url = f"{CHATWOOT_BASE_URL}/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{conversation_id}/messages"
@@ -177,8 +129,6 @@ async def ask(request: Request):
177
  json=message_payload,
178
  )
179
  print("📬 Chatwoot Response:", resp.status_code, resp.text)
180
-
181
  except Exception as e:
182
  print("❌ Chatwoot Send Error:", e)
183
-
184
  return {"status": "ok"}
 
28
  # Add at the top after imports:
29
  stop_reply_conversations = set()
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  @app.post("/ask")
32
  async def ask(request: Request):
33
  payload = await request.json()
 
37
  account_id = payload.get("account", {}).get("id")
38
  sender_id = payload.get("sender", {}).get("id")
39
  conversation_id = payload.get("conversation", {}).get("id")
40
+ sender_role = payload.get("sender", {}).get("role", "").lower() # e.g. "agent", "contact", "bot"
41
+ message_content = payload.get("content", "").strip()
42
 
43
  # Only respond to incoming messages
44
  if message_type != "incoming":
 
50
  print("⚠️ Ignoring message from bot itself")
51
  return {"status": "ignored"}
52
 
53
+ # Handle human agent takeover: if agent sends message, stop AI replies
54
+ if sender_role == "agent":
55
+ # If agent sends special command to resume bot
56
+ if message_content.lower() == "/botresume":
57
+ if conversation_id in stop_reply_conversations:
58
+ stop_reply_conversations.remove(conversation_id)
59
+ print(f"ℹ️ Bot resumed for conversation {conversation_id} by human agent command.")
60
+ # Optionally send confirmation message back to chatwoot
61
+ await send_chatwoot_message(conversation_id, "Bot resumed and will reply to users now.")
62
+ return {"status": "human takeover - bot resume command"}
63
+
64
+ # Otherwise, mark conversation as blacklisted to stop AI replies
65
+ stop_reply_conversations.add(conversation_id)
66
+ print(f"⚠️ Human agent message detected. Conversation {conversation_id} blacklisted for AI replies.")
67
+ return {"status": "human takeover activated"}
68
+
69
+ # If conversation is blacklisted, ignore user messages (don't reply)
70
  if conversation_id in stop_reply_conversations:
71
+ print(f"⚠️ Conversation {conversation_id} is blacklisted, no AI reply sent.")
72
+ return {"status": "ignored due to human takeover"}
73
 
74
+ if not message_content or not conversation_id or not CHATWOOT_ACCOUNT_ID:
75
+ print("❌ Missing message content, conversation ID, or account ID")
 
76
  return {"status": "invalid payload"}
77
 
78
+ # Prepare messages for OpenAI chat completion
79
  messages = [
80
  {"role": "system", "content": system_prompt},
81
+ {"role": "user", "content": message_content},
82
  ]
83
 
84
  try:
 
94
  print("❌ OpenAI Error:", e)
95
  answer = "Sorry, I'm having trouble answering right now."
96
 
97
+ # If fallback answer detected, blacklist conversation to stop further AI replies
98
+ fallback_msg = "I'm not sure about that. Let me connect you with a human agent."
99
+ if answer == fallback_msg:
100
  stop_reply_conversations.add(conversation_id)
101
+ print(f"⚠️ Added conversation {conversation_id} to stop reply blacklist due to fallback answer.")
102
+
103
+ # Send AI reply back to Chatwoot
104
+ await send_chatwoot_message(conversation_id, answer)
105
 
106
+ return {"status": "ok"}
107
+
108
+
109
+ async def send_chatwoot_message(conversation_id: str, content: str):
110
  message_payload = {
111
+ "content": content,
112
  "message_type": "outgoing",
113
  "private": False,
114
  "content_type": "text",
115
  "content_attributes": {}
116
  }
 
117
  try:
118
  async with httpx.AsyncClient() as http:
119
  chatwoot_url = f"{CHATWOOT_BASE_URL}/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{conversation_id}/messages"
 
129
  json=message_payload,
130
  )
131
  print("📬 Chatwoot Response:", resp.status_code, resp.text)
 
132
  except Exception as e:
133
  print("❌ Chatwoot Send Error:", e)
 
134
  return {"status": "ok"}