diff --git a/src/chat_template/mod.rs b/src/chat_template/mod.rs index 24c4bf7..48aefb4 100644 --- a/src/chat_template/mod.rs +++ b/src/chat_template/mod.rs @@ -102,6 +102,7 @@ impl<'a> ChatTemplate<'a> { pub fn apply_chat_template(&self, messages: &ChatCompletionParameters) -> Result { let context = context! { messages => &messages.messages, + tools => &messages.tools.as_ref(), add_generation_prompt => true, }; let template = self diff --git a/src/models/qwen3vl/generate.rs b/src/models/qwen3vl/generate.rs index 775b822..a5c3de1 100644 --- a/src/models/qwen3vl/generate.rs +++ b/src/models/qwen3vl/generate.rs @@ -171,6 +171,8 @@ impl<'a> GenerateModel for Qwen3VLGenerateModel<'a> { let image_grid_thw = image_grid_thw.as_ref(); let mut pixel_values_video = pixel_values_video.as_ref(); let video_grid_thw = video_grid_thw.as_ref(); + let mut tool_call_id = None; + let mut tool_call_content = String::new(); for _ in 0..sample_len { let logits = self.qwen3_vl.forward( &input_ids, @@ -203,8 +205,28 @@ impl<'a> GenerateModel for Qwen3VLGenerateModel<'a> { continue; } error_tokens.clear(); - let chunk = build_completion_chunk_response(decoded_token, &self.model_name, None, None); - yield Ok(chunk); + + if decoded_token.as_str() == "" { + tool_call_id = Some(uuid::Uuid::new_v4().to_string()); + continue; + } else { + if decoded_token.as_str() == "" { + let chunk = build_completion_chunk_response(decoded_token, &self.model_name, tool_call_id.clone(), Some(tool_call_content.clone())); + tool_call_id = None; + tool_call_content = String::new(); + yield Ok(chunk); + } + else { + if tool_call_id.is_some() { + tool_call_content.push_str(&decoded_token); + continue; + } + else { + let chunk = build_completion_chunk_response(decoded_token, &self.model_name, None, None); + yield Ok(chunk); + } + } + } if next_token == self.eos_token_id1 || next_token == self.eos_token_id2 { break; } diff --git a/tests/test_gelab_zero.rs b/tests/test_gelab_zero.rs index 29db2d7..06cfe3f 100644 --- a/tests/test_gelab_zero.rs +++ b/tests/test_gelab_zero.rs @@ -19,11 +19,39 @@ fn gelab_zero_generate() -> Result<()> { "content": [ { "type": "text", - "text": "Hello, GELab-Zero!" + "text": "Hello, GELab-Zero!, 现在几点了" } ] } - ] + ], + "tools": [ + { + "type": "function", + "function": { + "name": "get_current_time", + "description": "当你想知道现在的时间时非常有用。", + "parameters": {} + } + }, + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "当你想查询指定城市的天气时非常有用。", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "城市或县区,比如北京市、杭州市、余杭区等。" + } + }, + "required": ["location"] + } + } + } + ], + "tool_choice": null } "#; let mes: ChatCompletionParameters = serde_json::from_str(message)?; diff --git a/tests/test_qwen3vl.rs b/tests/test_qwen3vl.rs index 609ee59..12eb79d 100644 --- a/tests/test_qwen3vl.rs +++ b/tests/test_qwen3vl.rs @@ -19,15 +19,15 @@ fn qwen3vl_generate() -> Result<()> { "role": "user", "content": [ { - "type": "video", - "video_url": + "type": "image", + "image_url": { - "url": "./assets/video/video_test.mp4" + "url": "file://./assets/img/ocr_test1.png" } }, { "type": "text", - "text": "视频里发生了什么" + "text": "请分析图片并提取所有可见文本内容,按从左到右、从上到下的布局,返回纯文本" } ] } @@ -70,11 +70,39 @@ async fn qwen3vl_stream() -> Result<()> { }, { "type": "text", - "text": "视频中发生了什么?" + "text": "视频中发生了什么?, 现在几点了" } ] } - ] + ], + "tools": [ + { + "type": "function", + "function": { + "name": "get_current_time", + "description": "当你想知道现在的时间时非常有用。", + "parameters": {} + } + }, + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "当你想查询指定城市的天气时非常有用。", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "城市或县区,比如北京市、杭州市、余杭区等。" + } + }, + "required": ["location"] + } + } + } + ], + "tool_choice": null } "#; let mes: ChatCompletionParameters = serde_json::from_str(message)?;