added temporary api
This commit is contained in:
@@ -1,17 +1,35 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { LogOut, Settings } from "lucide-react";
|
||||
import { DailyAudio } from "@daily-co/daily-react";
|
||||
import { DailyAudio, useAppMessage, useDaily } from "@daily-co/daily-react";
|
||||
|
||||
import DeviceSelect from "../DeviceSelect";
|
||||
import Agent from "./agent";
|
||||
import { Button } from "../button";
|
||||
import styles from "./styles.module.css";
|
||||
import UserMicBubble from "../UserMicBubble";
|
||||
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export const Session: React.FC = () => {
|
||||
const daily = useDaily();
|
||||
const [showDevices, setShowDevices] = useState(false);
|
||||
const [canTalk, setCanTalk] = useState(false);
|
||||
const modalRef = useRef<HTMLDialogElement>(null);
|
||||
const [talkState, setTalkState] = useState<"user" | "assistant">("assistant");
|
||||
|
||||
useAppMessage({
|
||||
onAppMessage: (e) => {
|
||||
if (!daily || !e.data?.cue) return;
|
||||
|
||||
// Determine the UI state from the cue sent by the bot
|
||||
if (e.data?.cue === "user_turn") {
|
||||
// Delay enabling local mic input to avoid feedback from LLM
|
||||
setTimeout(() => daily.setLocalAudio(true), 500);
|
||||
setTalkState("user");
|
||||
} else {
|
||||
daily.setLocalAudio(false);
|
||||
setTalkState("assistant");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const current = modalRef.current;
|
||||
@@ -34,7 +52,7 @@ export const Session: React.FC = () => {
|
||||
|
||||
<div className={styles.agentContainer}>
|
||||
<Agent />
|
||||
<UserMicBubble active={canTalk} />
|
||||
<UserMicBubble active={talkState === "user"} />
|
||||
<DailyAudio />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useCallback, useRef, useState, useEffect } from "react";
|
||||
import React, { useCallback, useRef } from "react";
|
||||
|
||||
import {
|
||||
useAudioLevel,
|
||||
useAudioTrack,
|
||||
useLocalSessionId,
|
||||
useAppMessage,
|
||||
//useAppMessage,
|
||||
} from "@daily-co/daily-react";
|
||||
import { DailyEventObjectAppMessage } from "@daily-co/daily-js";
|
||||
//import { DailyEventObjectAppMessage } from "@daily-co/daily-js";
|
||||
import { Mic, MicOff } from "lucide-react";
|
||||
//import { TypewriterEffect } from "../ui/typewriter";
|
||||
import styles from "./styles.module.css";
|
||||
@@ -38,13 +38,13 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function UserMicBubble({ active }: Props) {
|
||||
/*
|
||||
const [transcription, setTranscription] = useState<string[]>([]);
|
||||
|
||||
useAppMessage({
|
||||
onAppMessage: (e: DailyEventObjectAppMessage<any>) => {
|
||||
if (e.fromId && e.fromId === "transcription") {
|
||||
if (e.data.user_id === "" && e.data.is_final) {
|
||||
setTranscription((t) => [...t, ...e.data.text.split(" ")]);
|
||||
//setTranscription((t) => [...t, ...e.data.text.split(" ")]);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -54,7 +54,7 @@ export default function UserMicBubble({ active }: Props) {
|
||||
if (active) return;
|
||||
const t = setTimeout(() => setTranscription([]), 4000);
|
||||
return () => clearTimeout(t);
|
||||
}, [active]);
|
||||
}, [active]);*/
|
||||
|
||||
return (
|
||||
<div className={`${styles.bubbleContainer} ${active ? styles.active : ""}`}>
|
||||
|
||||
89
examples/simple-chatbot/pipecat.py
Normal file
89
examples/simple-chatbot/pipecat.py
Normal file
@@ -0,0 +1,89 @@
|
||||
import os
|
||||
import argparse
|
||||
import uvicorn
|
||||
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, Request, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse, JSONResponse
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv(override=True)
|
||||
|
||||
|
||||
# ------------ Configuration ------------ #
|
||||
|
||||
MAX_SESSION_TIME = 5 * 1000
|
||||
BOT_CAN_IDLE = True
|
||||
SERVE_STATIC = True
|
||||
STATIC_DIR = "client/dist"
|
||||
STATIC_ROUTE = "/static"
|
||||
STATIC_INDEX = "index.html"
|
||||
|
||||
|
||||
# ----------------- API ----------------- #
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"]
|
||||
)
|
||||
|
||||
# Optionally serve client static files
|
||||
if SERVE_STATIC:
|
||||
app.mount(STATIC_ROUTE, StaticFiles(
|
||||
directory=STATIC_DIR, html=True), name="static")
|
||||
|
||||
@app.get("/{path_name:path}", response_class=FileResponse)
|
||||
async def catch_all(path_name: Optional[str] = ""):
|
||||
if path_name == "":
|
||||
return FileResponse(f"{STATIC_DIR}/{STATIC_INDEX}")
|
||||
|
||||
file_path = Path(STATIC_DIR) / (path_name or "")
|
||||
|
||||
if file_path.is_file():
|
||||
return file_path
|
||||
|
||||
html_file_path = file_path.with_suffix(".html")
|
||||
if html_file_path.is_file():
|
||||
return FileResponse(html_file_path)
|
||||
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Page not found")
|
||||
|
||||
|
||||
@app.post("/start_bot")
|
||||
async def start_bot(request: Request):
|
||||
return JSONResponse({"bot_id": 123, "user_token": "abc", "room_url": "https://jpt.daily.co/hello"})
|
||||
|
||||
|
||||
# ----------------- Main ----------------- #
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Pipecat Bot Runner")
|
||||
parser.add_argument("--host", type=str,
|
||||
default=os.getenv("HOST", "localhost"), help="Host address")
|
||||
parser.add_argument("--port", type=int,
|
||||
default=os.getenv("PORT", 7860), help="Port number")
|
||||
parser.add_argument("--reload", action="store_true",
|
||||
default=True, help="Reload code on change")
|
||||
|
||||
config = parser.parse_args()
|
||||
|
||||
try:
|
||||
uvicorn.run(
|
||||
"pipecat:app",
|
||||
host=config.host,
|
||||
port=config.port,
|
||||
reload=config.reload
|
||||
)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("Pipecat runner shutting down...")
|
||||
@@ -1,5 +1,6 @@
|
||||
python-dotenv
|
||||
requests
|
||||
fastapi[all]
|
||||
pipecat-ai[daily,openai,fal]
|
||||
fastapi
|
||||
uvicorn
|
||||
pipecat-ai[daily,openai,silero]
|
||||
requests
|
||||
python-dotenv
|
||||
loguru
|
||||
@@ -1,58 +0,0 @@
|
||||
import argparse
|
||||
import os
|
||||
import time
|
||||
import urllib
|
||||
import requests
|
||||
|
||||
|
||||
def configure():
|
||||
parser = argparse.ArgumentParser(description="Daily AI SDK Bot Sample")
|
||||
parser.add_argument(
|
||||
"-u",
|
||||
"--url",
|
||||
type=str,
|
||||
required=False,
|
||||
help="URL of the Daily room to join")
|
||||
parser.add_argument(
|
||||
"-k",
|
||||
"--apikey",
|
||||
type=str,
|
||||
required=False,
|
||||
help="Daily API Key (needed to create an owner token for the room)",
|
||||
)
|
||||
|
||||
args, unknown = parser.parse_known_args()
|
||||
|
||||
url = args.url or os.getenv("DAILY_SAMPLE_ROOM_URL")
|
||||
key = args.apikey or os.getenv("DAILY_API_KEY")
|
||||
|
||||
if not url:
|
||||
raise Exception(
|
||||
"No Daily room specified. use the -u/--url option from the command line, or set DAILY_SAMPLE_ROOM_URL in your environment to specify a Daily room URL.")
|
||||
|
||||
if not key:
|
||||
raise Exception("No Daily API key specified. use the -k/--apikey option from the command line, or set DAILY_API_KEY in your environment to specify a Daily API key, available from https://dashboard.daily.co/developers.")
|
||||
|
||||
# Create a meeting token for the given room with an expiration 1 hour in
|
||||
# the future.
|
||||
room_name: str = urllib.parse.urlparse(url).path[1:]
|
||||
expiration: float = time.time() + 60 * 60
|
||||
|
||||
res: requests.Response = requests.post(
|
||||
f"https://api.daily.co/v1/meeting-tokens",
|
||||
headers={
|
||||
"Authorization": f"Bearer {key}"},
|
||||
json={
|
||||
"properties": {
|
||||
"room_name": room_name,
|
||||
"is_owner": True,
|
||||
"exp": expiration}},
|
||||
)
|
||||
|
||||
if res.status_code != 200:
|
||||
raise Exception(
|
||||
f"Failed to create meeting token: {res.status_code} {res.text}")
|
||||
|
||||
token: str = res.json()["token"]
|
||||
|
||||
return (url, token)
|
||||
@@ -1,124 +0,0 @@
|
||||
import os
|
||||
import argparse
|
||||
import subprocess
|
||||
import atexit
|
||||
|
||||
from fastapi import FastAPI, Request, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse, RedirectResponse
|
||||
|
||||
from utils.daily_helpers import create_room as _create_room, get_token
|
||||
|
||||
MAX_BOTS_PER_ROOM = 1
|
||||
|
||||
# Bot sub-process dict for status reporting and concurrency control
|
||||
bot_procs = {}
|
||||
|
||||
|
||||
def cleanup():
|
||||
# Clean up function, just to be extra safe
|
||||
for proc in bot_procs.values():
|
||||
proc.terminate()
|
||||
proc.wait()
|
||||
|
||||
|
||||
atexit.register(cleanup)
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
@app.get("/start")
|
||||
async def start_agent(request: Request):
|
||||
print(f"!!! Creating room")
|
||||
room_url, room_name = _create_room()
|
||||
print(f"!!! Room URL: {room_url}")
|
||||
# Ensure the room property is present
|
||||
if not room_url:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Missing 'room' property in request data. Cannot start agent without a target room!")
|
||||
|
||||
# Check if there is already an existing process running in this room
|
||||
num_bots_in_room = sum(
|
||||
1 for proc in bot_procs.values() if proc[1] == room_url and proc[0].poll() is None)
|
||||
if num_bots_in_room >= MAX_BOTS_PER_ROOM:
|
||||
raise HTTPException(
|
||||
status_code=500, detail=f"Max bot limited reach for room: {room_url}")
|
||||
|
||||
# Get the token for the room
|
||||
token = get_token(room_url)
|
||||
|
||||
if not token:
|
||||
raise HTTPException(
|
||||
status_code=500, detail=f"Failed to get token for room: {room_url}")
|
||||
|
||||
# Spawn a new agent, and join the user session
|
||||
# Note: this is mostly for demonstration purposes (refer to 'deployment' in README)
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
[
|
||||
f"python3 -m bot -u {room_url} -t {token}"
|
||||
],
|
||||
shell=True,
|
||||
bufsize=1,
|
||||
cwd=os.path.dirname(os.path.abspath(__file__))
|
||||
)
|
||||
bot_procs[proc.pid] = (proc, room_url)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500, detail=f"Failed to start subprocess: {e}")
|
||||
|
||||
return RedirectResponse(room_url)
|
||||
|
||||
|
||||
@app.get("/status/{pid}")
|
||||
def get_status(pid: int):
|
||||
# Look up the subprocess
|
||||
proc = bot_procs.get(pid)
|
||||
|
||||
# If the subprocess doesn't exist, return an error
|
||||
if not proc:
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"Bot with process id: {pid} not found")
|
||||
|
||||
# Check the status of the subprocess
|
||||
if proc[0].poll() is None:
|
||||
status = "running"
|
||||
else:
|
||||
status = "finished"
|
||||
|
||||
return JSONResponse({"bot_id": pid, "status": status})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
default_host = os.getenv("HOST", "0.0.0.0")
|
||||
default_port = int(os.getenv("FAST_API_PORT", "7860"))
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Daily Storyteller FastAPI server")
|
||||
parser.add_argument("--host", type=str,
|
||||
default=default_host, help="Host address")
|
||||
parser.add_argument("--port", type=int,
|
||||
default=default_port, help="Port number")
|
||||
parser.add_argument("--reload", action="store_true",
|
||||
help="Reload code on change")
|
||||
|
||||
config = parser.parse_args()
|
||||
|
||||
uvicorn.run(
|
||||
"server:app",
|
||||
host=config.host,
|
||||
port=config.port,
|
||||
reload=config.reload,
|
||||
)
|
||||
Reference in New Issue
Block a user