-
Notifications
You must be signed in to change notification settings - Fork 714
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* migrate mongoengine to motor for mongodb * migrate from flask to fastapi for web framework
- Loading branch information
1 parent
acf4973
commit a3c3a13
Showing
45 changed files
with
768 additions
and
820 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,20 @@ | ||
FROM python:3.12.7-slim | ||
|
||
# Install common libraries | ||
RUN apt-get update -qq \ | ||
&& apt-get install -y --no-install-recommends build-essential && apt-get autoremove -y | ||
|
||
WORKDIR /usr/src/app | ||
|
||
COPY requirements.txt ./ | ||
RUN pip install --no-cache-dir -r requirements.txt | ||
# Install system dependencies | ||
RUN apt-get update && apt-get install -y \ | ||
build-essential \ | ||
python3-dev \ | ||
&& rm -rf /var/lib/apt/lists/* | ||
|
||
EXPOSE 80 | ||
# Copy requirements first to leverage Docker cache | ||
COPY requirements.txt . | ||
RUN pip install --no-cache-dir -r requirements.txt | ||
|
||
# Copy the rest of the application | ||
COPY . . | ||
|
||
CMD ["gunicorn", "run:app" ,"--log-level=debug", "--timeout", "90","--bind", "0.0.0.0:80" ] | ||
EXPOSE 80 | ||
|
||
CMD ["fastapi", "run" ,"--host", "0.0.0.0","--port", "80" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,68 +0,0 @@ | ||
import os | ||
from flask import Flask, send_from_directory, Blueprint | ||
from flask_cors import CORS | ||
from flask_mongoengine import MongoEngine | ||
from config import config | ||
from app.bot.dialogue_manager.dialogue_manager import DialogueManager | ||
|
||
admin_panel_dist = 'static/' | ||
|
||
db = MongoEngine() | ||
|
||
def create_app(env="Development"): | ||
app = Flask(__name__) | ||
|
||
# Configurations | ||
try: | ||
env = os.environ['APPLICATION_ENV'] | ||
except KeyError as e: | ||
app.logger.info('Unknown environment key, defaulting to Development') | ||
|
||
app.config.from_object(config[env]) | ||
app.config.from_prefixed_env(prefix='APP') | ||
|
||
CORS(app) | ||
db.init_app(app) | ||
|
||
# initialize dialogue_manager | ||
dialogue_manager = DialogueManager.from_config(app) | ||
dialogue_manager.update_model(app.config["MODELS_DIR"]) | ||
app.dialogue_manager : DialogueManager = dialogue_manager | ||
|
||
from app.admin.bots.controllers import bots | ||
from app.admin.intents.controllers import intents | ||
from app.admin.train.controllers import train | ||
from app.bot.chat.controllers import chat | ||
from app.admin.entities.controllers import entities_blueprint | ||
|
||
# bot endpoints | ||
# TODO: move to a isolated web server | ||
app.register_blueprint(chat) | ||
|
||
# admin endpoints | ||
admin_routes = Blueprint('admin', __name__, url_prefix='/admin/') | ||
admin_routes.register_blueprint(intents) | ||
admin_routes.register_blueprint(train) | ||
admin_routes.register_blueprint(bots) | ||
admin_routes.register_blueprint(entities_blueprint) | ||
app.register_blueprint(admin_routes) | ||
|
||
|
||
@app.route('/ready') | ||
def ready(): | ||
return "ok",200 | ||
|
||
@app.route('/<path:path>', methods=['GET']) | ||
def static_proxy(path): | ||
return send_from_directory(admin_panel_dist, path) | ||
|
||
@app.errorhandler(404) | ||
def not_found(error): | ||
return "Not found", 404 | ||
|
||
return app | ||
|
||
|
||
|
||
|
||
|
||
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from fastapi import APIRouter, HTTPException, UploadFile, File | ||
from fastapi.responses import Response | ||
from typing import Dict, Any | ||
import json | ||
|
||
from app.admin.bots import store | ||
|
||
router = APIRouter(prefix="/bots") | ||
|
||
@router.put("/{name}/config") | ||
async def set_config(name: str, config: Dict[str, Any]): | ||
""" | ||
Update bot config | ||
""" | ||
return await store.update_config(name, config) | ||
|
||
@router.get("/{name}/config") | ||
async def get_config(name: str): | ||
""" | ||
Get bot config | ||
""" | ||
return await store.get_config(name) | ||
|
||
@router.get("/{name}/export") | ||
async def export_bot(name: str): | ||
""" | ||
Export all intents and entities for the bot as a JSON file | ||
""" | ||
data = await store.export_bot(name) | ||
return Response( | ||
content=json.dumps(data), | ||
media_type='application/json', | ||
headers={'Content-Disposition': 'attachment;filename=chatbot_data.json'} | ||
) | ||
|
||
@router.post("/{name}/import") | ||
async def import_agent(name: str, file: UploadFile = File(...)): | ||
""" | ||
Import intents and entities from a JSON file for the bot | ||
""" | ||
if not file: | ||
raise HTTPException(status_code=400, detail="No file part") | ||
|
||
content = await file.read() | ||
json_data = json.loads(content) | ||
|
||
return await store.import_bot(name, json_data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from pydantic import BaseModel, Field | ||
from typing import Dict, Any | ||
from app.database import ObjectIdField | ||
|
||
class Bot(BaseModel): | ||
"""Base schema for bot""" | ||
id: ObjectIdField = Field(validation_alias="_id", default=None) | ||
name: str | ||
config: Dict[str, Any] = {} | ||
|
||
class Config: | ||
arbitrary_types_allowed=True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
from typing import Dict | ||
from app.admin.bots.schemas import Bot | ||
from app.admin.entities.store import list_entities | ||
from app.admin.intents.store import list_intents | ||
from app.database import database | ||
|
||
bot_collection = database.get_collection("bot") | ||
intent_collection = database.get_collection("intent") | ||
entity_collection = database.get_collection("entity") | ||
|
||
async def add_bot(data: dict): | ||
return await bot_collection.insert_one(data) | ||
|
||
async def get_bot(name: str)-> Bot: | ||
bot = await bot_collection.find_one({"name": name}) | ||
return Bot.model_validate(bot) | ||
|
||
async def get_config(name: str) -> Dict: | ||
bot = await get_bot(name) | ||
return bot.config | ||
|
||
async def update_config(name: str, entity_data: dict) -> dict: | ||
await bot_collection.update_one({"name": name}, {"$set": {"config": entity_data}}) | ||
|
||
async def export_bot(name) -> Dict: | ||
# Get all intents and entities | ||
intents = await list_intents() | ||
entities = await list_entities() | ||
|
||
entities = [entity.model_dump(exclude={"id"}) for entity in entities] | ||
intents = [intent.model_dump(exclude={"id"}) for intent in intents] | ||
|
||
export_data = { | ||
"intents": intents, | ||
"entities": entities | ||
} | ||
return export_data | ||
|
||
async def import_bot(name: str, data: Dict): | ||
intents = data.get("intents",[]) | ||
entities = data.get("entities",[]) | ||
|
||
created_intents = [] | ||
created_entities = [] | ||
|
||
# Import intents | ||
if intents: | ||
for intent in intents: | ||
result = await intent_collection.update_one({"name": intent.get("name")}, {"$set": intent},upsert=True) | ||
print(result) | ||
if result.upserted_id: | ||
created_intents.append(str(result.upserted_id)) | ||
|
||
# Import entities | ||
if entities: | ||
for entity in entities: | ||
result = await entity_collection.update_one({"name": entity.get("name")}, {"$set": entity},upsert=True) | ||
print(result) | ||
if result.upserted_id: | ||
created_entities.append(str(result.upserted_id)) | ||
|
||
return { | ||
"num_intents_created": len(created_intents), | ||
"num_entities_created": len(created_entities) | ||
} | ||
|
Oops, something went wrong.