Skip to content

Commit 3c1ba81

Browse files
Merge pull request #3 from Promptly-Technologies-LLC/1-finish-hooking-up-the-chat-component-to-accept-stream-from-api-endpoints
Connect chat component up to backend SSE stream
2 parents f3a83f2 + c291d2f commit 3c1ba81

File tree

14 files changed

+991
-829
lines changed

14 files changed

+991
-829
lines changed

.gitignore

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# local env files
2-
.env*.local
3-
.env
4-
.venv
1+
# local env files
2+
.env*.local
3+
.env
4+
.venv
5+
__pycache__
6+
*.pyc

README.md

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# OpenAI Assistants Quickstart with Python, Jinja2, and FastAPI
1+
# OpenAI Assistants API Quickstart with Python, Jinja2, and FastAPI
22

33
A quick-start template using the OpenAI [Assistants API](https://platform.openai.com/docs/assistants/overview) with [Python](https://www.python.org/), [Jinja2](https://jinja.palletsprojects.com/en/3.1.x/), and [FastAPI](https://fastapi.tiangolo.com/).
44

@@ -9,7 +9,7 @@ A quick-start template using the OpenAI [Assistants API](https://platform.openai
99
### 1. Clone repo
1010

1111
```shell
12-
git clone https://github.com/chriscarrollsmith/openai-assistants-python-quickstart.git
12+
git clone https://github.com/Promptly-Technologies-LLC/openai-assistants-python-quickstart.git
1313
cd openai-assistants-python-quickstart
1414
```
1515

@@ -38,27 +38,7 @@ uv run create_assistant.py
3838
uv run uvicorn main:app --host 0.0.0.0 --port 8000 --reload
3939
```
4040

41-
### 6. Navigate to [http://localhost:3000](http://localhost:3000).
42-
43-
## Overview
44-
45-
### Pages
46-
47-
- Basic Chat Example: [http://localhost:3000/examples/basic-chat](http://localhost:3000/examples/basic-chat)
48-
- Function Calling Example: [http://localhost:3000/examples/function-calling](http://localhost:3000/examples/function-calling)
49-
- File Search Example: [http://localhost:3000/examples/file-search](http://localhost:3000/examples/file-search)
50-
- Full-featured Example: [http://localhost:3000/examples/all](http://localhost:3000/examples/all)
51-
52-
### Main Components
53-
54-
- `templates/components/chat.html` - handles chat rendering, [streaming](https://platform.openai.com/docs/assistants/overview?context=with-streaming), and [function call](https://platform.openai.com/docs/assistants/tools/function-calling/quickstart?context=streaming&lang=node.js) forwarding
55-
- `templates/components/file-viewer.html` - handles uploading, fetching, and deleting files for [file search](https://platform.openai.com/docs/assistants/tools/file-search)
56-
57-
### Endpoints
58-
59-
- `api/assistants` - `POST`: create assistant (only used at startup)
60-
- `api/assistants/threads` - `POST`: create new thread
61-
- `api/assistants/threads/[threadId]/messages` - `POST`: send message to assistant
41+
### 6. Navigate to [http://localhost:8000](http://localhost:8000).
6242
- `api/assistants/threads/[threadId]/actions` - `POST`: inform assistant of the result of a function it decided to call
6343
- `api/assistants/files` - `GET`/`POST`/`DELETE`: fetch, upload, and delete assistant files for file search
6444

__pycache__/main.cpython-312.pyc

606 Bytes
Binary file not shown.

main.py

Lines changed: 113 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,113 @@
1-
import logging
2-
import dotenv
3-
from contextlib import asynccontextmanager
4-
from fastapi import FastAPI, Request
5-
from fastapi.staticfiles import StaticFiles
6-
from fastapi.templating import Jinja2Templates
7-
import os
8-
9-
10-
logger = logging.getLogger("uvicorn.error")
11-
12-
dotenv.load_dotenv()
13-
14-
@asynccontextmanager
15-
async def lifespan(app: FastAPI):
16-
# Optional startup logic
17-
yield
18-
# Optional shutdown logic
19-
20-
21-
app = FastAPI(lifespan=lifespan)
22-
23-
# Mount static files (e.g., CSS, JS)
24-
app.mount("/static", StaticFiles(directory=os.path.join(os.getcwd(), "static")), name="static")
25-
26-
# Initialize Jinja2 templates
27-
templates = Jinja2Templates(directory="templates")
28-
29-
30-
@app.get("/")
31-
async def read_home(request: Request):
32-
categories = {
33-
"Basic chat": "basic-chat",
34-
"File search": "file-search",
35-
"Function calling": "function-calling",
36-
"All": "all",
37-
}
38-
return templates.TemplateResponse("index.html", {"request": request, "categories": categories})
39-
40-
41-
@app.get("/basic-chat")
42-
async def read_basic_chat(request: Request):
43-
messages = []
44-
45-
return templates.TemplateResponse("examples/basic-chat.html", {"request": request, "messages": messages})
46-
47-
48-
@app.get("/file-search")
49-
async def read_file_search(request: Request):
50-
return templates.TemplateResponse("examples/file-search.html", {"request": request})
51-
52-
53-
@app.get("/function-calling")
54-
async def read_function_calling(request: Request):
55-
# Define the condition class map
56-
conditionClassMap = {
57-
"Cloudy": "weatherBGCloudy",
58-
"Sunny": "weatherBGSunny",
59-
"Rainy": "weatherBGRainy",
60-
"Snowy": "weatherBGSnowy",
61-
"Windy": "weatherBGWindy",
62-
}
63-
64-
# Set default values for the weather widget
65-
location = "---"
66-
temperature = "---"
67-
conditions = "Sunny"
68-
isEmpty = True
69-
70-
# Pass all necessary context variables to the template
71-
return templates.TemplateResponse(
72-
"examples/function-calling.html",
73-
{
74-
"conditionClassMap": conditionClassMap,
75-
"location": location,
76-
"temperature": temperature,
77-
"conditions": conditions,
78-
"isEmpty": isEmpty
79-
}
80-
)
81-
82-
83-
@app.get("/all")
84-
async def read_all(request: Request):
85-
return templates.TemplateResponse("examples/all.html", {"request": request})
86-
87-
88-
if __name__ == "__main__":
89-
import uvicorn
90-
91-
uvicorn.run(app, host="0.0.0.0", port=8000)
1+
import os
2+
import logging
3+
import dotenv
4+
from contextlib import asynccontextmanager
5+
from fastapi import FastAPI, Request
6+
from fastapi.staticfiles import StaticFiles
7+
from fastapi.templating import Jinja2Templates
8+
from routers import messages, assistants_files, tool_outputs
9+
10+
11+
logger = logging.getLogger("uvicorn.error")
12+
13+
dotenv.load_dotenv()
14+
15+
@asynccontextmanager
16+
async def lifespan(app: FastAPI):
17+
# Optional startup logic
18+
yield
19+
# Optional shutdown logic
20+
21+
app = FastAPI(lifespan=lifespan)
22+
23+
# Mount routers
24+
app.include_router(messages.router)
25+
app.include_router(assistants_files.router)
26+
app.include_router(tool_outputs.router)
27+
28+
29+
# Mount static files (e.g., CSS, JS)
30+
app.mount("/static", StaticFiles(directory=os.path.join(os.getcwd(), "static")), name="static")
31+
32+
# Initialize Jinja2 templates
33+
templates = Jinja2Templates(directory="templates")
34+
35+
@app.get("/")
36+
async def read_home(request: Request):
37+
logger.info("Home page requested")
38+
39+
categories = {
40+
"Basic chat": "basic-chat",
41+
"File search": "file-search",
42+
"Function calling": "function-calling",
43+
"All": "all",
44+
}
45+
return templates.TemplateResponse(
46+
"index.html",
47+
{
48+
"request": request,
49+
"categories": categories
50+
}
51+
)
52+
53+
@app.get("/basic-chat")
54+
async def read_basic_chat(request: Request, messages: list = [], thread_id: str = None):
55+
return templates.TemplateResponse(
56+
"examples/basic-chat.html",
57+
{
58+
"request": request,
59+
"messages": messages,
60+
"thread_id": thread_id
61+
}
62+
)
63+
64+
@app.get("/file-search")
65+
async def read_file_search(request: Request, messages: list = [], thread_id: str = None):
66+
return templates.TemplateResponse(
67+
"examples/file-search.html",
68+
{
69+
"request": request,
70+
"messages": messages,
71+
"thread_id": thread_id,
72+
}
73+
)
74+
75+
@app.get("/function-calling")
76+
async def read_function_calling(request: Request, messages: list = [], thread_id: str = None):
77+
# Define the condition class map
78+
conditionClassMap = {
79+
"Cloudy": "weatherBGCloudy",
80+
"Sunny": "weatherBGSunny",
81+
"Rainy": "weatherBGRainy",
82+
"Snowy": "weatherBGSnowy",
83+
"Windy": "weatherBGWindy",
84+
}
85+
86+
return templates.TemplateResponse(
87+
"examples/function-calling.html",
88+
{
89+
"conditionClassMap": conditionClassMap,
90+
"location": "---",
91+
"temperature": "---",
92+
"conditions": "Sunny",
93+
"isEmpty": True,
94+
"thread_id": thread_id,
95+
"messages": messages
96+
}
97+
)
98+
99+
@app.get("/all")
100+
async def read_all(request: Request, messages: list = [], thread_id: str = None):
101+
return templates.TemplateResponse(
102+
"examples/all.html",
103+
{
104+
"request": request,
105+
"thread_id": thread_id,
106+
"messages": messages
107+
}
108+
)
109+
110+
if __name__ == "__main__":
111+
import uvicorn
112+
113+
uvicorn.run(app, host="0.0.0.0", port=8000)

0 commit comments

Comments
 (0)