feat: add customer portal and RTC voice diagnostics
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
volcbase "github.com/volcengine/volc-sdk-golang/base"
|
||||
)
|
||||
|
||||
type responseEnvelope struct {
|
||||
ResponseMetadata struct {
|
||||
Error *struct {
|
||||
Code string `json:"Code"`
|
||||
Message string `json:"Message"`
|
||||
} `json:"Error"`
|
||||
} `json:"ResponseMetadata"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
akFile := flag.String("ak-file", "", "file containing the Volcengine AccessKey ID")
|
||||
skFile := flag.String("sk-file", "", "file containing the Volcengine SecretAccessKey")
|
||||
endpoint := flag.String("endpoint", "https://rtc.volcengineapi.com", "RTC OpenAPI endpoint")
|
||||
rtcAppID := flag.String("rtc-app-id", "", "RTC application ID used for staged validation probes")
|
||||
templateFile := flag.String("template-file", "", "voice-chat template bundle used for ProviderParams probes")
|
||||
roomID := flag.String("room-id", "", "RTC room ID to inspect without starting a task")
|
||||
flag.Parse()
|
||||
if *akFile == "" || *skFile == "" {
|
||||
panic("-ak-file and -sk-file are required")
|
||||
}
|
||||
ak := readSecret(*akFile)
|
||||
sk := readSecret(*skFile)
|
||||
credentials := volcbase.Credentials{AccessKeyID: ak, SecretAccessKey: sk, Service: "rtc", Region: "cn-north-1"}
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
if *rtcAppID != "" && *roomID != "" {
|
||||
queryRoom(client, credentials, *endpoint, *rtcAppID, *roomID)
|
||||
return
|
||||
}
|
||||
for _, version := range []string{"2024-06-01", "2024-12-01", "2025-06-01"} {
|
||||
probe(client, credentials, *endpoint, version, "empty", map[string]any{})
|
||||
}
|
||||
if *rtcAppID != "" {
|
||||
version := "2024-12-01"
|
||||
identity := map[string]any{
|
||||
"AppId": *rtcAppID, "RoomId": "probe-room", "TaskId": "probe-task",
|
||||
}
|
||||
agent := map[string]any{
|
||||
"TargetUserId": []string{"probe-user"}, "UserId": "probe-agent",
|
||||
}
|
||||
probe(client, credentials, *endpoint, version, "app-only", map[string]any{"AppId": *rtcAppID})
|
||||
probe(client, credentials, *endpoint, version, "identity-only", map[string]any{
|
||||
"AppId": *rtcAppID, "RoomId": "probe-room", "TaskId": "probe-task",
|
||||
})
|
||||
probe(client, credentials, *endpoint, version, "empty-config", map[string]any{
|
||||
"AppId": *rtcAppID, "RoomId": "probe-room", "TaskId": "probe-task",
|
||||
"Config": map[string]any{}, "AgentConfig": map[string]any{},
|
||||
})
|
||||
probe(client, credentials, *endpoint, version, "agent-valid", merge(identity, map[string]any{
|
||||
"Config": map[string]any{}, "AgentConfig": agent,
|
||||
}))
|
||||
probe(client, credentials, *endpoint, version, "s2s-shell", merge(identity, map[string]any{
|
||||
"Config": map[string]any{"S2SConfig": map[string]any{}}, "AgentConfig": agent,
|
||||
}))
|
||||
probe(client, credentials, *endpoint, version, "s2s-provider", merge(identity, map[string]any{
|
||||
"Config": map[string]any{"S2SConfig": map[string]any{
|
||||
"Provider": "volcano", "OutputMode": 0,
|
||||
}}, "AgentConfig": agent,
|
||||
}))
|
||||
probe(client, credentials, *endpoint, version, "s2s-params-empty", merge(identity, map[string]any{
|
||||
"Config": map[string]any{"S2SConfig": map[string]any{
|
||||
"Provider": "volcano", "OutputMode": 0, "ProviderParams": map[string]any{},
|
||||
}}, "AgentConfig": agent,
|
||||
}))
|
||||
if *templateFile != "" {
|
||||
providerParams := readProviderParams(*templateFile)
|
||||
for _, item := range []struct {
|
||||
label string
|
||||
keys []string
|
||||
}{
|
||||
{label: "params-app", keys: []string{"app"}},
|
||||
{label: "params-dialog", keys: []string{"dialog"}},
|
||||
{label: "params-asr", keys: []string{"asr"}},
|
||||
{label: "params-tts", keys: []string{"tts"}},
|
||||
{label: "params-full", keys: []string{"app", "dialog", "asr", "tts"}},
|
||||
} {
|
||||
selected := make(map[string]any, len(item.keys))
|
||||
for _, key := range item.keys {
|
||||
if value, ok := providerParams[key]; ok {
|
||||
selected[key] = value
|
||||
}
|
||||
}
|
||||
probeIdentity := merge(identity, map[string]any{"TaskId": "probe-" + item.label})
|
||||
payload := merge(probeIdentity, map[string]any{
|
||||
"Config": map[string]any{"S2SConfig": map[string]any{
|
||||
"Provider": "volcano", "OutputMode": 0, "ProviderParams": selected,
|
||||
}}, "AgentConfig": agent,
|
||||
})
|
||||
if probeAction(client, credentials, *endpoint, version, item.label, "StartVoiceChat", payload) {
|
||||
probeAction(client, credentials, *endpoint, version, item.label+"-cleanup", "StopVoiceChat", probeIdentity)
|
||||
}
|
||||
}
|
||||
fullTemplate := readHybridTemplate(*templateFile)
|
||||
fullIdentity := merge(identity, map[string]any{"TaskId": "probe-full-template"})
|
||||
fullTemplate = merge(fullTemplate, fullIdentity)
|
||||
fullAgent, _ := fullTemplate["AgentConfig"].(map[string]any)
|
||||
fullAgent["TargetUserId"] = []string{"probe-user"}
|
||||
fullAgent["UserId"] = "probe-agent"
|
||||
if probeAction(client, credentials, *endpoint, version, "full-template", "StartVoiceChat", fullTemplate) {
|
||||
probeAction(client, credentials, *endpoint, version, "full-template-cleanup", "StopVoiceChat", fullIdentity)
|
||||
}
|
||||
}
|
||||
probeAction(client, credentials, *endpoint, version, "cleanup", "StopVoiceChat", identity)
|
||||
}
|
||||
}
|
||||
|
||||
func queryRoom(client *http.Client, credentials volcbase.Credentials, endpoint, appID, roomID string) {
|
||||
target, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
query := target.Query()
|
||||
query.Set("Action", "GetRoomOnlineUsers")
|
||||
query.Set("Version", "2023-11-01")
|
||||
query.Set("AppId", appID)
|
||||
query.Set("RoomId", roomID)
|
||||
query.Set("Property", "false")
|
||||
target.RawQuery = query.Encode()
|
||||
request, err := http.NewRequest(http.MethodGet, target.String(), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request.Host = target.Host
|
||||
request.Header.Set("Accept", "application/json")
|
||||
credentials.Sign(request)
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(io.LimitReader(response.Body, 1<<20))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var decoded map[string]any
|
||||
if err := json.Unmarshal(body, &decoded); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
encoded, _ := json.Marshal(decoded)
|
||||
fmt.Printf("room-status=%d response=%s\n", response.StatusCode, encoded)
|
||||
}
|
||||
|
||||
func readProviderParams(path string) map[string]any {
|
||||
template := readHybridTemplate(path)
|
||||
config, _ := template["Config"].(map[string]any)
|
||||
s2s, _ := config["S2SConfig"].(map[string]any)
|
||||
params, _ := s2s["ProviderParams"].(map[string]any)
|
||||
if params == nil {
|
||||
panic("template does not contain s2s_hybrid Config.S2SConfig.ProviderParams")
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func readHybridTemplate(path string) map[string]any {
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var bundle map[string]any
|
||||
if err := json.Unmarshal(raw, &bundle); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
templates, _ := bundle["templates"].(map[string]any)
|
||||
template, _ := templates["s2s_hybrid"].(map[string]any)
|
||||
if template == nil {
|
||||
panic("template does not contain s2s_hybrid")
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func merge(base map[string]any, extra map[string]any) map[string]any {
|
||||
result := make(map[string]any, len(base)+len(extra))
|
||||
for key, value := range base {
|
||||
result[key] = value
|
||||
}
|
||||
for key, value := range extra {
|
||||
result[key] = value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func readSecret(path string) string {
|
||||
value, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return strings.TrimSpace(string(value))
|
||||
}
|
||||
|
||||
func probe(client *http.Client, credentials volcbase.Credentials, endpoint, version, label string, payload map[string]any) {
|
||||
probeAction(client, credentials, endpoint, version, label, "StartVoiceChat", payload)
|
||||
}
|
||||
|
||||
func probeAction(client *http.Client, credentials volcbase.Credentials, endpoint, version, label, action string, payload map[string]any) bool {
|
||||
target, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
query := target.Query()
|
||||
query.Set("Action", action)
|
||||
query.Set("Version", version)
|
||||
target.RawQuery = query.Encode()
|
||||
bodyBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request, err := http.NewRequest(http.MethodPost, target.String(), bytes.NewReader(bodyBytes))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request.Host = target.Host
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
request.Header.Set("Accept", "application/json")
|
||||
credentials.Sign(request)
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
fmt.Printf("label=%s version=%s transport_error=%v\n", label, version, err)
|
||||
return false
|
||||
}
|
||||
defer response.Body.Close()
|
||||
body, err := io.ReadAll(io.LimitReader(response.Body, 1<<20))
|
||||
if err != nil {
|
||||
fmt.Printf("label=%s version=%s status=%d read_error=%v\n", label, version, response.StatusCode, err)
|
||||
return false
|
||||
}
|
||||
var envelope responseEnvelope
|
||||
_ = json.Unmarshal(body, &envelope)
|
||||
if envelope.ResponseMetadata.Error == nil {
|
||||
fmt.Printf("label=%s version=%s status=%d code=none\n", label, version, response.StatusCode)
|
||||
return response.StatusCode >= 200 && response.StatusCode < 300
|
||||
}
|
||||
fmt.Printf("label=%s version=%s status=%d code=%s message=%s\n", label, version, response.StatusCode,
|
||||
envelope.ResponseMetadata.Error.Code, envelope.ResponseMetadata.Error.Message)
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
volcbase "github.com/volcengine/volc-sdk-golang/base"
|
||||
)
|
||||
|
||||
func main() {
|
||||
akFile := flag.String("ak-file", "", "file containing the Volcengine AccessKey ID")
|
||||
skFile := flag.String("sk-file", "", "file containing the Volcengine SecretAccessKey")
|
||||
resourceID := flag.String("resource-id", "volc.speech.dialog", "speech service resource ID")
|
||||
projectName := flag.String("project", "default", "Volcengine project name")
|
||||
flag.Parse()
|
||||
if *akFile == "" || *skFile == "" {
|
||||
panic("-ak-file and -sk-file are required")
|
||||
}
|
||||
target, _ := url.Parse("https://open.volcengineapi.com")
|
||||
query := target.Query()
|
||||
query.Set("Action", "QuotaMonitoring")
|
||||
query.Set("Version", "2025-05-21")
|
||||
target.RawQuery = query.Encode()
|
||||
today := time.Now().Format("2006-01-02")
|
||||
body, _ := json.Marshal(map[string]any{
|
||||
"ProjectName": *projectName,
|
||||
"ResourceID": *resourceID,
|
||||
"Start": today,
|
||||
"End": today,
|
||||
"Mode": "daily",
|
||||
"QuotaType": "concurrency",
|
||||
})
|
||||
request, _ := http.NewRequest(http.MethodPost, target.String(), bytes.NewReader(body))
|
||||
request.Host = target.Host
|
||||
request.Header.Set("Content-Type", "application/json; charset=UTF-8")
|
||||
credentials := volcbase.Credentials{
|
||||
AccessKeyID: readSecret(*akFile), SecretAccessKey: readSecret(*skFile),
|
||||
Service: "speech_saas_prod", Region: "cn-beijing",
|
||||
}
|
||||
credentials.Sign(request)
|
||||
response, err := (&http.Client{Timeout: 15 * time.Second}).Do(request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
responseBody, _ := io.ReadAll(io.LimitReader(response.Body, 1<<20))
|
||||
var decoded map[string]any
|
||||
_ = json.Unmarshal(responseBody, &decoded)
|
||||
encoded, _ := json.Marshal(decoded)
|
||||
fmt.Printf("status=%d response=%s\n", response.StatusCode, encoded)
|
||||
}
|
||||
|
||||
func readSecret(path string) string {
|
||||
value, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return strings.TrimSpace(string(value))
|
||||
}
|
||||
Reference in New Issue
Block a user