zenaight commited on
Commit
618e187
·
1 Parent(s): 5f13f2a

langgraph setup

Browse files
Files changed (2) hide show
  1. main.py +60 -75
  2. requirements.txt +5 -1
main.py CHANGED
@@ -5,31 +5,55 @@ import httpx
5
  from openai import OpenAI
6
  from pydantic import BaseModel
7
  from typing import Optional
 
 
 
 
8
 
 
9
  app = FastAPI()
10
-
11
  VERIFY_TOKEN = os.getenv("VERIFY_TOKEN", "")
12
  PHONE_NUMBER_ID = os.getenv("PHONE_NUMBER_ID", "")
13
  WHATSAPP_API_TOKEN = os.getenv("WHATSAPP_API_TOKEN", "")
14
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
15
 
16
- # Initialize OpenAI client
17
- openai_client = None
18
- if OPENAI_API_KEY:
19
- openai_client = OpenAI(api_key=OPENAI_API_KEY)
20
 
21
- # Pydantic model for chat requests
22
- class ChatRequest(BaseModel):
23
- message: str
24
- model: Optional[str] = "gpt-4o-mini" # Using the cheapest OpenAI model
25
- max_tokens: Optional[int] = 150
26
 
27
- # Pydantic model for chat responses
28
- class ChatResponse(BaseModel):
29
- response: str
30
- model: str
31
- tokens_used: Optional[int] = None
 
 
 
 
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  @app.get("/webhook")
34
  def verify_webhook(
35
  hub_mode: str = Query(None, alias="hub.mode"),
@@ -40,6 +64,7 @@ def verify_webhook(
40
  return PlainTextResponse(hub_challenge)
41
  raise HTTPException(status_code=403, detail="Invalid token")
42
 
 
43
  @app.post("/webhook")
44
  async def receive_message(req: Request):
45
  body = await req.json()
@@ -56,14 +81,9 @@ async def receive_message(req: Request):
56
  msg = messages[0]
57
 
58
  if msg.get("type") == "text":
59
- # Get the user's message
60
  user_message = msg.get("text", {}).get("body", "")
61
-
62
- # Generate AI response using OpenAI
63
- ai_response = await generate_ai_response(user_message)
64
-
65
- # Send the AI response back to WhatsApp
66
- await send_whatsapp_message(wa_id, ai_response)
67
  return JSONResponse({"status": "replied"})
68
 
69
  except Exception as e:
@@ -72,58 +92,7 @@ async def receive_message(req: Request):
72
 
73
  return JSONResponse({"status": "ignored"})
74
 
75
- async def generate_ai_response(user_message: str) -> str:
76
- """Generate AI response using OpenAI API"""
77
- if not openai_client:
78
- return "Sorry, AI chat is not available. Please check your OpenAI API key configuration."
79
-
80
- try:
81
- response = openai_client.chat.completions.create(
82
- model="gpt-4o-mini",
83
- messages=[
84
- {"role": "system", "content": "You are a helpful assistant. Keep your responses concise and friendly."},
85
- {"role": "user", "content": user_message}
86
- ],
87
- max_tokens=150,
88
- temperature=0.7
89
- )
90
-
91
- ai_response = response.choices[0].message.content
92
- return ai_response if ai_response else "I'm sorry, I couldn't generate a response."
93
-
94
- except Exception as e:
95
- print(f"Error generating AI response: {e}")
96
- return "Sorry, I'm having trouble processing your request right now."
97
-
98
- @app.post("/chat", response_model=ChatResponse)
99
- async def chat_with_ai(request: ChatRequest):
100
- """Basic chat endpoint for direct API calls"""
101
- if not openai_client:
102
- raise HTTPException(status_code=500, detail="OpenAI API key not configured")
103
-
104
- try:
105
- response = openai_client.chat.completions.create(
106
- model=request.model,
107
- messages=[
108
- {"role": "system", "content": "You are a helpful assistant. Keep your responses concise and friendly."},
109
- {"role": "user", "content": request.message}
110
- ],
111
- max_tokens=request.max_tokens,
112
- temperature=0.7
113
- )
114
-
115
- ai_response = response.choices[0].message.content
116
- usage = response.usage
117
-
118
- return ChatResponse(
119
- response=ai_response,
120
- model=request.model,
121
- tokens_used=usage.total_tokens if usage else None
122
- )
123
-
124
- except Exception as e:
125
- raise HTTPException(status_code=500, detail=f"Error generating response: {str(e)}")
126
-
127
  async def send_whatsapp_message(wa_id: str, message: str):
128
  url = f"https://graph.facebook.com/v18.0/{PHONE_NUMBER_ID}/messages"
129
  headers = {
@@ -142,13 +111,29 @@ async def send_whatsapp_message(wa_id: str, message: str):
142
  except Exception as e:
143
  print(f"Failed to send message: {e}")
144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  @app.get("/ping")
146
  def ping():
147
  return {"pong": True}
148
 
149
  @app.get("/health")
150
  def health_check():
151
- """Health check endpoint to verify API connectivity"""
152
  status = {
153
  "api": "healthy",
154
  "whatsapp": "configured" if WHATSAPP_API_TOKEN else "not configured",
 
5
  from openai import OpenAI
6
  from pydantic import BaseModel
7
  from typing import Optional
8
+ from langgraph.graph import StateGraph, END
9
+ from langchain_core.runnables import RunnableLambda
10
+ from langchain.memory import ConversationBufferMemory
11
+ from langchain_openai import ChatOpenAI
12
 
13
+ # --- App and Config ---
14
  app = FastAPI()
 
15
  VERIFY_TOKEN = os.getenv("VERIFY_TOKEN", "")
16
  PHONE_NUMBER_ID = os.getenv("PHONE_NUMBER_ID", "")
17
  WHATSAPP_API_TOKEN = os.getenv("WHATSAPP_API_TOKEN", "")
18
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
19
 
20
+ # --- OpenAI Client Setup ---
21
+ llm = ChatOpenAI(openai_api_key=OPENAI_API_KEY, model="gpt-4o-mini")
22
+ memory = ConversationBufferMemory(return_messages=True, memory_key="chat_history")
 
23
 
24
+ # Initialize LLM only if API key is available
25
+ if not OPENAI_API_KEY:
26
+ print("Warning: OPENAI_API_KEY not set. AI functionality will be limited.")
 
 
27
 
28
+ # --- LangGraph Setup ---
29
+ def chat_with_memory(state):
30
+ user_message = state["user_message"]
31
+ memory.chat_memory.add_user_message(user_message)
32
+
33
+ messages = memory.chat_memory.messages[-6:] # Use last few messages
34
+ messages = [{"role": msg.type, "content": msg.content} for msg in messages]
35
+
36
+ messages.insert(0, {"role": "system", "content": "You are a helpful and concise assistant."})
37
 
38
+ try:
39
+ if not OPENAI_API_KEY:
40
+ return {"response": "Sorry, AI chat is not available. Please check your OpenAI API key configuration."}
41
+
42
+ response = llm.invoke(messages)
43
+ memory.chat_memory.add_ai_message(response.content)
44
+ return {"response": response.content}
45
+ except Exception as e:
46
+ print(f"Error in chat_with_memory: {e}")
47
+ return {"response": "Sorry, something went wrong: " + str(e)}
48
+
49
+ # --- Build LangGraph ---
50
+ graph = StateGraph()
51
+ graph.add_node("chat", RunnableLambda(chat_with_memory))
52
+ graph.set_entry_point("chat")
53
+ graph.set_finish_point("chat")
54
+ chat_graph = graph.compile()
55
+
56
+ # --- Webhook Verification ---
57
  @app.get("/webhook")
58
  def verify_webhook(
59
  hub_mode: str = Query(None, alias="hub.mode"),
 
64
  return PlainTextResponse(hub_challenge)
65
  raise HTTPException(status_code=403, detail="Invalid token")
66
 
67
+ # --- Webhook Receiver ---
68
  @app.post("/webhook")
69
  async def receive_message(req: Request):
70
  body = await req.json()
 
81
  msg = messages[0]
82
 
83
  if msg.get("type") == "text":
 
84
  user_message = msg.get("text", {}).get("body", "")
85
+ ai_result = await chat_graph.ainvoke({"user_message": user_message})
86
+ await send_whatsapp_message(wa_id, ai_result["response"])
 
 
 
 
87
  return JSONResponse({"status": "replied"})
88
 
89
  except Exception as e:
 
92
 
93
  return JSONResponse({"status": "ignored"})
94
 
95
+ # --- WhatsApp Sender ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  async def send_whatsapp_message(wa_id: str, message: str):
97
  url = f"https://graph.facebook.com/v18.0/{PHONE_NUMBER_ID}/messages"
98
  headers = {
 
111
  except Exception as e:
112
  print(f"Failed to send message: {e}")
113
 
114
+ # --- Optional Direct Chat Endpoint ---
115
+ class ChatRequest(BaseModel):
116
+ message: str
117
+ model: Optional[str] = "gpt-4o-mini"
118
+ max_tokens: Optional[int] = 150
119
+
120
+ class ChatResponse(BaseModel):
121
+ response: str
122
+ model: str
123
+ tokens_used: Optional[int] = None
124
+
125
+ @app.post("/chat", response_model=ChatResponse)
126
+ async def chat_with_ai(request: ChatRequest):
127
+ ai_result = await chat_graph.ainvoke({"user_message": request.message})
128
+ return ChatResponse(response=ai_result["response"], model=request.model)
129
+
130
+ # --- Health ---
131
  @app.get("/ping")
132
  def ping():
133
  return {"pong": True}
134
 
135
  @app.get("/health")
136
  def health_check():
 
137
  status = {
138
  "api": "healthy",
139
  "whatsapp": "configured" if WHATSAPP_API_TOKEN else "not configured",
requirements.txt CHANGED
@@ -2,4 +2,8 @@ fastapi
2
  uvicorn
3
  python-dotenv
4
  httpx
5
- openai
 
 
 
 
 
2
  uvicorn
3
  python-dotenv
4
  httpx
5
+ openai
6
+ langchain
7
+ langchain-openai
8
+ langgraph
9
+ langchain-core