Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DB and API Refactors #99

Merged
merged 5 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export DATABASE_URL="postgresql://user:password@localhost:5432/database_name"
export SECRET_KEY="secret" # Secret key for signing tokens

# Origins to be allowed by the backend
export ORIGINS="https://beta.ansari.chat,http://beta.ansari.chat,https://ansari.chat,http://ansari.chat,https://hajiansari.ai,http://hajiansari.ai,https://ansari.endeavorpal.com"
export ORIGINS="https://beta.ansari.chat,http://beta.ansari.chat,https://ansari.chat,http://ansari.chat,https://hajiansari.ai,http://hajiansari.ai,https://ansari.endeavorpal.com,https://web.whatsapp.com"

# Vectara search engine configuration
export PGPASSWORD="" # Password for PostgreSQL database
Expand All @@ -25,15 +25,36 @@ export template_dir="." # Directory path for templates

# Related to WhatsApp Business and Meta (leave empty if you're not planning to use WhatsApp)
# Source 1: https://www.youtube.com/watch?v=KP6_BUw3i0U
# Watch Until 32:25
# Source 2: https://glitch.com/edit/#!/insidious-tartan-alvarezsaurus
# Source 3: https://developers.facebook.com/blog/post/2022/10/24/sending-messages-with-whatsapp-in-your-python-applications/#u_0_39_8q

# Moreover, if want to test whatsapp's webhook locally, you can use zrok on a reserved URL with a zrok "share token"
# obtained by contacting its current holder: https://github.com/OdyAsh (source 1, 2 below)
# Alternatively, you can change the webhook url all together (source 3, 4 below)
# Check these sources for more details:
# Source 1: https://dev.to/odyash/quickly-share-your-app-with-zrok-4ihp
# Source 2: https://openziti.discourse.group/t/how-do-i-use-a-reserved-share-on-different-devices/2379/2
# Source 3: https://youtu.be/KP6_BUw3i0U?t=1294
# (@21:33 and 25:30, however they use glitch instead of zrok, so you'll just need to change the webhook url to your zrok url)
# Source 4 (where you can change callback url, given that your facebook account gets access by the app's admins):
# https://developers.facebook.com/apps/871020755148175/whatsapp-business/wa-settings/
# Note 1: Obviously, that `871...175` is the testing app's public id, so if this link still doesn't work even after you gain access,
# then the admins most probably created a new test app instance
# Note 2: If an unexpected 3rd party discovers the ZROK_SHARE_TOKEN,
# a new one will have to be generated, then added to Meta's callback URL of the *testing* app
# (Noting that the *production* app's callback URL will be different anyway, so the 3rd party won't be able to access that app)
# (but we still don't want random calls to be made to our testing app, so that's why we'll still have to change an exposed token :])

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the extensive comments.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I was thinking of other ways to document these comments externally, but until we figure something out, will stick to inline commenting as I do think these should help newcomers .

export WHATSAPP_RECIPIENT_WAID="<<YOUR-RECIPIENT-TEST-PHONE-NUMBER>>"
export WHATSAPP_API_VERSION="<<CURRENT-VERSION-AS-MENTIONED-IN-SOURCE-URL-ABOVE>>"
export WHATSAPP_BUSINESS_PHONE_NUMBER_ID="<<YOUR-WHATSAPP-BUSINESS-PHONE-NUMBER-ID>>"
export WHATSAPP_ACCESS_TOKEN_FROM_SYS_USER="<<YOUR-SYSTEM-USER-ACCESS-TOKEN>"
export WHATSAPP_VERIFY_TOKEN_FOR_WEBHOOK="<<YOUR-VERIFIFY-TOKEN-TO-VERIFY-WHATSAPP-WEBHOOK>>"
export WHATSAPP_VERIFY_TOKEN_FOR_WEBHOOK="<<The-VERIFIFY-TOKEN-CURRENTLY-USED-TO-VERIFY-META'S-CALLBACK-URL>>"
export ZROK_SHARE_TOKEN="<<THE-ZROK-SHARE-TOKEN-CURRENTLY-USED-IN-META'S-CALLBACK-URL>>"

# Related to internal code logic
# Leave the values below when locally debugging the application
# In production, don't add them to environment variables, or add them as "INFO"/"False" respectively
export LOGGING_LEVEL="DEBUG"
export DEBUG_MODE="True"
2 changes: 1 addition & 1 deletion data/mawsuah/strip_tashkeel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from ansari.ansari_logger import get_logger

logger = get_logger(__name__)
logger = get_logger()


def strip_tashkeel_from_doc(input_file, output_file):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"scope": {
"type": "http",
"asgi": {
"version": "3.0",
"spec_version": "2.4"
},
"http_version": "1.1",
"server": ["127.0.0.1", 8000], // When running locally
"client": ["127.0.0.1", 11563], // The port here changes dynamically
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way of handling this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If "this" refers to the "port changes dynamically" comment, then I don't know...

To be honest, I don't even know why this port changes ... even though I've bounded Ansari frontend with port 3000 ... unless "client" here refers to something else, since origin does indeed have port 3000 ...

"scheme": "http",
"method": "POST",
"root_path": "",
"path": "/api/v2/users/login",
"raw_path": "/api/v2/users/login",
"query_string": "",
"headers": [
["host", "localhost:8000"],
["connection", "keep-alive"],
["content-length", "83"],
["sec-ch-ua-platform", "\"Windows\""],
["user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"],
["x-mobile-ansari", "ANSARI"],
["sec-ch-ua", "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\""],
["content-type", "application/json"],
["sec-ch-ua-mobile", "?0"],
["accept", "*/*"],
["origin", "http://localhost:3000"],
["sec-fetch-site", "same-site"],
["sec-fetch-mode", "cors"],
["sec-fetch-dest", "empty"],
["referer", "http://localhost:3000/"],
["accept-encoding", "gzip, deflate, br, zstd"],
["accept-language", "en-GB,en;q=0.9,ar-EG;q=0.8,ar;q=0.7,en-US;q=0.6"]
],
"state": {},
"app": "<fastapi.applications.FastAPI object>",
"starlette.exception_handlers": {
"<class 'starlette.exceptions.HTTPException'>": "<function http_exception_handler>",
"<class 'starlette.exceptions.WebSocketException'>": "<bound method ExceptionMiddleware.websocket_exception>",
"<class 'fastapi.exceptions.RequestValidationError'>": "<function request_validation_exception_handler>",
"<class 'fastapi.exceptions.WebSocketRequestValidationError'>": "<function websocket_request_validation_exception_handler>"
},
"router": "<fastapi.routing.APIRouter object>",
"endpoint": "<function login_user>",
"path_params": {},
"route": {
"path": "/api/v2/users/login",
"name": "login_user",
"methods": ["POST"]
}
},
"_receive": "<bound method RequestResponseCycle.receive>",
"_send": "<function wrap_app_handling_exceptions.<locals>.wrapped_app.<locals>.sender>",
"_stream_consumed": true,
"_is_disconnected": false,
"_form": null,
// _body's value (and other strings) were actually binary strings (i.e., start with b'...')
"_body": "{\"email\":\"guest_<<AUTO_GENERATED_KEY>>@endeavorpal.com\",\"password\":\"<<PASSWORD_SENT_VIA_ANSARI_WEBSITE>>\",\"guest\":true}",
// this is what actually gets returned when accessing headers property (e.g., `request.headers`)
// Check Starlette's implementation (which FastAPI uses) for details:
// https://github.com/encode/starlette/blob/b68a142a356ede730083347f254e1eae8b5c803e/starlette/requests.py#L12
"_headers": {
"host": "localhost:8000",
"connection": "...",
"...": "..."
// I.e., the value of the `_headers` key is a dictionary of the headers already mentioned above
},
"_json": {
"email": "guest_<<AUTO_GENERATED_KEY>>@endeavorpal.com",
"...": ["..."]
// I.e., the value of the `_json` key is simply the dictionary equivalent of `_body`'s string value
},
"_query_params": "",
"_cookies": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"scope": {
"type": "http",
"asgi": {
"version": "3.0",
"spec_version": "2.4"
},
"http_version": "1.1",
"server": ["127.0.0.1", 8000], // When running locally
"client": ["<<WHATSAPP.USER.IP>>", 0],
"scheme": "https",
"method": "POST",
"root_path": "",
"path": "/whatsapp/v1",
"raw_path": "/whatsapp/v1",
"query_string": "",
"headers": [
["host", "YOUR_ZROK_SHARE_TOKEN.share.zrok.io"],
["user-agent", "facebookexternalua"],
["content-length", "545"],
["accept", "*/*"],
["accept-encoding", "deflate, gzip"],
["content-type", "application/json"],
["x-amzn-trace-id", "Root=1-674b2035-0f0a8ab27075asce3324dcdb"], // trace value here is fake
["x-forwarded-for", "173.REST.OF.IP, <<WHATSAPP.USER.IP>>"],
["x-forwarded-port", "443"],
["x-forwarded-proto", "https"],
["x-hub-signature", "sha1=8a3e35da6fb5dfaaf5aaa46c8d059d519e18112d"], // sha1 hash here is fake
["x-hub-signature-256", "sha256=51d62480d40ffd0f48d1cde1ea47656452fd65b5ac29077fe3c6b4e68d74c827"], // sha256 here is fake
["x-proxy", "zrok"]
],
"state": {},
"app": "<FastAPI object>",
"starlette.exception_handlers": {
"<class 'starlette.exceptions.HTTPException'>": "<function http_exception_handler>",
"<class 'starlette.exceptions.WebSocketException'>": "<bound method ExceptionMiddleware.websocket_exception>",
"<class 'fastapi.exceptions.RequestValidationError'>": "<function request_validation_exception_handler>",
"<class 'fastapi.exceptions.WebSocketRequestValidationError'>": "<function websocket_request_validation_exception_handler>"
},
"router": "<APIRouter object>",
"endpoint": "<function main_webhook>",
"path_params": {},
"route": {
"path": "/whatsapp/v1",
"name": "main_webhook",
"methods": ["POST"]
}
},
"_receive": "<bound method RequestResponseCycle.receive>",
"_send": "<function wrap_app_handling_exceptions.<locals>.wrapped_app.<locals>.sender>",
"_stream_consumed": true,
"_is_disconnected": false,
"_form": null,
"_query_params": "",
// this is what actually gets returned when accessing headers property (e.g., `request.headers`)
// Check Starlette's implementation (which FastAPI uses) for details:
// https://github.com/encode/starlette/blob/b68a142a356ede730083347f254e1eae8b5c803e/starlette/requests.py#L125
"_headers": {
"host": "...",
"user-agent": "...",
"...": "..."
// I.e., the value of the `_headers` key is a dictionary of the headers already mentioned above
},
"_cookies": {},
// _body's value (and other strings) were actually binary strings (i.e., start with b'...')
// Also, it contains content mentioned in other `meta_whatsapp_*.json` files
"_body": "{\"object\":\"whatsapp_business_account\", ...}",
"_json": {
"object": "whatsapp_business_account",
"...": ["..."]
// I.e., the value of the `_json` key is simply the dictionary equivalent of `_body`'s string value
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "<<the WHATSAPP_BUSINESS_PHONE_NUMBER without non-numeric characters (e.g., +1 (555) 555-5555 -> 15555555555)>>",
"phone_number_id": "<<the WHATSAPP_BUSINESS_PHONE_NUMBER_ID (this ID is a numeric value)>>"
"phone_number_id": "<<the WHATSAPP_BUSINESS_PHONE_NUMBER_ID (this ID is a numeric value generated by Meta)>>"
},
"contacts": [
{
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ jinja2
# should be >= 2 in order for "from langfuse.decorators" to work
langfuse>=2.0.0
litellm
loguru
openai
pandas
psycopg2-binary
Expand Down
2 changes: 1 addition & 1 deletion setup_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from ansari.ansari_logger import get_logger
from ansari.config import get_settings

logger = get_logger(__name__)
logger = get_logger()


def import_sql_files(directory, db_url):
Expand Down
13 changes: 6 additions & 7 deletions sql/01_create_tables.sql
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(100) UNIQUE, -- can be null if it is a guest account
password_hash VARCHAR(255), -- can be null if it is a guest account
first_name VARCHAR(50), -- can be null if it is a guest account
last_name VARCHAR(50), -- can be null if it is a guest account
email VARCHAR(100) UNIQUE, -- Can be null if it is a guest account
password_hash VARCHAR(255), -- Can be null if it is a guest account
first_name VARCHAR(50), -- Can be null if it is a guest account
last_name VARCHAR(50), -- Can be null if it is a guest account
preferred_language VARCHAR(10) DEFAULT 'en',
is_guest BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);


CREATE TABLE preferences (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
Expand All @@ -35,7 +36,7 @@ CREATE TABLE messages (
user_id INTEGER NOT NULL,
thread_id INTEGER NOT NULL,
role TEXT NOT NULL,
-- TODO (odyash): check if "function" can be renamed to "tool" like the rest of the codebase or not
-- #TODO (odyash): check if "function" can be renamed to "tool" like the rest of the codebase or not
function_name TEXT,
content TEXT NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
Expand All @@ -44,5 +45,3 @@ CREATE TABLE messages (
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (thread_id) REFERENCES threads(id)
);


3 changes: 2 additions & 1 deletion src/ansari/agents/ansari.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
from ansari.tools.search_vectara import SearchVectara
from ansari.util.prompt_mgr import PromptMgr

logger = get_logger(__name__ + ".Ansari")
# previous logger name: __name__ + ".Ansari"
logger = get_logger()


class Ansari:
Expand Down
3 changes: 2 additions & 1 deletion src/ansari/agents/ansari_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
else:
logging_level = logging.INFO

logger = get_logger(__name__ + ".AnsariWorkflow", logging_level)
# previous logger name: __name__ + ".AnsariWorkflow"
logger = get_logger(logging_level)


class AnsariWorkflow:
Expand Down
Loading
Loading