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::GenerateContent | Operation::StreamGenerateContent, p) => {
76 let kind = match p {
77 P::OpenAi => ContentGenerationKind::OpenAiResponses,
78 P::Claude => ContentGenerationKind::ClaudeMessages,
79 P::Gemini => ContentGenerationKind::GeminiGenerateContent,
80 };
81 content_target(kind, model, stream)
82 }
83 }
84}
85
86fn content_target(kind: ContentGenerationKind, model: &str, stream: bool) -> RequestTarget {
88 use ContentGenerationKind as K;
89 match kind {
90 K::OpenAiChatCompletions => RequestTarget::post("/v1/chat/completions"),
91 K::OpenAiResponses => RequestTarget::post("/v1/responses"),
92 K::OpenAiResponsesWebSocket => RequestTarget::get("/v1/responses"),
93 K::ClaudeMessages => RequestTarget::post("/v1/messages"),
94 K::GeminiGenerateContent => {
95 let verb = if stream {
96 "streamGenerateContent"
97 } else {
98 "generateContent"
99 };
100 RequestTarget {
101 method: HttpMethod::Post,
102 path: format!("/v1beta/models/{model}:{verb}"),
103 query: stream.then(|| "alt=sse".to_owned()),
104 }
105 }
106 }
107}