ethiotech4848 commited on
Commit
ffee138
Β·
verified Β·
1 Parent(s): 6a717a0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +163 -25
app.py CHANGED
@@ -1,3 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import json
3
  import httpx
@@ -6,7 +142,7 @@ from openai import OpenAI
6
 
7
  app = FastAPI()
8
 
9
- # Load KB
10
  with open("kb.json") as f:
11
  kb = json.load(f)
12
 
@@ -23,10 +159,10 @@ client.base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
23
  # Chatwoot config
24
  CHATWOOT_BASE_URL = os.getenv("CHATWOOT_BASE_URL")
25
  CHATWOOT_API_KEY = os.getenv("CHATWOOT_API_KEY")
26
- CHATWOOT_ACCOUNT_ID = int(os.getenv("CHATWOOT_ACCOUNT_ID")) # e.g., 123911
27
 
28
- # Track conversations where AI should stop replying
29
- stop_reply_conversations = set()
30
 
31
  @app.post("/ask")
32
  async def ask(request: Request):
@@ -34,52 +170,56 @@ async def ask(request: Request):
34
  print("πŸ“₯ Incoming payload:", json.dumps(payload, indent=2))
35
 
36
  account_id = payload.get("account", {}).get("id")
37
- conversation_id = str(payload.get("conversation", {}).get("id"))
38
- sender = payload.get("sender") or {}
 
39
  sender_id = sender.get("id")
40
  sender_role = (sender.get("role") or "").lower()
41
  message_type = payload.get("message_type", "").lower()
42
  message_content = payload.get("content", "").strip()
 
 
 
 
43
 
44
- print(f"🧾 sender_id: {sender_id}, sender_role: {sender_role}, account_id: {account_id}")
45
 
46
- # Step 1: Detect agent message via Slack and disable AI for that conversation
47
  if message_type != "incoming":
48
- messages = payload.get("conversation", {}).get("messages", [])
49
  if messages:
50
  msg = messages[0]
51
  external_ids = msg.get("external_source_ids", {})
52
  if "slack" in external_ids:
53
- stop_reply_conversations.add(conversation_id)
54
- print(f"πŸ›‘ Human intervened via Slack in conversation {conversation_id}. Disabling AI.")
55
  return {"status": "AI disabled due to Slack intervention"}
56
-
57
  print("⚠️ Ignoring non-incoming message")
58
  return {"status": "ignored"}
59
 
60
- # Bot must not reply to itself
61
  if sender_id == account_id:
62
  print("⚠️ Ignoring bot's own message")
63
  return {"status": "ignored"}
64
 
65
- # Handle special bot resume command
66
  if sender_role == "agent" and message_content.lower() == "#botresume":
67
- stop_reply_conversations.discard(conversation_id)
68
- print(f"ℹ️ Bot resumed for conversation {conversation_id}")
69
  await send_chatwoot_message(conversation_id, "Bot resumed and will reply to users now.")
70
  return {"status": "bot resumed"}
71
 
72
- # Check if AI is blacklisted for this conversation
73
- if conversation_id in stop_reply_conversations:
74
- print(f"🚫 AI is disabled for conversation {conversation_id}")
75
  return {"status": "ignored: human takeover"}
76
 
77
- # Ensure all data is present
78
  if not message_content or not conversation_id:
79
  print("❌ Missing content or conversation ID")
80
  return {"status": "invalid payload"}
81
 
82
- # Build messages for GPT
83
  messages = [
84
  {"role": "system", "content": system_prompt},
85
  {"role": "user", "content": message_content},
@@ -99,11 +239,10 @@ async def ask(request: Request):
99
  answer = "Sorry, I'm having trouble answering right now."
100
 
101
  if answer == "I'm not sure about that. Let me connect you with a human agent.":
102
- stop_reply_conversations.add(conversation_id)
103
- print(f"🚫 Fallback answer, disabling AI for conversation {conversation_id}")
104
 
105
  await send_chatwoot_message(conversation_id, answer)
106
-
107
  return {"status": "ok"}
108
 
109
 
@@ -121,7 +260,6 @@ async def send_chatwoot_message(conversation_id: str, content: str):
121
  url = f"{CHATWOOT_BASE_URL}/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{conversation_id}/messages"
122
  print("πŸ“€ Sending to Chatwoot:", url)
123
  print("πŸ“¦ Payload:", json.dumps(message_payload, indent=2))
124
-
125
  resp = await http.post(
126
  url,
127
  headers={
 
1
+ # import os
2
+ # import json
3
+ # import httpx
4
+ # from fastapi import FastAPI, Request
5
+ # from openai import OpenAI
6
+
7
+ # app = FastAPI()
8
+
9
+ # # Load KB
10
+ # with open("kb.json") as f:
11
+ # kb = json.load(f)
12
+
13
+ # # Build system prompt
14
+ # system_prompt = "You are a helpful assistant. Only answer questions based on the following knowledge base:\n\n"
15
+ # for q, a in kb.items():
16
+ # system_prompt += f"Q: {q}\nA: {a}\n\n"
17
+ # system_prompt += "If the question is not in the knowledge base, respond with: 'I'm not sure about that. Let me connect you with a human agent.'"
18
+
19
+ # # OpenAI setup
20
+ # client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
21
+ # client.base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
22
+
23
+ # # Chatwoot config
24
+ # CHATWOOT_BASE_URL = os.getenv("CHATWOOT_BASE_URL")
25
+ # CHATWOOT_API_KEY = os.getenv("CHATWOOT_API_KEY")
26
+ # CHATWOOT_ACCOUNT_ID = int(os.getenv("CHATWOOT_ACCOUNT_ID")) # e.g., 123911
27
+
28
+ # # Track conversations where AI should stop replying
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
+ # account_id = payload.get("account", {}).get("id")
37
+ # conversation_id = str(payload.get("conversation", {}).get("id"))
38
+ # sender = payload.get("sender") or {}
39
+ # sender_id = sender.get("id")
40
+ # sender_role = (sender.get("role") or "").lower()
41
+ # message_type = payload.get("message_type", "").lower()
42
+ # message_content = payload.get("content", "").strip()
43
+
44
+ # print(f"🧾 sender_id: {sender_id}, sender_role: {sender_role}, account_id: {account_id}")
45
+
46
+ # # Step 1: Detect agent message via Slack and disable AI for that conversation
47
+ # if message_type != "incoming":
48
+ # messages = payload.get("conversation", {}).get("messages", [])
49
+ # if messages:
50
+ # msg = messages[0]
51
+ # external_ids = msg.get("external_source_ids", {})
52
+ # if "slack" in external_ids:
53
+ # stop_reply_conversations.add(conversation_id)
54
+ # print(f"πŸ›‘ Human intervened via Slack in conversation {conversation_id}. Disabling AI.")
55
+ # return {"status": "AI disabled due to Slack intervention"}
56
+
57
+ # print("⚠️ Ignoring non-incoming message")
58
+ # return {"status": "ignored"}
59
+
60
+ # # Bot must not reply to itself
61
+ # if sender_id == account_id:
62
+ # print("⚠️ Ignoring bot's own message")
63
+ # return {"status": "ignored"}
64
+
65
+ # # Handle special bot resume command
66
+ # if sender_role == "agent" and message_content.lower() == "#botresume":
67
+ # stop_reply_conversations.discard(conversation_id)
68
+ # print(f"ℹ️ Bot resumed for conversation {conversation_id}")
69
+ # await send_chatwoot_message(conversation_id, "Bot resumed and will reply to users now.")
70
+ # return {"status": "bot resumed"}
71
+
72
+ # # Check if AI is blacklisted for this conversation
73
+ # if conversation_id in stop_reply_conversations:
74
+ # print(f"🚫 AI is disabled for conversation {conversation_id}")
75
+ # return {"status": "ignored: human takeover"}
76
+
77
+ # # Ensure all data is present
78
+ # if not message_content or not conversation_id:
79
+ # print("❌ Missing content or conversation ID")
80
+ # return {"status": "invalid payload"}
81
+
82
+ # # Build messages for GPT
83
+ # messages = [
84
+ # {"role": "system", "content": system_prompt},
85
+ # {"role": "user", "content": message_content},
86
+ # ]
87
+
88
+ # try:
89
+ # response = client.chat.completions.create(
90
+ # model="gpt-4o-mini",
91
+ # messages=messages,
92
+ # temperature=0,
93
+ # max_tokens=200,
94
+ # )
95
+ # answer = response.choices[0].message.content.strip()
96
+ # print("βœ… GPT Answer:", answer)
97
+ # except Exception as e:
98
+ # print("❌ OpenAI Error:", e)
99
+ # answer = "Sorry, I'm having trouble answering right now."
100
+
101
+ # if answer == "I'm not sure about that. Let me connect you with a human agent.":
102
+ # stop_reply_conversations.add(conversation_id)
103
+ # print(f"🚫 Fallback answer, disabling AI for conversation {conversation_id}")
104
+
105
+ # await send_chatwoot_message(conversation_id, answer)
106
+
107
+ # return {"status": "ok"}
108
+
109
+
110
+ # async def send_chatwoot_message(conversation_id: str, content: str):
111
+ # message_payload = {
112
+ # "content": content,
113
+ # "message_type": "outgoing",
114
+ # "private": False,
115
+ # "content_type": "text",
116
+ # "content_attributes": {}
117
+ # }
118
+
119
+ # try:
120
+ # async with httpx.AsyncClient() as http:
121
+ # url = f"{CHATWOOT_BASE_URL}/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{conversation_id}/messages"
122
+ # print("πŸ“€ Sending to Chatwoot:", url)
123
+ # print("πŸ“¦ Payload:", json.dumps(message_payload, indent=2))
124
+
125
+ # resp = await http.post(
126
+ # url,
127
+ # headers={
128
+ # "Content-Type": "application/json",
129
+ # "api_access_token": CHATWOOT_API_KEY,
130
+ # },
131
+ # json=message_payload,
132
+ # )
133
+ # print("πŸ“¬ Chatwoot Response:", resp.status_code, resp.text)
134
+ # except Exception as e:
135
+ # print("❌ Chatwoot Send Error:", e)
136
+
137
  import os
138
  import json
139
  import httpx
 
142
 
143
  app = FastAPI()
144
 
145
+ # Load knowledge base
146
  with open("kb.json") as f:
147
  kb = json.load(f)
148
 
 
159
  # Chatwoot config
160
  CHATWOOT_BASE_URL = os.getenv("CHATWOOT_BASE_URL")
161
  CHATWOOT_API_KEY = os.getenv("CHATWOOT_API_KEY")
162
+ CHATWOOT_ACCOUNT_ID = int(os.getenv("CHATWOOT_ACCOUNT_ID"))
163
 
164
+ # Track temporarily blocked sessions (session_key = sender_id + last_seen_at)
165
+ stop_reply_sessions = set()
166
 
167
  @app.post("/ask")
168
  async def ask(request: Request):
 
170
  print("πŸ“₯ Incoming payload:", json.dumps(payload, indent=2))
171
 
172
  account_id = payload.get("account", {}).get("id")
173
+ conversation = payload.get("conversation", {})
174
+ conversation_id = str(conversation.get("id"))
175
+ sender = payload.get("sender", {}) or {}
176
  sender_id = sender.get("id")
177
  sender_role = (sender.get("role") or "").lower()
178
  message_type = payload.get("message_type", "").lower()
179
  message_content = payload.get("content", "").strip()
180
+ sender_last_seen = sender.get("last_seen_at") or "unknown"
181
+
182
+ # Session key: changes when user reloads/returns
183
+ session_key = f"{sender_id}_{sender_last_seen}"
184
 
185
+ print(f"🧾 session_key: {session_key}, sender_role: {sender_role}, account_id: {account_id}")
186
 
187
+ # Step 1: Detect agent message via Slack and disable AI for current session
188
  if message_type != "incoming":
189
+ messages = conversation.get("messages", [])
190
  if messages:
191
  msg = messages[0]
192
  external_ids = msg.get("external_source_ids", {})
193
  if "slack" in external_ids:
194
+ stop_reply_sessions.add(session_key)
195
+ print(f"πŸ›‘ Human intervened via Slack. Disabling AI for session {session_key}.")
196
  return {"status": "AI disabled due to Slack intervention"}
 
197
  print("⚠️ Ignoring non-incoming message")
198
  return {"status": "ignored"}
199
 
200
+ # Don't reply to own messages
201
  if sender_id == account_id:
202
  print("⚠️ Ignoring bot's own message")
203
  return {"status": "ignored"}
204
 
205
+ # Handle manual resume
206
  if sender_role == "agent" and message_content.lower() == "#botresume":
207
+ stop_reply_sessions.discard(session_key)
208
+ print(f"ℹ️ Bot resumed for session {session_key}")
209
  await send_chatwoot_message(conversation_id, "Bot resumed and will reply to users now.")
210
  return {"status": "bot resumed"}
211
 
212
+ # Check if AI is disabled for current session
213
+ if session_key in stop_reply_sessions:
214
+ print(f"🚫 AI is disabled for session {session_key}")
215
  return {"status": "ignored: human takeover"}
216
 
217
+ # Validate data
218
  if not message_content or not conversation_id:
219
  print("❌ Missing content or conversation ID")
220
  return {"status": "invalid payload"}
221
 
222
+ # Prepare messages for GPT
223
  messages = [
224
  {"role": "system", "content": system_prompt},
225
  {"role": "user", "content": message_content},
 
239
  answer = "Sorry, I'm having trouble answering right now."
240
 
241
  if answer == "I'm not sure about that. Let me connect you with a human agent.":
242
+ stop_reply_sessions.add(session_key)
243
+ print(f"🚫 Fallback answer, disabling AI for session {session_key}")
244
 
245
  await send_chatwoot_message(conversation_id, answer)
 
246
  return {"status": "ok"}
247
 
248
 
 
260
  url = f"{CHATWOOT_BASE_URL}/api/v1/accounts/{CHATWOOT_ACCOUNT_ID}/conversations/{conversation_id}/messages"
261
  print("πŸ“€ Sending to Chatwoot:", url)
262
  print("πŸ“¦ Payload:", json.dumps(message_payload, indent=2))
 
263
  resp = await http.post(
264
  url,
265
  headers={