@@ -16,55 +16,69 @@ import (
16
16
)
17
17
18
18
func HandleSpeech (c echo.Context , options mo.Option [types.SpeechRequestOptions ]) mo.Result [any ] {
19
+ // Extract options safely once
20
+ opt := options .MustGet ()
21
+
19
22
values := types.OpenAISpeechRequestOptions {
20
- Model : options . MustGet () .Model ,
21
- Input : options . MustGet () .Input ,
22
- Voice : options . MustGet () .Voice ,
23
- ResponseFormat : options . MustGet () .ResponseFormat ,
24
- Speed : options . MustGet () .Speed ,
23
+ Model : opt .Model ,
24
+ Input : opt .Input ,
25
+ Voice : opt .Voice ,
26
+ ResponseFormat : opt .ResponseFormat ,
27
+ Speed : opt .Speed ,
25
28
}
26
29
27
30
payload := lo .Must (json .Marshal (values ))
28
31
29
32
req , err := http .NewRequestWithContext (
30
33
c .Request ().Context (),
31
34
http .MethodPost ,
32
- "https://openai.com/v1/audio/speech" ,
35
+ "https://api. openai.com/v1/audio/speech" ,
33
36
bytes .NewBuffer (payload ),
34
37
)
35
38
if err != nil {
36
39
return mo.Err [any ](apierrors .NewErrInternal ().WithCaller ())
37
40
}
38
41
39
- // Proxy the Authorization header
40
42
req .Header .Set ("Authorization" , c .Request ().Header .Get ("Authorization" ))
41
43
req .Header .Set ("Content-Type" , "application/json" )
42
44
43
45
res , err := http .DefaultClient .Do (req )
44
46
if err != nil {
45
- return mo.Err [any ](apierrors .NewErrBadGateway ().WithDetail (err .Error ()).WithError (err ).WithCaller ())
47
+ return mo.Err [any ](
48
+ apierrors .NewErrBadGateway ().
49
+ WithDetail (err .Error ()).
50
+ WithError (err ).
51
+ WithCaller (),
52
+ )
46
53
}
47
-
48
54
defer func () { _ = res .Body .Close () }()
49
55
50
- if res .StatusCode >= 400 && res .StatusCode < 600 {
56
+ if res .StatusCode >= 400 {
57
+ ct := res .Header .Get ("Content-Type" )
51
58
switch {
52
- case strings .HasPrefix (res .Header .Get ("Content-Type" ), "application/json" ):
53
- return mo.Err [any ](apierrors .
54
- NewUpstreamError (res .StatusCode ).
55
- WithDetail (utils .NewJSONResponseError (res .StatusCode , res .Body ).OrEmpty ().Error ()))
56
- case strings .HasPrefix (res .Header .Get ("Content-Type" ), "text/" ):
57
- return mo.Err [any ](apierrors .
58
- NewUpstreamError (res .StatusCode ).
59
- WithDetail (utils .NewTextResponseError (res .StatusCode , res .Body ).OrEmpty ().Error ()))
59
+ case strings .HasPrefix (ct , "application/json" ):
60
+ return mo.Err [any ](
61
+ apierrors .NewUpstreamError (res .StatusCode ).
62
+ WithDetail (utils .NewJSONResponseError (res .StatusCode , res .Body ).OrEmpty ().Error ()),
63
+ )
64
+ case strings .HasPrefix (ct , "text/" ):
65
+ return mo.Err [any ](
66
+ apierrors .NewUpstreamError (res .StatusCode ).
67
+ WithDetail (utils .NewTextResponseError (res .StatusCode , res .Body ).OrEmpty ().Error ()),
68
+ )
60
69
default :
61
- slog .Warn ("unknown upstream error with unknown Content-Type " ,
70
+ slog .Warn ("unknown upstream error" ,
62
71
slog .Int ("status" , res .StatusCode ),
63
- slog .String ("content_type" , res . Header . Get ( "Content-Type" ) ),
72
+ slog .String ("content_type" , ct ),
64
73
slog .String ("content_length" , res .Header .Get ("Content-Length" )),
65
74
)
75
+ return mo.Err [any ](
76
+ apierrors .NewUpstreamError (res .StatusCode ).
77
+ WithDetail ("unknown Content-Type: " + ct ),
78
+ )
66
79
}
67
80
}
68
81
69
- return mo.Ok [any ](c .Stream (http .StatusOK , "audio/mp3" , res .Body ))
82
+ // Stream audio response with correct upstream content type
83
+ return mo.Ok [any ](c .Stream (http .StatusOK , res .Header .Get ("Content-Type" ), res .Body ))
70
84
}
0 commit comments