-
Notifications
You must be signed in to change notification settings - Fork 84
Expand file tree
/
Copy pathmain.py
More file actions
118 lines (104 loc) · 4.05 KB
/
Copy pathmain.py
File metadata and controls
118 lines (104 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from typing import AsyncGenerator
import openai
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from openai.types.chat import (
ChatCompletionAssistantMessageParam,
ChatCompletionMessageParam,
ChatCompletionSystemMessageParam,
ChatCompletionUserMessageParam,
)
from openbb_ai import message_chunk
from openbb_ai.models import MessageChunkSSE, QueryRequest
from sse_starlette.sse import EventSourceResponse
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/agents.json")
def get_copilot_description():
"""Agent descriptor for the OpenBB Workspace."""
return JSONResponse(
content={
"vanilla_agent_custom_features": {
"name": "Vanilla Agent Custom Features",
"description": "A simple agent that reports its feature status.",
"image": (
"https://github.com/OpenBB-finance/copilot-for-terminal-pro/"
"assets/14093308/7da2a512-93b9-478d-90bc-b8c3dd0cabcf"
),
"endpoints": {"query": "/v1/query"},
"features": {
"streaming": True,
"widget-dashboard-select": False,
"widget-dashboard-search": False,
"deep-research": {
"label": "Deep Research",
"default": False,
"description": "Allows the copilot to do deep research",
},
"web-search": {
"label": "Web Search",
"default": True,
"description": "Allows the copilot to search the web.",
},
},
}
}
)
@app.post("/v1/query")
async def query(request: QueryRequest) -> EventSourceResponse:
"""Stream a simple greeting with feature status."""
# Check workspace_options from request payload
# workspace_options is a list like ["web-search"] or ["deep-research", "web-search"]
workspace_options = getattr(request, "workspace_options", [])
# Check which features are enabled
deep_research_enabled = "deep-research" in workspace_options
web_search_enabled = "web-search" in workspace_options
# Build the feature status message
features_msg = (
f"- Deep Research: {'✅ Enabled' if deep_research_enabled else '❌ Disabled'}\n"
f"- Web Search: {'✅ Enabled' if web_search_enabled else '❌ Disabled'}"
)
openai_messages: list[ChatCompletionMessageParam] = [
ChatCompletionSystemMessageParam(
role="system",
content=(
"You are a simple greeting agent.\n"
"Greet the user and let them know their current feature settings:\n"
f"{features_msg}\n"
"Keep your response brief and friendly."
),
)
]
for message in request.messages:
if message.role == "human":
openai_messages.append(
ChatCompletionUserMessageParam(role="user", content=message.content)
)
elif message.role == "ai" and isinstance(message.content, str):
openai_messages.append(
ChatCompletionAssistantMessageParam(
role="assistant", content=message.content
)
)
async def execution_loop() -> AsyncGenerator[MessageChunkSSE, None]:
client = openai.AsyncOpenAI()
async for event in await client.chat.completions.create(
model="gpt-4o",
messages=openai_messages,
stream=True,
):
if chunk := event.choices[0].delta.content:
yield message_chunk(chunk)
return EventSourceResponse(
content=(
event.model_dump(exclude_none=True) async for event in execution_loop()
),
media_type="text/event-stream",
)