Skip to content

Commit 695ab9f

Browse files
committed
Added example home assistant.
1 parent d91d7b3 commit 695ab9f

File tree

6 files changed

+203
-0
lines changed

6 files changed

+203
-0
lines changed

BrotBoxEngine/String.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,10 @@ bbe::Utf8String bbe::Utf8String::hardBreakEvery(int32_t x) const
770770
int32_t column = 0;
771771
for (auto it = getIterator(); it.valid(); ++it)
772772
{
773+
if (*it == '\n')
774+
{
775+
column = 0;
776+
}
773777
if (column == x)
774778
{
775779
retVal += "\n";

Examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_subdirectory(ExampleFluidSimulation)
2222
if(BBE_ADD_EXPERIMENTAL)
2323
add_subdirectory(ExampleGrid)
2424
endif()
25+
add_subdirectory(ExampleHomeAssistant)
2526
add_subdirectory(ExampleMandelbrot)
2627
if(NOT EMSCRIPTEN) # Requires "double" in shader code.
2728
add_subdirectory(ExampleMandelbrotShader)
16.5 KB
Loading
19.8 KB
Loading
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add_trivial_project(ExampleHomeAssistant)
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#include "BBE/BrotBoxEngine.h"
2+
#include "AssetStore.h"
3+
#include <iostream>
4+
5+
class MyGame : public bbe::Game
6+
{
7+
bbe::String accessToken = "";
8+
bbe::String input;
9+
bbe::String reply;
10+
11+
std::map<std::string, bool> rooms;
12+
13+
virtual void onStart() override
14+
{
15+
rooms["Living room"] = false;
16+
rooms["Dining room"] = false;
17+
rooms["Kitchen"] = false;
18+
rooms["Bathroom"] = false;
19+
}
20+
21+
const bbe::Image* getLampState(const char* room)
22+
{
23+
return rooms[room] ? assetStore::LampOn() : assetStore::LampOff();
24+
}
25+
26+
void ToggleLight(const char* room, bool value)
27+
{
28+
rooms[room] = value;
29+
}
30+
31+
void renderRoom(bbe::PrimitiveBrush2D& brush, const char* room, float x, float y)
32+
{
33+
brush.drawImage(x, y, 189.f / 2.f, 338.f / 2.f, *getLampState(room));
34+
brush.fillText(x + 189.f / 4.f, y, room, 40, bbe::Anchor::BOTTOM_CENTER);
35+
}
36+
37+
virtual void update(float timeSinceLastFrame) override
38+
{
39+
}
40+
virtual void draw3D(bbe::PrimitiveBrush3D& brush) override
41+
{
42+
}
43+
virtual void draw2D(bbe::PrimitiveBrush2D& brush) override
44+
{
45+
ImGuiViewport fullViewport = *ImGui::GetMainViewport();
46+
fullViewport.WorkSize.x *= 0.5f;
47+
ImGui::SetNextWindowPos(fullViewport.WorkPos);
48+
ImGui::SetNextWindowSize(fullViewport.WorkSize);
49+
ImGui::Begin("Window", 0, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoBringToFrontOnFocus);
50+
{
51+
ImGui::bbe::InputText("Access Token", accessToken, ImGuiInputTextFlags_Password);
52+
if (ImGui::BeginTabBar("MainWindowTabs"))
53+
{
54+
if (ImGui::BeginTabItem("Demo1"))
55+
{
56+
bool send = false;
57+
send |= ImGui::bbe::InputText("Input", input, ImGuiInputTextFlags_EnterReturnsTrue);
58+
send |= ImGui::Button("Send");
59+
ImGui::SameLine();
60+
if (ImGui::Button("Answer To Clipboard"))
61+
{
62+
setClipboard(reply);
63+
}
64+
65+
if (send)
66+
{
67+
auto body = R"({
68+
"model": "openai/gpt-oss-120b:cerebras",
69+
"messages": [
70+
{
71+
"role": "system",
72+
"content": "Be a helpful bot. Answer in ASCII Characters only. No markdown."
73+
},
74+
{
75+
"role": "user",
76+
"content": ")" + input + R"("
77+
}
78+
]
79+
})";
80+
auto request = bbe::simpleUrlRequest::urlRequest(
81+
"https://router.huggingface.co/v1/chat/completions",
82+
{ "Authorization: Bearer " + accessToken, "Content-Type: application/json" },
83+
body);
84+
reply = nlohmann::json::parse(request.dataContainer.getRaw()).dump(1).c_str();
85+
reply = reply.hardBreakEvery(89);
86+
}
87+
ImGui::Text("%s", reply.getRaw());
88+
89+
ImGui::EndTabItem();
90+
}
91+
if (ImGui::BeginTabItem("Demo2"))
92+
{
93+
bool send = false;
94+
send |= ImGui::bbe::InputText("Input", input, ImGuiInputTextFlags_EnterReturnsTrue);
95+
send |= ImGui::Button("Send");
96+
ImGui::SameLine();
97+
if (ImGui::Button("Answer To Clipboard"))
98+
{
99+
setClipboard(reply);
100+
}
101+
102+
if (send)
103+
{
104+
auto body = R"({
105+
"model": "openai/gpt-oss-120b:cerebras",
106+
"messages": [
107+
{
108+
"role": "system",
109+
"content": "Be a useful home assistant."
110+
},
111+
{
112+
"role": "user",
113+
"content": ")" + input + R"("
114+
}
115+
],
116+
"tool_choice": "auto",
117+
"tools": [
118+
{
119+
"type": "function",
120+
"function": {
121+
"name": "toggle_light",
122+
"description": "Turns a light on or off.",
123+
"parameters": {
124+
"type": "object",
125+
"properties": {
126+
"device_id": {
127+
"type": "string",
128+
"enum": [
129+
"Living room",
130+
"Dining room",
131+
"Kitchen",
132+
"Bathroom"
133+
]
134+
},
135+
"state": {
136+
"type": "string",
137+
"enum": [
138+
"on",
139+
"off"
140+
]
141+
}
142+
},
143+
"required": [
144+
"device_id",
145+
"state"
146+
],
147+
"additionalProperties": false
148+
}
149+
}
150+
}
151+
]
152+
})";
153+
auto request = bbe::simpleUrlRequest::urlRequest(
154+
"https://router.huggingface.co/v1/chat/completions",
155+
{ "Authorization: Bearer " + accessToken, "Content-Type: application/json" },
156+
body);
157+
auto replyJson = nlohmann::json::parse(request.dataContainer.getRaw());
158+
auto nameLocation = nlohmann::json::json_pointer("/choices/0/message/tool_calls/0/function/name");
159+
if (replyJson.contains(nameLocation) && replyJson[nameLocation] == "toggle_light")
160+
{
161+
auto argumentsJson = nlohmann::json::parse(replyJson[nlohmann::json::json_pointer("/choices/0/message/tool_calls/0/function/arguments")].get<std::string>());
162+
ToggleLight(argumentsJson["device_id"].get<std::string>().c_str(), argumentsJson["state"] == "on");
163+
}
164+
reply = nlohmann::json::parse(request.dataContainer.getRaw()).dump(1).c_str();
165+
reply = reply.hardBreakEvery(89);
166+
}
167+
ImGui::Text("%s", reply.getRaw());
168+
169+
170+
171+
renderRoom(brush, "Living room", 640 + 320 - 95 - 150, 100);
172+
renderRoom(brush, "Dining room", 640 + 320 - 95 + 150, 100);
173+
renderRoom(brush, "Kitchen", 640 + 320 - 95 - 150, 400);
174+
renderRoom(brush, "Bathroom", 640 + 320 - 95 + 150, 400);
175+
176+
ImGui::EndTabItem();
177+
}
178+
ImGui::EndTabBar();
179+
}
180+
}
181+
ImGui::End();
182+
183+
}
184+
virtual void onEnd() override
185+
{
186+
}
187+
};
188+
189+
int main()
190+
{
191+
MyGame* mg = new MyGame();
192+
mg->start(1280, 720, "Home Assistant!");
193+
#ifndef __EMSCRIPTEN__
194+
delete mg;
195+
#endif
196+
}
197+

0 commit comments

Comments
 (0)