Add function message role and function name

This commit is contained in:
David Miguel
2023-06-17 21:04:34 +02:00
parent 9a1e91a83b
commit 0fc1574192
5 changed files with 121 additions and 39 deletions

3
.gitignore vendored
View File

@ -9,4 +9,5 @@ example/.env
env.g.dart
.env
*.mp3
*.png
*.png
.idea/

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:dart_openai/dart_openai.dart';
import 'env/env.dart';
@ -5,39 +7,100 @@ import 'env/env.dart';
Future<void> main() async {
OpenAI.apiKey = Env.apiKey;
final chatRes = await OpenAI.instance.chat.create(
model: "gpt-3.5-turbo-0613",
messages: [
OpenAIChatCompletionChoiceMessageModel(
content:
"send an email with a message asking about weather in Marrakech",
role: OpenAIChatMessageRole.user,
),
],
functions: [
OpenAIFunctionModel(
name: "sendEmail",
description: "sends an email with the given message",
parameters: OpenAIFunctionParameters.fromProperties(
[
OpenAIFunctionProperty(
name: "message",
type: 'string',
),
],
final function = OpenAIFunctionModel(
name: "getCurrentWeather",
description: "Get the current weather in a given location",
parameters: OpenAIFunctionParameters.fromProperties(
[
OpenAIFunctionProperty(
name: "location",
description: 'The city and state, e.g. San Francisco, CA',
type: OpenAIFunctionProperty.functionTypeString,
isRequired: true,
),
),
],
OpenAIFunctionProperty(
name: "unit",
description: 'The unit of temperature to return',
type: OpenAIFunctionProperty.functionTypeString,
enumValues: ["celsius", "fahrenheit"],
),
],
),
);
final funcCall = chatRes.choices.first.message.functionCall;
final userMsg = OpenAIChatCompletionChoiceMessageModel(
content: "Whats the weather like in Boston right now?",
role: OpenAIChatMessageRole.user,
);
if (funcCall != null && funcCall.name == "sendEmail") {
final message = funcCall.arguments["message"];
sendEmail(message);
final chatRes1 = await OpenAI.instance.chat.create(
model: "gpt-3.5-turbo-0613",
messages: [userMsg],
functions: [function],
);
final assistantMsg1 = chatRes1.choices.first.message;
final funcCall = assistantMsg1.functionCall;
if (funcCall == null || funcCall.name != "getCurrentWeather") {
print(assistantMsg1.content);
return;
}
final weather = getCurrentWeather(
location: funcCall.arguments["location"],
unit: funcCall.arguments["unit"],
);
final functionMsg = OpenAIChatCompletionChoiceMessageModel(
functionName: function.name,
content: json.encode(weather.toMap()),
role: OpenAIChatMessageRole.function,
);
final chatRes2 = await OpenAI.instance.chat.create(
model: "gpt-3.5-turbo-0613",
messages: [
userMsg,
assistantMsg1,
functionMsg,
],
functions: [function],
);
final assistantMsg2 = chatRes2.choices.first.message;
print(assistantMsg2.content);
// The weather in Boston right now is sunny with a temperature of 22 degrees Celsius.
}
Weather getCurrentWeather({
required String location,
String? unit = "celsius",
}) {
return Weather(
temperature: 22,
unit: unit ?? "celsius",
description: "Sunny",
);
}
class Weather {
final int temperature;
final String unit;
final String description;
const Weather({
required this.temperature,
required this.unit,
required this.description,
});
Map<String, dynamic> toMap() {
return {
'temperature': temperature,
'unit': unit,
'description': description,
};
}
}
void sendEmail(String message) {
print("message: $message... is sent successfully.");
}

View File

@ -11,11 +11,20 @@ final class OpenAIChatCompletionChoiceMessageModel {
/// The [content] of the message.
final String content;
/// The function that the model is requesting to call.
final FunctionCallResponse? functionCall;
/// The name of the function that was called.
final String? functionName;
bool get hasFunctionCall => functionCall != null;
@override
int get hashCode {
return role.hashCode ^ content.hashCode;
return role.hashCode ^
content.hashCode ^
functionCall.hashCode ^
functionName.hashCode;
}
/// {@macro openai_chat_completion_choice_message_model}
@ -23,10 +32,9 @@ final class OpenAIChatCompletionChoiceMessageModel {
required this.role,
required this.content,
this.functionCall,
this.functionName,
});
bool get hasFunctionCall => functionCall != null;
/// This is used to convert a [Map<String, dynamic>] object to a [OpenAIChatCompletionChoiceMessageModel] object.
factory OpenAIChatCompletionChoiceMessageModel.fromMap(
Map<String, dynamic> json,
@ -47,15 +55,24 @@ final class OpenAIChatCompletionChoiceMessageModel {
"role": role.name,
"content": content,
if (functionCall != null) "function_call": functionCall!.toMap(),
if (functionName != null) "name": functionName,
};
}
@override
String toString() {
String str = 'OpenAIChatCompletionChoiceMessageModel('
'role: $role, '
'content: $content, ';
if (functionCall != null) {
return 'OpenAIChatCompletionChoiceMessageModel(role: $role, content: $content, functionCall: $functionCall)';
str += 'functionCall: $functionCall, ';
}
return 'OpenAIChatCompletionChoiceMessageModel(role: $role, content: $content)';
if (functionName != null) {
str += 'functionName: $functionName, ';
}
str += ')';
return str;
}
@override
@ -65,6 +82,7 @@ final class OpenAIChatCompletionChoiceMessageModel {
return other is OpenAIChatCompletionChoiceMessageModel &&
other.role == role &&
other.content == content &&
other.functionCall == functionCall;
other.functionCall == functionCall &&
other.functionName == functionName;
}
}

View File

@ -140,7 +140,7 @@ class FunctionCallResponse {
Map<String, dynamic> toMap() {
return {
'name': name,
'arguments': arguments,
'arguments': json.encode(arguments),
};
}

View File

@ -4,4 +4,4 @@ enum OpenAIImageResponseFormat { url, b64Json }
enum OpenAIAudioResponseFormat { json, text, srt, verbose_json, vtt }
enum OpenAIChatMessageRole { system, user, assistant }
enum OpenAIChatMessageRole { system, user, assistant, function }