Skip to content

Commit 5dced40

Browse files
feat: Facebook channel (#183)
* add integrations backend apis * add integrations frontend * completed integrations admin ui * add facebook channel implementation * fix typo in ci * fix ui issues
1 parent ce1a572 commit 5dced40

File tree

26 files changed

+1050
-90
lines changed

26 files changed

+1050
-90
lines changed

.github/workflows/evaluate-frontend.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
branches:
99
- master
1010
paths:
11-
'frontend/*'
11+
- 'frontend/*'
1212

1313
jobs:
1414
test-nextjs:

README.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ You don’t need to be an expert at artificial intelligence to create an awesome
1313

1414
## Features
1515
- Fully Self Hosted
16+
- Low Code, DIY, Admin Dashboard
1617
- Multi-turn Conversations
1718
- Advanced Natural Language Understanding (NLU)
1819
- Spacy Word Embeddings
@@ -23,20 +24,30 @@ You don’t need to be an expert at artificial intelligence to create an awesome
2324
- API request fulfilment
2425
- Channel Integrations
2526
- Web using rest api/chat snippet
26-
- Facebook Messenger (coming soon)
27-
- WhatsApp via Twilio (coming soon)
27+
- Facebook Messenger
2828
- Slack (coming soon)
29-
- Low Code Admin Dashboard
29+
- WhatsApp via Twilio (coming soon)
30+
3031

3132
## Index
3233

34+
* [Tech Stack](#tech-stack)
3335
* [Installation](#installation)
3436
* [Docker Compose](#using-docker-compose)
3537
* [Helm](#using-helm)
3638
* [Development](#development)
3739
* [Tutorial](#tutorial)
3840
* [Dependencies](#dependencies-documentations)
3941

42+
### Tech Stack
43+
44+
- Python / FastAPI / Pydantic
45+
- MongoDB / Motor
46+
- React / NextJS
47+
- scikit-learn / Tensorflow / Keras
48+
- Spacy / python-crfsuite
49+
- Docker / docker-compose / Kubernetes / Helm
50+
4051
### Installation
4152

4253
### Using docker-compose (recommended)

app/admin/bots/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from app.admin.bots import store
77

8-
router = APIRouter(prefix="/bots")
8+
router = APIRouter(prefix="/bots", tags=["bots"])
99

1010

1111
@router.put("/{name}/config")

app/admin/entities/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from app.admin.entities import store
33
from app.admin.entities.schemas import Entity
44

5-
router = APIRouter(prefix="/entities")
5+
router = APIRouter(prefix="/entities", tags=["entities"])
66

77

88
@router.post("/")

app/admin/integrations/routes.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from typing import List
2+
from fastapi import APIRouter, HTTPException
3+
from . import store
4+
from .schemas import Integration, IntegrationUpdate
5+
6+
router = APIRouter(prefix="/integrations", tags=["integrations"])
7+
8+
9+
@router.get("/", response_model=List[Integration])
10+
async def list_integrations():
11+
"""List all available integrations."""
12+
return await store.list_integrations()
13+
14+
15+
@router.get("/{id}", response_model=Integration)
16+
async def get_integration(id: str):
17+
"""Get a specific integration by ID."""
18+
integration = await store.get_integration(id)
19+
if not integration:
20+
raise HTTPException(status_code=404, detail="Integration not found")
21+
return integration
22+
23+
24+
@router.put("/{id}", response_model=Integration)
25+
async def update_integration(id: str, integration: IntegrationUpdate):
26+
"""Update an integration's status and settings."""
27+
updated_integration = await store.update_integration(id, integration)
28+
if not updated_integration:
29+
raise HTTPException(status_code=404, detail="Integration not found")
30+
return updated_integration

app/admin/integrations/schemas.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from typing import Dict, Optional
2+
from pydantic import BaseModel
3+
4+
5+
class IntegrationBase(BaseModel):
6+
id: str
7+
name: str
8+
description: str
9+
status: bool = False
10+
settings: Optional[Dict] = {}
11+
12+
13+
class IntegrationCreate(IntegrationBase):
14+
pass
15+
16+
17+
class IntegrationUpdate(IntegrationBase):
18+
pass
19+
20+
21+
class Integration(IntegrationBase):
22+
class Config:
23+
from_attributes = True

app/admin/integrations/store.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from typing import List, Optional
2+
from app.database import database
3+
from .schemas import Integration, IntegrationUpdate
4+
5+
collection_name = "integrations"
6+
7+
8+
async def list_integrations() -> List[Integration]:
9+
"""Get all integrations."""
10+
cursor = database[collection_name].find()
11+
integrations = await cursor.to_list(length=None)
12+
return [Integration(**integration) for integration in integrations]
13+
14+
15+
async def get_integration(id: str) -> Optional[Integration]:
16+
"""Get a specific integration by ID."""
17+
integration = await database[collection_name].find_one({"id": id})
18+
if integration:
19+
return Integration(**integration)
20+
return None
21+
22+
23+
async def update_integration(
24+
id: str, integration: IntegrationUpdate
25+
) -> Optional[Integration]:
26+
"""Update an integration's status and settings."""
27+
update_data = integration.model_dump(exclude_unset=True)
28+
29+
result = await database[collection_name].find_one_and_update(
30+
{"id": id},
31+
{"$set": update_data},
32+
return_document=True,
33+
)
34+
35+
if result:
36+
return Integration(**result)
37+
return None
38+
39+
40+
async def ensure_default_integrations():
41+
"""Ensure default integrations exist in the database."""
42+
default_integrations = [
43+
{
44+
"id": "facebook",
45+
"name": "Facebook Messenger",
46+
"description": "Connect with Facebook Messenger",
47+
"status": False,
48+
"settings": {
49+
"verify": "ai-chatbot-framework",
50+
"secret": "",
51+
"page_access_token": "",
52+
},
53+
},
54+
{
55+
"id": "chat_widget",
56+
"name": "Chat Widget",
57+
"description": "Add a chat widget to your website",
58+
"status": True,
59+
"settings": {},
60+
},
61+
]
62+
63+
for integration in default_integrations:
64+
await database[collection_name].update_one(
65+
{"id": integration["id"]},
66+
{"$setOnInsert": integration},
67+
upsert=True,
68+
)

app/admin/intents/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from app.admin.intents import store
33
from app.admin.intents.schemas import Intent
44

5-
router = APIRouter(prefix="/intents")
5+
router = APIRouter(prefix="/intents", tags=["intents"])
66

77

88
@router.post("/")

app/admin/train/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from app.dependencies import reload_dialogue_manager
44
from app.bot.nlu.training import train_pipeline
55

6-
router = APIRouter(prefix="/train")
6+
router = APIRouter(prefix="/train", tags=["train"])
77

88

99
@router.post("/{intent_id}/data")

0 commit comments

Comments
 (0)