sync: migrate ai-operator to Gitea (2026-08-10)

This commit is contained in:
konturai-ops
2026-08-10 15:26:52 +00:00
commit 53652b95ad
173 changed files with 16676 additions and 0 deletions
+98
View File
@@ -0,0 +1,98 @@
package asteriskws
import (
"encoding/json"
"strconv"
"strings"
"ai-operator/internal/media"
)
type ControlEventType string
const (
ControlMediaStart ControlEventType = "MEDIA_START"
ControlDTMFEnd ControlEventType = "DTMF_END"
ControlMediaXOFF ControlEventType = "MEDIA_XOFF"
ControlMediaXON ControlEventType = "MEDIA_XON"
ControlStatus ControlEventType = "STATUS"
ControlMediaBufferingCompleted ControlEventType = "MEDIA_BUFFERING_COMPLETED"
ControlMediaMarkProcessed ControlEventType = "MEDIA_MARK_PROCESSED"
ControlQueueDrained ControlEventType = "QUEUE_DRAINED"
ControlUnknown ControlEventType = "UNKNOWN"
)
type ControlEvent struct {
Type ControlEventType
Raw string
Fields map[string]string
}
func ParseControlEvent(text string) ControlEvent {
raw := strings.TrimSpace(text)
if raw == "" {
return ControlEvent{Type: ControlUnknown, Raw: text, Fields: map[string]string{}}
}
if strings.HasPrefix(raw, "{") {
return parseJSONControl(raw)
}
parts := strings.Fields(raw)
fields := map[string]string{}
for _, part := range parts[1:] {
if k, v, ok := strings.Cut(part, ":"); ok {
fields[k] = v
} else if fields["correlation_id"] == "" {
fields["correlation_id"] = part
}
}
return ControlEvent{Type: knownType(parts[0]), Raw: raw, Fields: fields}
}
func parseJSONControl(raw string) ControlEvent {
var data map[string]any
if err := json.Unmarshal([]byte(raw), &data); err != nil {
return ControlEvent{Type: ControlUnknown, Raw: raw, Fields: map[string]string{"error": "invalid_json"}}
}
typeName, _ := data["event"].(string)
if typeName == "" {
typeName, _ = data["type"].(string)
}
fields := map[string]string{}
for k, v := range data {
switch t := v.(type) {
case string:
fields[k] = t
case float64:
fields[k] = strconv.Itoa(int(t))
case bool:
fields[k] = strconv.FormatBool(t)
}
}
return ControlEvent{Type: knownType(typeName), Raw: raw, Fields: fields}
}
func knownType(v string) ControlEventType {
switch ControlEventType(v) {
case ControlMediaStart, ControlDTMFEnd, ControlMediaXOFF, ControlMediaXON, ControlStatus, ControlMediaBufferingCompleted, ControlMediaMarkProcessed, ControlQueueDrained:
return ControlEventType(v)
}
return ControlUnknown
}
func (e ControlEvent) MediaStart() *media.MediaStartInfo {
if e.Type != ControlMediaStart {
return nil
}
opt, _ := strconv.Atoi(value(e.Fields, "optimal_frame_size", "optimalFrameSize"))
ptime, _ := strconv.Atoi(value(e.Fields, "ptime", "ptime_ms"))
return &media.MediaStartInfo{ConnectionID: e.Fields["connection_id"], Channel: e.Fields["channel"], ChannelID: e.Fields["channel_id"], Format: e.Fields["format"], OptimalFrameSize: opt, PTimeMS: ptime}
}
func value(m map[string]string, keys ...string) string {
for _, k := range keys {
if m[k] != "" {
return m[k]
}
}
return ""
}