-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bf161b7
commit c33f8f7
Showing
23 changed files
with
9,657 additions
and
3,645 deletions.
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
typescript/examples/dynamic/conversational-agent/.example.env
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
NEXT_PUBLIC_ELEVEN_LABS_AGENT_ID= | ||
NEXT_PUBLIC_SEPOLIA_RPC_URL= | ||
NEXT_PUBLIC_COINGECKO_API_KEY= | ||
NEXT_PUBLIC_DYNAMIC_ENVIRONMENT_ID= |
40 changes: 40 additions & 0 deletions
40
typescript/examples/dynamic/conversational-agent/.gitignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.* | ||
.yarn/* | ||
!.yarn/patches | ||
!.yarn/plugins | ||
!.yarn/releases | ||
!.yarn/versions | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# env files (can opt-in for committing if needed) | ||
.env* | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
12 changes: 12 additions & 0 deletions
12
typescript/examples/dynamic/conversational-agent/CHANGELOG.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# conversational-agent | ||
|
||
## 0.1.1 | ||
|
||
### Patch Changes | ||
|
||
- Updated dependencies [f5ea302] | ||
- Updated dependencies [e61b658] | ||
- @goat-sdk/wallet-viem@0.1.4 | ||
- @goat-sdk/core@0.3.11 | ||
- @goat-sdk/adapter-eleven-labs@0.1.3 | ||
- @goat-sdk/plugin-coingecko@0.1.1 |
30 changes: 30 additions & 0 deletions
30
typescript/examples/dynamic/conversational-agent/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Dynamic + Eleven Labs Conversational Agent Example | ||
|
||
This example uses the ElevenLabs base project described [here](https://elevenlabs.io/docs/conversational-ai/guides/conversational-ai-guide-nextjs) and follows the steps to add client tool calling described [here](https://elevenlabs.io/docs/conversational-ai/customization/client-tools) as well as the Dynamic SDK to connect to the wallet and handle network switching etc. | ||
|
||
Video demo: https://www.loom.com/share/5a89a3fc47a54df18ab051901bf7cc9b | ||
|
||
## Setup | ||
|
||
1. Copy the `.example.env` and populate with your values. | ||
|
||
``` | ||
cp .example.env .env | ||
``` | ||
|
||
2. Create an ElevenLabs agent and get the agent ID. You can follow this guide: https://elevenlabs.io/docs/conversational-ai/docs/agent-setup | ||
|
||
3. Set the `NEXT_PUBLIC_ELEVEN_LABS_AGENT_ID` environment variable with the agent ID. | ||
|
||
4. ElevenLabs requires you to register each tool manually through the ElevenLabs dashboard. To make it easier, we've added a `logTools` option to the `getOnChainTools` function. This will log the tools with their respective descriptions and parameters to the console. | ||
|
||
```typescript | ||
const tools = await getOnChainTools({ | ||
wallet: viem(wallet), | ||
options: { | ||
logTools: true, | ||
}, | ||
}); | ||
``` | ||
|
||
5. Run the app with `pnpm dev`, connect your wallet, and start the conversation! |
7 changes: 7 additions & 0 deletions
7
typescript/examples/dynamic/conversational-agent/next.config.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import type { NextConfig } from "next"; | ||
|
||
const nextConfig: NextConfig = { | ||
/* config options here */ | ||
}; | ||
|
||
export default nextConfig; |
33 changes: 33 additions & 0 deletions
33
typescript/examples/dynamic/conversational-agent/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
{ | ||
"name": "dynamic-conversational-agent", | ||
"version": "0.1.1", | ||
"private": true, | ||
"scripts": { | ||
"dev": "next dev", | ||
"build": "next build", | ||
"start": "next start", | ||
"lint": "next lint" | ||
}, | ||
"dependencies": { | ||
"@11labs/react": "^0.0.4", | ||
"@dynamic-labs/ethereum": "^3.0.0", | ||
"@dynamic-labs/sdk-react-core": "^3.0.0", | ||
"@dynamic-labs/wagmi-connector": "3.9.0", | ||
"@goat-sdk/adapter-eleven-labs": "workspace:*", | ||
"@goat-sdk/core": "workspace:*", | ||
"@goat-sdk/plugin-coingecko": "workspace:*", | ||
"@goat-sdk/wallet-viem": "workspace:*", | ||
"@tanstack/react-query": "^5.62.2", | ||
"next": "15.0.3", | ||
"react": "^18.0.0", | ||
"react-dom": "^18.0.0", | ||
"viem": "^2.21.49", | ||
"wagmi": "^2.13.3" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "^18", | ||
"@types/react-dom": "^18", | ||
"postcss": "^8", | ||
"tailwindcss": "^3.4.1" | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
typescript/examples/dynamic/conversational-agent/postcss.config.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** @type {import('postcss-load-config').Config} */ | ||
const config = { | ||
plugins: { | ||
tailwindcss: {}, | ||
}, | ||
}; | ||
|
||
export default config; |
1 change: 1 addition & 0 deletions
1
typescript/examples/dynamic/conversational-agent/public/file.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions
1
typescript/examples/dynamic/conversational-agent/public/globe.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions
1
typescript/examples/dynamic/conversational-agent/public/next.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions
1
typescript/examples/dynamic/conversational-agent/public/vercel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions
1
typescript/examples/dynamic/conversational-agent/public/window.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
129 changes: 129 additions & 0 deletions
129
typescript/examples/dynamic/conversational-agent/src/app/components/conversation.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
"use client"; | ||
|
||
import { useConversation } from "@11labs/react"; | ||
import { getOnChainTools } from "@goat-sdk/adapter-eleven-labs"; | ||
import { useCallback, useEffect } from "react"; | ||
|
||
import { coingecko } from "@goat-sdk/plugin-coingecko"; | ||
import { viem } from "@goat-sdk/wallet-viem"; | ||
import { DynamicWidget, getNetwork, useSwitchNetwork, useDynamicContext } from "@dynamic-labs/sdk-react-core"; | ||
import { isEthereumWallet } from "@dynamic-labs/ethereum"; | ||
import { useAccount, useWalletClient } from "wagmi"; | ||
import { sendETH } from "../../../../../../packages/core/dist/plugins/send-eth"; | ||
import { sepolia } from "viem/chains"; | ||
|
||
export function Conversation() { | ||
const { primaryWallet, sdkHasLoaded } = useDynamicContext(); | ||
const switchNetwork = useSwitchNetwork(); | ||
|
||
const checkAndSwitchNetwork = async () => { | ||
if (!primaryWallet) { | ||
throw new Error("Wallet not connected"); | ||
} | ||
|
||
if (!isEthereumWallet(primaryWallet)) { | ||
throw new Error("Wallet is not Ethereum"); | ||
} | ||
|
||
const network = await getNetwork(primaryWallet?.connector); | ||
|
||
if (network !== sepolia.id) { | ||
await switchNetwork({ wallet: primaryWallet, network: sepolia.id }); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
if (primaryWallet) { | ||
checkAndSwitchNetwork(); | ||
} | ||
}, [primaryWallet]); | ||
|
||
const { isConnected } = useAccount(); | ||
const { data: wallet } = useWalletClient(); // Get the viem wallet client from Wagmi | ||
|
||
console.log("wallet", wallet); | ||
|
||
const conversation = useConversation({ | ||
onConnect: () => console.log("Connected"), | ||
onDisconnect: () => console.log("Disconnected"), | ||
onMessage: (message) => console.log("Message:", message), | ||
onError: (error) => console.error("Error:", error), | ||
}); | ||
|
||
const startConversation = useCallback(async () => { | ||
try { | ||
// Request microphone permission | ||
await navigator.mediaDevices.getUserMedia({ audio: true }); | ||
|
||
if (!wallet) { | ||
throw new Error("Wallet not connected"); | ||
} | ||
|
||
// const wallet = viem Client | ||
const tools = await getOnChainTools({ | ||
wallet: viem(wallet), | ||
plugins: [ | ||
sendETH(), | ||
coingecko({ | ||
apiKey: process.env.NEXT_PUBLIC_COINGECKO_API_KEY ?? "", | ||
}), | ||
], | ||
options: { | ||
logTools: true, | ||
}, | ||
}); | ||
|
||
// Start the conversation with your agent | ||
await conversation.startSession({ | ||
agentId: process.env.NEXT_PUBLIC_ELEVEN_LABS_AGENT_ID ?? "", // Replace with your agent ID | ||
clientTools: tools, | ||
}); | ||
} catch (error) { | ||
console.error("Failed to start conversation:", error); | ||
} | ||
}, [conversation, wallet]); | ||
|
||
const stopConversation = useCallback(async () => { | ||
await conversation.endSession(); | ||
}, [conversation]); | ||
|
||
if (!sdkHasLoaded) { | ||
return <div>Loading...</div>; | ||
} | ||
|
||
return ( | ||
<div className="flex flex-col items-center gap-4"> | ||
<h1 className="text-2xl font-bold">{isConnected ? "1. You're Connected" : "1. Connect Wallet to start"}</h1> | ||
<DynamicWidget /> | ||
|
||
<h1 className="text-2xl font-bold">2. Start Conversation with Agent</h1> | ||
<div className="flex flex-col items-center gap-4"> | ||
<div className="flex gap-2"> | ||
<button | ||
onClick={startConversation} | ||
disabled={conversation.status === "connected" || !isConnected} | ||
className="px-4 py-2 bg-blue-500 text-white rounded disabled:bg-gray-300" | ||
type="button" | ||
> | ||
Start Conversation | ||
</button> | ||
<button | ||
onClick={stopConversation} | ||
disabled={conversation.status !== "connected"} | ||
className="px-4 py-2 bg-red-500 text-white rounded disabled:bg-gray-300" | ||
type="button" | ||
> | ||
Stop Conversation | ||
</button> | ||
</div> | ||
|
||
<div className="flex flex-col items-center"> | ||
<p>Status: {conversation.status}</p> | ||
{conversation.status === "connected" && ( | ||
<p>Agent is {conversation.isSpeaking ? "speaking" : "listening"}</p> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
Binary file not shown.
Binary file added
BIN
+66.3 KB
typescript/examples/dynamic/conversational-agent/src/app/fonts/GeistMonoVF.woff
Binary file not shown.
Binary file added
BIN
+64.7 KB
typescript/examples/dynamic/conversational-agent/src/app/fonts/GeistVF.woff
Binary file not shown.
21 changes: 21 additions & 0 deletions
21
typescript/examples/dynamic/conversational-agent/src/app/globals.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; | ||
|
||
:root { | ||
--background: #ffffff; | ||
--foreground: #171717; | ||
} | ||
|
||
@media (prefers-color-scheme: dark) { | ||
:root { | ||
--background: #0a0a0a; | ||
--foreground: #ededed; | ||
} | ||
} | ||
|
||
body { | ||
color: var(--foreground); | ||
background: var(--background); | ||
font-family: Arial, Helvetica, sans-serif; | ||
} |
34 changes: 34 additions & 0 deletions
34
typescript/examples/dynamic/conversational-agent/src/app/layout.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import type { Metadata } from "next"; | ||
import localFont from "next/font/local"; | ||
import "./globals.css"; | ||
import { Web3Provider } from "./providers"; | ||
|
||
const geistSans = localFont({ | ||
src: "./fonts/GeistVF.woff", | ||
variable: "--font-geist-sans", | ||
weight: "100 900", | ||
}); | ||
const geistMono = localFont({ | ||
src: "./fonts/GeistMonoVF.woff", | ||
variable: "--font-geist-mono", | ||
weight: "100 900", | ||
}); | ||
|
||
export const metadata: Metadata = { | ||
title: "Create Next App", | ||
description: "Generated by create next app", | ||
}; | ||
|
||
export default function RootLayout({ | ||
children, | ||
}: Readonly<{ | ||
children: React.ReactNode; | ||
}>) { | ||
return ( | ||
<html lang="en"> | ||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}> | ||
<Web3Provider>{children}</Web3Provider> | ||
</body> | ||
</html> | ||
); | ||
} |
12 changes: 12 additions & 0 deletions
12
typescript/examples/dynamic/conversational-agent/src/app/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Conversation } from "./components/conversation"; | ||
|
||
export default function Home() { | ||
return ( | ||
<main className="flex min-h-screen flex-col items-center justify-between p-24"> | ||
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm"> | ||
<h1 className="text-4xl font-bold mb-8 text-center">GOAT 🐐 Conversational AI</h1> | ||
<Conversation /> | ||
</div> | ||
</main> | ||
); | ||
} |
38 changes: 38 additions & 0 deletions
38
typescript/examples/dynamic/conversational-agent/src/app/providers.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
"use client"; | ||
|
||
import { DynamicContextProvider } from "@dynamic-labs/sdk-react-core"; | ||
import { DynamicWagmiConnector } from "@dynamic-labs/wagmi-connector"; | ||
import { http, createConfig, WagmiProvider } from "wagmi"; | ||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; | ||
import { sepolia } from "viem/chains"; | ||
import { EthereumWalletConnectors } from "@dynamic-labs/ethereum"; | ||
|
||
const config = createConfig({ | ||
chains: [sepolia], | ||
multiInjectedProviderDiscovery: false, | ||
transports: { | ||
[sepolia.id]: http(process.env.NEXT_PUBLIC_SEPOLIA_RPC_URL ?? ""), | ||
}, | ||
}); | ||
|
||
const queryClient = new QueryClient(); | ||
|
||
export const Web3Provider = ({ children }: { children: React.ReactNode }) => { | ||
return ( | ||
<DynamicContextProvider | ||
settings={{ | ||
// Find your environment id at https://app.dynamic.xyz/dashboard/developer | ||
environmentId: process.env.NEXT_PUBLIC_DYNAMIC_ENVIRONMENT_ID ?? "", | ||
walletConnectors: [EthereumWalletConnectors], | ||
}} | ||
> | ||
<WagmiProvider config={config}> | ||
<QueryClientProvider client={queryClient}> | ||
<DynamicWagmiConnector> | ||
{children} | ||
</DynamicWagmiConnector> | ||
</QueryClientProvider> | ||
</WagmiProvider> | ||
</DynamicContextProvider> | ||
); | ||
}; |
Oops, something went wrong.