Unity 工具 之 Azure 微软 【GPT4o】HttpClient 异步流式请求的简单封装

news2024/10/25 10:32:49

Unity 工具 之 Azure 微软 【GPT4o】HttpClient 异步流式请求的简单封装

目录

Unity 工具 之 Azure 微软 【GPT4o】HttpClient 异步流式请求的简单封装

一、简单介绍

二、实现原理

三、注意实现

四、简单效果预览

五、案例简单实现步骤

六、关键代码


一、简单介绍

Unity 工具类,自己整理的一些游戏开发可能用到的模块,单独独立使用,方便游戏开发。

本节介绍,这里在使用微软的Azure 进行语音合成的两个方法的做简单整理,这里简单说明,如果你有更好的方法,欢迎留言交流。

官网注册:

面向学生的 Azure - 免费帐户额度 | Microsoft Azure

官网技术文档网址:

技术文档 | Microsoft Learn

Azure OpenAI 一些模型介绍:

Azure OpenAI 服务模型 - Azure OpenAI | Microsoft Learn

GPT-4o 和 GPT-4 Turbo

GPT-4o 是 OpenAI 的最新模型。 GPT-4o 在单个模型中集成文本和图像,从而能够同时处理多个数据类型。 这种多模式方法提高了人机交互的准确性和响应能力。 GPT-4o 在英语文本和编码任务方面与 GPT-4 Turbo 相当,但在非英语语言和视觉任务方面具有更优越的性能,为 AI 功能设定了新的基准。

如何访问 GPT-4o 模型?

GPT-4o 可用于标准和全球标准模型部署。

需要在该模型可用的受支持标准或全球标准区域中创建或使用现有资源。

创建资源后,可以部署 GPT-4o 模型。 

发起请求的json 格式:

{
            "messages": [ 
                {
                    "role": "system", 
                    "content": "You are a helpful assistant." 
                },
                {
                    "role": "user", 
                    "content": [
	                    {
	                        "type": "text",
	                        "text": "Describe this picture:"
	                    },
	                    {
	                        "type": "image_url",
	                        "image_url": {
                                "url": "<image URL>"
                            }
                        } 
                   ] 
                }
            ],
            "max_tokens": 100, 
            "stream": false 
        }

返回的格式根据是否是流式返回,略有所不同:

非流式的:

 {
	"id": "chatcmpl-8X0uY6Xbv4XpU4zo0KXhVk4iTldJf",
	"object": "chat.completion",
	"created": 1702879018,
	"model": "gpt-4v",
	"prompt_filter_results": [{
		"prompt_index": 0,
		"content_filter_results": {
			"hate": {
				"filtered": false,
				"severity": "safe"
			},
			"self_harm": {
				"filtered": false,
				"severity": "safe"
			},
			"sexual": {
				"filtered": false,
				"severity": "safe"
			},
			"violence": {
				"filtered": false,
				"severity": "safe"
			}
		}
	}],
	"choices": [{
		"finish_details": {
			"type": "stop",
			"stop": "<|fim_suffix|>"
		},
		"index": 0,
		"message": {
			"role": "assistant",
			"content": "这张图片展示了一辆银灰色的跑车,停靠在一个内饰精致的展厅里。车身呈流线型,前脸上有显著的品牌标志和数字“10”。车身上的漆面光洁明亮,反射着展厅内柔和的灯光。背景中可以看到其他几辆停放整齐的高端车辆,以及墙上挂着的一些装饰性画作。整个场景显得高端大气,彰显了跑车的豪华品质。"
		},
		"content_filter_results": {
			"hate": {
				"filtered": false,
				"severity": "safe"
			},
			"self_harm": {
				"filtered": false,
				"severity": "safe"
			},
			"sexual": {
				"filtered": false,
				"severity": "safe"
			},
			"violence": {
				"filtered": false,
				"severity": "safe"
			}
		}
	}],
	"usage": {
		"prompt_tokens": 826,
		"completion_tokens": 175,
		"total_tokens": 1001
	}
}

流式的根据数据内容不同,data 数据不同:

data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_result":{"jailbreak":{"filtered":false,"detected":false},"custom_blocklists":{"filtered":false,"details":[]}}},{"prompt_index":1,"content_filter_result":{"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"},"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"custom_blocklists":{"filtered":false,"details":[]}}}]}

data: {"choices":[{"content_filter_results":{},"delta":{"content":"","role":"assistant"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"镜"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"腿"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"\n"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"眼"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"镜"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"框"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"\n"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"控制"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"电"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"路"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"\n"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"连接"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"电"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"路"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"\n"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"前"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"顶"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"盖"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"\n"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"摄"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"像"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"头"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"\n"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"投"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"影"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"模块"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"\n"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"鼻"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"梁"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"\n"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"显示"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"光"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"学"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"元"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"件"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"\n"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"麦"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"克"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"风"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"stop","index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}

data: [DONE]

二、实现原理

1、官网申请得到对应使用 GPT4o 模型的相关key 等信息(和之前申请GPT3.5、GPT4 类似)

2、使用 HttpClinet 进行网络 Post 请求,且使用异步请求 ,使用 cancellationToken 用于取消请求

// 发送请求并获取响应
HttpResponseMessage response = await client.SendAsync(request, cancellationToken);

3、根据请求流式和非流式的标志 “stream”,false 为非流式,true 为流式返回数据

4、其中 HttpClient 的异步请求也是可以打断的

 cancellationTokenSource.Cancel();

三、注意实现

1、GPT4o 支持文本和图片数据发起 Post 请求访问,其中 图片数据,可以是 url ,也可以是 Base64 ,其中 Base64 数据注意添加上前缀,例如 png 图片,前缀:data:image/png;base64,

 string IMAGE_png_EXTRA_PREFIXES_BASE64 = "data:image/png;base64,";
 string base64 = await ImageLoader.Instance.LoadImageAndConvertToBase64();
 base64 = IMAGE_png_EXTRA_PREFIXES_BASE64 + base64;

2、这里没有添加历史数据,需要的话可以自动添加历史数据,添加到请求的 public List<Message> messages; 列表中即可,不过,提问要放到最后

 public class JsonRequestStruct
    {
        public int max_tokens;
        public bool stream;
        public float temperature;
        public List<Message> messages;

    }

    public class Message
    {
        public string role;
        public object content; //这个是不规则的json 列表
    }

四、简单效果预览

五、案例简单实现步骤

1、新建 Unity 工程

2、创建接口脚本,定义一些基本功能和回调

3、创建基类,HttpClient 实现数据的请求,取消请求的基本功能

4、创建实现了,填写自己的 GPT4o key 相关信息

5、测试接口,先测试非流式的文字请求

6、测试流式,图片请求的接口

六、关键代码

1、IAzureGpt4o


using System;
using System.Threading.Tasks;

public interface IAzureGpt4o
{
    /// <summary>
    /// 请求失败的回调
    /// </summary>
    Action<string> OnSendRequestFailed { get; set; }

    /// <summary>
    /// 响应的流式数据
    /// </summary>
    Action<string> OnResponsingData { get; set; }
    /// <summary>
    /// 响应接收完的数据
    /// </summary>
    Action<string> OnResponseFinished { get; set; }

    /// <summary>
    /// 发送请求
    /// </summary>
    /// <param name="askContent"></param>
    /// <param name="imgData">图片数据,支持 url/base64</param>
    /// <returns></returns>
    Task<string> SendRequestAsync(string askContent, string imgData);

    /// <summary>
    /// 发送请求(流式返回数据)
    /// </summary>
    /// <param name="askContent"></param>
    /// <param name="imgData">图片数据,支持 url/base64</param>
    /// <returns></returns>
    Task<string> SendRequestStreamResponseAsync(string askContent, string imgData);

    /// <summary>
    /// Helper function to cancel the ongoing request
    /// </summary>
    public void CancelRequest();
}

2、BaseAzureGpt4o

using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Text;
using UnityEngine;
using System;
using System.Threading.Tasks;
using System.Threading;
using System.Net.Http;

/// <summary>
/// GPT 4o 基类
/// </summary>
/// <typeparam name="T"></typeparam>
public class BaseAzureGpt4o : IAzureGpt4o
{
    #region Data
    /// <summary>
    /// TAG
    /// </summary>
    protected virtual string TAG { get; } = "[BaseAzureGpt4o]";
    /// <summary>
    /// API_BASE
    /// </summary>
    protected virtual string API_BASE { get; } = "https://gpt4o-version.openai.azure.com/";
    /// <summary>
    /// DEPLOYMENT_NAME
    /// </summary>
    protected virtual string DEPLOYMENT_NAME { get; } = "Your_Deplyment_Name";
    /// <summary>
    /// API_KEY
    /// </summary>
    protected virtual string API_KEY { get; } = "YOur_API_Key";

    /// <summary>
    /// 对应模型接口的发行版本
    /// </summary>
    protected virtual string MODEL_VERSION { get; } = "2024-05-01-preview";

    /// <summary>
    /// 组织基础的 Url
    /// </summary>
    protected virtual string m_BaseUrl { get{ return $"{API_BASE}/openai/deployments/{DEPLOYMENT_NAME}"; } }  
    /// <summary>
    /// 组成最后访问的 Url 
    /// </summary>
    protected virtual string m_EndPointend { get {return $"{m_BaseUrl}/chat/completions?api-version={MODEL_VERSION}"; } } 

    /// <summary>
    /// 最大的 Tokens
    /// </summary>
    protected virtual int MAX_TOKENS { get; } = 100;

    /// <summary>
    /// 请求失败的回调
    /// </summary>
    public Action<string> OnSendRequestFailed { get; set; }
    /// <summary>
    /// 响应的流式数据
    /// </summary>
    public Action<string> OnResponsingData { get; set; }
    /// <summary>
    /// 响应接收完的数据
    /// </summary>
    public Action<string> OnResponseFinished { get; set; }

    /// <summary>
    /// CancellationTokenSource
    /// </summary>
    private CancellationTokenSource cancellationTokenSource;

    /// <summary>
    /// HttpClient
    /// </summary>
    private static readonly HttpClient client = new HttpClient();

    #endregion

    #region Inteface function

    /// <summary>
    /// 发送请求(正常返回数据)
    /// </summary>
    /// <param name="askContent"></param>
    /// <param name="imgData">图片数据,支持 url/base64</param>
    /// <returns></returns>
    public virtual async Task<string> SendRequestAsync(string askContent, string imgData)
    {
        Debug.Log(TAG + "Start HttpWebRequest m_EndPointend : " + m_EndPointend);

        cancellationTokenSource = new CancellationTokenSource();
        CancellationToken cancellationToken = cancellationTokenSource.Token;

        // json 数据
        string jsonData = GetJsonStr(askContent, imgData);

        /// 设置请求头
        client.DefaultRequestHeaders.Clear();
        client.DefaultRequestHeaders.Add("api-key", API_KEY);

        // 创建 HTTP 内容
        var content = new StringContent(jsonData, Encoding.UTF8, "application/json");

        try
        {
            // 创建请求
            var request = new HttpRequestMessage(HttpMethod.Post, m_EndPointend)
            {
                Content = content
            };

            // 发送请求并获取响应
            HttpResponseMessage response = await client.SendAsync(request, cancellationToken);

            // 检查响应状态码
            if (response.IsSuccessStatusCode)
            {
                // 读取整个响应内容
                string responseText = await response.Content.ReadAsStringAsync();

                if (cancellationToken.IsCancellationRequested)
                {
                    Debug.Log(TAG + "Operation was canceled.");
                    OnSendRequestFailed?.Invoke("Operation was canceled.");
                    return null; // 或抛出异常,根据需要处理
                }

                Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + responseText);
                string jsonString = DecodeUnicode(responseText);

                string parseWholeRlt;

                // 使用 Newtonsoft.Json 将 JSON 字符串映射到对应的对象
                JsonResponseStruct data = JsonConvert.DeserializeObject<JsonResponseStruct>(jsonString);
                if (data != null)
                {
                    parseWholeRlt = data.choices[0].message.content.ToString();
                    Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + parseWholeRlt);
                }
                else
                {
                    Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + jsonString);
                    parseWholeRlt = jsonString;
                }

                if (OnResponseFinished != null)
                {
                    Debug.Log(TAG + " PostRequestStreamToStringAsync OnResponseFinished is  not null ");
                    OnResponseFinished?.Invoke(parseWholeRlt);
                }
                else
                {
                    Debug.Log(TAG + " PostRequestStreamToStringAsync OnResponseFinished is null ");
                }

                return parseWholeRlt;
            }
            else
            {
                // 打印错误状态码
                Debug.LogError(TAG + "Error: " + response.StatusCode);
                OnSendRequestFailed?.Invoke(response.Content.ToString());
                return null;
            }
        }
        catch (OperationCanceledException e)
        {
            Debug.Log(TAG + "Operation was canceled. " + e.Message);
            OnSendRequestFailed?.Invoke(e.Message);
            return null; // 或抛出异常,根据需要处理
        }
        catch (WebException e)
        {
            Debug.Log(TAG + " e.Message: " + e.Message);
            OnSendRequestFailed?.Invoke(e.Message);
            return null;
        }
    }

    /// <summary>
    /// 发送请求(流式返回数据)
    /// </summary>
    /// <param name="askContent"></param>
    /// <param name="imgData">图片数据,支持 url/base64</param>
    /// <returns></returns>
    public virtual async Task<string> SendRequestStreamResponseAsync(string askContent, string imgData) {

        Debug.Log(TAG + "Start HttpWebRequest m_EndPointend : " + m_EndPointend);

        cancellationTokenSource = new CancellationTokenSource();
        CancellationToken cancellationToken = cancellationTokenSource.Token;

        // json 数据
        string jsonData = GetJsonStr(askContent, imgData, true);

        /// 设置请求头
        client.DefaultRequestHeaders.Clear();
        client.DefaultRequestHeaders.Add("api-key", API_KEY);

        // 创建 HTTP 内容
        var content = new StringContent(jsonData, Encoding.UTF8, "application/json");

        try
        {
            // 创建请求
            var request = new HttpRequestMessage(HttpMethod.Post, m_EndPointend)
            {
                Content = content
            };

            // 发送请求并获取响应头
            HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

            // 检查响应状态码
            if (response.IsSuccessStatusCode)
            {
                // 以流的方式读取响应内容
                using (var stream = await response.Content.ReadAsStreamAsync())
                {
                    using (var reader = new StreamReader(stream))
                    {
                        StringBuilder sb = new StringBuilder();
                        string line;
                        while ((line = await reader.ReadLineAsync()) != null)
                        {

                            string parseRlt = HandleStreamData(line);
                            if (string.IsNullOrEmpty(parseRlt) == false)
                            {
                                OnResponsingData?.Invoke(parseRlt);
                            }

                            sb.AppendLine(line); // 逐行读取并累积响应数据
                            Debug.Log(TAG + " PostRequestStreamToStringAsync getting steam data : " + sb.ToString());

                            // Check for cancellation
                            if (cancellationToken.IsCancellationRequested)
                            {
                                Debug.Log(TAG + "Operation was canceled.");
                                return null; // or throw an exception, handle as needed
                            }
                        }

                        Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + sb.ToString());
                        string jsonString = DecodeUnicode(sb.ToString());

                        string parseWholeRlt = HandleStreamData(jsonString);
                        Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + parseWholeRlt);

                        if (OnResponseFinished != null)
                        {
                            Debug.Log(TAG + " PostRequestStreamToStringAsync OnResponseFinished is  not null ");
                            OnResponseFinished?.Invoke(parseWholeRlt);
                        }
                        else
                        {
                            Debug.Log(TAG + " PostRequestStreamToStringAsync OnResponseFinished is null ");
                        }

                        return parseWholeRlt;
                    }
                }
            }
            else
            {
                // 打印错误状态码
                Debug.LogError(TAG + "Error: " + response.StatusCode);
                OnSendRequestFailed?.Invoke(response.Content.ToString());
                return null;
            }
        }
        catch (OperationCanceledException e)
        {
            Debug.Log(TAG + "Operation was canceled. " + e.Message);
            OnSendRequestFailed?.Invoke(e.Message);
            return null; // or throw an exception, handle as needed
        }
        catch (WebException e)
        {
            Debug.Log(TAG + " e.Message: " + e.Message);
            OnSendRequestFailed?.Invoke(e.Message);
            return null;
        }
    }

    /// <summary>
    /// Helper function to cancel the ongoing request
    /// </summary>
    public virtual void CancelRequest()
    {
        if (cancellationTokenSource != null && !cancellationTokenSource.IsCancellationRequested)
        {
            cancellationTokenSource.Cancel();
        }
    }

    #endregion

    #region Protected function

    /// <summary>
    /// 将 Unicode 转义字符解码为 UTF-8 字符串的方法
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    protected string DecodeUnicode(string input)
    {
        return Regex.Replace(input, @"\\u([0-9a-fA-F]{4})", match =>
        {
            string hex = match.Groups[1].Value;
            int codePoint = Convert.ToInt32(hex, 16);
            return char.ConvertFromUtf32(codePoint);
        });
    }

    /// <summary>
    /// 组织提问和图片数据
    /// </summary>
    /// <param name="askContent"></param>
    /// <param name="imgBase64OrUrlg"></param>
    /// <param name="isStreamResponse">是否流式响应返回数据</param>
    /// <returns></returns>
    protected string GetJsonStr(string askContent, string imgBase64OrUrlg, bool isStreamResponse = false)
    {
        List<object> contentList = new List<object>();
        contentList.Add(new
        {
            type = "text",
            text = askContent,

        });

        if (imgBase64OrUrlg != null)
        {
            // 创建一个包含指定数据结构的对象列表
            contentList.Add(new
            {
                type = "image_url",
                image_url = new
                {
                    url = imgBase64OrUrlg
                },
            });
        }

        // 将对象列表转换为 JSON 字符串
        string jsonString = JsonConvert.SerializeObject(contentList, Formatting.Indented);

        Message messageS = new Message() { role = "system", content = "You are a helpful assistant." };
        Message message = new Message() { role = "user", content = contentList };
        List<Message> messages = new List<Message>();
        messages.Add(messageS);
        messages.Add(message);

        JsonRequestStruct jsonRequest = new JsonRequestStruct() { messages = messages, max_tokens = MAX_TOKENS, stream = isStreamResponse };
        jsonString = JsonConvert.SerializeObject(jsonRequest, Formatting.Indented);
        Debug.Log(jsonString);

        return jsonString;
    }

    #region Stream Response 数据解析

    /*
     data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"克"},"finish_reason":null,"index":0,"logprobs":null}],"created":1718690676,"id":"chatcmpl-9bMFIE4gPNKU6Z1QyKvFsjwqNTOtw","model":"gpt-4o-2024-05-13","object":"chat.completion.chunk","system_fingerprint":"fp_abc28019ad"}
     */

    /// <summary>
    ///  流式处理数据
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    string HandleStreamData(string data)
    {
        try
        {
            string[] dataLines = data.Split(new string[] { "data: " }, StringSplitOptions.RemoveEmptyEntries);
            StringBuilder sb = new StringBuilder();
            foreach (var line in dataLines)
            {
                sb.Append(ProcessDataLine(line));
            }

            return sb.ToString();
        }
        catch (Exception e)
        {
            return null;
        }
        
    }

    /// <summary>
    /// 处理单行数据,解析获取 content,finish_reason 数据
    /// content : 回复内容
    /// finish_reason : 判断流式回答是否结束
    /// </summary>
    /// <param name="dataLine"></param>
    /// /// <returns></returns>
    string ProcessDataLine(string dataLine)
    {
        string content = ExtractField(dataLine, "\"content\":\"", "\"},");
        string finishReason = ExtractField(dataLine, "\"finish_reason\":", ",");

        Debug.Log(TAG + "ProcessDataLine():Content: " + content);
        content = content == null ? "" : content;
        // 排除这个情况 "delta":{"content":"","role":"assistant"},"finish_reason":null,"
        if(content.Contains("\"role\":\"assistant")) content="";

        if (finishReason!=null && finishReason == "\"stop\"")
        {
            Debug.Log(TAG+ "ProcessDataLine(): Finish reason is stop. Stopping further processing.");
            return "";  // 如果 finish_reason 是 stop,停止进一步处理
        }
        else
        {
            return content;
        }
    }

    /// <summary>
    /// 抽取块数据
    /// </summary>
    /// <param name="dataLine">行数据</param>
    /// <param name="fieldName">块名称</param>
    /// <param name="delimiter">分割符</param>
    /// <returns></returns>
    string ExtractField(string dataLine, string fieldName, string delimiter)
    {
        int fieldIndex = dataLine.IndexOf(fieldName);
        if (fieldIndex == -1)
        {
            return null;
        }

        int startIndex = fieldIndex + fieldName.Length;
        int endIndex = dataLine.IndexOf(delimiter, startIndex);
        if (endIndex == -1)
        {
            return dataLine.Substring(startIndex).Trim(' ', '}', ']');
        }

        return dataLine.Substring(startIndex, endIndex - startIndex);
    }

    #endregion

    #endregion

    #region JsonRequestStruct
    /* json 字符串
     {
        "messages": [
            { "role": "system", "content": "You are a helpful assistant." }, # Content can be a string, OR
            { "role": "user", "content": [       # It can be an array containing strings and images.
                "描述一下这张图,请用中文回答",
                { "image": "img_base64" }      # Images are represented like this.
            ] }
        ],
        "max_tokens": 100
    }   

     */

    /* 更新 json 字符串
     
        {
            "messages": [ 
                {
                    "role": "system", 
                    "content": "You are a helpful assistant." 
                },
                {
                    "role": "user", 
                    "content": [
	                    {
	                        "type": "text",
	                        "text": "Describe this picture:"
	                    },
	                    {
	                        "type": "image_url",
	                        "image_url": {
                                "url": "<image URL>"
                            }
                        } 
                   ] 
                }
            ],
            "max_tokens": 100, 
            "stream": false 
        }
     
     */

    public class JsonRequestStruct
    {
        public int max_tokens;
        public bool stream;
        public float temperature;
        public List<Message> messages;

    }

    public class Message
    {
        public string role;
        public object content; //这个是不规则的json 列表
    }

    #endregion

    #region JsonResponseStruct
    /* json 字符串
     {
	"id": "chatcmpl-8X0uY6Xbv4XpU4zo0KXhVk4iTldJf",
	"object": "chat.completion",
	"created": 1702879018,
	"model": "gpt-4v",
	"prompt_filter_results": [{
		"prompt_index": 0,
		"content_filter_results": {
			"hate": {
				"filtered": false,
				"severity": "safe"
			},
			"self_harm": {
				"filtered": false,
				"severity": "safe"
			},
			"sexual": {
				"filtered": false,
				"severity": "safe"
			},
			"violence": {
				"filtered": false,
				"severity": "safe"
			}
		}
	}],
	"choices": [{
		"finish_details": {
			"type": "stop",
			"stop": "<|fim_suffix|>"
		},
		"index": 0,
		"message": {
			"role": "assistant",
			"content": "这张图片展示了一辆银灰色的跑车,停靠在一个内饰精致的展厅里。车身呈流线型,前脸上有显著的品牌标志和数字“10”。车身上的漆面光洁明亮,反射着展厅内柔和的灯光。背景中可以看到其他几辆停放整齐的高端车辆,以及墙上挂着的一些装饰性画作。整个场景显得高端大气,彰显了跑车的豪华品质。"
		},
		"content_filter_results": {
			"hate": {
				"filtered": false,
				"severity": "safe"
			},
			"self_harm": {
				"filtered": false,
				"severity": "safe"
			},
			"sexual": {
				"filtered": false,
				"severity": "safe"
			},
			"violence": {
				"filtered": false,
				"severity": "safe"
			}
		}
	}],
	"usage": {
		"prompt_tokens": 826,
		"completion_tokens": 175,
		"total_tokens": 1001
	}
}
     */
    public class JsonResponseStruct
    {
        public string id { get; set; }
        public string @object { get; set; }
        public long created { get; set; }
        public string model { get; set; }
        public Usage usage { get; set; }
        public List<Choice> choices { get; set; }
        public List<PromptFilterResult> prompt_filter_results { get; set; }
    }

    public class Usage
    {
        public int prompt_tokens { get; set; }
        public int completion_tokens { get; set; }
        public int total_tokens { get; set; }
    }

    public class Choice
    {
        public RMessage message { get; set; }
        public FinishDetails finish_details { get; set; }
        public int index { get; set; }
        public ContentFilterResult content_filter_results { get; set; }
    }

    public class RMessage
    {
        public string role;
        public string content; //这个是不规则的json 列表
    }

    public class FinishDetails
    {
        public string type { get; set; }
        public string stop { get; set; }
    }

    public class PromptFilterResult
    {
        public int index { get; set; }
        public ContentFilterResult content_filter_results { get; set; }

    }

    public class ContentFilterResult
    {
        public FilterReuslt hate { get; set; }
        public FilterReuslt self_harm { get; set; }
        public FilterReuslt sexual { get; set; }
        public FilterReuslt violence { get; set; }
    }

    public class FilterReuslt
    {
        public bool filtered { get; set; }
        public string severity { get; set; }
    }

    #endregion
}

3、AzureGPT4o



public class AzureGPT4o : BaseAzureGpt4o
{
    /// <summary>
    /// TAG
    /// </summary>
    protected override string TAG { get; } = "[AzureGPT4o]";
    /// <summary>
    /// API_BASE
    /// </summary>
    protected override string API_BASE { get; } = "https://gpt4o-version.openai.azure.com/";
    /// <summary>
    /// DEPLOYMENT_NAME
    /// </summary>
    protected override string DEPLOYMENT_NAME { get; } = "Your_Deployment_Name";
    /// <summary>
    /// API_KEY
    /// </summary>
    protected override string API_KEY { get; } = "Your_API_Key";

    /// <summary>
    /// 对应模型接口的发行版本
    /// </summary>
    protected override string MODEL_VERSION { get; } = "2024-05-01-preview";

    /// <summary>
    /// 最大的 Tokens
    /// </summary>
    protected override int MAX_TOKENS { get; } = 300;
}

4、TestAzureGPT4o

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestAzureGPT4o : MonoBehaviour
{
    string TAG = "[TestAzureGPT4o] ";

    IAzureGpt4o m_AzureGpt4o;

    // Start is called before the first frame update
    void Start()
    {
        //TestGPT4o_Text();
        TestGPT4o_Image();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space)) {
            m_AzureGpt4o?.CancelRequest();
        }
    }

    async void TestGPT4o_Text()
    {
        m_AzureGpt4o = new AzureGPT4o();
        m_AzureGpt4o.OnSendRequestFailed = (err) => { Debug.Log(TAG + "TestGPT4o_Text(): OnSendRequestFailed err " + err); };
        m_AzureGpt4o.OnResponseFinished = (str) => { Debug.Log(TAG + "TestGPT4o_Text(): OnResponseFinished str " + str); };
        m_AzureGpt4o.OnResponsingData = (str) => { Debug.Log(TAG + "TestGPT4o_Text(): OnResponsingData str " + str); };
        string rlt = await m_AzureGpt4o.SendRequestAsync(
            "你好呀,你是谁?", 
            null);
        Debug.Log(TAG + "TestGPT4o_Text(): rlt " + rlt);
    }

    async void TestGPT4o_Image()
    {
        m_AzureGpt4o = new AzureGPT4o();
        m_AzureGpt4o.OnSendRequestFailed = (err) => { Debug.Log(TAG + "TestGPT4o_Image(): OnSendRequestFailed err " + err); };
        m_AzureGpt4o.OnResponseFinished = (str) => { Debug.Log(TAG + "TestGPT4o_Image(): OnResponseFinished str " + str); };
        m_AzureGpt4o.OnResponsingData = (str) => { Debug.Log(TAG + "TestGPT4o_Image(): OnResponsingData str " + str); };
        string rlt = await m_AzureGpt4o.SendRequestStreamResponseAsync(
            "描述一下",
            "https://d1.faiusr.com/4/AAEIABAEGAAggOra9AUooNDeiAEwoAY45gM.png");
        Debug.Log(TAG + "TestGPT4o_Image(): rlt " + rlt);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1842542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring系统学习 - FactoryBean和基于XML的自动装配

Factory Bean Spring的FactoryBean是一个特殊的Bean&#xff0c;用于创建其他Bean实例。FactoryBean接口定义了一个工厂Bean&#xff0c;该Bean可以用来生成其他Bean的实例。通过实现FactoryBean接口&#xff0c;开发人员可以自定义Bean的创建逻辑&#xff0c;实现更灵活的Bea…

动态竞拍与寄售模式:引领企业增长的新引擎

在当今日新月异的商业环境中&#xff0c;企业的生存与发展不仅需要卓越的产品和服务&#xff0c;更需要紧跟市场脉搏&#xff0c;勇于创新。接下来&#xff0c;我将为您详细介绍一种引领行业新风尚的商业模式——动态竞拍与寄售相结合的模式。这一模式凭借其灵活性和创新性&…

图像处理与视觉感知复习--频率域图像增强图像变换

文章目录 图像变换与信号分解正弦信号与傅里叶级数傅里叶变换离散傅里叶变换(DFT)频率域滤波 图像变换与信号分解 空间域&#xff1a;就是像素域&#xff0c;在空间域的处理是在像素级的处理&#xff0c;如像素级的叠加。 频率域&#xff1a;任何一个波形都可以分解用多个正弦…

【类型转换】C++中char、char*、int、string相互转换函数及string转不同进制数函数

参考资料&#xff1a;cplusplus官方资料strtol 函数用法 总结&#xff1a; 1、这些在做编程题处理输入数据时常用&#xff0c;需要牢记。

【CT】LeetCode手撕—23. 合并 K 个升序链表

目录 题目1- 思路2- 实现⭐23. 合并 K 个升序链表——题解思路 3- ACM 实现 题目 原题连接&#xff1a;23. 合并 K 个升序链表 1- 思路 模式识别&#xff1a;合并 K 个链表 ——> 优先队列 思路 借助优先队列&#xff0c;每次从 k 个链表中&#xff0c;各取一个元素&…

前 OpenAI 首席科学家建「安全超级智能」实验室;Meta 重组元宇宙团队丨 RTE 开发者日报 Vol.228

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「…

Cytoscape之操作界面介绍

Cytoscape 简介 Cytoscape是一个专注于开源网络可视化和分析的软件。软件的核心部分提供了网络显示、布局、查询等方面的基本功能。软件的核心可以通过插件架构进行扩展&#xff0c;这样就能快速地开发出新的功能。 Cytoscape 源自系统生物学&#xff0c;用于将生物分子交互网…

springboot+vue+mysql+mybatis 二手交易平台

springbootvuemysqlmybatis 二手交易平台 相关技术 javaspringbootmybatismysqlvueelementui

Jenkins For Windows编译构建C#项目环境搭建(完整版)

安装Jenkins 下载Windows安装包 官方下载地址 选择稳定版&#xff0c;这里下载的是最新版&#xff0c;如需下载指定版本点击 以前的发行版 配置java环境 下载 java jdk 17 jdk17官方下载链接 这里下载的是msi版本的安装包 安装jdk17 双击运行安装包&#xff0c;一直下…

企业微信内嵌H5项目接入聊天功能

产品需求是,在列表中把符合条件的列表接入聊天功能,以下是详细步骤: 1.引入企业微信 <script src"https://res.wx.qq.com/wwopen/js/jsapi/jweixin-1.0.0.js"></script> 2.获取wx签名(必须要) /*** 获取wx签名**/ export function getWxJsApi(data) {r…

通过Socket通信实现局域网下Amov无人机连接与数据传输

1.局域网下的通信 1.1 局域网 厂家提供的方式是通过Homer图数传工具(硬件)构建的amov局域网实现通信连接. 好处是通信距离足够长,支持150m;坏处是"局部",无法访问互联网. &#xff3b;&#xff29;&#xff2d;&#xff21;&#xff27;&#xff25;&#xff1a;…

使用Python进行音频处理和机器学习

使用Python进行音频处理和机器学习的简介 从高层次上讲&#xff0c;任何机器学习问题都可以分为三种任务&#xff1a;数据任务&#xff08;数据收集&#xff0c;数据清理和特征形成&#xff09;&#xff0c;培训&#xff08;使用数据特征构建机器学习模型&#xff09;和评估&am…

学习新语言方法总结(一)

随着工作时间越长&#xff0c;单一语言越来越难找工作了&#xff0c;需要不停地学习新语言来适应&#xff0c;总结一下自己学习新语言的方法&#xff0c;这次以GO为例&#xff0c;原来主语言是PHP &#xff0c;自学GO 了解语言特性&#xff0c;知道他是干嘛的 go语言&#xff0…

Pikachu靶场--XSS

参考借鉴 Pikachu靶场之XSS漏洞详解_pikachu xss-CSDN博客 一个视频讲清楚XSS跨站脚本&#xff08;CTF教程&#xff0c;Web安全渗透测试入门&#xff09;_bilibili 反射型xss(get) 输入payload&#xff1a;<script>alert(123)</script> 解决一&#xff1a;在URL框内…

安装MySQL5.7版本步骤遇到问题

方法一&#xff1a;下载zip版本&#xff08;我用的这个&#xff09; 参考视频&#xff08;已收藏&#xff09;&#xff1a;windows安装MySQL5.7_哔哩哔哩_bilibili 下载zip压缩包的MySQL的网址&#xff1a;上面这个视频中有哦。 my.ini文件内容如下&#xff1a; [client] p…

动手学自然语言处理:解读大模型背后的核心技术

自从 ChatGPT 横空出世以来&#xff0c;自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09; 研究领域就出现了一种消极的声音&#xff0c;认为大模型技术导致 NLP “死了”。在某乎上就有一条热门问答&#xff0c;大家热烈地讨论了这个问题。 有…

部署RAC到单实例ADG(11G)

服务器信息 主库RAC环境信息 主库RAC基本环境 节点1 节点2 OS centos 7.9 centos 7.9 数据库版本 11.2.0.4 11.2.0.4 规格 1C4G 1C4G 主机名 racdb01 racdb02 public ip 192.168.40.135 192.168.40.145 vip 192.168.40.13 192.168.40.14 private ip 192…

Pikachu靶场--文件上传

参考借鉴 Pikachu靶场之文件上传漏洞详解_皮卡丘文件上传漏洞-CSDN博客 文件上传漏洞&#xff1a;pikachu靶场中的文件上传漏洞通关_pikachu文件上传通关-CSDN博客 client check 在桌面新建一个文件夹&#xff0c;准备一个hello.php文件&#xff0c;文件写入如下代码 <?p…

【C++】类和对象(三)构造与析构

文章目录 一、类的6个默认成员函数二、 构造函数干嘛的&#xff1f;语法定义特性综上总结什么是默认构造函数&#xff1f; 三、析构函数干嘛的 &#xff1f;语法定义析构顺序 一、类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。空类中并不是真的什么…

还在为Android开发找不到图片测试资源发愁吗? DummyImage来助你加速开发

使用 DummyImage 模拟电影应用数据 在开发和测试过程中&#xff0c;模拟数据是不可或缺的工具。它可以帮助我们在没有真实数据的情况下测试应用程序的功能和性能。本文将介绍如何使用 [DummyImage]https://dummyimage.com生成占位符图像来模拟电影应用的数据&#xff0c;并深入…