Skip to content

Commit

Permalink
Merge branch 'deep-search' into v2
Browse files Browse the repository at this point in the history
  • Loading branch information
valgaze committed May 20, 2024
2 parents c300730 + 730150c commit ed6a81f
Show file tree
Hide file tree
Showing 63 changed files with 6,527 additions and 6,324 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ abc.ts
.vitepress/cache
docs/.vitepress/cache/*
coverage/
todo.md
todo.md
message_log.txt
changelog.md
5 changes: 4 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ coverage/
todo.md
.github
.vscode
trickyoperation.ts
trickyoperation.ts
contributing.md
devtools/
changelog.md
126 changes: 61 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<img src="https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/memes/logo4.jpeg?raw=true" />

tl;dr: SpeedyBot helps you efficiently design, deploy, and secure rich conversation systems
tl;dr: SpeedyBot helps you efficiently design, deploy, and secure rich conversation systems-- go from zero to a bot in seconds **[here](https://speedybot.js.org/new)**

## Setup

Expand All @@ -21,105 +21,101 @@ npm install speedybot

## Speedy & Easy

- SpeedyBot offers a buttery-smooth developer experience to keep you building your bots rather than scouring the docs. It's written in typescript + built-in type hints with autocomplete, has zero external dependencies, supports ESM + CommonJS, provides lots of other DX goodness that makes building bots a breeze like local development with live-reload (see **[here for details](https://github.com/valgaze/speedybot/blob/v2/examples/speedybot-starter/settings/bot.ts)**).
- SpeedyBot offers a buttery-smooth developer experience to keep you building your bots rather than scouring the docs. It's written in typescript + built-in type hints with autocomplete, **has zero external dependencies**, supports ESM + CommonJS, provides lots of other DX goodness like live-reload on code changes that makes building bots speedy and easy (see **[here for details](https://speedybot.js.org/new)**).

- SpeedyBot shrinks away all the complexity and makes it a breeze to handle user input regardless of the source/modality-- text, file uploads, form submission from SpeedyCards, etc

- SpeedyBot seamlessly operates across diverse severless/container-less platforms (Lambda/Deno/Workers/etc) as well as conventional fixed servers and even within CI/CD scripts. As long you've got internet connectivity, SpeedyBot functions seamlessly

## SpeedyBot basics

You can see fleshed-out examples at **[https://speedybot.js.org/examples/](https://speedybot.js.org/examples/)** and see how SpeedyBot has you covered for crafting bots that can do it all-- securely integrate w/ LLMs + content management systems, **[process file-uploads](https://speedybot.js.org/patterns.md#handle-file-uploads)**, **[segment content based on user data + behavior](https://speedybot.js.org/patterns.md#restrict-emails)**, create + manage **[SpeedyCards](https://speedybot.js.org/speedycard)**, ask for a user's location in a privacy-respecting way and lots more.
You can get a bot up and running fast by grabbing one of the batteries-included samples at **[https://speedybot.js.org/examples](https://speedybot.js.org/examples/)** and see how SpeedyBot has you covered for crafting bots that can do it all-- **[securely integrate w/ LLMs + content management systems](https://speedybot.js.org/examples/voiceflow/README)**, **[process file-uploads](https://speedybot.js.org/patterns.md#handle-file-uploads)**, **[segment content based on user data + behavior](https://speedybot.js.org/patterns.md#restrict-emails)**, create + manage **[SpeedyCards](https://speedybot.js.org/speedycard)**, **[ask for a user's location in a privacy-respecting way](https://speedybot.js.org/examples/location/README)** and lots more.

### Auto-binding
## The basics

As a convenience, SpeedyBot's "magic" $ parameter will auto-bind to the incoming message and give you access to all kinds of useful features
- SpeedyBot streamlines the creation of conversation systems, making it easy to deploy and manage bots. When your SpeedyBot receives an event from a user (such as a message, card, or file upload), it processes the event through a sequence of steps, similar to how a car moves through a carwash.

```js
const Bot = new SpeedyBot();
- Each step is just a function which **must** return either $.next to proceed to the next step or $.end to terminate the chain. Each step can be synchronous or asynchronous depending on what you need to do

// You get an incoming messsage
Bot.addStep(async ($) => {
await $.send("Hello the originating person/room");
await $.reply("Reply to the originating person/room");
- A step can do **whatever** you want (ex send the user a message or a **[SpeedyCard](https://speedybot.js.org/speedycard)**, call an API to interact with some external system, or do nothing at all)

- Whatever you're up to in a step, however, try not to take too long to do it because you probably don't want to keep your user waiting

// The same as the following
await Bot.sendTo($.author.email, "my message");
Here's a starter `bot.ts`:

const parentMessageID = $.id;
await Bot.replyTo(parentMessageID, $.author.email, "my great reply message");
```ts
import { SpeedyBot } from "speedybot";

const Bot = new SpeedyBot();

Bot.addStep(async ($) => {
await $.send("Step 1");
if ($.text === "hi") {
await $.reply(`Hi there ${$.author.name}!`);
}
return $.next;
});
```

There's also a lot more you can do
Bot.addStep(($) => {
$.ctx.scribbledData = "someData_" + Math.random();
return $.next;
});

<img src="https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/autocomplete.gif?raw=true" />
Bot.addStep(async ($) => {
await $.send("Step 2");
const card = $.card()
.addTitle("My great card!")
.addText(`The random scribbled data is ${$.ctx.scribbledData}`)
.addTable([
["Label", "Data 1"],
["Label 2", "Data 2"],
["Label 3", "Data 3"],
]);
await $.send(card); // send a card, not just text
return $.next;
});

## SpeedyCards
Bot.addStep(async ($) => {
await $.send("Step 3");
return $.end; // <--- Stops the train!
});

SpeedyCards make it (yep) speedy and easy to build **[Adaptive Cards](https://adaptivecards.io)** where you can easily collect structured data from users and add colors, "chips", formatting and other visual embellishments.
Bot.addStep(async ($) => {
await $.send("Step 4 (we never reach this!");
return $.end;
});
```

<img src="https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/speedycard.gif?raw=true" />
<img src="https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/demo_basics.gif?raw=true">

<img src="https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/demo_chips.gif?raw=true" />
- The $ parameter provides a bunch of useful features, allowing you to reply to messages, send and check card data (see **[details on that](https://speedybot.js.org/patterns.html#simple-card-handler)**), and access information about the message and its author.

## LLM Token Streaming
<img src="https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/autocomplete.gif?raw=true" />

SpeedyBot makes it speedy & easy to build serverless bots for the LLM era. See the **[LLM steam example](https://speedybot.js.org/examples/llm-stream)**
- Important: Avoid excessive usage of steps. If you find yourself writing a lot of "handlers" or checks in your steps you might be making things harder than they need to be. For a natural language "conversation", for example, focus on capturing user utterances (`$.text`) in your steps and then all you need to do is transmit back and forth to an external service and keep your steps short and sweet and simple

<img src="https://github.com/valgaze/speedybot-utils/blob/main/assets/various/llm_stream.gif?raw=true" />
- Execution Order: Generally speaking, steps will fire in the order they are added to your `bot.ts`-- for convenience, there is a `Bot.insertStepToFront` step which will slip the supplied step to the front of the chain and also `Bot.addStepSequence` to add a list of steps all at once

## SpeedyBot "listener"
## Garage

You can use SpeedyBot to only send messages + cards and nothing more. But if you have data on those cards you want to capture or if you want to provide an automated conversation experience SpeedyBot takes of all the hassle.
SpeedyBot's docs are special-- they're interactive and you can do things with them. From the Patterns docs you can grab **[code snippets](https://speedybot.js.org/patterns)** and throw them right into your bot. Inside the visaul **[SpeedyBot Garage](https://speedybot.js.org/garage)** experience you can register webhooks and design + preview + send **[SpeedyCards](https://speedybot.js.org/speedycard)**

Ex. Here is a minimal handler that will echo back information if a user transmits data via text, file, and adaptive card. Write "show card" to display a card. You can chain multiple addSteps if you need to, but in this era you probably don't need/want to be doing much logic in code.
<img src="https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/webhook_steps.gif" />

See full example applications here: **[https://speedybot.js.org/examples](https://speedybot.js.org/examples)**
## SpeedyCards

```ts
import { SpeedyBot } from "speedybot";
SpeedyCards make it speedy and easy to build **[Adaptive Cards](https://adaptivecards.io)** where you can easily collect structured data from users and add colors, "chips", formatting and other visual embellishments.

const Bot = new SpeedyBot();
Bot.addStep(async ($) => {
// handle text
if ($.text) {
await $.send(`You said "${$.text}`);

if ($.text.toLowerCase() === "showcard") {
const card = $.card()
.addTitle("Capture data")
.addTextarea("Submit data")
.addPickerDropdown(["option 1", "option 2", "option 3", "option 4"]);
await $.send(card);
}
}
<img src="https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/speedycard.gif?raw=true" />

// file handler
if ($.file) {
const { name, extension, contentType } = $.file;
await $.send(
`You uploaded "${name}", a *.${extension} file [${contentType}]`
);
// Fetch raw bytes (which you can pass onto other systems)
// const TheData = await $.file.getData(); // do something w/ the contents/bytes
}
<img src="https://raw.githubusercontent.com/valgaze/speedybot-utils/main/assets/various/demo_chips.gif?raw=true" />

// form/card submissions
if ($.data) {
const dataSnippet = $.buildDataSnippet($.data);
await $.send(`This data was submitted:`);
await $.send(dataSnippet);
}
## LLM Token Streaming

return $.next;
});
SpeedyBot makes it speedy & easy to build serverless bots for the LLM era. See the **[LLM steam example](https://speedybot.js.org/examples/llm-stream)**

export default Bot;
```
<img src="https://github.com/valgaze/speedybot-utils/blob/main/assets/various/llm_stream.gif?raw=true" />

## 🐍 Speedybot-Python

If you want to build bots with Python rather than Typescript, you can check out [🐍Speedybot-Python🐍](https://pypi.org/project/speedybot)
If you want to build bots with Python rather than Typescript, you can also check out [🐍Speedybot-Python🐍](https://pypi.org/project/speedybot)
13 changes: 13 additions & 0 deletions contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Contributing

Contributions and better ways of doing things always welcome

If you want to extend SpeedyBot or add an example, take a look at the codebase and feel free to make a PR

## Wishlist

- VSC Extension

- Stable Tauri (crashes on M1) for no-fuss coding

- Bulk send, bulk add to space, get all 1st messages
7 changes: 7 additions & 0 deletions docs/.vitepress/components/SendMsg.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<TokenInput
v-if="!store.state.tokenValid && showToken"
:autofocus="autofocus"
:skipRoomConfig="skipRoomConfig"
/>
</div>

Expand Down Expand Up @@ -57,6 +58,12 @@ const targetRoom = ref("");
const showToken = ref(true);
const props = defineProps({
skipRoomConfig: {
type: Boolean,
default() {
return true;
},
},
msg: {
type: Object,
},
Expand Down
8 changes: 4 additions & 4 deletions docs/.vitepress/components/SpeedyCardEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@
></compact-select>

<el-tabs v-model="activeName" :class="{ 'is-dark': isDark }">
<el-tab-pane label="SpeedyCard editor" name="editor">
<el-tab-pane label="📝 SpeedyCard editor" name="editor">
<MonacoEditor
@editorReady="initParent"
@valChanged="handleChange"
:isDark="isDark"
/>
</el-tab-pane>
<el-tab-pane label="Preview" name="preview">
<el-tab-pane label="🔭 Preview" name="preview">
<el-card class="box-card">
<AdaptiveCardRender :jsonData="jsonData" />
</el-card>
</el-tab-pane>
<el-tab-pane label="Send Message" name="sendmessage">
<SendMsg :msg="jsonData" :showRecents="false" />
<el-tab-pane label="📤 Send Message" name="sendmessage">
<SendMsg :msg="jsonData" :showRecents="false" :skipRoomConfig="true" />
</el-tab-pane>
</el-tabs>
</client-only>
Expand Down
64 changes: 63 additions & 1 deletion docs/.vitepress/components/token_handler.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
<template>
<client-only>
<div>
<el-collapse accordion @change="handleChange" v-if="!skipRoomConfig">
<el-collapse-item
:title="label + ' Room Filter Options ' + label"
name="2"
>
<el-form-item label="FULL Room Scan">
<el-switch v-model="store.state.deepSearch" />
</el-form-item>

<el-form-item label="Room Type">
<el-radio-group v-model="store.state.roomFilters.type">
<el-radio :label="undefined">Both</el-radio>
<el-radio :label="'group'">Group</el-radio>
<el-radio :label="'direct'">Direct</el-radio>
</el-radio-group>
</el-form-item>

<el-form-item label="Sort By">
<el-radio-group v-model="store.state.roomFilters.sortBy">
<el-radio :label="''">None</el-radio>
<el-radio :label="'created'">Created</el-radio>
<el-radio :label="'lastactivity'">Last Activity</el-radio>
<el-radio :label="'id'">ID</el-radio>
</el-radio-group>
</el-form-item>
</el-collapse-item>
</el-collapse>
<el-input
v-model="store.state.token"
@input="checkToken(store.state.token)"
Expand All @@ -18,6 +45,12 @@
>
</template>
</el-input>

<!-- <el-switch
v-model="store.state.deepSearch"
label="Full Room Search"
size="small"
/> -->
<el-alert
v-if="
store.state.tokenValid === false &&
Expand Down Expand Up @@ -61,11 +94,14 @@
</template>

<script lang="ts" setup>
import { ref } from "vue";
import { Refresh } from "@element-plus/icons-vue";
import { useCustomStore } from "./../util/store";
import { computed, watch } from "vue";
// import { ElLoading } from "element-plus";
const store = useCustomStore();
const label = ref("⭐️");
const emit = defineEmits();
const checkToken = async (tokenCandidate: string) => {
if (tokenCandidate.length > 5) {
Expand All @@ -76,7 +112,33 @@ const checkToken = async (tokenCandidate: string) => {
}
};
const watchFilters = computed(() => ({
roomFiltersSort: store.state.roomFilters.sortBy,
roomFiltersType: store.state.roomFilters.type,
deepSearch: store.state.deepSearch,
}));
watch(watchFilters, async (newValues, oldValues) => {
if (store.state.token) {
await store.validateToken(store.state.token);
}
});
const handleChange = (val: string[]) => {
if (val) {
label.value = "🌟";
} else {
label.value = "⭐️";
}
};
const props = defineProps({
skipRoomConfig: {
type: Boolean,
default() {
return false;
},
},
showInfo: {
type: Boolean,
default() {
Expand Down
Loading

0 comments on commit ed6a81f

Please sign in to comment.