mirror of
https://github.com/wisdgod/cursor-api.git
synced 2025-10-05 22:56:54 +08:00
v0.1.3-rc.4.1
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -361,7 +361,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cursor-api"
|
name = "cursor-api"
|
||||||
version = "0.1.3-rc.4"
|
version = "0.1.3-rc.4.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"base64",
|
"base64",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cursor-api"
|
name = "cursor-api"
|
||||||
version = "0.1.3-rc.4"
|
version = "0.1.3-rc.4.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["wisdgod <nav@wisdgod.com>"]
|
authors = ["wisdgod <nav@wisdgod.com>"]
|
||||||
description = "OpenAI format compatibility layer for the Cursor API"
|
description = "OpenAI format compatibility layer for the Cursor API"
|
||||||
|
@@ -508,48 +508,15 @@ pub async fn handle_chat(
|
|||||||
response_data
|
response_data
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream = {
|
// 首先处理stream直到获得第一个结果
|
||||||
let mut stream = response.bytes_stream();
|
let mut stream = response.bytes_stream();
|
||||||
|
while !decoder.lock().await.is_first_result_ready() {
|
||||||
// 处理第一个chunk并获取first_result
|
match stream.next().await {
|
||||||
while !decoder.lock().await.is_first_result_ready() {
|
Some(Ok(chunk)) => {
|
||||||
match stream.next().await {
|
if let Err(StreamError::ChatError(error)) =
|
||||||
Some(first_chunk) => {
|
decoder.lock().await.decode(&chunk, convert_web_ref)
|
||||||
let chunk = first_chunk.map_err(|e| {
|
{
|
||||||
let error_message = format!("Failed to read response chunk: {}", e);
|
let error_response = error.to_error_response();
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Json(ChatError::RequestFailed(error_message).to_json()),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if let Err(StreamError::ChatError(error)) =
|
|
||||||
decoder.lock().await.decode(&chunk, convert_web_ref)
|
|
||||||
{
|
|
||||||
let error_response = error.to_error_response();
|
|
||||||
// 更新请求日志为失败
|
|
||||||
{
|
|
||||||
let mut state = state.lock().await;
|
|
||||||
if let Some(log) = state
|
|
||||||
.request_logs
|
|
||||||
.iter_mut()
|
|
||||||
.rev()
|
|
||||||
.find(|log| log.id == current_id)
|
|
||||||
{
|
|
||||||
log.status = LogStatus::Failed;
|
|
||||||
log.error = Some(error_response.native_code());
|
|
||||||
log.timing.total =
|
|
||||||
format_time_ms(start_time.elapsed().as_secs_f64());
|
|
||||||
state.error_requests += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err((
|
|
||||||
error_response.status_code(),
|
|
||||||
Json(error_response.to_common()),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// 更新请求日志为失败
|
// 更新请求日志为失败
|
||||||
{
|
{
|
||||||
let mut state = state.lock().await;
|
let mut state = state.lock().await;
|
||||||
@@ -560,77 +527,102 @@ pub async fn handle_chat(
|
|||||||
.find(|log| log.id == current_id)
|
.find(|log| log.id == current_id)
|
||||||
{
|
{
|
||||||
log.status = LogStatus::Failed;
|
log.status = LogStatus::Failed;
|
||||||
log.error = Some("Empty stream response".to_string());
|
log.error = Some(error_response.native_code());
|
||||||
|
log.timing.total = format_time_ms(start_time.elapsed().as_secs_f64());
|
||||||
state.error_requests += 1;
|
state.error_requests += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err((
|
return Err((
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
error_response.status_code(),
|
||||||
Json(
|
Json(error_response.to_common()),
|
||||||
ChatError::RequestFailed("Empty stream response".to_string())
|
|
||||||
.to_json(),
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some(Err(e)) => {
|
||||||
|
let error_message = format!("Failed to read response chunk: {}", e);
|
||||||
|
return Err((
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
Json(ChatError::RequestFailed(error_message).to_json()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// 更新请求日志为失败
|
||||||
|
{
|
||||||
|
let mut state = state.lock().await;
|
||||||
|
if let Some(log) = state
|
||||||
|
.request_logs
|
||||||
|
.iter_mut()
|
||||||
|
.rev()
|
||||||
|
.find(|log| log.id == current_id)
|
||||||
|
{
|
||||||
|
log.status = LogStatus::Failed;
|
||||||
|
log.error = Some("Empty stream response".to_string());
|
||||||
|
state.error_requests += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err((
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
Json(ChatError::RequestFailed("Empty stream response".to_string()).to_json()),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stream.then({
|
// 处理后续的stream
|
||||||
|
let stream = stream.then({
|
||||||
|
let decoder = decoder.clone();
|
||||||
|
let response_id = response_id.clone();
|
||||||
|
let model = request.model.clone();
|
||||||
|
let is_start = is_start.clone();
|
||||||
|
let first_chunk_time = first_chunk_time.clone();
|
||||||
|
let state = state.clone();
|
||||||
|
|
||||||
|
move |chunk| {
|
||||||
let decoder = decoder.clone();
|
let decoder = decoder.clone();
|
||||||
let response_id = response_id.clone();
|
let response_id = response_id.clone();
|
||||||
let model = request.model.clone();
|
let model = model.clone();
|
||||||
let is_start = is_start.clone();
|
let is_start = is_start.clone();
|
||||||
let first_chunk_time = first_chunk_time.clone();
|
let first_chunk_time = first_chunk_time.clone();
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
|
|
||||||
move |chunk| {
|
async move {
|
||||||
let decoder = decoder.clone();
|
let chunk = chunk.unwrap_or_default();
|
||||||
let response_id = response_id.clone();
|
|
||||||
let model = model.clone();
|
|
||||||
let is_start = is_start.clone();
|
|
||||||
let first_chunk_time = first_chunk_time.clone();
|
|
||||||
let state = state.clone();
|
|
||||||
|
|
||||||
async move {
|
let ctx = MessageProcessContext {
|
||||||
let chunk = chunk.unwrap_or_default();
|
response_id: &response_id,
|
||||||
|
model: &model,
|
||||||
|
is_start: &is_start,
|
||||||
|
first_chunk_time: &first_chunk_time,
|
||||||
|
start_time,
|
||||||
|
state: &state,
|
||||||
|
current_id,
|
||||||
|
};
|
||||||
|
|
||||||
let ctx = MessageProcessContext {
|
// 使用decoder处理chunk
|
||||||
response_id: &response_id,
|
let messages = match decoder.lock().await.decode(&chunk, convert_web_ref) {
|
||||||
model: &model,
|
Ok(msgs) => msgs,
|
||||||
is_start: &is_start,
|
Err(e) => {
|
||||||
first_chunk_time: &first_chunk_time,
|
eprintln!("[警告] Stream error: {}", e);
|
||||||
start_time,
|
return Ok::<_, Infallible>(Bytes::new());
|
||||||
state: &state,
|
}
|
||||||
current_id,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let messages = match decoder.lock().await.decode(&chunk, convert_web_ref) {
|
let mut response_data = String::new();
|
||||||
Ok(msgs) => msgs,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("[警告] Stream error: {}", e);
|
|
||||||
return Ok::<_, Infallible>(Bytes::new());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// let mut response_data = String::new();
|
if let Some(first_msg) = decoder.lock().await.take_first_result() {
|
||||||
|
let first_response = process_messages(first_msg, &ctx).await;
|
||||||
// if let Some(first_msg) = decoder.lock().await.take_first_result() {
|
response_data.push_str(&first_response);
|
||||||
// let first_response = process_messages(first_msg, &ctx).await;
|
|
||||||
// if !first_response.is_empty() {
|
|
||||||
// response_data.push_str(&first_response);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
let response_data = process_messages(messages, &ctx).await;
|
|
||||||
// if !current_response.is_empty() {
|
|
||||||
// response_data.push_str(¤t_response);
|
|
||||||
// }
|
|
||||||
|
|
||||||
Ok(Bytes::from(response_data))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let current_response = process_messages(messages, &ctx).await;
|
||||||
|
if !current_response.is_empty() {
|
||||||
|
response_data.push_str(¤t_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Bytes::from(response_data))
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
Ok(Response::builder()
|
Ok(Response::builder()
|
||||||
.header("Cache-Control", "no-cache")
|
.header("Cache-Control", "no-cache")
|
||||||
|
@@ -77,15 +77,15 @@ impl StreamDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn take_first_result(&mut self) -> Option<Vec<StreamMessage>> {
|
pub fn take_first_result(&mut self) -> Option<Vec<StreamMessage>> {
|
||||||
// if !self.buffer.is_empty() {
|
if !self.buffer.is_empty() {
|
||||||
// return None;
|
return None;
|
||||||
// }
|
}
|
||||||
// if self.first_result.is_some() {
|
if self.first_result.is_some() {
|
||||||
// self.first_result_taken = true;
|
self.first_result_taken = true;
|
||||||
// }
|
}
|
||||||
// self.first_result.take()
|
self.first_result.take()
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn is_incomplete(&self) -> bool {
|
fn is_incomplete(&self) -> bool {
|
||||||
|
Reference in New Issue
Block a user