Skip to content

Commit c2b4fc5

Browse files
committed
add textbase frontend
1 parent 3edf302 commit c2b4fc5

40 files changed

+7328
-0
lines changed

.env

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
OPEN_API_KEY = "sk-HHIbAZHmOmU6UC3ev56UT3BlbkFJOuixAgpEC7YGofM2bGj"

.gitignore

Whitespace-only changes.

README.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Textbase
2+
3+
✨ Textbase is a framework for building chatbots using NLP and ML. ✨
4+
5+
Just implement the `on_message` function in `main.py` and Textbase will take care of the rest :)
6+
7+
Since it is just Python you can use whatever models, libraries, vector databases and APIs you want.
8+
9+
_Coming soon:_
10+
11+
- [ ] PyPI package
12+
- [ ] SMS integration
13+
- [ ] Easy web deployment via `textbase deploy`
14+
- [ ] Native integration of other models (Claude, Llama, ...)
15+
16+
## Installation
17+
18+
Clone the repository and install the dependencies using [Poetry](https://python-poetry.org/) (you might have to [install Poetry](https://python-poetry.org/docs/#installation) first).
19+
20+
```bash
21+
git clone https://github.com/cofactoryai/textbase
22+
cd textbase
23+
poetry install
24+
```
25+
26+
## Start development server
27+
28+
> If you're using the default template, **remember to set the OpenAI API key** in `main.py`.
29+
30+
Run the following command:
31+
32+
```bash
33+
poetry run python textbase/textbase_cli.py test main.py
34+
```
35+
36+
Now go to [http://localhost:4000](http://localhost:4000) and start chatting with your bot! The bot will automatically reload when you change the code.
37+
38+
_Simpler version using PyPI package and CLI coming soon!_
39+
40+
## Contributions
41+
42+
Contributions are welcome! Please open an issue or a pull request.

__pycache__/main.cpython-311.pyc

1.66 KB
Binary file not shown.

main.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import textbase
2+
from textbase.message import Message
3+
from textbase import models
4+
import os
5+
from typing import List
6+
# Load your OpenAI API key
7+
models.OpenAI.api_key = ""
8+
# or from environment variable:
9+
models.OpenAI.api_key = os.getenv("OPENAI_API_KEY")
10+
11+
# Prompt for GPT-3.5 Turbo
12+
SYSTEM_PROMPT = """I want you to be an AI doctor and tell me how you can help me and I don't want you to respond to irrelevant to medical terms. Please understand that you are a AI doctor and can help with anything realted to medical. Also, Please be specific and explain it like a five year child. Also please present the data systematically points by points
13+
"""
14+
15+
16+
@textbase.chatbot("talking-bot")
17+
def on_message(message_history: List[Message], state: dict = None):
18+
"""Your chatbot logic here
19+
message_history: List of user messages
20+
state: A dictionary to store any stateful information
21+
22+
Return a string with the bot_response or a tuple of (bot_response: str, new_state: dict)
23+
"""
24+
25+
if state is None or "counter" not in state:
26+
state = {"counter": 0}
27+
else:
28+
state["counter"] += 1
29+
30+
# # Generate GPT-3.5 Turbo response
31+
bot_response = models.OpenAI.generate(
32+
system_prompt=SYSTEM_PROMPT,
33+
message_history=message_history,
34+
model="gpt-3.5-turbo",
35+
)
36+
37+
return bot_response, state

poetry.lock

+2,894
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[tool.poetry]
2+
name = "textbase"
3+
version = "0.1.0"
4+
description = "A python library to help you create chatbots easily with some more configurations"
5+
authors = ["kaus-cofactory <[email protected]>"]
6+
readme = "README.md"
7+
8+
[tool.poetry.dependencies]
9+
python = "^3.8.1"
10+
requests = "^2.31.0"
11+
openai = "^0.27.8"
12+
twilio = "^8.5.0"
13+
python-dotenv = "^1.0.0"
14+
langchain = "^0.0.239"
15+
pinecone-client = "^2.2.2"
16+
chromadb = "^0.4.2"
17+
guardrails-ai = "^0.1.8"
18+
llama-index = "^0.7.11.post1"
19+
jinja2 = "^3.1.2"
20+
21+
22+
[build-system]
23+
requires = ["poetry-core"]
24+
build-backend = "poetry.core.masonry.api"
25+
26+
[tool.poetry.scripts]
27+
textbase = "textbase.textbase_cli:cli"

tests/__init__.py

Whitespace-only changes.

textbase/__init__.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class ChatbotRegistry:
2+
_registry = {}
3+
4+
@classmethod
5+
def register(cls, bot_name):
6+
def decorator(func):
7+
cls._registry[bot_name] = func
8+
return func
9+
return decorator
10+
11+
@classmethod
12+
def get_bot(cls, bot_name):
13+
return cls._registry.get(bot_name, None)
14+
15+
registry = ChatbotRegistry()
16+
17+
def chatbot(bot_name):
18+
return registry.register(bot_name)
19+
20+
1.29 KB
Binary file not shown.
5.34 KB
Binary file not shown.
517 Bytes
Binary file not shown.
1.37 KB
Binary file not shown.

textbase/backend.py

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# textbase/backend.py
2+
from fastapi import FastAPI
3+
from fastapi.staticfiles import StaticFiles
4+
from fastapi.responses import HTMLResponse
5+
from textbase.message import Message
6+
from dotenv import load_dotenv
7+
import os
8+
from fastapi.middleware.cors import CORSMiddleware
9+
import sys
10+
import logging
11+
from typing import List
12+
import importlib
13+
14+
logging.basicConfig(level=logging.INFO)
15+
16+
load_dotenv()
17+
18+
from .message import Message
19+
20+
app = FastAPI()
21+
22+
origins = [
23+
"http://localhost:3000",
24+
"http://localhost:4000",
25+
"http://localhost:5173",
26+
"*",
27+
]
28+
29+
app.add_middleware(
30+
CORSMiddleware,
31+
allow_origins=origins,
32+
allow_credentials=True,
33+
allow_methods=["*"],
34+
allow_headers=["*"],
35+
)
36+
37+
38+
@app.get("/", response_class=HTMLResponse)
39+
async def read_root():
40+
"""
41+
The `read_root` function reads and returns the contents of an HTML file specified by the path
42+
"textbase/frontend/index.html".
43+
:return: The content of the "index.html" file located in the "textbase/frontend" directory is being
44+
returned.
45+
"""
46+
with open("textbase/frontend/dist/index.html") as f:
47+
return f.read()
48+
49+
50+
def get_module_from_file_path(file_path: str):
51+
"""
52+
The function `get_module_from_file_path` takes a file path as input, loads the module from the file,
53+
and returns the module.
54+
55+
:param file_path: The file path is the path to the Python file that you want to import as a module.
56+
It should be a string representing the absolute or relative path to the file
57+
:type file_path: str
58+
:return: the module that is loaded from the given file path.
59+
"""
60+
module_name = os.path.splitext(os.path.basename(file_path))[0]
61+
spec = importlib.util.spec_from_file_location(module_name, file_path)
62+
module = importlib.util.module_from_spec(spec)
63+
sys.modules[module_name] = module
64+
spec.loader.exec_module(module)
65+
return module
66+
67+
68+
@app.post("/chat", response_model=dict)
69+
async def chat(messages: List[Message], state: dict = None):
70+
"""
71+
The above function is a Python API endpoint that receives a list of messages and a state dictionary,
72+
loads a module from a file path, calls the on_message function from the module with the messages and
73+
state, and returns the bot messages generated by the module.
74+
75+
:param messages: The `messages` parameter is a list of `Message` objects. It represents the messages
76+
exchanged between the user and the chatbot. Each `Message` object typically contains information
77+
such as the text of the message, the sender, the timestamp, etc
78+
:type messages: List[Message]
79+
:param state: The `state` parameter is a dictionary that stores the state of the conversation. It
80+
can be used to store information or context that needs to be maintained across multiple requests or
81+
messages in the conversation. The `state` parameter is optional and can be set to `None` if not
82+
needed
83+
:type state: dict
84+
:return: a list of `Message` objects.
85+
"""
86+
file_path = os.environ.get("FILE_PATH", None)
87+
logging.info(file_path)
88+
if not file_path:
89+
return []
90+
91+
module = get_module_from_file_path(file_path)
92+
93+
print("here", state)
94+
95+
# Call the on_message function from the dynamically loaded module
96+
response = module.on_message(messages, state)
97+
if type(response) is tuple:
98+
bot_response, new_state = response
99+
return {
100+
"botResponse": {"content": bot_response, "role": "assistant"},
101+
"newState": new_state,
102+
}
103+
elif type(response) is str:
104+
return {"botResponse": {"content": response, "role": "assistant"}}
105+
106+
107+
# Mount the static directory (frontend files)
108+
app.mount(
109+
"/assets",
110+
StaticFiles(directory="textbase/frontend/dist/assets", html=True),
111+
name="static",
112+
)

textbase/download.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import os
2+
import zipfile
3+
import requests
4+
5+
def download_and_extract_zip(zip_url, destination_folder):
6+
"""
7+
The function `download_and_extract_zip` downloads a zip file from a given URL and extracts its
8+
contents to a specified destination folder.
9+
10+
:param zip_url: The URL of the zip file that you want to download and extract
11+
:param destination_folder: The destination_folder parameter is the path where you want to save the
12+
downloaded zip file and extract its contents. It can be an absolute path or a relative path to the
13+
current working directory
14+
"""
15+
# Create the destination folder if it doesn't exist
16+
os.makedirs(destination_folder, exist_ok=True)
17+
18+
# Download the zip file
19+
response = requests.get(zip_url)
20+
if response.status_code == 200:
21+
zip_file_path = os.path.join(destination_folder, "frontend.zip")
22+
with open(zip_file_path, 'wb') as f:
23+
f.write(response.content)
24+
25+
# Extract the contents of the zip file
26+
with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
27+
zip_ref.extractall(destination_folder)
28+
29+
# Remove the zip file after extraction
30+
os.remove(zip_file_path)
31+
32+
print("Zip file downloaded and extracted successfully.")
33+
else:
34+
print("Failed to download the zip file.")

textbase/frontend/.eslintrc.cjs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module.exports = {
2+
root: true,
3+
env: { browser: true, es2020: true },
4+
extends: [
5+
'eslint:recommended',
6+
'plugin:@typescript-eslint/recommended',
7+
'plugin:react-hooks/recommended',
8+
],
9+
ignorePatterns: ['dist', '.eslintrc.cjs'],
10+
parser: '@typescript-eslint/parser',
11+
plugins: ['react-refresh'],
12+
rules: {
13+
'react-refresh/only-export-components': [
14+
'warn',
15+
{ allowConstantExport: true },
16+
],
17+
},
18+
}

textbase/frontend/.gitignore

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist-ssr
12+
*.local
13+
14+
# Editor directories and files
15+
.vscode/*
16+
!.vscode/extensions.json
17+
.idea
18+
.DS_Store
19+
*.suo
20+
*.ntvs*
21+
*.njsproj
22+
*.sln
23+
*.sw?

textbase/frontend/README.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# React + TypeScript + Vite
2+
3+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4+
5+
Currently, two official plugins are available:
6+
7+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9+
10+
## Expanding the ESLint configuration
11+
12+
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
13+
14+
- Configure the top-level `parserOptions` property like this:
15+
16+
```js
17+
parserOptions: {
18+
ecmaVersion: 'latest',
19+
sourceType: 'module',
20+
project: ['./tsconfig.json', './tsconfig.node.json'],
21+
tsconfigRootDir: __dirname,
22+
},
23+
```
24+
25+
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
26+
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
27+
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list

textbase/frontend/dist/assets/index-761a2309.css

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)