Bot config no longer gives errors on frontend
This commit is contained in:
parent
bef73a8af4
commit
716c508f45
@ -3,24 +3,13 @@
|
||||
!server
|
||||
!client
|
||||
!shared
|
||||
node_modules
|
||||
build
|
||||
dist
|
||||
**/node_modules
|
||||
**/build
|
||||
**/dist
|
||||
**/__pycache__
|
||||
**/.venv
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
*.log
|
||||
*.swp
|
||||
*.swo
|
||||
.env
|
||||
.env.*
|
||||
*.pem
|
||||
*.key
|
||||
*.bak
|
||||
*.tmp
|
||||
*.local
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
**/.env
|
||||
**/*.pem
|
||||
**/*.key
|
||||
**/package-lock.json
|
||||
**/*.pyc
|
@ -1,4 +1,4 @@
|
||||
FROM ubuntu:oracular
|
||||
FROM ubuntu:noble
|
||||
# Stick with Python3.12 (plucky has 3.13)
|
||||
|
||||
# Install some utilities frequently used
|
||||
|
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
find . -name .venv | while read path; do
|
||||
echo "Removing ${path}"
|
||||
sudo rm -rf "${path}"
|
||||
done
|
||||
find . -name .python-version | while read path; do
|
||||
echo "Removing ${path}"
|
||||
sudo rm "${path}"
|
||||
done
|
@ -2,6 +2,6 @@ To deploy:
|
||||
|
||||
```bash
|
||||
export PUBLIC_URL=/ai-voicebot
|
||||
npm run build
|
||||
rsync --delete -avrpl build/ webserver:/var/www/ketrenos.com/ai-voicebot/
|
||||
docker compose exec client npm run build
|
||||
rsync --delete -avrpl client/build/ webserver:/var/www/ketrenos.com/ai-voicebot/
|
||||
```
|
||||
|
0
client/entrypoint.sh
Normal file → Executable file
0
client/entrypoint.sh
Normal file → Executable file
@ -727,14 +727,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ai-voicebot/api/bots/config/lobby/{lobby_id}/bot/{bot_name}": {
|
||||
"/ai-voicebot/api/bots/config/lobby/{lobby_id}/bot/{bot_instance_id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Bot Configuration"
|
||||
],
|
||||
"summary": "Get Lobby Bot Config",
|
||||
"description": "Get specific bot configuration for a lobby",
|
||||
"operationId": "get_lobby_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_name__get",
|
||||
"operationId": "get_lobby_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_instance_id__get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "lobby_id",
|
||||
@ -746,12 +746,12 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bot_name",
|
||||
"name": "bot_instance_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Bot Name"
|
||||
"title": "Bot Instance Id"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -784,7 +784,7 @@
|
||||
],
|
||||
"summary": "Delete Bot Config",
|
||||
"description": "Delete bot configuration for a lobby",
|
||||
"operationId": "delete_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_name__delete",
|
||||
"operationId": "delete_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_instance_id__delete",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "lobby_id",
|
||||
@ -796,12 +796,12 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bot_name",
|
||||
"name": "bot_instance_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Bot Name"
|
||||
"title": "Bot Instance Id"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -813,7 +813,7 @@
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"title": "Response Delete Bot Config Ai Voicebot Api Bots Config Lobby Lobby Id Bot Bot Name Delete"
|
||||
"title": "Response Delete Bot Config Ai Voicebot Api Bots Config Lobby Lobby Id Bot Bot Instance Id Delete"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1644,9 +1644,9 @@
|
||||
},
|
||||
"BotConfigUpdateRequest": {
|
||||
"properties": {
|
||||
"bot_name": {
|
||||
"bot_instance_id": {
|
||||
"type": "string",
|
||||
"title": "Bot Name"
|
||||
"title": "Bot Instance Id"
|
||||
},
|
||||
"lobby_id": {
|
||||
"type": "string",
|
||||
@ -1660,7 +1660,7 @@
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"bot_name",
|
||||
"bot_instance_id",
|
||||
"lobby_id",
|
||||
"config_values"
|
||||
],
|
||||
|
@ -213,6 +213,9 @@ const LobbyView: React.FC<LobbyProps> = (props: LobbyProps) => {
|
||||
<Box sx={{ mb: 2, display: "flex", gap: 2, alignItems: "flex-start", flexDirection: "column" }}>
|
||||
<Box>
|
||||
<Typography variant="h5">AI Voice Chat Lobby: {lobbyName}</Typography>
|
||||
<Typography variant="caption">
|
||||
{lobby ? `Lobby ID: ${lobby.id}` : creatingLobby ? "Joining lobby..." : "Not in a lobby"}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
{session.name && <Typography>You are logged in as: {session.name}</Typography>}
|
||||
|
@ -6,51 +6,21 @@
|
||||
* form controls for each configuration parameter.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { base } from "./Common";
|
||||
import "./BotConfig.css";
|
||||
|
||||
interface ConfigParameter {
|
||||
name: string;
|
||||
type: "string" | "number" | "boolean" | "select" | "range";
|
||||
label: string;
|
||||
description: string;
|
||||
default_value?: any;
|
||||
required?: boolean;
|
||||
options?: Array<{ value: string; label: string }>;
|
||||
min_value?: number;
|
||||
max_value?: number;
|
||||
step?: number;
|
||||
max_length?: number;
|
||||
pattern?: string;
|
||||
}
|
||||
|
||||
interface ConfigSchema {
|
||||
bot_name: string;
|
||||
version: string;
|
||||
parameters: ConfigParameter[];
|
||||
categories?: Array<{ name: string; parameters: string[] }>;
|
||||
}
|
||||
|
||||
interface BotConfig {
|
||||
bot_name: string;
|
||||
lobby_id: string;
|
||||
provider_id: string;
|
||||
config_values: { [key: string]: any };
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
created_by: string;
|
||||
}
|
||||
import type { components } from "./api-types";
|
||||
|
||||
interface BotConfigProps {
|
||||
botInstanceId?: string;
|
||||
botName: string;
|
||||
lobbyId: string;
|
||||
onConfigUpdate?: (config: BotConfig) => void;
|
||||
onConfigUpdate?: (config: components["schemas"]["BotLobbyConfig"]) => void;
|
||||
}
|
||||
|
||||
const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConfigUpdate }) => {
|
||||
const [schema, setSchema] = useState<ConfigSchema | null>(null);
|
||||
const [currentConfig, setCurrentConfig] = useState<BotConfig | null>(null);
|
||||
const BotConfigComponent: React.FC<BotConfigProps> = ({ botInstanceId, botName, lobbyId, onConfigUpdate }) => {
|
||||
const [schema, setSchema] = useState<components["schemas"]["BotConfigSchema"] | null>(null);
|
||||
const [currentConfig, setCurrentConfig] = useState<components["schemas"]["BotLobbyConfig"] | null>(null);
|
||||
const [configValues, setConfigValues] = useState<{ [key: string]: any }>({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@ -58,50 +28,52 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
// Fetch configuration schema
|
||||
const fetchSchema = async (forceRefresh = false) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const fetchSchema = useCallback(
|
||||
async (forceRefresh = false) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
// Use refresh endpoint if force refresh is requested
|
||||
const url = forceRefresh
|
||||
? `${base}/api/bots/config/schema/${botName}/refresh`
|
||||
: `${base}/api/bots/config/schema/${botName}`;
|
||||
// Use refresh endpoint if force refresh is requested
|
||||
const url = forceRefresh
|
||||
? `${base}/api/bots/config/schema/${botName}/refresh`
|
||||
: `${base}/api/bots/config/schema/${botName}`;
|
||||
|
||||
const method = forceRefresh ? "POST" : "GET";
|
||||
const method = forceRefresh ? "POST" : "GET";
|
||||
|
||||
const response = await fetch(url, { method });
|
||||
const response = await fetch(url, { method });
|
||||
|
||||
if (response.ok) {
|
||||
const responseData = await response.json();
|
||||
// For refresh endpoint, the schema is in the 'schema' field
|
||||
const schemaData = forceRefresh ? responseData.schema : responseData;
|
||||
if (response.ok) {
|
||||
const responseData = await response.json();
|
||||
// For refresh endpoint, the schema is in the 'schema' field
|
||||
const schemaData = forceRefresh ? responseData.schema : responseData;
|
||||
setSchema(schemaData);
|
||||
|
||||
setSchema(schemaData);
|
||||
|
||||
// Initialize config values with defaults
|
||||
const defaultValues: { [key: string]: any } = {};
|
||||
schemaData.parameters.forEach((param: ConfigParameter) => {
|
||||
if (param.default_value !== undefined) {
|
||||
defaultValues[param.name] = param.default_value;
|
||||
}
|
||||
});
|
||||
setConfigValues(defaultValues);
|
||||
} else if (response.status === 404) {
|
||||
setError(`Bot "${botName}" does not support configuration`);
|
||||
} else {
|
||||
setError("Failed to fetch configuration schema");
|
||||
// Initialize config values with defaults
|
||||
const defaultValues: { [key: string]: any } = {};
|
||||
schemaData.parameters.forEach((param: components["schemas"]["BotConfigParameter"]) => {
|
||||
if (param.default_value !== undefined) {
|
||||
defaultValues[param.name] = param.default_value;
|
||||
}
|
||||
});
|
||||
setConfigValues(defaultValues);
|
||||
} else if (response.status === 404) {
|
||||
setError(`Bot "${botName}" does not support configuration`);
|
||||
} else {
|
||||
setError("Failed to fetch configuration schema");
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Network error while fetching configuration schema");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Network error while fetching configuration schema");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
},
|
||||
[botName]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchSchema();
|
||||
}, [botName]);
|
||||
}, [botName, fetchSchema]);
|
||||
|
||||
// Handle schema refresh
|
||||
const handleRefreshSchema = async () => {
|
||||
@ -114,12 +86,12 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
useEffect(() => {
|
||||
const fetchCurrentConfig = async () => {
|
||||
try {
|
||||
const response = await fetch(`${base}/api/bots/config/lobby/${lobbyId}/bot/${botName}`);
|
||||
const response = await fetch(`${base}/api/bots/config/lobby/${lobbyId}/bot/${botInstanceId}`);
|
||||
|
||||
if (response.ok) {
|
||||
const config = await response.json();
|
||||
setCurrentConfig(config);
|
||||
setConfigValues({ ...configValues, ...config.config_values });
|
||||
setConfigValues((prev) => ({ ...prev, ...config.config_values }));
|
||||
}
|
||||
// If 404, no existing config - that's fine
|
||||
} catch (err) {
|
||||
@ -127,10 +99,15 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
}
|
||||
};
|
||||
|
||||
if (schema) {
|
||||
if (schema && botInstanceId) {
|
||||
fetchCurrentConfig();
|
||||
}
|
||||
}, [botName, lobbyId, schema]);
|
||||
}, [botName, lobbyId, schema, botInstanceId]);
|
||||
|
||||
// Check if bot instance ID is available
|
||||
if (!botInstanceId) {
|
||||
return <div className="bot-config-unavailable">Configuration not available - no bot instance selected</div>;
|
||||
}
|
||||
|
||||
const handleValueChange = (paramName: string, value: any) => {
|
||||
setConfigValues((prev) => ({
|
||||
@ -150,7 +127,7 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
bot_name: botName,
|
||||
bot_instance_id: botInstanceId,
|
||||
lobby_id: lobbyId,
|
||||
config_values: configValues,
|
||||
}),
|
||||
@ -173,7 +150,7 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
}
|
||||
};
|
||||
|
||||
const renderParameter = (param: ConfigParameter) => {
|
||||
const renderParameter = (param: components["schemas"]["BotConfigParameter"]) => {
|
||||
const value = configValues[param.name];
|
||||
|
||||
switch (param.type) {
|
||||
@ -201,11 +178,18 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
onChange={(e) => handleValueChange(param.name, e.target.value)}
|
||||
className="config-select"
|
||||
>
|
||||
{param.options?.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
{param.options?.map((option, index) => {
|
||||
// Handle both formats: {value: string, label: string} and generic {[key: string]: string}
|
||||
const optionValue =
|
||||
typeof option === "object" && "value" in option ? option.value : Object.keys(option)[0];
|
||||
const optionLabel =
|
||||
typeof option === "object" && "label" in option ? option.label : Object.values(option)[0];
|
||||
return (
|
||||
<option key={index} value={optionValue}>
|
||||
{optionLabel}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
<p className="config-description">{param.description}</p>
|
||||
</div>
|
||||
@ -237,9 +221,9 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
<label className="config-label">{param.label}</label>
|
||||
<input
|
||||
type="number"
|
||||
min={param.min_value}
|
||||
max={param.max_value}
|
||||
step={param.step || 1}
|
||||
min={param.min_value ?? undefined}
|
||||
max={param.max_value ?? undefined}
|
||||
step={param.step ?? 1}
|
||||
value={value || ""}
|
||||
onChange={(e) => handleValueChange(param.name, Number(e.target.value))}
|
||||
className="config-input"
|
||||
@ -255,8 +239,8 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
<label className="config-label">{param.label}</label>
|
||||
<input
|
||||
type="text"
|
||||
maxLength={param.max_length}
|
||||
pattern={param.pattern}
|
||||
maxLength={param.max_length ?? undefined}
|
||||
pattern={param.pattern ?? undefined}
|
||||
value={value || ""}
|
||||
onChange={(e) => handleValueChange(param.name, e.target.value)}
|
||||
className="config-input"
|
||||
@ -271,17 +255,22 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
if (!schema) return null;
|
||||
|
||||
if (schema.categories && schema.categories.length > 0) {
|
||||
return schema.categories.map((category) => (
|
||||
<div key={category.name} className="config-category">
|
||||
<h4 className="category-title">{category.name}</h4>
|
||||
<div className="category-parameters">
|
||||
{category.parameters?.map((paramName) => {
|
||||
const param = schema.parameters?.find((p) => p.name === paramName);
|
||||
return param ? <div key={paramName}>{renderParameter(param)}</div> : null;
|
||||
}) || null}
|
||||
return schema.categories.map((category, categoryIndex) => {
|
||||
// Handle API format: each category is an object with string keys mapping to string arrays
|
||||
const categoryName = Object.keys(category)[0];
|
||||
const parameterNames = category[categoryName];
|
||||
return (
|
||||
<div key={categoryIndex} className="config-category">
|
||||
<h4 className="category-title">{categoryName}</h4>
|
||||
<div className="category-parameters">
|
||||
{parameterNames?.map((paramName: string) => {
|
||||
const param = schema.parameters?.find((p) => p.name === paramName);
|
||||
return param ? <div key={paramName}>{renderParameter(param)}</div> : null;
|
||||
}) || null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return schema.parameters?.map((param) => <div key={param.name}>{renderParameter(param)}</div>) || null;
|
||||
}
|
||||
@ -303,7 +292,7 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
<div className="bot-config-container">
|
||||
<div className="bot-config-header">
|
||||
<div className="bot-config-title">
|
||||
<h3>Configure {botName}</h3>
|
||||
<h3>Configure Bot {botInstanceId}</h3>
|
||||
<button
|
||||
onClick={handleRefreshSchema}
|
||||
disabled={refreshing || loading}
|
||||
@ -319,7 +308,9 @@ const BotConfigComponent: React.FC<BotConfigProps> = ({ botName, lobbyId, onConf
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="bot-config-form">{renderParametersByCategory()}</div>
|
||||
<div className="bot-config-form">
|
||||
<React.Fragment key="parameters-container">{renderParametersByCategory()}</React.Fragment>
|
||||
</div>
|
||||
|
||||
<div className="bot-config-actions">
|
||||
<button onClick={handleSave} disabled={saving} className="config-save-button">
|
||||
|
@ -29,7 +29,6 @@ import {
|
||||
} from "@mui/icons-material";
|
||||
import { botsApi, BotInfoModel, BotProviderPublicModel, BotJoinLobbyRequest } from "./api-client";
|
||||
import BotConfig from "./BotConfig";
|
||||
import BotConfigComponent from "./BotConfig";
|
||||
|
||||
interface BotManagerProps {
|
||||
lobbyId: string;
|
||||
@ -239,7 +238,7 @@ const BotManager: React.FC<BotManagerProps> = ({ lobbyId, onBotAdded, sx }) => {
|
||||
}
|
||||
secondaryTypographyProps={{ component: "div" }}
|
||||
/>
|
||||
{isBotConfigurable(botInfo) && (
|
||||
{false && isBotConfigurable(botInfo) && (
|
||||
<IconButton
|
||||
onClick={() => handleOpenConfigDialog(botInfo.name)}
|
||||
size="small"
|
||||
|
@ -237,6 +237,7 @@ const UserList: React.FC<UserListProps> = (props: UserListProps) => {
|
||||
<DialogContent>
|
||||
{selectedBotForConfig && (
|
||||
<BotConfig
|
||||
botInstanceId={selectedBotForConfig.bot_instance_id || ""}
|
||||
botName={selectedBotForConfig.name?.replace(/-bot$/, "") || "unknown"}
|
||||
lobbyId={lobbyId}
|
||||
onConfigUpdate={(config) => {
|
||||
|
@ -182,7 +182,10 @@ export class ApiClient {
|
||||
}
|
||||
|
||||
async createRegisterBotProvider(data: any): Promise<any> {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/providers/register`), { method: "POST", body: data });
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/providers/register`), {
|
||||
method: "POST",
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
async getListBotProviders(): Promise<any> {
|
||||
@ -198,7 +201,9 @@ export class ApiClient {
|
||||
}
|
||||
|
||||
async createRequestBotLeaveLobby(bot_instance_id: string): Promise<any> {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/instances/${bot_instance_id}/leave`), { method: "POST" });
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/instances/${bot_instance_id}/leave`), {
|
||||
method: "POST",
|
||||
});
|
||||
}
|
||||
|
||||
async getBotInstance(bot_instance_id: string): Promise<any> {
|
||||
@ -217,16 +222,24 @@ export class ApiClient {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/lobby/${lobby_id}`), { method: "DELETE" });
|
||||
}
|
||||
|
||||
async getLobbyBotConfig(lobby_id: string, bot_name: string): Promise<any> {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/lobby/${lobby_id}/bot/${bot_name}`), { method: "GET" });
|
||||
async getLobbyBotConfig(lobby_id: string, bot_instance_id: string): Promise<any> {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/lobby/${lobby_id}/bot/${bot_instance_id}`), {
|
||||
method: "GET",
|
||||
});
|
||||
}
|
||||
|
||||
async deleteBotConfig(lobby_id: string, bot_name: string): Promise<any> {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/lobby/${lobby_id}/bot/${bot_name}`), { method: "DELETE" });
|
||||
async deleteBotConfig(lobby_id: string, bot_instance_id: string): Promise<any> {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/lobby/${lobby_id}/bot/${bot_instance_id}`), {
|
||||
method: "DELETE",
|
||||
});
|
||||
}
|
||||
|
||||
async createUpdateBotConfig(data: any, params?: Record<string, string>): Promise<any> {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/update`), { method: "POST", body: data, params });
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/update`), {
|
||||
method: "POST",
|
||||
body: data,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
async getConfigStatistics(): Promise<any> {
|
||||
@ -238,11 +251,15 @@ export class ApiClient {
|
||||
}
|
||||
|
||||
async createRefreshBotSchema(bot_name: string): Promise<any> {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/schema/${bot_name}/refresh`), { method: "POST" });
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/schema/${bot_name}/refresh`), {
|
||||
method: "POST",
|
||||
});
|
||||
}
|
||||
|
||||
async deleteClearBotSchemaCache(bot_name: string): Promise<any> {
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/schema/${bot_name}/cache`), { method: "DELETE" });
|
||||
return this.request<any>(this.getApiPath(`/ai-voicebot/api/bots/config/schema/${bot_name}/cache`), {
|
||||
method: "DELETE",
|
||||
});
|
||||
}
|
||||
|
||||
async getReadinessProbe(): Promise<any> {
|
||||
@ -323,13 +340,13 @@ export const botsApi = {
|
||||
getSchema: (bot_name: string) => apiClient.getBotConfigSchema(bot_name),
|
||||
getBotConfigs: (lobby_id: string) => apiClient.getLobbyBotConfigs(lobby_id),
|
||||
deleteBotConfigs: (lobby_id: string) => apiClient.deleteLobbyConfigs(lobby_id),
|
||||
getBotConfig: (lobby_id: string, bot_name: string) => apiClient.getLobbyBotConfig(lobby_id, bot_name),
|
||||
deleteBotConfig: (lobby_id: string, bot_name: string) => apiClient.deleteBotConfig(lobby_id, bot_name),
|
||||
getBotConfig: (lobby_id: string, bot_instance_id: string) => apiClient.getLobbyBotConfig(lobby_id, bot_instance_id),
|
||||
deleteBotConfig: (lobby_id: string, bot_instance_id: string) => apiClient.deleteBotConfig(lobby_id, bot_instance_id),
|
||||
updateConfig: (data: any) => apiClient.createUpdateBotConfig(data),
|
||||
getConfigStatistics: () => apiClient.getConfigStatistics(),
|
||||
refreshAllSchemas: () => apiClient.createRefreshBotSchemas(),
|
||||
refreshSchema: (bot_name: string) => apiClient.createRefreshBotSchema(bot_name),
|
||||
clearSchemaCache: (bot_name: string) => apiClient.deleteClearBotSchemaCache(bot_name)
|
||||
clearSchemaCache: (bot_name: string) => apiClient.deleteClearBotSchemaCache(bot_name),
|
||||
};
|
||||
|
||||
export const metricsApi = {
|
||||
|
@ -5,14 +5,14 @@ import { base } from './Common';
|
||||
|
||||
export const knownEndpoints = new Set([
|
||||
`DELETE:${base}/api/bots/config/lobby/{lobby_id}`,
|
||||
`DELETE:${base}/api/bots/config/lobby/{lobby_id}/bot/{bot_name}`,
|
||||
`DELETE:${base}/api/bots/config/lobby/{lobby_id}/bot/{bot_instance_id}`,
|
||||
`DELETE:${base}/api/bots/config/schema/{bot_name}/cache`,
|
||||
`GET:${base}/api/admin/names`,
|
||||
`GET:${base}/api/admin/session_metrics`,
|
||||
`GET:${base}/api/admin/validate_sessions`,
|
||||
`GET:${base}/api/bots`,
|
||||
`GET:${base}/api/bots/config/lobby/{lobby_id}`,
|
||||
`GET:${base}/api/bots/config/lobby/{lobby_id}/bot/{bot_name}`,
|
||||
`GET:${base}/api/bots/config/lobby/{lobby_id}/bot/{bot_instance_id}`,
|
||||
`GET:${base}/api/bots/config/schema/{bot_name}`,
|
||||
`GET:${base}/api/bots/config/statistics`,
|
||||
`GET:${base}/api/bots/instances/{bot_instance_id}`,
|
||||
|
@ -127,17 +127,17 @@ export interface paths {
|
||||
*/
|
||||
delete: operations["delete_lobby_configs_ai_voicebot_api_bots_config_lobby__lobby_id__delete"];
|
||||
};
|
||||
"/ai-voicebot/api/bots/config/lobby/{lobby_id}/bot/{bot_name}": {
|
||||
"/ai-voicebot/api/bots/config/lobby/{lobby_id}/bot/{bot_instance_id}": {
|
||||
/**
|
||||
* Get Lobby Bot Config
|
||||
* @description Get specific bot configuration for a lobby
|
||||
*/
|
||||
get: operations["get_lobby_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_name__get"];
|
||||
get: operations["get_lobby_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_instance_id__get"];
|
||||
/**
|
||||
* Delete Bot Config
|
||||
* @description Delete bot configuration for a lobby
|
||||
*/
|
||||
delete: operations["delete_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_name__delete"];
|
||||
delete: operations["delete_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_instance_id__delete"];
|
||||
};
|
||||
"/ai-voicebot/api/bots/config/update": {
|
||||
/**
|
||||
@ -402,9 +402,11 @@ export interface components {
|
||||
*/
|
||||
required?: boolean;
|
||||
/** Options */
|
||||
options?: {
|
||||
[key: string]: string;
|
||||
}[] | null;
|
||||
options?:
|
||||
| {
|
||||
[key: string]: string;
|
||||
}[]
|
||||
| null;
|
||||
/** Min Value */
|
||||
min_value?: number | null;
|
||||
/** Max Value */
|
||||
@ -431,17 +433,19 @@ export interface components {
|
||||
/** Parameters */
|
||||
parameters: components["schemas"]["BotConfigParameter"][];
|
||||
/** Categories */
|
||||
categories?: {
|
||||
[key: string]: string[];
|
||||
}[] | null;
|
||||
categories?:
|
||||
| {
|
||||
[key: string]: string[];
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
/**
|
||||
* BotConfigUpdateRequest
|
||||
* @description Request to update bot configuration
|
||||
*/
|
||||
BotConfigUpdateRequest: {
|
||||
/** Bot Name */
|
||||
bot_name: string;
|
||||
/** Bot Instance Id */
|
||||
bot_instance_id: string;
|
||||
/** Lobby Id */
|
||||
lobby_id: string;
|
||||
/** Config Values */
|
||||
@ -793,7 +797,6 @@ export type $defs = Record<string, never>;
|
||||
export type external = Record<string, never>;
|
||||
|
||||
export interface operations {
|
||||
|
||||
/**
|
||||
* System Health
|
||||
* @description System health check showing manager status and enhanced monitoring
|
||||
@ -1225,11 +1228,11 @@ export interface operations {
|
||||
* Get Lobby Bot Config
|
||||
* @description Get specific bot configuration for a lobby
|
||||
*/
|
||||
get_lobby_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_name__get: {
|
||||
get_lobby_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_instance_id__get: {
|
||||
parameters: {
|
||||
path: {
|
||||
lobby_id: string;
|
||||
bot_name: string;
|
||||
bot_instance_id: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
@ -1251,11 +1254,11 @@ export interface operations {
|
||||
* Delete Bot Config
|
||||
* @description Delete bot configuration for a lobby
|
||||
*/
|
||||
delete_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_name__delete: {
|
||||
delete_bot_config_ai_voicebot_api_bots_config_lobby__lobby_id__bot__bot_instance_id__delete: {
|
||||
parameters: {
|
||||
path: {
|
||||
lobby_id: string;
|
||||
bot_name: string;
|
||||
bot_instance_id: string;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
|
@ -52,6 +52,7 @@ services:
|
||||
- ./shared:/shared:ro
|
||||
- ./server:/server:rw
|
||||
- ./server/.venv:/server/.venv:rw
|
||||
- ./server/entrypoint.sh:/entrypoint.sh:ro
|
||||
- ./client/build:/client/build:ro
|
||||
- ./dev-keys:/keys:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
@ -79,6 +80,7 @@ services:
|
||||
- ./shared:/shared:ro
|
||||
- ./voicebot:/voicebot:rw
|
||||
- ./voicebot/.venv:/voicebot/.venv:rw
|
||||
- ./voicebot/entrypoint.sh:/entrypoint.sh:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
# network_mode: host
|
||||
|
@ -51,11 +51,13 @@ except ImportError:
|
||||
|
||||
|
||||
def create_bot_config_router(
|
||||
config_manager: BotConfigManager, bot_manager: BotManager
|
||||
config_manager: BotConfigManager, bot_manager: BotManager, public_url: str = "/"
|
||||
) -> APIRouter:
|
||||
"""Create FastAPI router for bot configuration endpoints"""
|
||||
|
||||
router = APIRouter(prefix="/api/bots/config", tags=["Bot Configuration"])
|
||||
router = APIRouter(
|
||||
prefix=f"{public_url}api/bots/config", tags=["Bot Configuration"]
|
||||
)
|
||||
|
||||
@router.get("/schema/{bot_name}")
|
||||
async def get_bot_config_schema(bot_name: str) -> BotConfigSchema: # type: ignore
|
||||
@ -137,24 +139,41 @@ def create_bot_config_router(
|
||||
logger.error(f"Failed to get lobby configs for {lobby_id}: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
@router.get("/lobby/{lobby_id}/bot/{bot_name}")
|
||||
async def get_lobby_bot_config(lobby_id: str, bot_name: str) -> BotLobbyConfig:
|
||||
@router.get("/lobby/{lobby_id}/bot/{bot_instance_id}")
|
||||
async def get_lobby_bot_config(
|
||||
lobby_id: str, bot_instance_id: str
|
||||
) -> BotLobbyConfig:
|
||||
"""Get specific bot configuration for a lobby"""
|
||||
logger.info(
|
||||
f"Route handler called: get_lobby_bot_config({lobby_id}, {bot_instance_id})"
|
||||
)
|
||||
try:
|
||||
# Get bot instance to find the bot_name
|
||||
bot_instance = await bot_manager.get_bot_instance(bot_instance_id)
|
||||
bot_name = bot_instance.bot_name
|
||||
|
||||
config = config_manager.get_lobby_bot_config(lobby_id, bot_name)
|
||||
if not config:
|
||||
logger.warning(
|
||||
f"No configuration found for bot instance '{bot_instance_id}' (bot: '{bot_name}') in lobby '{lobby_id}'"
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"No configuration found for bot '{bot_name}' in lobby '{lobby_id}'",
|
||||
detail=f"No configuration found for bot instance '{bot_instance_id}' in lobby '{lobby_id}'",
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
except ValueError:
|
||||
# Bot instance not found
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"Bot instance '{bot_instance_id}' not found"
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Failed to get config for bot {bot_name} in lobby {lobby_id}: {e}"
|
||||
f"Failed to get config for bot instance {bot_instance_id} in lobby {lobby_id}: {e}"
|
||||
)
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
@ -165,54 +184,39 @@ def create_bot_config_router(
|
||||
session_id: str = "unknown", # TODO: Get from auth/session context
|
||||
) -> BotConfigUpdateResponse:
|
||||
"""Update bot configuration for a lobby"""
|
||||
logger.info(
|
||||
f"Route handler called: update_bot_config({request.bot_instance_id}, {request.lobby_id})"
|
||||
)
|
||||
try:
|
||||
# Find the provider for this bot
|
||||
provider_id = None
|
||||
provider_url = None
|
||||
# Get bot instance information
|
||||
bot_instance = await bot_manager.get_bot_instance(request.bot_instance_id)
|
||||
bot_name = bot_instance.bot_name
|
||||
provider_id = bot_instance.provider_id
|
||||
|
||||
providers_response = bot_manager.list_providers()
|
||||
for provider in providers_response.providers:
|
||||
try:
|
||||
provider_bots = await bot_manager.get_provider_bots(
|
||||
provider.provider_id
|
||||
)
|
||||
bot_names = [bot.name for bot in provider_bots.bots]
|
||||
|
||||
if request.bot_name in bot_names:
|
||||
provider_id = provider.provider_id
|
||||
provider_url = provider.base_url
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not provider_id:
|
||||
# Find the provider URL
|
||||
provider = bot_manager.get_provider(provider_id)
|
||||
if not provider:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Bot '{request.bot_name}' not found in any provider"
|
||||
status_code=404, detail=f"Provider '{provider_id}' not found"
|
||||
)
|
||||
provider_url = provider.base_url
|
||||
|
||||
# Update configuration
|
||||
if not provider_id or not provider_url:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Bot {request.bot_name} not found in any registered provider",
|
||||
)
|
||||
|
||||
config = config_manager.set_bot_config(
|
||||
lobby_id=request.lobby_id,
|
||||
bot_name=request.bot_name,
|
||||
bot_name=bot_name,
|
||||
provider_id=provider_id,
|
||||
config_values=request.config_values,
|
||||
session_id=session_id
|
||||
session_id=session_id,
|
||||
)
|
||||
|
||||
# Notify bot provider in background
|
||||
background_tasks.add_task(
|
||||
config_manager.notify_bot_config_change,
|
||||
provider_url,
|
||||
request.bot_name,
|
||||
bot_name,
|
||||
request.lobby_id,
|
||||
config
|
||||
config,
|
||||
)
|
||||
|
||||
return BotConfigUpdateResponse(
|
||||
@ -222,10 +226,9 @@ def create_bot_config_router(
|
||||
)
|
||||
|
||||
except ValueError as e:
|
||||
# Validation error
|
||||
# Bot instance not found
|
||||
return BotConfigUpdateResponse(
|
||||
success=False,
|
||||
message=f"Validation error: {str(e)}"
|
||||
success=False, message=f"Bot instance not found: {str(e)}"
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
@ -233,20 +236,29 @@ def create_bot_config_router(
|
||||
logger.error(f"Failed to update bot config: {e}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
@router.delete("/lobby/{lobby_id}/bot/{bot_name}")
|
||||
async def delete_bot_config(lobby_id: str, bot_name: str) -> Dict[str, Any]:
|
||||
@router.delete("/lobby/{lobby_id}/bot/{bot_instance_id}")
|
||||
async def delete_bot_config(lobby_id: str, bot_instance_id: str) -> Dict[str, Any]:
|
||||
"""Delete bot configuration for a lobby"""
|
||||
try:
|
||||
# Get bot instance to find the bot_name
|
||||
bot_instance = await bot_manager.get_bot_instance(bot_instance_id)
|
||||
bot_name = bot_instance.bot_name
|
||||
|
||||
success = config_manager.delete_bot_config(lobby_id, bot_name)
|
||||
|
||||
if not success:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"No configuration found for bot '{bot_name}' in lobby '{lobby_id}'"
|
||||
detail=f"No configuration found for bot instance '{bot_instance_id}' in lobby '{lobby_id}'",
|
||||
)
|
||||
|
||||
return {"success": True, "message": "Configuration deleted successfully"}
|
||||
|
||||
except ValueError:
|
||||
# Bot instance not found
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"Bot instance '{bot_instance_id}' not found"
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
@ -328,8 +340,13 @@ def create_bot_config_router(
|
||||
# Find the provider for this bot
|
||||
providers_response = bot_manager.list_providers()
|
||||
|
||||
for provider in providers_response.providers:
|
||||
for provider_public in providers_response.providers:
|
||||
try:
|
||||
# Get the full provider object to access base_url
|
||||
provider = bot_manager.get_provider(provider_public.provider_id)
|
||||
if not provider:
|
||||
continue
|
||||
|
||||
provider_bots = await bot_manager.get_provider_bots(
|
||||
provider.provider_id
|
||||
)
|
||||
@ -353,7 +370,7 @@ def create_bot_config_router(
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"Failed to check provider {provider.provider_id}: {e}"
|
||||
f"Failed to check provider {provider_public.provider_id}: {e}"
|
||||
)
|
||||
continue
|
||||
|
||||
|
@ -20,10 +20,12 @@ except ImportError as e:
|
||||
)
|
||||
|
||||
|
||||
def create_bot_router(bot_manager, session_manager, lobby_manager):
|
||||
def create_bot_router(
|
||||
bot_manager, session_manager, lobby_manager, public_url: str = "/"
|
||||
) -> APIRouter:
|
||||
"""Create bot API router with dependencies"""
|
||||
|
||||
router = APIRouter(prefix="/bots", tags=["bots"])
|
||||
router = APIRouter(prefix=f"{public_url}api/bots", tags=["bots"])
|
||||
|
||||
@router.post("/providers/register", response_model=BotProviderRegisterResponse)
|
||||
async def register_bot_provider(request: BotProviderRegisterRequest) -> BotProviderRegisterResponse:
|
||||
|
0
server/entrypoint.sh
Normal file → Executable file
0
server/entrypoint.sh
Normal file → Executable file
@ -19,6 +19,7 @@ import os
|
||||
import asyncio
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import datetime
|
||||
import time
|
||||
|
||||
from fastapi import FastAPI, WebSocket, Path, Request
|
||||
from fastapi.responses import Response
|
||||
@ -64,10 +65,14 @@ try:
|
||||
from api.monitoring import router as monitoring_router
|
||||
from core.performance import metrics_collector
|
||||
from core.health import (
|
||||
health_monitor, DatabaseHealthCheck, WebSocketHealthCheck,
|
||||
LobbyHealthCheck, SystemResourceHealthCheck
|
||||
health_monitor,
|
||||
DatabaseHealthCheck,
|
||||
WebSocketHealthCheck,
|
||||
LobbyHealthCheck,
|
||||
SystemResourceHealthCheck,
|
||||
)
|
||||
from core.cache import cache_manager
|
||||
|
||||
monitoring_available = True
|
||||
logger.info("Performance monitoring modules loaded successfully")
|
||||
except ImportError as e:
|
||||
@ -100,6 +105,27 @@ app = FastAPI(
|
||||
redoc_url=redoc_url,
|
||||
)
|
||||
|
||||
|
||||
@app.middleware("http")
|
||||
async def log_requests(request: Request, call_next): # type: ignore
|
||||
start_time = time.time()
|
||||
|
||||
# Log information before the request is processed
|
||||
logger.info(
|
||||
f"Incoming request: Method={request.method}, URL={request.url.path}, Client={request.client.host}"
|
||||
)
|
||||
|
||||
response = await call_next(request)
|
||||
|
||||
# Log information after the response is generated
|
||||
process_time = time.time() - start_time
|
||||
logger.info(
|
||||
f"Outgoing response: Status={response.status_code}, Time Taken={process_time:.4f}s"
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
logger.info(f"Starting server with public URL: {public_url}")
|
||||
|
||||
|
||||
@ -123,7 +149,6 @@ async def lifespan(app: FastAPI):
|
||||
bot_config_manager, \
|
||||
websocket_manager
|
||||
|
||||
|
||||
# Startup
|
||||
logger.info("Starting AI Voice Bot server with modular architecture...")
|
||||
|
||||
@ -177,17 +202,35 @@ async def lifespan(app: FastAPI):
|
||||
)
|
||||
|
||||
# Create bot API router
|
||||
bot_router = create_bot_router(bot_manager, session_manager, lobby_manager)
|
||||
bot_router = create_bot_router(
|
||||
bot_manager, session_manager, lobby_manager, public_url=public_url
|
||||
)
|
||||
|
||||
# Create bot configuration API router
|
||||
bot_config_router = create_bot_config_router(bot_config_manager, bot_manager)
|
||||
bot_config_router = create_bot_config_router(
|
||||
bot_config_manager, bot_manager, public_url=public_url
|
||||
)
|
||||
logger.info(
|
||||
f"Bot config router created with {len(bot_config_router.routes)} routes"
|
||||
)
|
||||
|
||||
# Register API routes during startup
|
||||
app.include_router(admin_api.router)
|
||||
app.include_router(session_api.router)
|
||||
app.include_router(lobby_api.router)
|
||||
app.include_router(bot_router, prefix=public_url.rstrip("/") + "/api")
|
||||
app.include_router(bot_config_router, prefix=public_url.rstrip("/"))
|
||||
app.include_router(bot_router)
|
||||
|
||||
try:
|
||||
app.include_router(bot_config_router)
|
||||
logger.info(
|
||||
f"Bot config router included successfully with {len(bot_config_router.routes)} routes"
|
||||
)
|
||||
logger.info(f"Bot config router prefix: {bot_config_router.prefix}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to include bot config router: {e}")
|
||||
raise
|
||||
|
||||
logger.info(f"Total routes in app after inclusion: {len(app.routes)}")
|
||||
|
||||
# Add monitoring router if available
|
||||
if monitoring_available and monitoring_router:
|
||||
@ -203,7 +246,9 @@ async def lifespan(app: FastAPI):
|
||||
health_monitor.register_component(DatabaseHealthCheck(session_manager))
|
||||
health_monitor.register_component(WebSocketHealthCheck(session_manager))
|
||||
health_monitor.register_component(LobbyHealthCheck(lobby_manager))
|
||||
health_monitor.register_component(SystemResourceHealthCheck(metrics_collector))
|
||||
health_monitor.register_component(
|
||||
SystemResourceHealthCheck(metrics_collector)
|
||||
)
|
||||
|
||||
# Start monitoring tasks
|
||||
if metrics_collector:
|
||||
@ -395,7 +440,9 @@ async def system_health():
|
||||
statistics = {
|
||||
"sessions": session_manager.get_session_count() if session_manager else 0,
|
||||
"lobbies": lobby_manager.get_lobby_count() if lobby_manager else 0,
|
||||
"protected_names": auth_manager.get_protection_count() if auth_manager else 0,
|
||||
"protected_names": auth_manager.get_protection_count()
|
||||
if auth_manager
|
||||
else 0,
|
||||
}
|
||||
|
||||
# Get performance metrics if available
|
||||
@ -410,8 +457,10 @@ async def system_health():
|
||||
"managers": manager_status,
|
||||
"monitoring": monitoring_status,
|
||||
"statistics": statistics,
|
||||
"performance": performance_summary.get("health_status", "unknown") if performance_summary else "unknown",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
"performance": performance_summary.get("health_status", "unknown")
|
||||
if performance_summary
|
||||
else "unknown",
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
@ -419,7 +468,7 @@ async def system_health():
|
||||
return {
|
||||
"status": "error",
|
||||
"message": str(e),
|
||||
"timestamp": datetime.now().isoformat()
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,8 +126,8 @@ def _setup_logging(level: str=logging_level) -> logging.Logger:
|
||||
"uvicorn",
|
||||
"uvicorn.error",
|
||||
"uvicorn.access",
|
||||
"fastapi",
|
||||
"starlette",
|
||||
# "fastapi",
|
||||
# "starlette",
|
||||
):
|
||||
logger = logging.getLogger(noisy_logger)
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
@ -402,7 +402,7 @@ class BotLobbyConfig(BaseModel):
|
||||
class BotConfigUpdateRequest(BaseModel):
|
||||
"""Request to update bot configuration"""
|
||||
|
||||
bot_name: str
|
||||
bot_instance_id: str
|
||||
lobby_id: str
|
||||
config_values: Dict[str, Any]
|
||||
|
||||
@ -467,7 +467,7 @@ class BotProviderPublicModel(BaseModel):
|
||||
last_seen: float
|
||||
|
||||
|
||||
class BotProviderListResponse(BaseModel):
|
||||
class kBotProviderListResponse(BaseModel):
|
||||
"""Response listing all registered bot providers"""
|
||||
|
||||
providers: List[BotProviderPublicModel]
|
||||
|
@ -243,12 +243,16 @@ def discover_bots() -> "List[BotInfoModel]":
|
||||
if hasattr(mod, "agent_info") and callable(getattr(mod, "agent_info")):
|
||||
try:
|
||||
info = mod.agent_info()
|
||||
# Convert string has_media to boolean for compatibility
|
||||
# Convert string has_media and configurable to boolean for compatibility
|
||||
processed_info = dict(info)
|
||||
has_media_value = processed_info.get("has_media", True)
|
||||
if isinstance(has_media_value, str):
|
||||
processed_info["has_media"] = has_media_value.lower() in ("true", "1", "yes")
|
||||
|
||||
configurable_value = processed_info.get("configurable", False)
|
||||
if isinstance(configurable_value, str):
|
||||
processed_info["configurable"] = configurable_value.lower() in ("true", "1", "yes")
|
||||
|
||||
# Create BotInfoModel using model_validate
|
||||
bot_info = BotInfoModel.model_validate(processed_info)
|
||||
bots.append(bot_info)
|
||||
@ -279,6 +283,8 @@ def discover_bots() -> "List[BotInfoModel]":
|
||||
try:
|
||||
config_schema = mod.get_config_schema()
|
||||
logger.info(f"Bot {bot_info.name} supports configuration")
|
||||
# Set the config_schema on the BotInfoModel
|
||||
bot_info.config_schema = config_schema
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to get config schema for {bot_info.name}: {e}")
|
||||
|
||||
|
0
voicebot/entrypoint.sh
Normal file → Executable file
0
voicebot/entrypoint.sh
Normal file → Executable file
@ -5,12 +5,164 @@ description = "AI Voicebot Environment"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"about-time>=4.2.1",
|
||||
"aiofiles>=24.1.0",
|
||||
"aiohappyeyeballs>=2.6.1",
|
||||
"aiohttp>=3.12.15",
|
||||
"aioice>=0.10.1",
|
||||
"aiortc>=1.13.0",
|
||||
"numpy<2.3",
|
||||
"opencv-python>=4.11.0.86",
|
||||
"pydantic>=2.11.7",
|
||||
"aiosignal>=1.4.0",
|
||||
"alive-progress>=3.2.0",
|
||||
"annotated-types>=0.7.0",
|
||||
"anyio>=4.10.0",
|
||||
"attrs>=25.3.0",
|
||||
"audioread>=3.0.1",
|
||||
"autograd>=1.8.0",
|
||||
"av>=14.4.0",
|
||||
"brotli>=1.1.0",
|
||||
"certifi>=2025.8.3",
|
||||
"cffi>=2.0.0",
|
||||
"charset-normalizer>=3.4.3",
|
||||
"click>=8.2.1",
|
||||
"cma>=4.3.0",
|
||||
"contourpy>=1.3.3",
|
||||
"cryptography>=45.0.7",
|
||||
"cycler>=0.12.1",
|
||||
"datasets>=4.1.0",
|
||||
"decorator>=5.2.1",
|
||||
"deprecated>=1.2.18",
|
||||
"dill>=0.4.0",
|
||||
"dnspython>=2.8.0",
|
||||
"fastapi>=0.116.1",
|
||||
"ffmpy>=0.6.1",
|
||||
"filelock>=3.19.1",
|
||||
"fonttools>=4.59.2",
|
||||
"frozenlist>=1.7.0",
|
||||
"fsspec>=2025.9.0",
|
||||
"google-crc32c>=1.7.1",
|
||||
"gradio>=5.45.0",
|
||||
"gradio-client>=1.13.0",
|
||||
"graphemeu>=0.8.0",
|
||||
"groovy>=0.1.2",
|
||||
"h11>=0.16.0",
|
||||
"hf-xet>=1.1.10",
|
||||
"httpcore>=1.0.9",
|
||||
"httpx>=0.28.1",
|
||||
"huggingface-hub>=0.34.5",
|
||||
"idna>=3.10",
|
||||
"ifaddr>=0.2.0",
|
||||
"iniconfig>=2.1.0",
|
||||
"jinja2>=3.1.6",
|
||||
"jiwer>=4.0.0",
|
||||
"joblib>=1.5.2",
|
||||
"jsonschema>=4.25.1",
|
||||
"jsonschema-specifications>=2025.9.1",
|
||||
"kiwisolver>=1.4.9",
|
||||
"lazy-loader>=0.4",
|
||||
"librosa>=0.11.0",
|
||||
"llvmlite>=0.44.0",
|
||||
"markdown-it-py>=4.0.0",
|
||||
"markupsafe>=3.0.2",
|
||||
"matplotlib>=3.10.6",
|
||||
"mdurl>=0.1.2",
|
||||
"ml-dtypes>=0.5.3",
|
||||
"more-itertools>=10.8.0",
|
||||
"mpmath>=1.3.0",
|
||||
"msgpack>=1.1.1",
|
||||
"multidict>=6.6.4",
|
||||
"multiprocess>=0.70.16",
|
||||
"natsort>=8.4.0",
|
||||
"networkx>=3.4.2",
|
||||
"ninja>=1.13.0",
|
||||
"nncf>=2.18.0",
|
||||
"numba>=0.61.2",
|
||||
"numpy>=2.2.6",
|
||||
"onnx>=1.19.0",
|
||||
"openai-whisper",
|
||||
"opencv-python>=4.12.0.88",
|
||||
"openvino>=2025.3.0",
|
||||
"openvino-genai>=2025.3.0.0",
|
||||
"openvino-telemetry>=2025.2.0",
|
||||
"openvino-tokenizers>=2025.3.0.0",
|
||||
"optimum>=1.27.0",
|
||||
"optimum-intel",
|
||||
"orjson>=3.11.3",
|
||||
"packaging>=25.0",
|
||||
"pandas>=2.3.2",
|
||||
"pillow>=11.3.0",
|
||||
"platformdirs>=4.4.0",
|
||||
"pluggy>=1.6.0",
|
||||
"pooch>=1.8.2",
|
||||
"propcache>=0.3.2",
|
||||
"protobuf>=6.32.1",
|
||||
"psutil>=7.0.0",
|
||||
"pyarrow>=21.0.0",
|
||||
"pycparser>=2.23",
|
||||
"pydantic>=2.11.9",
|
||||
"pydantic-core>=2.33.2",
|
||||
"pydot>=3.0.4",
|
||||
"pydub>=0.25.1",
|
||||
"pyee>=13.0.0",
|
||||
"pygments>=2.19.2",
|
||||
"pylibsrtp>=0.12.0",
|
||||
"pymoo>=0.6.1.5",
|
||||
"pyopencl>=2025.2.6",
|
||||
"pyopenssl>=25.2.0",
|
||||
"pyparsing>=3.2.4",
|
||||
"pytest>=8.4.2",
|
||||
"pytest-asyncio>=1.2.0",
|
||||
"python-dateutil>=2.9.0.post0",
|
||||
"python-ffmpeg>=2.0.12",
|
||||
"python-multipart>=0.0.20",
|
||||
"pytools>=2025.2.4",
|
||||
"pytz>=2025.2",
|
||||
"pyyaml>=6.0.2",
|
||||
"rapidfuzz>=3.14.1",
|
||||
"referencing>=0.36.2",
|
||||
"regex>=2025.9.1",
|
||||
"requests>=2.32.5",
|
||||
"resampy>=0.4.3",
|
||||
"rich>=14.1.0",
|
||||
"rpds-py>=0.27.1",
|
||||
"ruff>=0.13.0",
|
||||
"safehttpx>=0.1.6",
|
||||
"safetensors>=0.6.2",
|
||||
"scikit-learn>=1.7.2",
|
||||
"scipy>=1.16.2",
|
||||
"semantic-version>=2.10.0",
|
||||
"setuptools>=80.9.0",
|
||||
"shellingham>=1.5.4",
|
||||
"siphash24>=1.8",
|
||||
"six>=1.17.0",
|
||||
"sniffio>=1.3.1",
|
||||
"soundfile>=0.13.1",
|
||||
"soxr>=1.0.0",
|
||||
"speechrecognition>=3.14.3",
|
||||
"starlette>=0.47.3",
|
||||
"sympy>=1.14.0",
|
||||
"tabulate>=0.9.0",
|
||||
"threadpoolctl>=3.6.0",
|
||||
"tiktoken>=0.11.0",
|
||||
"tokenizers>=0.21.4",
|
||||
"tomlkit>=0.13.3",
|
||||
"torch>=2.8.0",
|
||||
"torchvision>=0.23.0",
|
||||
"tqdm>=4.67.1",
|
||||
"transformers>=4.53.3",
|
||||
"triton>=3.4.0",
|
||||
"typer>=0.17.4",
|
||||
"typing-extensions>=4.15.0",
|
||||
"typing-inspection>=0.4.1",
|
||||
"tzdata>=2025.2",
|
||||
"urllib3>=2.5.0",
|
||||
"uvicorn>=0.35.0",
|
||||
"watchdog>=6.0.0",
|
||||
"websockets>=15.0.1",
|
||||
"librosa>=0.10.0",
|
||||
"torch>=2.0.0",
|
||||
"openai-whisper>=20231117",
|
||||
"wrapt>=1.17.3",
|
||||
"xxhash>=3.5.0",
|
||||
"yarl>=1.20.1",
|
||||
]
|
||||
|
||||
[tool.uv.sources]
|
||||
openai-whisper = { git = "https://github.com/openai/whisper.git", rev = "c0d2f624c09dc18e709e37c2ad90c039a4eb72a2" }
|
||||
optimum-intel = { git = "https://github.com/huggingface/optimum-intel.git", rev = "b9c151fec6b414d9ca78be8643d08e267b133bfc" }
|
||||
|
@ -1,171 +1,156 @@
|
||||
about-time==4.2.1
|
||||
-e file:///voicebot
|
||||
aiofiles==24.1.0
|
||||
aiohappyeyeballs==2.6.1
|
||||
aiohttp==3.12.15
|
||||
aioice==0.10.1
|
||||
aiortc==1.13.0
|
||||
aiosignal==1.4.0
|
||||
alive-progress==3.3.0
|
||||
annotated-types==0.7.0
|
||||
anyio==4.10.0
|
||||
attrs==25.3.0
|
||||
audioread==3.0.1
|
||||
autograd==1.8.0
|
||||
av==14.4.0
|
||||
brotli==1.1.0
|
||||
certifi==2025.8.3
|
||||
cffi==1.17.1
|
||||
charset-normalizer==3.4.3
|
||||
click==8.2.1
|
||||
cma==4.3.0
|
||||
contourpy==1.3.3
|
||||
cryptography==45.0.7
|
||||
cycler==0.12.1
|
||||
datasets==4.0.0
|
||||
decorator==5.2.1
|
||||
deprecated==1.2.18
|
||||
dill==0.3.8
|
||||
dnspython==2.7.0
|
||||
fastapi==0.116.1
|
||||
ffmpy==0.6.1
|
||||
filelock==3.19.1
|
||||
fonttools==4.59.2
|
||||
frozenlist==1.7.0
|
||||
fsspec==2025.3.0
|
||||
google-crc32c==1.7.1
|
||||
gradio==5.44.1
|
||||
gradio-client==1.12.1
|
||||
graphemeu==0.7.2
|
||||
groovy==0.1.2
|
||||
h11==0.16.0
|
||||
hf-xet==1.1.9
|
||||
httpcore==1.0.9
|
||||
httpx==0.28.1
|
||||
huggingface-hub==0.34.4
|
||||
idna==3.10
|
||||
ifaddr==0.2.0
|
||||
iniconfig==2.1.0
|
||||
jinja2==3.1.6
|
||||
jiwer==4.0.0
|
||||
joblib==1.5.2
|
||||
jsonschema==4.25.1
|
||||
jsonschema-specifications==2025.9.1
|
||||
kiwisolver==1.4.9
|
||||
lazy-loader==0.4
|
||||
librosa==0.11.0
|
||||
llvmlite==0.44.0
|
||||
markdown-it-py==4.0.0
|
||||
markupsafe==3.0.2
|
||||
matplotlib==3.10.6
|
||||
mdurl==0.1.2
|
||||
ml-dtypes==0.5.3
|
||||
more-itertools==10.8.0
|
||||
mpmath==1.3.0
|
||||
msgpack==1.1.1
|
||||
multidict==6.6.4
|
||||
multiprocess==0.70.16
|
||||
natsort==8.4.0
|
||||
networkx==3.5
|
||||
ninja==1.13.0
|
||||
nncf==2.18.0
|
||||
numba==0.61.2
|
||||
numpy==2.2.6
|
||||
nvidia-cublas-cu12==12.8.4.1
|
||||
nvidia-cuda-cupti-cu12==12.8.90
|
||||
nvidia-cuda-nvrtc-cu12==12.8.93
|
||||
nvidia-cuda-runtime-cu12==12.8.90
|
||||
nvidia-cudnn-cu12==9.10.2.21
|
||||
nvidia-cufft-cu12==11.3.3.83
|
||||
nvidia-cufile-cu12==1.13.1.3
|
||||
nvidia-curand-cu12==10.3.9.90
|
||||
nvidia-cusolver-cu12==11.7.3.90
|
||||
nvidia-cusparse-cu12==12.5.8.93
|
||||
nvidia-cusparselt-cu12==0.7.1
|
||||
nvidia-nccl-cu12==2.27.3
|
||||
nvidia-nvjitlink-cu12==12.8.93
|
||||
nvidia-nvtx-cu12==12.8.90
|
||||
onnx==1.19.0
|
||||
about-time
|
||||
aiofiles
|
||||
aiohappyeyeballs
|
||||
aiohttp
|
||||
aioice
|
||||
aiortc
|
||||
aiosignal
|
||||
alive-progress
|
||||
annotated-types
|
||||
anyio
|
||||
attrs
|
||||
audioread
|
||||
autograd
|
||||
av
|
||||
brotli
|
||||
certifi
|
||||
cffi
|
||||
charset-normalizer
|
||||
click
|
||||
cma
|
||||
contourpy
|
||||
cryptography
|
||||
cycler
|
||||
datasets
|
||||
decorator
|
||||
deprecated
|
||||
dill
|
||||
dnspython
|
||||
fastapi
|
||||
ffmpy
|
||||
filelock
|
||||
fonttools
|
||||
frozenlist
|
||||
fsspec
|
||||
google-crc32c
|
||||
gradio
|
||||
gradio-client
|
||||
graphemeu
|
||||
groovy
|
||||
h11
|
||||
hf-xet
|
||||
httpcore
|
||||
httpx
|
||||
huggingface-hub
|
||||
idna
|
||||
ifaddr
|
||||
iniconfig
|
||||
jinja2
|
||||
jiwer
|
||||
joblib
|
||||
jsonschema
|
||||
jsonschema-specifications
|
||||
kiwisolver
|
||||
lazy-loader
|
||||
librosa
|
||||
llvmlite
|
||||
markdown-it-py
|
||||
markupsafe
|
||||
matplotlib
|
||||
mdurl
|
||||
ml-dtypes
|
||||
more-itertools
|
||||
mpmath
|
||||
msgpack
|
||||
multidict
|
||||
multiprocess
|
||||
natsort
|
||||
networkx
|
||||
ninja
|
||||
nncf
|
||||
numba
|
||||
numpy
|
||||
onnx
|
||||
openai-whisper @ git+https://github.com/openai/whisper.git@c0d2f624c09dc18e709e37c2ad90c039a4eb72a2
|
||||
opencv-python==4.11.0.86
|
||||
openvino==2025.3.0
|
||||
openvino-genai==2025.3.0.0
|
||||
openvino-telemetry==2025.2.0
|
||||
openvino-tokenizers==2025.3.0.0
|
||||
optimum==1.27.0
|
||||
opencv-python
|
||||
openvino
|
||||
openvino-genai
|
||||
openvino-telemetry
|
||||
openvino-tokenizers
|
||||
optimum
|
||||
optimum-intel @ git+https://github.com/huggingface/optimum-intel.git@b9c151fec6b414d9ca78be8643d08e267b133bfc
|
||||
orjson==3.11.3
|
||||
packaging==25.0
|
||||
pandas==2.3.2
|
||||
pillow==11.3.0
|
||||
platformdirs==4.4.0
|
||||
pluggy==1.6.0
|
||||
pooch==1.8.2
|
||||
propcache==0.3.2
|
||||
protobuf==6.32.0
|
||||
psutil==7.0.0
|
||||
pyarrow==21.0.0
|
||||
pycparser==2.22
|
||||
pydantic==2.11.7
|
||||
pydantic-core==2.33.2
|
||||
pydot==3.0.4
|
||||
pydub==0.25.1
|
||||
pyee==13.0.0
|
||||
pygments==2.19.2
|
||||
pylibsrtp==0.12.0
|
||||
pymoo==0.6.1.5
|
||||
pyopencl==2025.2.6
|
||||
pyopenssl==25.1.0
|
||||
pyparsing==3.2.3
|
||||
pytest==8.4.2
|
||||
pytest-asyncio==1.1.0
|
||||
python-dateutil==2.9.0.post0
|
||||
python-ffmpeg==1.0.16
|
||||
python-multipart==0.0.20
|
||||
pytools==2025.2.4
|
||||
pytz==2025.2
|
||||
pyyaml==6.0.2
|
||||
rapidfuzz==3.14.0
|
||||
referencing==0.36.2
|
||||
regex==2025.9.1
|
||||
requests==2.32.5
|
||||
resampy==0.4.3
|
||||
rich==14.1.0
|
||||
rpds-py==0.27.1
|
||||
ruff==0.12.11
|
||||
safehttpx==0.1.6
|
||||
safetensors==0.6.2
|
||||
scikit-learn==1.7.1
|
||||
scipy==1.16.1
|
||||
semantic-version==2.10.0
|
||||
setuptools==80.9.0
|
||||
shellingham==1.5.4
|
||||
siphash24==1.8
|
||||
six==1.17.0
|
||||
sniffio==1.3.1
|
||||
soundfile==0.13.1
|
||||
soxr==0.5.0.post1
|
||||
speechrecognition==3.14.3
|
||||
starlette==0.47.3
|
||||
sympy==1.14.0
|
||||
tabulate==0.9.0
|
||||
threadpoolctl==3.6.0
|
||||
tiktoken==0.11.0
|
||||
tokenizers==0.21.4
|
||||
tomlkit==0.13.3
|
||||
torch==2.8.0
|
||||
torchvision==0.23.0
|
||||
tqdm==4.67.1
|
||||
transformers==4.53.3
|
||||
triton==3.4.0
|
||||
typer==0.17.3
|
||||
typing-extensions==4.15.0
|
||||
typing-inspection==0.4.1
|
||||
tzdata==2025.2
|
||||
urllib3==2.5.0
|
||||
uvicorn==0.35.0
|
||||
watchdog==6.0.0
|
||||
websockets==15.0.1
|
||||
wrapt==1.17.3
|
||||
xxhash==3.5.0
|
||||
yarl==1.20.1
|
||||
orjson
|
||||
packaging
|
||||
pandas
|
||||
pillow
|
||||
platformdirs
|
||||
pluggy
|
||||
pooch
|
||||
propcache
|
||||
protobuf
|
||||
psutil
|
||||
pyarrow
|
||||
pycparser
|
||||
pydantic
|
||||
pydantic-core
|
||||
pydot
|
||||
pydub
|
||||
pyee
|
||||
pygments
|
||||
pylibsrtp
|
||||
pymoo
|
||||
pyopencl
|
||||
pyopenssl
|
||||
pyparsing
|
||||
pytest
|
||||
pytest-asyncio
|
||||
python-dateutil
|
||||
python-ffmpeg
|
||||
python-multipart
|
||||
pytools
|
||||
pytz
|
||||
pyyaml
|
||||
rapidfuzz
|
||||
referencing
|
||||
regex
|
||||
requests
|
||||
resampy
|
||||
rich
|
||||
rpds-py
|
||||
ruff
|
||||
safehttpx
|
||||
safetensors
|
||||
scikit-learn
|
||||
scipy
|
||||
semantic-version
|
||||
setuptools
|
||||
shellingham
|
||||
siphash24
|
||||
six
|
||||
sniffio
|
||||
soundfile
|
||||
soxr
|
||||
speechrecognition
|
||||
starlette
|
||||
sympy
|
||||
tabulate
|
||||
threadpoolctl
|
||||
tiktoken
|
||||
tokenizers
|
||||
tomlkit
|
||||
torch
|
||||
torchvision
|
||||
tqdm
|
||||
transformers
|
||||
triton
|
||||
typer
|
||||
typing-extensions
|
||||
typing-inspection
|
||||
tzdata
|
||||
urllib3
|
||||
uvicorn
|
||||
watchdog
|
||||
websockets
|
||||
wrapt
|
||||
xxhash
|
||||
yarl
|
||||
|
2837
voicebot/uv.lock
generated
2837
voicebot/uv.lock
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user