ethiotech4848 commited on
Commit
7b866e7
·
verified ·
1 Parent(s): ffee138

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +25 -163
app.py CHANGED
@@ -1,139 +1,3 @@
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,7 +6,7 @@ from openai import OpenAI
142
 
143
  app = FastAPI()
144
 
145
- # Load knowledge base
146
  with open("kb.json") as f:
147
  kb = json.load(f)
148
 
@@ -159,10 +23,10 @@ client.base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
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,56 +34,52 @@ 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,10 +99,11 @@ async def ask(request: Request):
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,6 +121,7 @@ async def send_chatwoot_message(conversation_id: str, content: str):
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={
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import json
3
  import httpx
 
6
 
7
  app = FastAPI()
8
 
9
+ # Load KB
10
  with open("kb.json") as f:
11
  kb = json.load(f)
12
 
 
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
  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
  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
  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={