修复一些问题,作为v0.1.3-rc.4的补充

This commit is contained in:
wisdgod
2025-01-27 17:39:31 +08:00
parent c58f2697f0
commit 00a6980da9
8 changed files with 162 additions and 141 deletions

View File

@@ -34,6 +34,7 @@ reqwest = { version = "0.12.12", default-features = false, features = ["gzip", "
rkyv = { version = "0.7.45", default-features = false, features = ["alloc", "std", "bytecheck", "size_64", "validation", "std"] }
serde = { version = "1.0.217", default-features = false, features = ["std", "derive"] }
serde_json = { package = "sonic-rs", version = "0.3.17" }
# serde_json = "1.0.137"
sha2 = { version = "0.10.8", default-features = false }
sysinfo = { version = "0.33.1", default-features = false, features = ["system"] }
tokio = { version = "1.43.0", features = ["rt-multi-thread", "macros", "net", "sync", "time", "fs", "signal"] }

View File

@@ -6,7 +6,7 @@ RUN apt-get update && \
build-essential protobuf-compiler pkg-config libssl-dev nodejs npm \
&& rm -rf /var/lib/apt/lists/*
COPY . .
ENV RUSTFLAGS="-C link-arg=-s -C target-cpu=native"
ENV RUSTFLAGS="-C link-arg=-s -C target-cpu=x86-64-v3"
RUN cargo build --release && \
cp target/release/cursor-api /app/cursor-api
@@ -18,7 +18,7 @@ RUN apt-get update && \
build-essential protobuf-compiler pkg-config libssl-dev nodejs npm \
&& rm -rf /var/lib/apt/lists/*
COPY . .
ENV RUSTFLAGS="-C link-arg=-s -C target-cpu=native"
ENV RUSTFLAGS="-C link-arg=-s -C target-cpu=apple-m1"
RUN cargo build --release && \
cp target/release/cursor-api /app/cursor-api

View File

@@ -1,9 +1,7 @@
# Dockerfile.cross
# 使用与你 GitHub Actions 中相同的基础镜像
FROM rust:1.84.0-slim-bookworm
FROM --platform=linux/amd64 rust:1.84.0-slim-bookworm
# 设置工作目录
WORKDIR /app
# 安装必要的软件包

View File

@@ -48,32 +48,32 @@ def_pub_const!(GEMINI_2_0_FLASH_EXP, "gemini-2.0-flash-exp");
def_pub_const!(DEEPSEEK_V3, "deepseek-v3");
def_pub_const!(DEEPSEEK_R1, "deepseek-r1");
#[derive(Clone, PartialEq, rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)]
pub enum ModelType {
Claude35Sonnet,
Gpt4,
Gpt4o,
Claude3Opus,
CursorFast,
CursorSmall,
Gpt35Turbo,
Gpt4Turbo202404,
Gpt4o128k,
Gemini15Flash500k,
Claude3Haiku200k,
Claude35Sonnet200k,
Claude35Sonnet20241022,
Gpt4oMini,
O1Mini,
O1Preview,
O1,
Claude35Haiku,
GeminiExp1206,
Gemini20FlashThinkingExp,
Gemini20FlashExp,
DeepseekV3,
DeepseekR1,
}
// #[derive(Clone, PartialEq, rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)]
// pub enum ModelType {
// Claude35Sonnet,
// Gpt4,
// Gpt4o,
// Claude3Opus,
// CursorFast,
// CursorSmall,
// Gpt35Turbo,
// Gpt4Turbo202404,
// Gpt4o128k,
// Gemini15Flash500k,
// Claude3Haiku200k,
// Claude35Sonnet200k,
// Claude35Sonnet20241022,
// Gpt4oMini,
// O1Mini,
// O1Preview,
// O1,
// Claude35Haiku,
// GeminiExp1206,
// Gemini20FlashThinkingExp,
// Gemini20FlashExp,
// DeepseekV3,
// DeepseekR1,
// }
macro_rules! create_model {
($($id:expr, $owner:expr),* $(,)?) => {
@@ -95,64 +95,64 @@ macro_rules! count {
(($id:expr, $owner:expr) $( ($id2:expr, $owner2:expr) )*) => (1 + count!($( ($id2, $owner2) )*));
}
impl ModelType {
pub fn as_str_name(&self) -> &'static str {
match self {
ModelType::Claude35Sonnet => CLAUDE_3_5_SONNET,
ModelType::Gpt4 => GPT_4,
ModelType::Gpt4o => GPT_4O,
ModelType::Claude3Opus => CLAUDE_3_OPUS,
ModelType::CursorFast => CURSOR_FAST,
ModelType::CursorSmall => CURSOR_SMALL,
ModelType::Gpt35Turbo => GPT_3_5_TURBO,
ModelType::Gpt4Turbo202404 => GPT_4_TURBO_2024_04_09,
ModelType::Gpt4o128k => GPT_4O_128K,
ModelType::Gemini15Flash500k => GEMINI_1_5_FLASH_500K,
ModelType::Claude3Haiku200k => CLAUDE_3_HAIKU_200K,
ModelType::Claude35Sonnet200k => CLAUDE_3_5_SONNET_200K,
ModelType::Claude35Sonnet20241022 => CLAUDE_3_5_SONNET_20241022,
ModelType::Gpt4oMini => GPT_4O_MINI,
ModelType::O1Mini => O1_MINI,
ModelType::O1Preview => O1_PREVIEW,
ModelType::O1 => O1,
ModelType::Claude35Haiku => CLAUDE_3_5_HAIKU,
ModelType::GeminiExp1206 => GEMINI_EXP_1206,
ModelType::Gemini20FlashThinkingExp => GEMINI_2_0_FLASH_THINKING_EXP,
ModelType::Gemini20FlashExp => GEMINI_2_0_FLASH_EXP,
ModelType::DeepseekV3 => DEEPSEEK_V3,
ModelType::DeepseekR1 => DEEPSEEK_R1,
}
}
// impl ModelType {
// pub fn as_str_name(&self) -> &'static str {
// match self {
// ModelType::Claude35Sonnet => CLAUDE_3_5_SONNET,
// ModelType::Gpt4 => GPT_4,
// ModelType::Gpt4o => GPT_4O,
// ModelType::Claude3Opus => CLAUDE_3_OPUS,
// ModelType::CursorFast => CURSOR_FAST,
// ModelType::CursorSmall => CURSOR_SMALL,
// ModelType::Gpt35Turbo => GPT_3_5_TURBO,
// ModelType::Gpt4Turbo202404 => GPT_4_TURBO_2024_04_09,
// ModelType::Gpt4o128k => GPT_4O_128K,
// ModelType::Gemini15Flash500k => GEMINI_1_5_FLASH_500K,
// ModelType::Claude3Haiku200k => CLAUDE_3_HAIKU_200K,
// ModelType::Claude35Sonnet200k => CLAUDE_3_5_SONNET_200K,
// ModelType::Claude35Sonnet20241022 => CLAUDE_3_5_SONNET_20241022,
// ModelType::Gpt4oMini => GPT_4O_MINI,
// ModelType::O1Mini => O1_MINI,
// ModelType::O1Preview => O1_PREVIEW,
// ModelType::O1 => O1,
// ModelType::Claude35Haiku => CLAUDE_3_5_HAIKU,
// ModelType::GeminiExp1206 => GEMINI_EXP_1206,
// ModelType::Gemini20FlashThinkingExp => GEMINI_2_0_FLASH_THINKING_EXP,
// ModelType::Gemini20FlashExp => GEMINI_2_0_FLASH_EXP,
// ModelType::DeepseekV3 => DEEPSEEK_V3,
// ModelType::DeepseekR1 => DEEPSEEK_R1,
// }
// }
pub fn from_str_name(id :&str) -> Option<ModelType> {
match id {
CLAUDE_3_5_SONNET => Some(ModelType::Claude35Sonnet),
GPT_4 => Some(ModelType::Gpt4),
GPT_4O => Some(ModelType::Gpt4o),
CLAUDE_3_OPUS => Some(ModelType::Claude3Opus),
CURSOR_FAST => Some(ModelType::CursorFast),
CURSOR_SMALL => Some(ModelType::CursorSmall),
GPT_3_5_TURBO => Some(ModelType::Gpt35Turbo),
GPT_4_TURBO_2024_04_09 => Some(ModelType::Gpt4Turbo202404),
GPT_4O_128K => Some(ModelType::Gpt4o128k),
GEMINI_1_5_FLASH_500K => Some(ModelType::Gemini15Flash500k),
CLAUDE_3_HAIKU_200K => Some(ModelType::Claude3Haiku200k),
CLAUDE_3_5_SONNET_200K => Some(ModelType::Claude35Sonnet200k),
CLAUDE_3_5_SONNET_20241022 => Some(ModelType::Claude35Sonnet20241022),
GPT_4O_MINI => Some(ModelType::Gpt4oMini),
O1_MINI => Some(ModelType::O1Mini),
O1_PREVIEW => Some(ModelType::O1Preview),
O1 => Some(ModelType::O1),
CLAUDE_3_5_HAIKU => Some(ModelType::Claude35Haiku),
GEMINI_EXP_1206 => Some(ModelType::GeminiExp1206),
GEMINI_2_0_FLASH_THINKING_EXP => Some(ModelType::Gemini20FlashThinkingExp),
GEMINI_2_0_FLASH_EXP => Some(ModelType::Gemini20FlashExp),
DEEPSEEK_V3 => Some(ModelType::DeepseekV3),
DEEPSEEK_R1 => Some(ModelType::DeepseekR1),
_ => None,
}
}
}
// pub fn from_str_name(id :&str) -> Option<ModelType> {
// match id {
// CLAUDE_3_5_SONNET => Some(ModelType::Claude35Sonnet),
// GPT_4 => Some(ModelType::Gpt4),
// GPT_4O => Some(ModelType::Gpt4o),
// CLAUDE_3_OPUS => Some(ModelType::Claude3Opus),
// CURSOR_FAST => Some(ModelType::CursorFast),
// CURSOR_SMALL => Some(ModelType::CursorSmall),
// GPT_3_5_TURBO => Some(ModelType::Gpt35Turbo),
// GPT_4_TURBO_2024_04_09 => Some(ModelType::Gpt4Turbo202404),
// GPT_4O_128K => Some(ModelType::Gpt4o128k),
// GEMINI_1_5_FLASH_500K => Some(ModelType::Gemini15Flash500k),
// CLAUDE_3_HAIKU_200K => Some(ModelType::Claude3Haiku200k),
// CLAUDE_3_5_SONNET_200K => Some(ModelType::Claude35Sonnet200k),
// CLAUDE_3_5_SONNET_20241022 => Some(ModelType::Claude35Sonnet20241022),
// GPT_4O_MINI => Some(ModelType::Gpt4oMini),
// O1_MINI => Some(ModelType::O1Mini),
// O1_PREVIEW => Some(ModelType::O1Preview),
// O1 => Some(ModelType::O1),
// CLAUDE_3_5_HAIKU => Some(ModelType::Claude35Haiku),
// GEMINI_EXP_1206 => Some(ModelType::GeminiExp1206),
// GEMINI_2_0_FLASH_THINKING_EXP => Some(ModelType::Gemini20FlashThinkingExp),
// GEMINI_2_0_FLASH_EXP => Some(ModelType::Gemini20FlashExp),
// DEEPSEEK_V3 => Some(ModelType::DeepseekV3),
// DEEPSEEK_R1 => Some(ModelType::DeepseekR1),
// _ => None,
// }
// }
// }
create_model!(
CLAUDE_3_5_SONNET, ANTHROPIC,

View File

@@ -491,8 +491,13 @@ pub async fn handle_chat(
}
StreamMessage::Debug(debug_prompt) => {
if let Ok(mut state) = ctx.state.try_lock() {
if let Some(last_log) = state.request_logs.last_mut() {
last_log.prompt = Some(debug_prompt);
if let Some(log) = state
.request_logs
.iter_mut()
.rev()
.find(|log| log.id == ctx.current_id)
{
log.prompt = Some(debug_prompt);
}
}
}
@@ -507,7 +512,7 @@ pub async fn handle_chat(
let mut stream = response.bytes_stream();
// 处理第一个chunk并获取first_result
while decoder.lock().await.has_no_first_result() {
while !decoder.lock().await.is_first_result_ready() {
match stream.next().await {
Some(first_chunk) => {
let chunk = first_chunk.map_err(|e| {
@@ -642,9 +647,8 @@ pub async fn handle_chat(
let mut decoder = StreamDecoder::new();
let mut full_text = String::with_capacity(1024);
let mut stream = response.bytes_stream();
let mut all_chunks = Vec::new();
// 收集所有的chunks
// 逐个处理chunks
while let Some(chunk) = stream.next().await {
let chunk = chunk.map_err(|e| {
let error_message = format!("Failed to read response chunk: {}", e);
@@ -653,12 +657,34 @@ pub async fn handle_chat(
Json(ChatError::RequestFailed(error_message).to_json()),
)
})?;
all_chunks.extend(chunk);
}
// 一次性解码所有数据
let messages = match decoder.decode(&all_chunks, convert_web_ref) {
Ok(msgs) => msgs,
// 立即处理当前chunk
match decoder.decode(&chunk, convert_web_ref) {
Ok(messages) => {
for message in messages {
match message {
StreamMessage::Content(text) => {
if first_chunk_time.is_none() {
first_chunk_time = Some(start_time.elapsed().as_secs_f64());
}
full_text.push_str(&text);
}
StreamMessage::Debug(debug_prompt) => {
if let Ok(mut state) = state.try_lock() {
if let Some(log) = state
.request_logs
.iter_mut()
.rev()
.find(|log| log.id == current_id)
{
log.prompt = Some(debug_prompt);
}
}
}
_ => {}
}
}
}
Err(StreamError::ChatError(error)) => {
let error_response = error.to_error_response();
return Err((
@@ -675,25 +701,6 @@ pub async fn handle_chat(
};
return Err((StatusCode::INTERNAL_SERVER_ERROR, Json(error_response)));
}
};
// 处理所有消息
for message in messages {
match message {
StreamMessage::Content(text) => {
if first_chunk_time.is_none() {
first_chunk_time = Some(start_time.elapsed().as_secs_f64());
}
full_text.push_str(&text);
}
StreamMessage::Debug(debug_prompt) => {
if let Ok(mut state) = state.try_lock() {
if let Some(last_log) = state.request_logs.last_mut() {
last_log.prompt = Some(debug_prompt);
}
}
}
_ => {}
}
}

View File

@@ -79,7 +79,7 @@ impl StreamDecoder {
// 获取第一个结果的引用
pub fn take_first_result(&mut self) -> Option<Vec<StreamMessage>> {
if self.is_incomplete() {
if !self.buffer.is_empty() {
return None;
}
if self.first_result.is_some() {
@@ -88,12 +88,13 @@ impl StreamDecoder {
self.first_result.take()
}
#[cfg(test)]
fn is_incomplete(&self) -> bool {
!self.buffer.is_empty()
}
pub fn has_no_first_result(&self) -> bool {
self.first_result.is_none()
pub fn is_first_result_ready(&self) -> bool {
self.first_result.is_some() && self.buffer.is_empty() && !self.first_result_taken
}
pub fn decode(&mut self, data: &[u8], convert_web_ref: bool) -> Result<Vec<StreamMessage>, StreamError> {

View File

@@ -39,14 +39,14 @@ use tower_http::{cors::CorsLayer, limit::RequestBodyLimitLayer};
#[tokio::main]
async fn main() {
// 设置自定义 panic hook
std::panic::set_hook(Box::new(|info| {
// std::env::set_var("RUST_BACKTRACE", "1");
if let Some(msg) = info.payload().downcast_ref::<String>() {
eprintln!("{}", msg);
} else if let Some(msg) = info.payload().downcast_ref::<&str>() {
eprintln!("{}", msg);
}
}));
// std::panic::set_hook(Box::new(|info| {
// // std::env::set_var("RUST_BACKTRACE", "1");
// if let Some(msg) = info.payload().downcast_ref::<String>() {
// eprintln!("{}", msg);
// } else if let Some(msg) = info.payload().downcast_ref::<&str>() {
// eprintln!("{}", msg);
// }
// }));
// 加载环境变量
dotenvy::dotenv().ok();

View File

@@ -106,6 +106,15 @@
style="display: none;">
</div>
<div class="form-group">
<label>包含网络引用:</label>
<select id="include_web_references">
<option value="">保持不变</option>
<option value="true">启用</option>
<option value="false">禁用</option>
</select>
</div>
<div class="form-group">
<label>共享令牌(空表示禁用):</label>
<input type="text" id="shareToken">
@@ -173,6 +182,8 @@
document.getElementById('usage_check_models_list').value = data.data.usage_check_models?.type === 'list' ? data.data.usage_check_models?.content || '' : document.getElementById('usage_check_models_list').value;
document.getElementById('enable_dynamic_key').value =
parseStringFromBoolean(data.data.enable_dynamic_key, '');
document.getElementById('include_web_references').value =
parseStringFromBoolean(data.data.include_web_references, '');
// 处理代理设置
const proxies = data.data.proxies || '';
@@ -260,6 +271,9 @@
}
})()
}),
...(document.getElementById('include_web_references').value && {
include_web_references: parseBooleanFromString(document.getElementById('include_web_references').value)
}),
share_token: document.getElementById('shareToken').value.trim(),
};