diff --git a/examples/career-prep-coach/.env.example b/examples/career-prep-coach/.env.example index 85d27328..f47f330a 100644 --- a/examples/career-prep-coach/.env.example +++ b/examples/career-prep-coach/.env.example @@ -1 +1,2 @@ -NEXT_LB_PIPE_API_KEY="" \ No newline at end of file +LANGBASE_PIPE_API_KEY="" + diff --git a/examples/career-prep-coach/README.md b/examples/career-prep-coach/README.md index d8bb31a4..c3035894 100755 --- a/examples/career-prep-coach/README.md +++ b/examples/career-prep-coach/README.md @@ -36,7 +36,7 @@ To get started with Langbase, you'll need to [create a free personal account on 6. Add the following environment variables (.env.local): ``` # Replace `PIPE_API_KEY` with the copied API key. - NEXT_LB_PIPE_API_KEY="PIPE_API_KEY" + LANGBASE_PIPE_API_KEY="PIPE_API_KEY" ``` 7. Issue the following in your CLI: @@ -65,7 +65,7 @@ This project is created by [Langbase][lb] team members, with contributions from: [demo]: https://career-prep-coach.langbase.dev [lb]: https://langbase.com -[pipe]: https://beta.langbase.com/examples/career-prep-coach +[pipe]: https://langbase.com/examples/career-prep-coach [gh]: https://github.com/LangbaseInc/langbase-examples/tree/main/examples/career-prep-coach [cover]:https://raw.githubusercontent.com/LangbaseInc/docs-images/main/examples/career-prep-coach/career-prep-coach.png [download]:https://download-directory.github.io/?url=https://github.com/LangbaseInc/langbase-examples/tree/main/examples/career-prep-coach diff --git a/examples/career-prep-coach/app/api/chat/route.ts b/examples/career-prep-coach/app/api/chat/route.ts index 70710650..4874861a 100755 --- a/examples/career-prep-coach/app/api/chat/route.ts +++ b/examples/career-prep-coach/app/api/chat/route.ts @@ -26,9 +26,9 @@ export async function POST(req: Request) { } - if (!process.env.NEXT_LB_PIPE_API_KEY) { + if (!process.env.LANGBASE_PIPE_API_KEY) { throw new Error( - 'Please set NEXT_LB_PIPE_API_KEY in your environment variables.' + 'Please set LANGBASE_PIPE_API_KEY in your environment variables.' ) } @@ -39,14 +39,14 @@ export async function POST(req: Request) { } else if (action === 'getMemorySets') { return handleGetMemorySets(userApiKey) } else if (action === 'updatePipe') { - const { memoryName } = await req.json() + const { memoryName } = body; return updatePipe(ownerLogin, memoryName, userApiKey) } else { const endpointUrl = 'https://api.langbase.com/beta/chat' const headers = { 'Content-Type': 'application/json', - Authorization: `Bearer ${process.env.NEXT_LB_PIPE_API_KEY}` + Authorization: `Bearer ${process.env.LANGBASE_PIPE_API_KEY}` } // Get chat prompt messages and threadId from the client. @@ -153,11 +153,18 @@ async function handleFileUpload(req: Request, userApiKey: string, ownerLogin: st } async function updatePipe(ownerLogin: string | undefined, memoryName: string, userApiKey: string) { - const url = `https://api.langbase.com/beta/pipes/${ownerLogin}/shoes-expert`; + + if (!ownerLogin || !memoryName || !userApiKey) { + return new Response(JSON.stringify({ error: 'Missing required parameters' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + const url = `https://api.langbase.com/beta/pipes/${ownerLogin}/career-prep-coach`; const pipe = { - name: "shoes-expert", - description: "An AI-powered shoe expert that recommends Nike and Adidas footwear based on customer preferences and provides personalized shopping assistance.", + name: "career-prep-coach", + description: "Your AI-powered personal interview coach, expertly preparing you for success using proven techniques and tailored feedback.", status: "private", config: { memorysets: [memoryName] diff --git a/examples/career-prep-coach/components/chatbot-page.tsx b/examples/career-prep-coach/components/chatbot-page.tsx index bb7214f7..019ec0b0 100755 --- a/examples/career-prep-coach/components/chatbot-page.tsx +++ b/examples/career-prep-coach/components/chatbot-page.tsx @@ -7,6 +7,7 @@ import { useState, useCallback } from 'react' import { toast } from 'sonner' import { ChatInput } from './chat-input' import { Opening } from './opening' +import { Suggestions } from './suggestions' export interface ChatProps extends React.ComponentProps<'div'> { id?: string // Optional: Thread ID if you want to persist the chat in a DB @@ -38,10 +39,24 @@ export function Chatbot({ id, initialMessages, className }: ChatProps) { }) const fetchMemorySets = useCallback(async () => { + + if (!userApiKey || !ownerLogin) { + toast.error('Please set both API Key and Owner Login first'); + return; + } try { const response = await fetch('/api/chat?action=getMemorySets', { method: 'POST', - body: JSON.stringify({ userApiKey, ownerLogin }) + body: JSON.stringify({ userApiKey, ownerLogin, + pipe: { + name: "career-prep-coach", + description: "Your AI-powered personal interview coach", + status: "private", + config: { + memorysets: [] // This will be populated when memory is selected + }, + } + }) }) if (!response.ok) throw new Error('Failed to fetch memory sets') const data = await response.json() @@ -59,6 +74,11 @@ export function Chatbot({ id, initialMessages, className }: ChatProps) { const handleMemorySelect = useCallback((memoryUrl: string) => { setSelectedMemory(memoryUrl) }, []) + + const sendSuggestedPrompt = (prompt: string) => { + setInput(prompt) + } + return (
@@ -68,7 +88,10 @@ export function Chatbot({ id, initialMessages, className }: ChatProps) { ) : ( + <> + + )} diff --git a/examples/career-prep-coach/components/opening.tsx b/examples/career-prep-coach/components/opening.tsx index bef2de6a..ba30d194 100755 --- a/examples/career-prep-coach/components/opening.tsx +++ b/examples/career-prep-coach/components/opening.tsx @@ -18,7 +18,7 @@ export function Opening() { pipe on ⌘ Langbase @@ -31,7 +31,7 @@ export function Opening() {

Learn more by checking out:

- + 1. Fork this Career Prep Coach Chatbot Pipe on ⌘ Langbase diff --git a/examples/career-prep-coach/components/prompt-form.tsx b/examples/career-prep-coach/components/prompt-form.tsx index ff87018a..8b40f7a2 100755 --- a/examples/career-prep-coach/components/prompt-form.tsx +++ b/examples/career-prep-coach/components/prompt-form.tsx @@ -6,6 +6,7 @@ import * as React from 'react' import Textarea from 'react-textarea-autosize' import { Popover, PopoverTrigger, PopoverContent } from '@radix-ui/react-popover' import { MemorySidebar } from './memory-sidebar' +import { HoverCard, HoverCardTrigger, HoverCardContent } from 'components/ui/hovercard' export interface PromptProps extends Pick { @@ -71,6 +72,25 @@ export function PromptForm({ aria-hidden="true" />

Chat

+ + + + + +
+ + +
diff --git a/examples/career-prep-coach/components/suggestions.tsx b/examples/career-prep-coach/components/suggestions.tsx new file mode 100644 index 00000000..33ea9fa6 --- /dev/null +++ b/examples/career-prep-coach/components/suggestions.tsx @@ -0,0 +1,48 @@ +import cn from 'mxcn' +import { IconSparkles } from './ui/icons' + +// Prompt suggestions – Change these to match your use-case/company +const suggestions = [ + { + title: `How to use this chatbot?`, + prompt: `How can I use your services?` + }, +] + +export const Suggestions = ({ + sendSuggestedPrompt +}: { + sendSuggestedPrompt: (prompt: string) => void +}) => { + const handleClick = (prompt: string) => { + sendSuggestedPrompt(prompt) + } + + return ( +
+ +
+ {suggestions.map((suggestion, index) => { + return ( +
handleClick(suggestion.prompt)} + > +
+ ) + })} +
+
+ ) +} \ No newline at end of file diff --git a/examples/career-prep-coach/components/ui/hovercard.tsx b/examples/career-prep-coach/components/ui/hovercard.tsx new file mode 100644 index 00000000..cc819857 --- /dev/null +++ b/examples/career-prep-coach/components/ui/hovercard.tsx @@ -0,0 +1,29 @@ +"use client" + +import * as React from "react" +import * as HoverCardPrimitive from "@radix-ui/react-hover-card" + +import cn from 'mxcn' + +const HoverCard = HoverCardPrimitive.Root + +const HoverCardTrigger = HoverCardPrimitive.Trigger + +const HoverCardContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( + +)) +HoverCardContent.displayName = HoverCardPrimitive.Content.displayName + +export { HoverCard, HoverCardTrigger, HoverCardContent } \ No newline at end of file diff --git a/examples/career-prep-coach/package.json b/examples/career-prep-coach/package.json index c5ee569d..8720138e 100755 --- a/examples/career-prep-coach/package.json +++ b/examples/career-prep-coach/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@radix-ui/react-hover-card": "^1.1.2", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-popover": "^1.1.1", "@radix-ui/react-select": "^2.1.1",