Ronio Jerico Roque commited on
Commit
83a4aff
·
1 Parent(s): e94f698

Add initial implementation of chatbot with PostgreSQL query tool and environment configuration

Browse files
Files changed (7) hide show
  1. .env +1 -0
  2. __pycache__/app.cpython-313.pyc +0 -0
  3. agent.py +59 -0
  4. app.py +30 -7
  5. mcp_config.json +7 -0
  6. python +0 -0
  7. requirements.txt +15 -4
.env ADDED
@@ -0,0 +1 @@
 
 
1
+ OPENAI_API_KEY=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
__pycache__/app.cpython-313.pyc ADDED
Binary file (3.94 kB). View file
 
agent.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Annotated
2
+ from typing_extensions import TypedDict
3
+ from langgraph.graph import StateGraph, START, END
4
+ from langgraph.graph.message import add_messages
5
+ from langchain.chat_models import init_chat_model
6
+ import os
7
+
8
+ class State(TypedDict):
9
+ messages: Annotated[list, add_messages]
10
+
11
+ graph_builder = StateGraph(State)
12
+
13
+ key = os.getenv("OPENAI_API_KEY")
14
+
15
+ llm = init_chat_model("openai:gpt-4o-mini")
16
+ tool = {"type": "web_search_preview"}
17
+ llm_with_tools = llm.bind_tools(
18
+ [
19
+ {
20
+ "type": "mcp",
21
+ "server_label": "clickup_data",
22
+ "server_url": "http://127.0.0.1:8000",
23
+ "require_approval": "never",
24
+ }
25
+ ]
26
+ + [tool]
27
+
28
+ )
29
+
30
+ def chatbot(state: State):
31
+ return {"messages": [llm_with_tools.invoke(state["messages"])]}
32
+
33
+ graph_builder.add_node("chatbot", chatbot)
34
+ graph_builder.add_edge(START, "chatbot")
35
+ graph_builder.add_edge("chatbot", END)
36
+ graph = graph_builder.compile()
37
+
38
+ if __name__ == "__main__":
39
+ print("Chatbot started! Type 'quit' to exit.")
40
+
41
+ while True:
42
+ user_input = input("\nYou: ")
43
+
44
+ if user_input.lower() in ['quit', 'exit', 'bye']:
45
+ print("Goodbye!")
46
+ break
47
+
48
+ # Create initial state with user message
49
+ initial_state = {
50
+ "messages": [{"role": "user", "content": user_input}]
51
+ }
52
+
53
+ # Run the graph
54
+ result = graph.invoke(initial_state)
55
+
56
+ # Get the bot's response
57
+ bot_response = result["messages"][-1].content
58
+ print(f"Bot: {bot_response}")
59
+
app.py CHANGED
@@ -1,13 +1,12 @@
1
  import os
 
2
  from fastapi import FastAPI, HTTPException
3
  from fastapi_mcp import FastApiMCP
4
  from pydantic import BaseModel
5
  from typing import Optional
6
 
7
- # Create a FastAPI instance
8
  app = FastAPI()
9
 
10
- # --- Keep this root endpoint for health checks and basic access ---
11
  @app.get("/")
12
  async def read_root():
13
  return {"message": "Server is running and healthy!"}
@@ -19,27 +18,51 @@ class ToolInput(BaseModel):
19
  class ToolOutput(BaseModel):
20
  result: str
21
 
 
 
 
22
  @app.post("/tools/echo", operation_id="echo_tool")
23
  async def echo_tool(input_data: ToolInput) -> ToolOutput:
24
  """
25
  A simple echo tool that returns the input text with a prefix
26
  """
27
  try:
28
- # Process the input
29
  result = f"Echo: {input_data.text}"
30
  return ToolOutput(result=result)
31
  except Exception as e:
32
  raise HTTPException(status_code=500, detail=str(e))
33
 
34
- # Initialize MCP with the tool endpoint
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  mcp = FastApiMCP(
36
  app,
37
- include_operations=["echo_tool"]
38
- )
39
  mcp.mount()
40
 
41
  if __name__ == "__main__":
42
  import uvicorn
43
- # Use the PORT environment variable provided by Hugging Face, default to 7860
44
  port = int(os.environ.get("PORT", "7860"))
45
  uvicorn.run(app, host="0.0.0.0", port=port)
 
1
  import os
2
+ import asyncpg
3
  from fastapi import FastAPI, HTTPException
4
  from fastapi_mcp import FastApiMCP
5
  from pydantic import BaseModel
6
  from typing import Optional
7
 
 
8
  app = FastAPI()
9
 
 
10
  @app.get("/")
11
  async def read_root():
12
  return {"message": "Server is running and healthy!"}
 
18
  class ToolOutput(BaseModel):
19
  result: str
20
 
21
+ class QueryInput(BaseModel):
22
+ query: str
23
+
24
  @app.post("/tools/echo", operation_id="echo_tool")
25
  async def echo_tool(input_data: ToolInput) -> ToolOutput:
26
  """
27
  A simple echo tool that returns the input text with a prefix
28
  """
29
  try:
 
30
  result = f"Echo: {input_data.text}"
31
  return ToolOutput(result=result)
32
  except Exception as e:
33
  raise HTTPException(status_code=500, detail=str(e))
34
 
35
+ @app.post("/tools/query_postgres", operation_id="query_postgres")
36
+ async def query_postgres(input_data: QueryInput) -> ToolOutput:
37
+ """
38
+ Query PostgreSQL database
39
+ """
40
+ try:
41
+ # Only allow SELECT queries
42
+ if not input_data.query.lower().strip().startswith('select'):
43
+ return ToolOutput(result="Error: Only SELECT queries are allowed")
44
+
45
+ conn = await asyncpg.connect('postgres://postgres:apple@172.17.21.23:5432/agency_data')
46
+ rows = await conn.fetch(input_data.query + " LIMIT 10")
47
+ await conn.close()
48
+
49
+ if not rows:
50
+ return ToolOutput(result="No results found")
51
+
52
+ results = [dict(row) for row in rows]
53
+ return ToolOutput(result=f"Found {len(results)} rows: {results}")
54
+
55
+ except Exception as e:
56
+ return ToolOutput(result=f"Database error: {str(e)}")
57
+
58
+ # Initialize MCP with both tools
59
  mcp = FastApiMCP(
60
  app,
61
+ include_operations=["echo_tool", "query_postgres"]
62
+ )
63
  mcp.mount()
64
 
65
  if __name__ == "__main__":
66
  import uvicorn
 
67
  port = int(os.environ.get("PORT", "7860"))
68
  uvicorn.run(app, host="0.0.0.0", port=port)
mcp_config.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcpServers": {
3
+ "fastapi-mcp": {
4
+ "serverUrl": "https://roniorque-fastapi-test-server.hf.space/mcp"
5
+ }
6
+ }
7
+ }
python ADDED
File without changes
requirements.txt CHANGED
@@ -1,4 +1,15 @@
1
- fastapi
2
- uvicorn
3
- fastapi-mcp
4
- pydantic
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi>=0.104.0
2
+ fastapi-mcp>=0.1.0
3
+ uvicorn[standard]>=0.24.0
4
+ pydantic>=2.5.0
5
+ asyncpg>=0.29.0
6
+ psycopg2-binary>=2.9.7
7
+ sqlalchemy[asyncio]>=2.0.0
8
+ python-dotenv>=1.0.0
9
+ httpx>=0.25.0
10
+ langchain>=0.1.0
11
+ langchain-community>=0.0.10
12
+ langchain-core>=0.1.0
13
+ langchain-openai>=0.3.1
14
+ langgraph>=0.0.30
15
+ typing-extensions>=4.8.0