Skip to content

Commit ccda6be

Browse files
authored
Merge pull request #48 from second-state/feat/cc_backend
Feat/cc backend
2 parents fe01bbd + 528af77 commit ccda6be

11 files changed

Lines changed: 1194 additions & 33 deletions

File tree

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ lip_sync = { version = "0.1", git = "https://github.com/L-jasmine/lip_sync.git"
3333
rand = "0.9.0"
3434
uuid = { version = "1.14", features = [
3535
"v4", # Lets you generate random UUIDs
36+
"v5", # Lets you generate namespace-based UUIDs
3637
"fast-rng",
3738
] }
38-
bytes = "1.10.0"
39+
bytes = "1.11.0"
3940
aho-corasick = "1.1.3"
4041
lazy-regex = "3.4.2"
4142

src/config.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,12 @@ pub struct RecordConfig {
353353
pub callback_url: Option<String>,
354354
}
355355

356+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
357+
pub struct EchokitCC {
358+
pub url: String,
359+
// pub output_optimization: TTSTextOptimizationConfig,
360+
}
361+
356362
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
357363
#[serde(untagged)]
358364
pub enum AIConfig {
@@ -361,6 +367,11 @@ pub enum AIConfig {
361367
tts: TTSConfig,
362368
asr: ASRConfig,
363369
},
370+
Claude {
371+
claude: EchokitCC,
372+
asr: ASRConfig,
373+
tts: TTSConfig,
374+
},
364375
GeminiAndTTS {
365376
gemini: GeminiConfig,
366377
tts: TTSConfig,

src/main.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::sync::Arc;
1+
use std::sync::{Arc, RwLock};
22

33
use axum::{
44
Router,
@@ -163,6 +163,27 @@ async fn routes(
163163
}
164164
});
165165
}
166+
config::AIConfig::Claude { claude, asr, tts } => {
167+
let session = Arc::new(RwLock::new(Default::default()));
168+
let session_ = session.clone();
169+
170+
tokio::spawn(async move {
171+
if let Err(e) = crate::services::ws::stable::claude::run_session_manager(
172+
&tts, &asr, &claude, rx, session,
173+
)
174+
.await
175+
{
176+
log::error!("Claude session manager exited with error: {}", e);
177+
}
178+
});
179+
180+
router = router
181+
.route(
182+
"/proxy/state/{id}",
183+
get(services::ws::stable::claude::has_notification),
184+
)
185+
.layer(axum::Extension(session_));
186+
}
166187
}
167188

168189
router = router

src/protocol.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ pub enum ServerEvent {
99

1010
ASR { text: String },
1111
Action { action: String },
12+
Choices { message: String, items: Vec<String> },
1213
StartAudio { text: String },
1314
AudioChunk { data: Vec<u8> },
15+
DisplayText { text: String },
1416
AudioChunkWithVowel { data: Vec<u8>, vowel: u8 },
1517
EndAudio,
1618
StartVideo,
@@ -47,6 +49,7 @@ pub enum ClientCommand {
4749
StartChat,
4850
Submit,
4951
Text { input: String },
52+
Select { index: usize },
5053
}
5154

5255
#[test]

src/services/ws.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ pub enum WsCommand {
2525
Video(Vec<Vec<u8>>),
2626
EndResponse,
2727
EndVad,
28+
Choices(String, Vec<String>),
29+
DisplayText(String),
30+
Close,
2831
}
2932
type WsTx = tokio::sync::mpsc::UnboundedSender<WsCommand>;
3033
type WsRx = tokio::sync::mpsc::UnboundedReceiver<WsCommand>;
@@ -113,6 +116,7 @@ pub enum ClientMsg {
113116
AudioChunk(Bytes),
114117
Submit,
115118
Text(String),
119+
Select(usize),
116120
}
117121

118122
pub struct ConnectConfig {
@@ -151,6 +155,11 @@ async fn process_socket_io(
151155

152156
match r {
153157
Some(WsEvent::Command(cmd)) => {
158+
if matches!(cmd, WsCommand::Close) {
159+
log::info!("Received Close command, closing websocket");
160+
return Ok(());
161+
}
162+
154163
if config.enable_opus {
155164
process_command_with_opus(
156165
socket,
@@ -184,6 +193,12 @@ async fn process_socket_io(
184193
.send(ClientMsg::Text(input))
185194
.await
186195
.map_err(|_| anyhow::anyhow!("audio_tx closed"))?,
196+
ProcessMessageResult::Select(index) => {
197+
audio_tx
198+
.send(ClientMsg::Select(index))
199+
.await
200+
.map_err(|_| anyhow::anyhow!("audio_tx closed"))?;
201+
}
187202
ProcessMessageResult::Skip => {}
188203
ProcessMessageResult::StartChat => {
189204
audio_tx
@@ -285,6 +300,18 @@ async fn process_command(ws: &mut WebSocket, cmd: WsCommand) -> anyhow::Result<(
285300
ws.send(Message::binary(audio_chunk)).await?;
286301
}
287302
}
303+
WsCommand::Choices(message, items) => {
304+
let choices =
305+
rmp_serde::to_vec(&crate::protocol::ServerEvent::Choices { message, items })
306+
.expect("Failed to serialize Choices ServerEvent");
307+
ws.send(Message::binary(choices)).await?;
308+
}
309+
WsCommand::DisplayText(text) => {
310+
let display_text =
311+
rmp_serde::to_vec(&crate::protocol::ServerEvent::DisplayText { text })
312+
.expect("Failed to serialize DisplayText ServerEvent");
313+
ws.send(Message::binary(display_text)).await?;
314+
}
288315
WsCommand::EndAudio => {
289316
log::trace!("EndAudio");
290317
let end_audio = rmp_serde::to_vec(&crate::protocol::ServerEvent::EndAudio)
@@ -306,6 +333,7 @@ async fn process_command(ws: &mut WebSocket, cmd: WsCommand) -> anyhow::Result<(
306333
.expect("Failed to serialize EndVad ServerEvent");
307334
ws.send(Message::binary(end_vad)).await?;
308335
}
336+
WsCommand::Close => {}
309337
}
310338
Ok(())
311339
}
@@ -341,12 +369,23 @@ async fn process_command_with_opus(
341369
.expect("Failed to serialize ASR ServerEvent");
342370
ws.send(Message::binary(asr)).await?;
343371
}
344-
345372
WsCommand::Action { action } => {
346373
let action = rmp_serde::to_vec(&crate::protocol::ServerEvent::Action { action })
347374
.expect("Failed to serialize Action ServerEvent");
348375
ws.send(Message::binary(action)).await?;
349376
}
377+
WsCommand::Choices(message, items) => {
378+
let choices =
379+
rmp_serde::to_vec(&crate::protocol::ServerEvent::Choices { message, items })
380+
.expect("Failed to serialize Choices ServerEvent");
381+
ws.send(Message::binary(choices)).await?;
382+
}
383+
WsCommand::DisplayText(text) => {
384+
let display_text =
385+
rmp_serde::to_vec(&crate::protocol::ServerEvent::DisplayText { text })
386+
.expect("Failed to serialize DisplayText ServerEvent");
387+
ws.send(Message::binary(display_text)).await?;
388+
}
350389
WsCommand::StartAudio(text) => {
351390
log::trace!("StartAudio: {text:?}");
352391
opus_encode
@@ -453,6 +492,7 @@ async fn process_command_with_opus(
453492
.expect("Failed to serialize EndVad ServerEvent");
454493
ws.send(Message::binary(end_vad)).await?;
455494
}
495+
WsCommand::Close => {}
456496
}
457497
Ok(())
458498
}
@@ -461,6 +501,7 @@ enum ProcessMessageResult {
461501
Audio(Bytes),
462502
Submit,
463503
Text(String),
504+
Select(usize),
464505
StartChat,
465506
Close,
466507
Skip,
@@ -478,13 +519,16 @@ fn process_message(msg: Message) -> ProcessMessageResult {
478519
crate::protocol::ClientCommand::Text { input } => {
479520
ProcessMessageResult::Text(input)
480521
}
522+
crate::protocol::ClientCommand::Select { index } => {
523+
ProcessMessageResult::Select(index)
524+
}
481525
}
482526
} else {
483527
ProcessMessageResult::Skip
484528
}
485529
}
486530
Message::Binary(d) => {
487-
log::debug!("Received binary message of size: {}", d.len());
531+
log::trace!("Received binary message of size: {}", d.len());
488532
ProcessMessageResult::Audio(d)
489533
}
490534
Message::Close(c) => {

src/services/ws/stable/asr.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ impl WhisperASRSession {
9898
vad_started |= self.vad_session.detect(&audio_chunk)?;
9999
}
100100
}
101+
ClientMsg::Select(..) => {}
101102
}
102103
}
103104
}
@@ -205,6 +206,7 @@ impl WhisperASRSession {
205206
log::warn!("`{id}` received a Unexpected Submit during Stream ASR");
206207
return Err(anyhow::anyhow!("Unexpected Submit during Stream ASR"));
207208
}
209+
ClientMsg::Select(..) => {}
208210
}
209211
}
210212

@@ -384,6 +386,7 @@ impl ParaformerASRSession {
384386

385387
continue;
386388
}
389+
ClientMsg::Select(..) => {}
387390
}
388391
}
389392

@@ -518,6 +521,7 @@ impl ParaformerASRSession {
518521
}
519522
start_submit = true;
520523
}
524+
ClientMsg::Select(..) => {}
521525
}
522526
} else {
523527
log::warn!("`{}` client rx channel closed unexpectedly", session.id);

0 commit comments

Comments
 (0)