refactor: 统一实时协议类型并扩展会话状态字段
This commit is contained in:
@@ -8,15 +8,22 @@ import "encoding/json"
|
|||||||
type MsgType string
|
type MsgType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MsgStart MsgType = "start" // Begin recording session
|
MsgHello MsgType = "hello"
|
||||||
MsgStop MsgType = "stop" // End recording session
|
MsgStart MsgType = "start"
|
||||||
MsgPaste MsgType = "paste" // Re-paste a history item
|
MsgStop MsgType = "stop"
|
||||||
|
MsgPaste MsgType = "paste"
|
||||||
|
MsgPing MsgType = "ping"
|
||||||
|
MsgPong MsgType = "pong"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClientMsg is a JSON control message from the phone.
|
// ClientMsg is a JSON control message from the phone.
|
||||||
type ClientMsg struct {
|
type ClientMsg struct {
|
||||||
Type MsgType `json:"type"`
|
Type MsgType `json:"type"`
|
||||||
|
SessionID string `json:"sessionId,omitempty"`
|
||||||
|
Seq int64 `json:"seq,omitempty"`
|
||||||
Text string `json:"text,omitempty"` // Only for "paste"
|
Text string `json:"text,omitempty"` // Only for "paste"
|
||||||
|
Version int `json:"version,omitempty"`
|
||||||
|
TS int64 `json:"ts,omitempty"`
|
||||||
// Future extension: dynamic hotwords (Phase 2)
|
// Future extension: dynamic hotwords (Phase 2)
|
||||||
// Hotwords []string `json:"hotwords,omitempty"`
|
// Hotwords []string `json:"hotwords,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -24,17 +31,33 @@ type ClientMsg struct {
|
|||||||
// ── Server → Client messages ──
|
// ── Server → Client messages ──
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MsgPartial MsgType = "partial" // Interim ASR result
|
MsgReady MsgType = "ready"
|
||||||
MsgFinal MsgType = "final" // Final ASR result
|
MsgState MsgType = "state"
|
||||||
MsgPasted MsgType = "pasted" // Paste confirmed
|
MsgStartAck MsgType = "start_ack"
|
||||||
MsgError MsgType = "error" // Error notification
|
MsgStopAck MsgType = "stop_ack"
|
||||||
|
MsgPartial MsgType = "partial"
|
||||||
|
MsgFinal MsgType = "final"
|
||||||
|
MsgPasted MsgType = "pasted"
|
||||||
|
MsgError MsgType = "error"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
StateIdle = "idle"
|
||||||
|
StateRecording = "recording"
|
||||||
|
StateStopping = "stopping"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServerMsg is a JSON message sent to the phone.
|
// ServerMsg is a JSON message sent to the phone.
|
||||||
type ServerMsg struct {
|
type ServerMsg struct {
|
||||||
Type MsgType `json:"type"`
|
Type MsgType `json:"type"`
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
SessionID string `json:"sessionId,omitempty"`
|
||||||
|
Seq int64 `json:"seq,omitempty"`
|
||||||
Text string `json:"text,omitempty"`
|
Text string `json:"text,omitempty"`
|
||||||
Message string `json:"message,omitempty"` // For errors
|
Message string `json:"message,omitempty"` // For errors
|
||||||
|
Code string `json:"code,omitempty"`
|
||||||
|
Retryable bool `json:"retryable,omitempty"`
|
||||||
|
TS int64 `json:"ts,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m ServerMsg) Bytes() []byte {
|
func (m ServerMsg) Bytes() []byte {
|
||||||
|
|||||||
35
web/src/protocol.ts
Normal file
35
web/src/protocol.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
export type ClientMsgType = "hello" | "start" | "stop" | "paste" | "ping";
|
||||||
|
|
||||||
|
export type ServerMsgType =
|
||||||
|
| "ready"
|
||||||
|
| "state"
|
||||||
|
| "start_ack"
|
||||||
|
| "stop_ack"
|
||||||
|
| "partial"
|
||||||
|
| "final"
|
||||||
|
| "pasted"
|
||||||
|
| "error"
|
||||||
|
| "pong";
|
||||||
|
|
||||||
|
export type SessionState = "idle" | "recording" | "stopping";
|
||||||
|
|
||||||
|
export interface ClientMsg {
|
||||||
|
type: ClientMsgType;
|
||||||
|
sessionId?: string;
|
||||||
|
seq?: number;
|
||||||
|
text?: string;
|
||||||
|
version?: number;
|
||||||
|
ts?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerMsg {
|
||||||
|
type: ServerMsgType;
|
||||||
|
state?: SessionState;
|
||||||
|
sessionId?: string;
|
||||||
|
seq?: number;
|
||||||
|
text?: string;
|
||||||
|
message?: string;
|
||||||
|
code?: string;
|
||||||
|
retryable?: boolean;
|
||||||
|
ts?: number;
|
||||||
|
}
|
||||||
@@ -13,9 +13,13 @@ type ConnectionStatus = "connected" | "disconnected" | "connecting";
|
|||||||
interface AppState {
|
interface AppState {
|
||||||
// Connection
|
// Connection
|
||||||
connectionStatus: ConnectionStatus;
|
connectionStatus: ConnectionStatus;
|
||||||
|
weakNetwork: boolean;
|
||||||
// Recording
|
// Recording
|
||||||
recording: boolean;
|
recording: boolean;
|
||||||
pendingStart: boolean;
|
pendingStart: boolean;
|
||||||
|
stopping: boolean;
|
||||||
|
micReady: boolean;
|
||||||
|
activeSessionId: string | null;
|
||||||
// Preview
|
// Preview
|
||||||
previewText: string;
|
previewText: string;
|
||||||
previewActive: boolean;
|
previewActive: boolean;
|
||||||
@@ -24,8 +28,12 @@ interface AppState {
|
|||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
setConnectionStatus: (status: ConnectionStatus) => void;
|
setConnectionStatus: (status: ConnectionStatus) => void;
|
||||||
|
setWeakNetwork: (weak: boolean) => void;
|
||||||
setRecording: (recording: boolean) => void;
|
setRecording: (recording: boolean) => void;
|
||||||
setPendingStart: (pending: boolean) => void;
|
setPendingStart: (pending: boolean) => void;
|
||||||
|
setStopping: (stopping: boolean) => void;
|
||||||
|
setMicReady: (ready: boolean) => void;
|
||||||
|
setActiveSessionId: (sessionId: string | null) => void;
|
||||||
setPreview: (text: string, isFinal: boolean) => void;
|
setPreview: (text: string, isFinal: boolean) => void;
|
||||||
clearPreview: () => void;
|
clearPreview: () => void;
|
||||||
addHistory: (text: string) => void;
|
addHistory: (text: string) => void;
|
||||||
@@ -36,15 +44,23 @@ export const useAppStore = create<AppState>()(
|
|||||||
persist(
|
persist(
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
connectionStatus: "connecting",
|
connectionStatus: "connecting",
|
||||||
|
weakNetwork: false,
|
||||||
recording: false,
|
recording: false,
|
||||||
pendingStart: false,
|
pendingStart: false,
|
||||||
|
stopping: false,
|
||||||
|
micReady: false,
|
||||||
|
activeSessionId: null,
|
||||||
previewText: "",
|
previewText: "",
|
||||||
previewActive: false,
|
previewActive: false,
|
||||||
history: [],
|
history: [],
|
||||||
|
|
||||||
setConnectionStatus: (connectionStatus) => set({ connectionStatus }),
|
setConnectionStatus: (connectionStatus) => set({ connectionStatus }),
|
||||||
|
setWeakNetwork: (weakNetwork) => set({ weakNetwork }),
|
||||||
setRecording: (recording) => set({ recording }),
|
setRecording: (recording) => set({ recording }),
|
||||||
setPendingStart: (pendingStart) => set({ pendingStart }),
|
setPendingStart: (pendingStart) => set({ pendingStart }),
|
||||||
|
setStopping: (stopping) => set({ stopping }),
|
||||||
|
setMicReady: (micReady) => set({ micReady }),
|
||||||
|
setActiveSessionId: (activeSessionId) => set({ activeSessionId }),
|
||||||
|
|
||||||
setPreview: (text, isFinal) =>
|
setPreview: (text, isFinal) =>
|
||||||
set({
|
set({
|
||||||
|
|||||||
Reference in New Issue
Block a user