Skip to content

Commit

Permalink
Merge branch 'main' into ben/dev-80
Browse files Browse the repository at this point in the history
  • Loading branch information
bLopata committed Oct 21, 2024
2 parents 6f4329c + 9027d51 commit 44c3811
Show file tree
Hide file tree
Showing 12 changed files with 645 additions and 263 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ __pycache__/
*.pyc
*.pyo
.python-version
api/api.egg-info/*

# Visual Studio Code
.vscode/
Expand Down
2 changes: 1 addition & 1 deletion agent/agent/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def template(self) -> dict[str, str]:
system = (
{
"role": "system",
"content": f"""You are Bloom, a subversive-minded learning companion. Your job is to employ your theory of mind skills to predict the users mental state.
"content": f"""You are Bloom, a subversive-minded learning companion. Your job is to employ your theory of mind skills to predict the user's mental state.
Generate a thought that makes a prediction about the user's needs given current dialogue and also lists other pieces of data that would help improve your prediction
previous commentary: {self.history}""",
},
Expand Down
6 changes: 2 additions & 4 deletions api/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
name = "api"
version = "0.6.0"
description = "The REST API Implementation of Tutor-GPT"
authors = [
{name = "Plastic Labs", email = "hello@plasticlabs.ai"},
]
authors = [{ name = "Plastic Labs", email = "hello@plasticlabs.ai" }]
requires-python = ">=3.11"
dependencies = [
"fastapi[standard]>=0.112.2",
Expand All @@ -16,4 +14,4 @@ dependencies = [

[tool.uv.sources]
# agent = { path = "../agent", editable = true }
agent = {workspace=true}
agent = { workspace = true }
164 changes: 106 additions & 58 deletions api/routers/chat.py
Original file line number Diff line number Diff line change
@@ -1,82 +1,130 @@
from fastapi import APIRouter
from fastapi.responses import StreamingResponse
from fastapi import APIRouter, HTTPException
from fastapi.responses import StreamingResponse, JSONResponse

from api import schemas
from api.dependencies import app, honcho

from agent.chain import ThinkCall, RespondCall

import logging

router = APIRouter(prefix="/api", tags=["chat"])


@router.post("/stream")
async def stream(
inp: schemas.ConversationInput,
):
"""Stream the response too the user, currently only used by the Web UI and has integration to be able to use Honcho is not anonymous"""
user = honcho.apps.users.get_or_create(app_id=app.id, name=inp.user_id)
async def stream(inp: schemas.ConversationInput):
try:
user = honcho.apps.users.get_or_create(app_id=app.id, name=inp.user_id)

def convo_turn():
thought_stream = ThinkCall(
user_input=inp.message,
app_id=app.id,
user_id=user.id,
session_id=str(inp.conversation_id),
honcho=honcho,
).stream()
thought = ""
for chunk in thought_stream:
thought += chunk
yield chunk
async def convo_turn():
thought = ""
response = ""
try:
thought_stream = ThinkCall(
user_input=inp.message,
app_id=app.id,
user_id=user.id,
session_id=str(inp.conversation_id),
honcho=honcho,
).stream()
for chunk in thought_stream:
thought += chunk
yield chunk

yield "❀"
response_stream = RespondCall(
user_input=inp.message,
thought=thought,
app_id=app.id,
user_id=user.id,
session_id=str(inp.conversation_id),
honcho=honcho,
).stream()
response = ""
for chunk in response_stream:
response += chunk
yield chunk
yield "❀"
yield "❀"
response_stream = RespondCall(
user_input=inp.message,
thought=thought,
app_id=app.id,
user_id=user.id,
session_id=str(inp.conversation_id),
honcho=honcho,
).stream()
for chunk in response_stream:
response += chunk
yield chunk
yield "❀"
except Exception as e:
logging.error(f"Error during streaming: {str(e)}")
yield f"Error: {str(e)}"
return

honcho.apps.users.sessions.messages.create(
await create_messages_and_metamessages(
app.id, user.id, inp.conversation_id, inp.message, thought, response
)

return StreamingResponse(convo_turn())
except Exception as e:
logging.error(f"An error occurred: {str(e)}")
if "rate limit" in str(e).lower():
return JSONResponse(
status_code=429,
content={
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please try again later.",
},
)
else:
return JSONResponse(
status_code=500,
content={
"error": "internal_server_error",
"message": "An internal server error has occurred.",
},
)


async def create_messages_and_metamessages(
app_id, user_id, conversation_id, user_message, thought, ai_response
):
try:
# These operations will use the DB layer's built-in retry logic
await honcho.apps.users.sessions.messages.create(
is_user=True,
session_id=str(inp.conversation_id),
app_id=app.id,
user_id=user.id,
content=inp.message,
session_id=str(conversation_id),
app_id=app_id,
user_id=user_id,
content=user_message,
)
new_ai_message = honcho.apps.users.sessions.messages.create(
new_ai_message = await honcho.apps.users.sessions.messages.create(
is_user=False,
session_id=str(inp.conversation_id),
app_id=app.id,
user_id=user.id,
content=response,
session_id=str(conversation_id),
app_id=app_id,
user_id=user_id,
content=ai_response,
)
honcho.apps.users.sessions.metamessages.create(
app_id=app.id,
session_id=str(inp.conversation_id),
user_id=user.id,
await honcho.apps.users.sessions.metamessages.create(
app_id=app_id,
session_id=str(conversation_id),
user_id=user_id,
message_id=new_ai_message.id,
metamessage_type="thought",
content=thought,
)
return StreamingResponse(convo_turn())
except Exception as e:
logging.error(f"Error in create_messages_and_metamessages: {str(e)}")
raise # Re-raise the exception to be handled by the caller


@router.get("/thought/{message_id}")
async def get_thought(conversation_id: str, message_id: str, user_id: str):
user = honcho.apps.users.get_or_create(app_id=app.id, name=user_id)
thought = honcho.apps.users.sessions.metamessages.list(
session_id=conversation_id,
app_id=app.id,
user_id=user.id,
message_id=message_id,
metamessage_type="thought"
)
# In practice, there should only be one thought per message
return {"thought": thought.items[0].content if thought.items else None}
try:
user = honcho.apps.users.get_or_create(app_id=app.id, name=user_id)
thought = honcho.apps.users.sessions.metamessages.list(
session_id=conversation_id,
app_id=app.id,
user_id=user.id,
message_id=message_id,
metamessage_type="thought",
)
# In practice, there should only be one thought per message
return {"thought": thought.items[0].content if thought.items else None}
except Exception as e:
logging.error(f"An error occurred: {str(e)}")
return JSONResponse(
status_code=500,
content={
"error": "internal_server_error",
"message": "An internal server error has occurred.",
},
)
1 change: 1 addition & 0 deletions api/routers/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ async def get_messages(user_id: str, conversation_id: uuid.UUID):
"id": message.id,
"content": message.content,
"isUser": message.is_user,
"metadata": message.metadata,
}
for message in honcho.apps.users.sessions.messages.list(
app_id=app.id, user_id=user.id, session_id=str(conversation_id)
Expand Down
Loading

0 comments on commit 44c3811

Please sign in to comment.