@@ -10,10 +10,12 @@ use std::{
1010
1111use anyhow:: { Context , Result , bail} ;
1212use chrono:: Utc ;
13+ use clap:: builder:: { PossibleValuesParser , TypedValueParser } ;
14+ use clap:: { Parser , ValueEnum } ;
1315use context_switch:: { InputModality , OutputModality } ;
1416use cpal:: traits:: { DeviceTrait , HostTrait , StreamTrait } ;
1517use openai_api_rs:: realtime:: types;
16- use openai_dialog:: { OpenAIDialog , ServiceInputEvent , ServiceOutputEvent } ;
18+ use openai_dialog:: { OpenAIDialog , Protocol , ServiceInputEvent , ServiceOutputEvent } ;
1719use rodio:: { DeviceSinkBuilder , Player , Source } ;
1820use serde_json:: json;
1921use tokio:: {
@@ -27,8 +29,48 @@ use context_switch_core::{
2729 conversation:: { Conversation , Input , Output } ,
2830} ;
2931
32+ #[ derive( Debug , Parser ) ]
33+ struct Cli {
34+ #[ arg( long, value_enum) ]
35+ protocol : Option < CliProtocol > ,
36+ #[ arg( long) ]
37+ endpoint : Option < String > ,
38+ #[ arg( long, value_parser = realtime_voice_value_parser( ) ) ]
39+ voice : Option < types:: RealtimeVoice > ,
40+ }
41+
42+ #[ derive( Debug , Clone , Copy , ValueEnum ) ]
43+ enum CliProtocol {
44+ #[ value( name = "openai" ) ]
45+ OpenAI ,
46+ Azure ,
47+ }
48+
49+ fn realtime_voice_value_parser ( ) -> impl TypedValueParser < Value = types:: RealtimeVoice > {
50+ PossibleValuesParser :: new ( <types:: RealtimeVoice as strum:: VariantNames >:: VARIANTS ) . try_map (
51+ |value| {
52+ parse_realtime_voice_value ( & value)
53+ . map_err ( |e| format ! ( "Invalid voice value `{value}`: {e}" ) )
54+ } ,
55+ )
56+ }
57+
58+ fn parse_realtime_voice_value ( value : & str ) -> Result < types:: RealtimeVoice , strum:: ParseError > {
59+ types:: RealtimeVoice :: from_str ( value)
60+ }
61+
62+ impl From < CliProtocol > for Protocol {
63+ fn from ( value : CliProtocol ) -> Self {
64+ match value {
65+ CliProtocol :: OpenAI => Protocol :: OpenAI ,
66+ CliProtocol :: Azure => Protocol :: Azure ,
67+ }
68+ }
69+ }
70+
3071#[ tokio:: main]
3172async fn main ( ) -> Result < ( ) > {
73+ let cli = Cli :: parse ( ) ;
3274 dotenvy:: dotenv_override ( ) . context ( "Reading .env file" ) ?;
3375 tracing_subscriber:: fmt:: init ( ) ;
3476
@@ -76,6 +118,12 @@ async fn main() -> Result<()> {
76118
77119 let openai = OpenAIDialog ;
78120 let mut params = openai_dialog:: Params :: new ( key, model) ;
121+ params. host = cli
122+ . endpoint
123+ . or_else ( || env:: var ( "OPENAI_REALTIME_ENDPOINT" ) . ok ( ) )
124+ . filter ( |endpoint| !endpoint. trim ( ) . is_empty ( ) ) ;
125+ params. protocol = cli. protocol . map ( Into :: into) ;
126+ params. voice = cli. voice ;
79127 params. tools . push ( get_time_function_definition ( ) ) ;
80128
81129 let ( output_sender, output_receiver) = unbounded_channel ( ) ;
0 commit comments