Skip to content

Commit

Permalink
Merge pull request #163 from NimbleBoxAI/yash/multiapi-bugfix
Browse files Browse the repository at this point in the history
Make storing I/O in DB optional
  • Loading branch information
yashbonde authored Oct 16, 2023
2 parents 7a40c76 + 23e5bec commit c070050
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 24 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,5 @@ api_docs/_build/
api_docs/_static/
cf
locust_file.py
demo/
demo/
logs.py
29 changes: 26 additions & 3 deletions server/chainfury_server/api/chains.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ def run_chain(
prompt: T.ApiPromptBody,
stream: bool = False,
as_task: bool = False,
store_ir: bool = False,
store_io: bool = False,
db: Session = Depends(DB.fastapi_db_session),
) -> Union[StreamingResponse, T.CFPromptResult, T.ApiResponse]:
"""
Expand Down Expand Up @@ -227,7 +229,14 @@ def run_chain(

#
if as_task:
result = engine.submit(chatbot=chatbot, prompt=prompt, db=db, start=time.time())
result = engine.submit(
chatbot=chatbot,
prompt=prompt,
db=db,
start=time.time(),
store_ir=store_ir,
store_io=store_io,
)
return result
elif stream:

Expand All @@ -242,10 +251,24 @@ def _get_streaming_response(result):
result = {**ir, "done": done}
yield json.dumps(result) + "\n"

streaming_result = engine.stream(chatbot=chatbot, prompt=prompt, db=db, start=time.time())
streaming_result = engine.stream(
chatbot=chatbot,
prompt=prompt,
db=db,
start=time.time(),
store_ir=store_ir,
store_io=store_io,
)
return StreamingResponse(content=_get_streaming_response(streaming_result))
else:
result = engine.run(chatbot=chatbot, prompt=prompt, db=db, start=time.time())
result = engine.run(
chatbot=chatbot,
prompt=prompt,
db=db,
start=time.time(),
store_ir=store_ir,
store_io=store_io,
)
return result


Expand Down
11 changes: 3 additions & 8 deletions server/chainfury_server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import chainfury_server.api.user as api_user
import chainfury_server.api.chains as api_chains
import chainfury_server.api.prompts as api_prompts
from chainfury_server.landing import landing_page

app = FastAPI(
title="ChainFury",
Expand All @@ -34,6 +35,8 @@
# TODO: deprecate this
app.add_api_route("/api/v1/chatbot/{id}/prompt", api_chains.run_chain, methods=["POST"], tags=["deprecated"], response_model=None) # type: ignore

app.add_api_route("/", landing_page, methods=["GET"], tags=["deprecated"], response_class=HTMLResponse) # type: ignore

# user
app.add_api_route("/user/login/", api_user.login, methods=["POST"], tags=["user"]) # type: ignore
app.add_api_route("/user/signup/", api_user.sign_up, methods=["POST"], tags=["user"]) # type: ignore
Expand All @@ -58,14 +61,6 @@
# Static files
# ------------


@app.get("/")
async def serve_framer():
"""Serves the landing page for ChainFury"""
r = requests.get("https://chainfury.framer.website/")
return HTMLResponse(content=r.text, status_code=r.status_code)


# add static files
_static_fp = joinp(folder(__file__), "static")
static = Jinja2Templates(directory=_static_fp)
Expand Down
43 changes: 34 additions & 9 deletions server/chainfury_server/engines/fury.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,20 @@ class FuryEngine(EngineInterface):
def engine_name(self) -> str:
return "fury"

def run(self, chatbot: DB.ChatBot, prompt: T.ApiPromptBody, db: Session, start: float) -> T.CFPromptResult:
def run(
self,
chatbot: DB.ChatBot,
prompt: T.ApiPromptBody,
db: Session,
start: float,
store_ir: bool,
store_io: bool,
) -> T.CFPromptResult:
if prompt.new_message and prompt.data:
raise HTTPException(status_code=400, detail="prompt cannot have both new_message and data")
try:
logger.debug("Adding prompt to database")
prompt_row = create_prompt(db, chatbot.id, prompt.new_message, prompt.session_id) # type: ignore
prompt_row = create_prompt(db, chatbot.id, prompt.new_message if store_io else "", prompt.session_id) # type: ignore

# Create a Fury chain then run the chain while logging all the intermediate steps
dag = T.Dag(**chatbot.dag) # type: ignore
Expand All @@ -46,7 +54,8 @@ def run(self, chatbot: DB.ChatBot, prompt: T.ApiPromptBody, db: Session, start:
)

# commit the prompt to DB
prompt_row.response = result.result # type: ignore
if store_io:
prompt_row.response = result.result # type: ignore
prompt_row.time_taken = float(time.time() - start) # type: ignore
db.commit()

Expand All @@ -59,13 +68,19 @@ def run(self, chatbot: DB.ChatBot, prompt: T.ApiPromptBody, db: Session, start:
raise HTTPException(status_code=500, detail=str(e)) from e

def stream(
self, chatbot: DB.ChatBot, prompt: T.ApiPromptBody, db: Session, start: float
self,
chatbot: DB.ChatBot,
prompt: T.ApiPromptBody,
db: Session,
start: float,
store_ir: bool,
store_io: bool,
) -> Generator[Tuple[Union[T.CFPromptResult, Dict[str, Any]], bool], None, None]:
if prompt.new_message and prompt.data:
raise HTTPException(status_code=400, detail="prompt cannot have both new_message and data")
try:
logger.debug("Adding prompt to database")
prompt_row = create_prompt(db, chatbot.id, prompt.new_message, prompt.session_id) # type: ignore
prompt_row = create_prompt(db, chatbot.id, prompt.new_message if store_io else "", prompt.session_id) # type: ignore

# Create a Fury chain then run the chain while logging all the intermediate steps
dag = T.Dag(**chatbot.dag) # type: ignore
Expand Down Expand Up @@ -96,7 +111,8 @@ def stream(
)

# commit the prompt to DB
prompt_row.response = result.result # type: ignore
if store_io:
prompt_row.response = result.result # type: ignore
prompt_row.time_taken = float(time.time() - start) # type: ignore
db.commit()

Expand All @@ -108,12 +124,20 @@ def stream(
logger.exception(e)
raise HTTPException(status_code=500, detail=str(e)) from e

def submit(self, chatbot: DB.ChatBot, prompt: T.ApiPromptBody, db: Session, start: float) -> T.CFPromptResult:
def submit(
self,
chatbot: DB.ChatBot,
prompt: T.ApiPromptBody,
db: Session,
start: float,
store_ir: bool,
store_io: bool,
) -> T.CFPromptResult:
if prompt.new_message and prompt.data:
raise HTTPException(status_code=400, detail="prompt cannot have both new_message and data")
try:
logger.debug("Adding prompt to database")
prompt_row = create_prompt(db, chatbot.id, prompt.new_message, prompt.session_id) # type: ignore
prompt_row = create_prompt(db, chatbot.id, prompt.new_message if store_io else "", prompt.session_id) # type: ignore

# Create a Fury chain then run the chain while logging all the intermediate steps
dag = T.Dag(**chatbot.dag) # type: ignore
Expand All @@ -128,7 +152,8 @@ def submit(self, chatbot: DB.ChatBot, prompt: T.ApiPromptBody, db: Session, star
prompt_id=prompt_row.id,
task_id=task_id,
)
prompt_row.response = result.result # type: ignore
if store_io:
prompt_row.response = result.result # type: ignore
prompt_row.time_taken = float(time.time() - start) # type: ignore
db.commit()

Expand Down
28 changes: 25 additions & 3 deletions server/chainfury_server/engines/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,43 @@ class EngineInterface(object):
def engine_name(self) -> str:
raise NotImplementedError("Subclass this and implement engine_name")

def run(self, chatbot: DB.ChatBot, prompt: T.ApiPromptBody, db: Session, start: float) -> T.CFPromptResult:
def run(
self,
chatbot: DB.ChatBot,
prompt: T.ApiPromptBody,
db: Session,
start: float,
store_ir: bool,
store_io: bool,
) -> T.CFPromptResult:
"""
This is the main entry point for the engine. It should return a CFPromptResult.
"""
raise NotImplementedError("Subclass this and implement run()")

def stream(
self, chatbot: DB.ChatBot, prompt: T.ApiPromptBody, db: Session, start: float
self,
chatbot: DB.ChatBot,
prompt: T.ApiPromptBody,
db: Session,
start: float,
store_ir: bool,
store_io: bool,
) -> Generator[Tuple[Union[T.CFPromptResult, Dict[str, Any]], bool], None, None]:
"""
This is the main entry point for the engine. It should return a CFPromptResult.
"""
raise NotImplementedError("Subclass this and implement stream()")

def submit(self, chatbot: DB.ChatBot, prompt: T.ApiPromptBody, db: Session, start: float) -> T.CFPromptResult:
def submit(
self,
chatbot: DB.ChatBot,
prompt: T.ApiPromptBody,
db: Session,
start: float,
store_ir: bool,
store_io: bool,
) -> T.CFPromptResult:
"""
This is the main entry point for the engine. It should return a CFPromptResult.
"""
Expand Down
63 changes: 63 additions & 0 deletions server/chainfury_server/landing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# this is the landing page UI for the app

from time import time
from fastapi.responses import HTMLResponse


async def landing_page():
"""Serves the landing page for ChainFury"""

return HTMLResponse(
status_code=200,
content="""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ChainFury Page</title>
<style>
/* Basic styling for better appearance */
body {
font-family: Arial, sans-serif;
text-align: center;
margin: 50px;
}
img {
width: 512px;
height: 512px;
}
h1 {
font-size: 32px;
}
h2 {
font-size: 24px;
color: #666;
}
.btn {
display: inline-block;
padding: 10px 20px;
margin: 10px;
border: none;
background-color: #007BFF;
color: #fff;
cursor: pointer;
}
</style>
</head>
<body>
<!-- Image with cloudflare URL -->
<img src="https://d2e931syjhr5o9.cloudfront.net/nbox/cf_banner.jpg" alt="ChainFury logo">
<!-- Subtitle below image -->
<h2>ChainFury is a production grade chaining engine used by TuneChat (formerly ChatNBX)</h2>
<!-- Three buttons -->
<a href="https://github.com/NimbleBoxAI/ChainFury" class="btn" target="_blank">GitHub</a>
<a href="https://nimbleboxai.github.io/ChainFury/" class="btn" target="_blank">Documentation</a>
<a href="https://chat.nbox.ai/" class="btn" target="_blank">ChatNBX</a>
</body>
</html>
""",
)

0 comments on commit c070050

Please sign in to comment.