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