gproxy_protocol/protocol/
endpoint.rs1use crate::protocol::operation::{
6 ContentGenerationKind, HttpMethod, Operation, OperationKey, OperationKind, Provider,
7};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct RequestTarget {
12 pub method: HttpMethod,
13 pub path: String,
14 pub query: Option<String>,
16}
17
18impl RequestTarget {
19 fn get(path: impl Into<String>) -> Self {
20 Self {
21 method: HttpMethod::Get,
22 path: path.into(),
23 query: None,
24 }
25 }
26
27 fn post(path: impl Into<String>) -> Self {
28 Self {
29 method: HttpMethod::Post,
30 path: path.into(),
31 query: None,
32 }
33 }
34}
35
36pub fn request_target(target: OperationKey, model: &str, stream: bool) -> RequestTarget {
40 use Provider as P;
41 let provider = match target.kind {
42 OperationKind::ContentGeneration(kind) => return content_target(kind, model, stream),
43 OperationKind::Provider(provider) => provider,
44 };
45 match (target.operation, provider) {
46 (Operation::ListModels, P::OpenAi | P::Claude) => RequestTarget::get("/v1/models"),
47 (Operation::ListModels, P::Gemini) => RequestTarget::get("/v1beta/models"),
48 (Operation::GetModel, P::OpenAi | P::Claude) => {
49 RequestTarget::get(format!("/v1/models/{model}"))
50 }
51 (Operation::GetModel, P::Gemini) => RequestTarget::get(format!("/v1beta/models/{model}")),
52 (Operation::CountTokens, P::OpenAi) => RequestTarget::post("/v1/responses/input_tokens"),
53 (Operation::CountTokens, P::Claude) => RequestTarget::post("/v1/messages/count_tokens"),
54 (Operation::CountTokens, P::Gemini) => {
55 RequestTarget::post(format!("/v1beta/models/{model}:countTokens"))
56 }
57 (Operation::CreateEmbedding, P::OpenAi | P::Claude) => {
60 RequestTarget::post("/v1/embeddings")
61 }
62 (Operation::CreateEmbedding, P::Gemini) => {
64 RequestTarget::post(format!("/v1beta/models/{model}:embedContent"))
65 }
66 (Operation::CreateImage, _) => RequestTarget::post("/v1/images/generations"),
70 (Operation::EditImage, _) => RequestTarget::post("/v1/images/edits"),
71 (Operation::CompactContent, _) => RequestTarget::post("/v1/responses/compact"),
72 (Operation::CreateConversation, _) => RequestTarget::post("/v1/conversations"),
73 (Operation::ConnectRealtime, _) => RequestTarget {
74 method: HttpMethod::Get,
75 path: "/v1/realtime".to_owned(),
76 query: Some(format!("model={model}")),
77 },
78 (Operation::GenerateContent | Operation::StreamGenerateContent, p) => {
81 let kind = match p {
82 P::OpenAi => ContentGenerationKind::OpenAiResponses,
83 P::Claude => ContentGenerationKind::ClaudeMessages,
84 P::Gemini => ContentGenerationKind::GeminiGenerateContent,
85 };
86 content_target(kind, model, stream)
87 }
88 }
89}
90
91fn content_target(kind: ContentGenerationKind, model: &str, stream: bool) -> RequestTarget {
93 use ContentGenerationKind as K;
94 match kind {
95 K::OpenAiChatCompletions => RequestTarget::post("/v1/chat/completions"),
96 K::OpenAiResponses => RequestTarget::post("/v1/responses"),
97 K::OpenAiResponsesWebSocket => RequestTarget::get("/v1/responses"),
98 K::ClaudeMessages => RequestTarget::post("/v1/messages"),
99 K::GeminiGenerateContent => {
100 let verb = if stream {
101 "streamGenerateContent"
102 } else {
103 "generateContent"
104 };
105 RequestTarget {
106 method: HttpMethod::Post,
107 path: format!("/v1beta/models/{model}:{verb}"),
108 query: stream.then(|| "alt=sse".to_owned()),
109 }
110 }
111 }
112}