LLM
/
            
              Azure-OpenAI
              
                 
                
            
          copied
				 3 changed files with 226 additions and 1 deletions
			
			
		| @ -1,2 +1,135 @@ | |||
| # Azure-OpenAI | |||
| # OpenAI Chat Completion | |||
| 
 | |||
| *author: David Wang* | |||
| 
 | |||
| <br /> | |||
| 
 | |||
| ## Description | |||
| 
 | |||
| A LLM operator generates answer given prompt in messages using a large language model or service. | |||
| This operator is implemented with Chat Completion method from [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/chatgpt?pivots=programming-language-chat-completions). | |||
| Please note you need an [OpenAI API key](https://platform.openai.com/account/api-keys) to access OpenAI. | |||
| 
 | |||
| <br /> | |||
| 
 | |||
| ## Code Example | |||
| 
 | |||
| Use the default model to continue the conversation from given messages. | |||
| 
 | |||
| *Write a pipeline with explicit inputs/outputs name specifications:* | |||
| 
 | |||
| ```python | |||
| from towhee import pipe, ops | |||
| 
 | |||
| p = ( | |||
|     pipe.input('messages') | |||
|         .map('messages', 'answer', ops.LLM.Azure_OpenAI(api_key=OPENAI_API_KEY, api_base=OPENAI_API_BASE)) | |||
|         .output('messages', 'answer') | |||
| ) | |||
| 
 | |||
| messages=[ | |||
|         {'question': 'Who won the world series in 2020?', 'answer': 'The Los Angeles Dodgers won the World Series in 2020.'}, | |||
|         {'question': 'Where was it played?'} | |||
|     ] | |||
| answer = p(messages).get()[0] | |||
| ``` | |||
| 
 | |||
| *Write a [retrieval-augmented generation pipeline](https://towhee.io/tasks/detail/pipeline/retrieval-augmented-generation) with explicit inputs/outputs name specifications:* | |||
| 
 | |||
| ```python | |||
| from towhee import pipe, ops | |||
| 
 | |||
| 
 | |||
| temp = '''Use the following pieces of context to answer the question at the end. | |||
| If you don't know the answer, just say that you don't know, don't try to make up an answer. | |||
| 
 | |||
| {context} | |||
| 
 | |||
| Question: {question} | |||
| 
 | |||
| Helpful Answer: | |||
| ''' | |||
| 
 | |||
| 
 | |||
| docs = ['You can install towhee via command `pip install towhee`.'] | |||
| history = [ | |||
|     ('What is Towhee?', 'Towhee is an open-source machine learning pipeline that helps you encode your unstructured data into embeddings.') | |||
| ] | |||
| question = 'How to install it?' | |||
| 
 | |||
| p = ( | |||
|     pipe.input('question', 'docs', 'history') | |||
|         .map(('question', 'docs', 'history'), 'prompt', ops.prompt.template(temp, ['question', 'context'])) | |||
|         .map('prompt', 'answer', | |||
|              ops.LLM.Azure_OpenAI(api_key=OPENAI_API_KEY, api_base=OPENAI_API_BASE, temperature=0.5, max_tokens=100) | |||
|              ) | |||
|         .output('answer') | |||
| ) | |||
| 
 | |||
| answer = p(question, docs, history).get()[0] | |||
| ``` | |||
| 
 | |||
| <br /> | |||
| 
 | |||
| ## Factory Constructor | |||
| 
 | |||
| Create the operator via the following factory method: | |||
| 
 | |||
| ***LLM.OpenAI(model_name: str, api_key: str)*** | |||
| 
 | |||
| **Parameters:** | |||
| 
 | |||
| ***model_name***: *str* | |||
| 
 | |||
| The model name in string, defaults to 'gpt-3.5-turbo'. Supported model names: | |||
| - gpt-3.5-turbo | |||
| - gpt-3.5-turbo-16k | |||
| - gpt-3.5-turbo-instruct | |||
| - gpt-3.5-turbo-0613 | |||
| - gpt-3.5-turbo-16k-0613 | |||
| 
 | |||
| ***api_type***: *str=None* | |||
| 
 | |||
| The OpenAI API type in string, defaults to None. | |||
| 
 | |||
| ***api_version***: *str=None* | |||
| 
 | |||
| The OpenAI API version in string, defaults to None. | |||
| 
 | |||
| ***api_key***: *str=None* | |||
| 
 | |||
| The OpenAI API key in string, defaults to None. | |||
| 
 | |||
| ***api_base***: *str=None* | |||
| 
 | |||
| The OpenAI API base in string, defaults to None. | |||
| 
 | |||
| ***\*\*kwargs*** | |||
| 
 | |||
| Other OpenAI parameters such as max_tokens, stream, temperature, etc. | |||
| 
 | |||
| <br /> | |||
| 
 | |||
| ## Interface | |||
| 
 | |||
| The operator takes a piece of text in string as input. | |||
| It returns answer in json. | |||
| 
 | |||
| ***\_\_call\_\_(txt)*** | |||
| 
 | |||
| **Parameters:** | |||
| 
 | |||
| ***messages***: *list* | |||
| 
 | |||
| ​	A list of messages to set up chat. | |||
| Must be a list of dictionaries with key value from "system", "question", "answer". For example, [{"question": "a past question?", "answer": "a past answer."}, {"question": "current question?"}] | |||
| 
 | |||
| **Returns**: | |||
| 
 | |||
| *answer: str* | |||
| 
 | |||
| ​	The next answer generated by role "assistant". | |||
| 
 | |||
| <br /> | |||
| 
 | |||
| 
 | |||
|  | |||
| @ -0,0 +1,5 @@ | |||
| from .azure_openai_chat import AzureOpenaiChat | |||
| 
 | |||
| 
 | |||
| def AzureOpenAI(*args, **kwargs): | |||
|     return AzureOpenaiChat(*args, **kwargs) | |||
| @ -0,0 +1,87 @@ | |||
| # Copyright 2021 Zilliz. All rights reserved. | |||
| # | |||
| # Licensed under the Apache License, Version 2.0 (the "License"); | |||
| # you may not use this file except in compliance with the License. | |||
| # You may obtain a copy of the License at | |||
| # | |||
| #     http://www.apache.org/licenses/LICENSE-2.0 | |||
| # | |||
| # Unless required by applicable law or agreed to in writing, software | |||
| # distributed under the License is distributed on an "AS IS" BASIS, | |||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| # See the License for the specific language governing permissions and | |||
| # limitations under the License. | |||
| 
 | |||
| import os | |||
| from typing import List | |||
| 
 | |||
| import openai | |||
| from towhee.operator.base import PyOperator | |||
| 
 | |||
| class AzureOpenaiChat(PyOperator): | |||
|     '''Wrapper of OpenAI Chat API''' | |||
|     def __init__(self, | |||
|                  model_name: str = 'gpt-3.5-turbo', | |||
|                  api_type: str = 'azure',  | |||
|                  api_version: str = '2023-07-01-preview', | |||
|                  api_key: str = None, | |||
|                  api_base = None, | |||
|                  **kwargs | |||
|                  ): | |||
|         openai.api_key = api_key or os.getenv('OPENAI_API_KEY') | |||
|         openai.api_base = api_base or os.getenv('OPENAI_API_BASE') | |||
|         self._model = model_name | |||
|         self.stream = kwargs.pop('stream') if 'stream' in kwargs else False | |||
|         self.kwargs = kwargs | |||
| 
 | |||
|     def __call__(self, messages: List[dict]): | |||
|         messages = self.parse_inputs(messages) | |||
|         response = openai.ChatCompletion.create( | |||
|             model=self._model, | |||
|             messages=messages, | |||
|             n=1, | |||
|             stream=self.stream, | |||
|             **self.kwargs | |||
|         ) | |||
|         if self.stream: | |||
|             return self.stream_output(response) | |||
|         else: | |||
|             answer = response['choices'][0]['message']['content'] | |||
|             return answer | |||
| 
 | |||
|     def parse_inputs(self, messages: List[dict]): | |||
|         assert isinstance(messages, list), \ | |||
|             'Inputs must be a list of dictionaries with keys from ["system", "question", "answer"].' | |||
|         new_messages = [] | |||
|         for m in messages: | |||
|             if ('role' and 'content' in m) and (m['role'] in ['system', 'assistant', 'user']): | |||
|                 new_messages.append(m) | |||
|             else: | |||
|                 for k, v in m.items(): | |||
|                     if k == 'question': | |||
|                         new_m = {'role': 'user', 'content': v} | |||
|                     elif k == 'answer': | |||
|                         new_m = {'role': 'assistant', 'content': v} | |||
|                     elif k == 'system': | |||
|                         new_m = {'role': 'system', 'content': v} | |||
|                     else: | |||
|                         raise KeyError('Invalid message key: only accept key value from ["system", "question", "answer"].') | |||
|                     new_messages.append(new_m) | |||
|         return new_messages | |||
|      | |||
|     def stream_output(self, response): | |||
|         for resp in response: | |||
|             yield resp['choices'][0]['delta'] | |||
| 
 | |||
|     @staticmethod | |||
|     def supported_model_names(): | |||
|         model_list = [ | |||
|             'gpt-3.5-turbo', | |||
|             'gpt-3.5-turbo-16k', | |||
|             'gpt-3.5-turbo-instruct', | |||
|             'gpt-3.5-turbo-0613', | |||
|             'gpt-3.5-turbo-16k-0613' | |||
|         ] | |||
|         model_list.sort() | |||
|         return model_list | |||
| 
 | |||
					Loading…
					
					
				
		Reference in new issue
	
	