| 
									
										
										
										
											2024-09-21 07:07:57 +08:00
										 |  |  | import json | 
					
						
							| 
									
										
										
										
											2025-02-05 13:42:49 +08:00
										 |  |  | from uuid import uuid4 | 
					
						
							| 
									
										
										
										
											2024-09-21 06:30:13 +08:00
										 |  |  | from open_webui.utils.misc import ( | 
					
						
							| 
									
										
										
										
											2024-09-21 07:07:57 +08:00
										 |  |  |     openai_chat_chunk_message_template, | 
					
						
							| 
									
										
										
										
											2024-09-21 06:30:13 +08:00
										 |  |  |     openai_chat_completion_message_template, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-13 14:04:02 +08:00
										 |  |  | def convert_ollama_tool_call_to_openai(tool_calls: dict) -> dict: | 
					
						
							| 
									
										
										
										
											2025-02-12 16:11:26 +08:00
										 |  |  |     openai_tool_calls = [] | 
					
						
							|  |  |  |     for tool_call in tool_calls: | 
					
						
							|  |  |  |         openai_tool_call = { | 
					
						
							|  |  |  |             "index": tool_call.get("index", 0), | 
					
						
							|  |  |  |             "id": tool_call.get("id", f"call_{str(uuid4())}"), | 
					
						
							|  |  |  |             "type": "function", | 
					
						
							|  |  |  |             "function": { | 
					
						
							|  |  |  |                 "name": tool_call.get("function", {}).get("name", ""), | 
					
						
							|  |  |  |                 "arguments": json.dumps( | 
					
						
							| 
									
										
										
										
											2025-02-13 16:13:33 +08:00
										 |  |  |                     tool_call.get("function", {}).get("arguments", {}) | 
					
						
							| 
									
										
										
										
											2025-02-12 16:11:26 +08:00
										 |  |  |                 ), | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         openai_tool_calls.append(openai_tool_call) | 
					
						
							|  |  |  |     return openai_tool_calls | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-20 17:01:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-19 22:28:39 +08:00
										 |  |  | def convert_ollama_usage_to_openai(data: dict) -> dict: | 
					
						
							|  |  |  |     return { | 
					
						
							| 
									
										
										
										
											2025-01-30 13:07:22 +08:00
										 |  |  |         "response_token/s": ( | 
					
						
							|  |  |  |             round( | 
					
						
							|  |  |  |                 ( | 
					
						
							|  |  |  |                     ( | 
					
						
							|  |  |  |                         data.get("eval_count", 0) | 
					
						
							|  |  |  |                         / ((data.get("eval_duration", 0) / 10_000_000)) | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                     * 100 | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 2, | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             if data.get("eval_duration", 0) > 0 | 
					
						
							|  |  |  |             else "N/A" | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         "prompt_token/s": ( | 
					
						
							|  |  |  |             round( | 
					
						
							|  |  |  |                 ( | 
					
						
							|  |  |  |                     ( | 
					
						
							|  |  |  |                         data.get("prompt_eval_count", 0) | 
					
						
							|  |  |  |                         / ((data.get("prompt_eval_duration", 0) / 10_000_000)) | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                     * 100 | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 2, | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             if data.get("prompt_eval_duration", 0) > 0 | 
					
						
							|  |  |  |             else "N/A" | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         "total_duration": data.get("total_duration", 0), | 
					
						
							|  |  |  |         "load_duration": data.get("load_duration", 0), | 
					
						
							|  |  |  |         "prompt_eval_count": data.get("prompt_eval_count", 0), | 
					
						
							| 
									
										
										
										
											2025-02-20 17:01:29 +08:00
										 |  |  |         "prompt_tokens": int( | 
					
						
							|  |  |  |             data.get("prompt_eval_count", 0) | 
					
						
							|  |  |  |         ),  # This is the OpenAI compatible key | 
					
						
							| 
									
										
										
										
											2025-01-30 13:07:22 +08:00
										 |  |  |         "prompt_eval_duration": data.get("prompt_eval_duration", 0), | 
					
						
							|  |  |  |         "eval_count": data.get("eval_count", 0), | 
					
						
							| 
									
										
										
										
											2025-02-20 17:01:29 +08:00
										 |  |  |         "completion_tokens": int( | 
					
						
							|  |  |  |             data.get("eval_count", 0) | 
					
						
							|  |  |  |         ),  # This is the OpenAI compatible key | 
					
						
							| 
									
										
										
										
											2025-01-30 13:07:22 +08:00
										 |  |  |         "eval_duration": data.get("eval_duration", 0), | 
					
						
							|  |  |  |         "approximate_total": (lambda s: f"{s // 3600}h{(s % 3600) // 60}m{s % 60}s")( | 
					
						
							|  |  |  |             (data.get("total_duration", 0) or 0) // 1_000_000_000 | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2025-02-20 17:01:29 +08:00
										 |  |  |         "total_tokens": int(  # This is the OpenAI compatible key | 
					
						
							| 
									
										
										
										
											2025-02-19 22:28:39 +08:00
										 |  |  |             data.get("prompt_eval_count", 0) + data.get("eval_count", 0) | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2025-02-20 17:01:29 +08:00
										 |  |  |         "completion_tokens_details": {  # This is the OpenAI compatible key | 
					
						
							| 
									
										
										
										
											2025-02-19 22:28:39 +08:00
										 |  |  |             "reasoning_tokens": 0, | 
					
						
							|  |  |  |             "accepted_prediction_tokens": 0, | 
					
						
							| 
									
										
										
										
											2025-02-20 17:01:29 +08:00
										 |  |  |             "rejected_prediction_tokens": 0, | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2025-01-30 13:07:22 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-20 17:01:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-19 22:28:39 +08:00
										 |  |  | def convert_response_ollama_to_openai(ollama_response: dict) -> dict: | 
					
						
							|  |  |  |     model = ollama_response.get("model", "ollama") | 
					
						
							|  |  |  |     message_content = ollama_response.get("message", {}).get("content", "") | 
					
						
							|  |  |  |     tool_calls = ollama_response.get("message", {}).get("tool_calls", None) | 
					
						
							|  |  |  |     openai_tool_calls = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if tool_calls: | 
					
						
							|  |  |  |         openai_tool_calls = convert_ollama_tool_call_to_openai(tool_calls) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data = ollama_response | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     usage = convert_ollama_usage_to_openai(data) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-13 16:13:33 +08:00
										 |  |  |     response = openai_chat_completion_message_template( | 
					
						
							|  |  |  |         model, message_content, openai_tool_calls, usage | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-09-21 06:30:13 +08:00
										 |  |  |     return response | 
					
						
							| 
									
										
										
										
											2024-09-21 07:07:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async def convert_streaming_response_ollama_to_openai(ollama_streaming_response): | 
					
						
							|  |  |  |     async for data in ollama_streaming_response.body_iterator: | 
					
						
							|  |  |  |         data = json.loads(data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         model = data.get("model", "ollama") | 
					
						
							|  |  |  |         message_content = data.get("message", {}).get("content", "") | 
					
						
							| 
									
										
										
										
											2025-02-05 13:42:49 +08:00
										 |  |  |         tool_calls = data.get("message", {}).get("tool_calls", None) | 
					
						
							|  |  |  |         openai_tool_calls = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if tool_calls: | 
					
						
							| 
									
										
										
										
											2025-02-13 14:04:02 +08:00
										 |  |  |             openai_tool_calls = convert_ollama_tool_call_to_openai(tool_calls) | 
					
						
							| 
									
										
										
										
											2025-02-05 13:42:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-21 07:07:57 +08:00
										 |  |  |         done = data.get("done", False) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-13 15:31:08 +08:00
										 |  |  |         usage = None | 
					
						
							|  |  |  |         if done: | 
					
						
							| 
									
										
										
										
											2025-02-19 22:28:39 +08:00
										 |  |  |             usage = convert_ollama_usage_to_openai(data) | 
					
						
							| 
									
										
										
										
											2024-12-13 15:31:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-21 07:07:57 +08:00
										 |  |  |         data = openai_chat_chunk_message_template( | 
					
						
							| 
									
										
										
										
											2025-02-05 13:42:49 +08:00
										 |  |  |             model, message_content if not done else None, openai_tool_calls, usage | 
					
						
							| 
									
										
										
										
											2024-09-21 07:07:57 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         line = f"data: {json.dumps(data)}\n\n" | 
					
						
							|  |  |  |         yield line | 
					
						
							| 
									
										
										
										
											2024-10-22 04:45:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     yield "data: [DONE]\n\n" |