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


    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 格式:

    1. {
    2. "messages": [
    3. {
    4. "role": "system",
    5. "content": "You are a helpful assistant."
    6. },
    7. {
    8. "role": "user",
    9. "content": [
    10. {
    11. "type": "text",
    12. "text": "Describe this picture:"
    13. },
    14. {
    15. "type": "image_url",
    16. "image_url": {
    17. "url": ""
    18. }
    19. }
    20. ]
    21. }
    22. ],
    23. "max_tokens": 100,
    24. "stream": false
    25. }

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

    非流式的:

    1. {
    2. "id": "chatcmpl-8X0uY6Xbv4XpU4zo0KXhVk4iTldJf",
    3. "object": "chat.completion",
    4. "created": 1702879018,
    5. "model": "gpt-4v",
    6. "prompt_filter_results": [{
    7. "prompt_index": 0,
    8. "content_filter_results": {
    9. "hate": {
    10. "filtered": false,
    11. "severity": "safe"
    12. },
    13. "self_harm": {
    14. "filtered": false,
    15. "severity": "safe"
    16. },
    17. "sexual": {
    18. "filtered": false,
    19. "severity": "safe"
    20. },
    21. "violence": {
    22. "filtered": false,
    23. "severity": "safe"
    24. }
    25. }
    26. }],
    27. "choices": [{
    28. "finish_details": {
    29. "type": "stop",
    30. "stop": "<|fim_suffix|>"
    31. },
    32. "index": 0,
    33. "message": {
    34. "role": "assistant",
    35. "content": "这张图片展示了一辆银灰色的跑车,停靠在一个内饰精致的展厅里。车身呈流线型,前脸上有显著的品牌标志和数字“10”。车身上的漆面光洁明亮,反射着展厅内柔和的灯光。背景中可以看到其他几辆停放整齐的高端车辆,以及墙上挂着的一些装饰性画作。整个场景显得高端大气,彰显了跑车的豪华品质。"
    36. },
    37. "content_filter_results": {
    38. "hate": {
    39. "filtered": false,
    40. "severity": "safe"
    41. },
    42. "self_harm": {
    43. "filtered": false,
    44. "severity": "safe"
    45. },
    46. "sexual": {
    47. "filtered": false,
    48. "severity": "safe"
    49. },
    50. "violence": {
    51. "filtered": false,
    52. "severity": "safe"
    53. }
    54. }
    55. }],
    56. "usage": {
    57. "prompt_tokens": 826,
    58. "completion_tokens": 175,
    59. "total_tokens": 1001
    60. }
    61. }

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

    1. 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":[]}}}]}
    2. 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"}
    3. 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"}
    4. 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"}
    5. 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"}
    6. 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"}
    7. 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"}
    8. 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"}
    9. 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"}
    10. 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"}
    11. 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"}
    12. 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"}
    13. 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"}
    14. 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"}
    15. 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"}
    16. 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"}
    17. 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"}
    18. 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"}
    19. 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"}
    20. 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"}
    21. 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"}
    22. 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"}
    23. 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"}
    24. 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"}
    25. 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"}
    26. 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"}
    27. 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"}
    28. 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"}
    29. 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"}
    30. 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"}
    31. 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"}
    32. 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"}
    33. 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"}
    34. 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"}
    35. 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"}
    36. 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"}
    37. 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"}
    38. 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"}
    39. 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"}
    40. 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"}
    41. 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"}
    42. 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"}
    43. data: [DONE]

    二、实现原理

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

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

    1. // 发送请求并获取响应
    2. 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,

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

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

    1. public class JsonRequestStruct
    2. {
    3. public int max_tokens;
    4. public bool stream;
    5. public float temperature;
    6. public List messages;
    7. }
    8. public class Message
    9. {
    10. public string role;
    11. public object content; //这个是不规则的json 列表
    12. }

    四、简单效果预览

    五、案例简单实现步骤

    1、新建 Unity 工程

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

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

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

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

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

    六、关键代码

    1、IAzureGpt4o

    1. using System;
    2. using System.Threading.Tasks;
    3. public interface IAzureGpt4o
    4. {
    5. ///
    6. /// 请求失败的回调
    7. ///
    8. Action<string> OnSendRequestFailed { get; set; }
    9. ///
    10. /// 响应的流式数据
    11. ///
    12. Action<string> OnResponsingData { get; set; }
    13. ///
    14. /// 响应接收完的数据
    15. ///
    16. Action<string> OnResponseFinished { get; set; }
    17. ///
    18. /// 发送请求
    19. ///
    20. ///
    21. /// 图片数据,支持 url/base64
    22. ///
    23. Task<string> SendRequestAsync(string askContent, string imgData);
    24. ///
    25. /// 发送请求(流式返回数据)
    26. ///
    27. ///
    28. /// 图片数据,支持 url/base64
    29. ///
    30. Task<string> SendRequestStreamResponseAsync(string askContent, string imgData);
    31. ///
    32. /// Helper function to cancel the ongoing request
    33. ///
    34. public void CancelRequest();
    35. }

    2、BaseAzureGpt4o

    1. using Newtonsoft.Json;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Net;
    5. using System.Text.RegularExpressions;
    6. using System.Text;
    7. using UnityEngine;
    8. using System;
    9. using System.Threading.Tasks;
    10. using System.Threading;
    11. using System.Net.Http;
    12. ///
    13. /// GPT 4o 基类
    14. ///
    15. ///
    16. public class BaseAzureGpt4o : IAzureGpt4o
    17. {
    18. #region Data
    19. ///
    20. /// TAG
    21. ///
    22. protected virtual string TAG { get; } = "[BaseAzureGpt4o]";
    23. ///
    24. /// API_BASE
    25. ///
    26. protected virtual string API_BASE { get; } = "https://gpt4o-version.openai.azure.com/";
    27. ///
    28. /// DEPLOYMENT_NAME
    29. ///
    30. protected virtual string DEPLOYMENT_NAME { get; } = "Your_Deplyment_Name";
    31. ///
    32. /// API_KEY
    33. ///
    34. protected virtual string API_KEY { get; } = "YOur_API_Key";
    35. ///
    36. /// 对应模型接口的发行版本
    37. ///
    38. protected virtual string MODEL_VERSION { get; } = "2024-05-01-preview";
    39. ///
    40. /// 组织基础的 Url
    41. ///
    42. protected virtual string m_BaseUrl { get{ return $"{API_BASE}/openai/deployments/{DEPLOYMENT_NAME}"; } }
    43. ///
    44. /// 组成最后访问的 Url
    45. ///
    46. protected virtual string m_EndPointend { get {return $"{m_BaseUrl}/chat/completions?api-version={MODEL_VERSION}"; } }
    47. ///
    48. /// 最大的 Tokens
    49. ///
    50. protected virtual int MAX_TOKENS { get; } = 100;
    51. ///
    52. /// 请求失败的回调
    53. ///
    54. public Action<string> OnSendRequestFailed { get; set; }
    55. ///
    56. /// 响应的流式数据
    57. ///
    58. public Action<string> OnResponsingData { get; set; }
    59. ///
    60. /// 响应接收完的数据
    61. ///
    62. public Action<string> OnResponseFinished { get; set; }
    63. ///
    64. /// CancellationTokenSource
    65. ///
    66. private CancellationTokenSource cancellationTokenSource;
    67. ///
    68. /// HttpClient
    69. ///
    70. private static readonly HttpClient client = new HttpClient();
    71. #endregion
    72. #region Inteface function
    73. ///
    74. /// 发送请求(正常返回数据)
    75. ///
    76. ///
    77. /// 图片数据,支持 url/base64
    78. ///
    79. public virtual async Task<string> SendRequestAsync(string askContent, string imgData)
    80. {
    81. Debug.Log(TAG + "Start HttpWebRequest m_EndPointend : " + m_EndPointend);
    82. cancellationTokenSource = new CancellationTokenSource();
    83. CancellationToken cancellationToken = cancellationTokenSource.Token;
    84. // json 数据
    85. string jsonData = GetJsonStr(askContent, imgData);
    86. /// 设置请求头
    87. client.DefaultRequestHeaders.Clear();
    88. client.DefaultRequestHeaders.Add("api-key", API_KEY);
    89. // 创建 HTTP 内容
    90. var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
    91. try
    92. {
    93. // 创建请求
    94. var request = new HttpRequestMessage(HttpMethod.Post, m_EndPointend)
    95. {
    96. Content = content
    97. };
    98. // 发送请求并获取响应
    99. HttpResponseMessage response = await client.SendAsync(request, cancellationToken);
    100. // 检查响应状态码
    101. if (response.IsSuccessStatusCode)
    102. {
    103. // 读取整个响应内容
    104. string responseText = await response.Content.ReadAsStringAsync();
    105. if (cancellationToken.IsCancellationRequested)
    106. {
    107. Debug.Log(TAG + "Operation was canceled.");
    108. OnSendRequestFailed?.Invoke("Operation was canceled.");
    109. return null; // 或抛出异常,根据需要处理
    110. }
    111. Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + responseText);
    112. string jsonString = DecodeUnicode(responseText);
    113. string parseWholeRlt;
    114. // 使用 Newtonsoft.Json 将 JSON 字符串映射到对应的对象
    115. JsonResponseStruct data = JsonConvert.DeserializeObject(jsonString);
    116. if (data != null)
    117. {
    118. parseWholeRlt = data.choices[0].message.content.ToString();
    119. Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + parseWholeRlt);
    120. }
    121. else
    122. {
    123. Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + jsonString);
    124. parseWholeRlt = jsonString;
    125. }
    126. if (OnResponseFinished != null)
    127. {
    128. Debug.Log(TAG + " PostRequestStreamToStringAsync OnResponseFinished is not null ");
    129. OnResponseFinished?.Invoke(parseWholeRlt);
    130. }
    131. else
    132. {
    133. Debug.Log(TAG + " PostRequestStreamToStringAsync OnResponseFinished is null ");
    134. }
    135. return parseWholeRlt;
    136. }
    137. else
    138. {
    139. // 打印错误状态码
    140. Debug.LogError(TAG + "Error: " + response.StatusCode);
    141. OnSendRequestFailed?.Invoke(response.Content.ToString());
    142. return null;
    143. }
    144. }
    145. catch (OperationCanceledException e)
    146. {
    147. Debug.Log(TAG + "Operation was canceled. " + e.Message);
    148. OnSendRequestFailed?.Invoke(e.Message);
    149. return null; // 或抛出异常,根据需要处理
    150. }
    151. catch (WebException e)
    152. {
    153. Debug.Log(TAG + " e.Message: " + e.Message);
    154. OnSendRequestFailed?.Invoke(e.Message);
    155. return null;
    156. }
    157. }
    158. ///
    159. /// 发送请求(流式返回数据)
    160. ///
    161. ///
    162. /// 图片数据,支持 url/base64
    163. ///
    164. public virtual async Task<string> SendRequestStreamResponseAsync(string askContent, string imgData) {
    165. Debug.Log(TAG + "Start HttpWebRequest m_EndPointend : " + m_EndPointend);
    166. cancellationTokenSource = new CancellationTokenSource();
    167. CancellationToken cancellationToken = cancellationTokenSource.Token;
    168. // json 数据
    169. string jsonData = GetJsonStr(askContent, imgData, true);
    170. /// 设置请求头
    171. client.DefaultRequestHeaders.Clear();
    172. client.DefaultRequestHeaders.Add("api-key", API_KEY);
    173. // 创建 HTTP 内容
    174. var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
    175. try
    176. {
    177. // 创建请求
    178. var request = new HttpRequestMessage(HttpMethod.Post, m_EndPointend)
    179. {
    180. Content = content
    181. };
    182. // 发送请求并获取响应头
    183. HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
    184. // 检查响应状态码
    185. if (response.IsSuccessStatusCode)
    186. {
    187. // 以流的方式读取响应内容
    188. using (var stream = await response.Content.ReadAsStreamAsync())
    189. {
    190. using (var reader = new StreamReader(stream))
    191. {
    192. StringBuilder sb = new StringBuilder();
    193. string line;
    194. while ((line = await reader.ReadLineAsync()) != null)
    195. {
    196. string parseRlt = HandleStreamData(line);
    197. if (string.IsNullOrEmpty(parseRlt) == false)
    198. {
    199. OnResponsingData?.Invoke(parseRlt);
    200. }
    201. sb.AppendLine(line); // 逐行读取并累积响应数据
    202. Debug.Log(TAG + " PostRequestStreamToStringAsync getting steam data : " + sb.ToString());
    203. // Check for cancellation
    204. if (cancellationToken.IsCancellationRequested)
    205. {
    206. Debug.Log(TAG + "Operation was canceled.");
    207. return null; // or throw an exception, handle as needed
    208. }
    209. }
    210. Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + sb.ToString());
    211. string jsonString = DecodeUnicode(sb.ToString());
    212. string parseWholeRlt = HandleStreamData(jsonString);
    213. Debug.Log(TAG + " PostRequestStreamToStringAsync whole stream data : " + parseWholeRlt);
    214. if (OnResponseFinished != null)
    215. {
    216. Debug.Log(TAG + " PostRequestStreamToStringAsync OnResponseFinished is not null ");
    217. OnResponseFinished?.Invoke(parseWholeRlt);
    218. }
    219. else
    220. {
    221. Debug.Log(TAG + " PostRequestStreamToStringAsync OnResponseFinished is null ");
    222. }
    223. return parseWholeRlt;
    224. }
    225. }
    226. }
    227. else
    228. {
    229. // 打印错误状态码
    230. Debug.LogError(TAG + "Error: " + response.StatusCode);
    231. OnSendRequestFailed?.Invoke(response.Content.ToString());
    232. return null;
    233. }
    234. }
    235. catch (OperationCanceledException e)
    236. {
    237. Debug.Log(TAG + "Operation was canceled. " + e.Message);
    238. OnSendRequestFailed?.Invoke(e.Message);
    239. return null; // or throw an exception, handle as needed
    240. }
    241. catch (WebException e)
    242. {
    243. Debug.Log(TAG + " e.Message: " + e.Message);
    244. OnSendRequestFailed?.Invoke(e.Message);
    245. return null;
    246. }
    247. }
    248. ///
    249. /// Helper function to cancel the ongoing request
    250. ///
    251. public virtual void CancelRequest()
    252. {
    253. if (cancellationTokenSource != null && !cancellationTokenSource.IsCancellationRequested)
    254. {
    255. cancellationTokenSource.Cancel();
    256. }
    257. }
    258. #endregion
    259. #region Protected function
    260. ///
    261. /// 将 Unicode 转义字符解码为 UTF-8 字符串的方法
    262. ///
    263. ///
    264. ///
    265. protected string DecodeUnicode(string input)
    266. {
    267. return Regex.Replace(input, @"\\u([0-9a-fA-F]{4})", match =>
    268. {
    269. string hex = match.Groups[1].Value;
    270. int codePoint = Convert.ToInt32(hex, 16);
    271. return char.ConvertFromUtf32(codePoint);
    272. });
    273. }
    274. ///
    275. /// 组织提问和图片数据
    276. ///
    277. ///
    278. ///
    279. /// 是否流式响应返回数据
    280. ///
    281. protected string GetJsonStr(string askContent, string imgBase64OrUrlg, bool isStreamResponse = false)
    282. {
    283. List<object> contentList = new List<object>();
    284. contentList.Add(new
    285. {
    286. type = "text",
    287. text = askContent,
    288. });
    289. if (imgBase64OrUrlg != null)
    290. {
    291. // 创建一个包含指定数据结构的对象列表
    292. contentList.Add(new
    293. {
    294. type = "image_url",
    295. image_url = new
    296. {
    297. url = imgBase64OrUrlg
    298. },
    299. });
    300. }
    301. // 将对象列表转换为 JSON 字符串
    302. string jsonString = JsonConvert.SerializeObject(contentList, Formatting.Indented);
    303. Message messageS = new Message() { role = "system", content = "You are a helpful assistant." };
    304. Message message = new Message() { role = "user", content = contentList };
    305. List messages = new List();
    306. messages.Add(messageS);
    307. messages.Add(message);
    308. JsonRequestStruct jsonRequest = new JsonRequestStruct() { messages = messages, max_tokens = MAX_TOKENS, stream = isStreamResponse };
    309. jsonString = JsonConvert.SerializeObject(jsonRequest, Formatting.Indented);
    310. Debug.Log(jsonString);
    311. return jsonString;
    312. }
    313. #region Stream Response 数据解析
    314. /*
    315. 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"}
    316. */
    317. ///
    318. /// 流式处理数据
    319. ///
    320. ///
    321. ///
    322. string HandleStreamData(string data)
    323. {
    324. try
    325. {
    326. string[] dataLines = data.Split(new string[] { "data: " }, StringSplitOptions.RemoveEmptyEntries);
    327. StringBuilder sb = new StringBuilder();
    328. foreach (var line in dataLines)
    329. {
    330. sb.Append(ProcessDataLine(line));
    331. }
    332. return sb.ToString();
    333. }
    334. catch (Exception e)
    335. {
    336. return null;
    337. }
    338. }
    339. ///
    340. /// 处理单行数据,解析获取 content,finish_reason 数据
    341. /// content : 回复内容
    342. /// finish_reason : 判断流式回答是否结束
    343. ///
    344. ///
    345. /// ///
    346. string ProcessDataLine(string dataLine)
    347. {
    348. string content = ExtractField(dataLine, "\"content\":\"", "\"},");
    349. string finishReason = ExtractField(dataLine, "\"finish_reason\":", ",");
    350. Debug.Log(TAG + "ProcessDataLine():Content: " + content);
    351. content = content == null ? "" : content;
    352. // 排除这个情况 "delta":{"content":"","role":"assistant"},"finish_reason":null,"
    353. if(content.Contains("\"role\":\"assistant")) content="";
    354. if (finishReason!=null && finishReason == "\"stop\"")
    355. {
    356. Debug.Log(TAG+ "ProcessDataLine(): Finish reason is stop. Stopping further processing.");
    357. return ""; // 如果 finish_reason 是 stop,停止进一步处理
    358. }
    359. else
    360. {
    361. return content;
    362. }
    363. }
    364. ///
    365. /// 抽取块数据
    366. ///
    367. /// 行数据
    368. /// 块名称
    369. /// 分割符
    370. ///
    371. string ExtractField(string dataLine, string fieldName, string delimiter)
    372. {
    373. int fieldIndex = dataLine.IndexOf(fieldName);
    374. if (fieldIndex == -1)
    375. {
    376. return null;
    377. }
    378. int startIndex = fieldIndex + fieldName.Length;
    379. int endIndex = dataLine.IndexOf(delimiter, startIndex);
    380. if (endIndex == -1)
    381. {
    382. return dataLine.Substring(startIndex).Trim(' ', '}', ']');
    383. }
    384. return dataLine.Substring(startIndex, endIndex - startIndex);
    385. }
    386. #endregion
    387. #endregion
    388. #region JsonRequestStruct
    389. /* json 字符串
    390. {
    391. "messages": [
    392. { "role": "system", "content": "You are a helpful assistant." }, # Content can be a string, OR
    393. { "role": "user", "content": [ # It can be an array containing strings and images.
    394. "描述一下这张图,请用中文回答",
    395. { "image": "img_base64" } # Images are represented like this.
    396. ] }
    397. ],
    398. "max_tokens": 100
    399. }
    400. */
    401. /* 更新 json 字符串
    402. {
    403. "messages": [
    404. {
    405. "role": "system",
    406. "content": "You are a helpful assistant."
    407. },
    408. {
    409. "role": "user",
    410. "content": [
    411. {
    412. "type": "text",
    413. "text": "Describe this picture:"
    414. },
    415. {
    416. "type": "image_url",
    417. "image_url": {
    418. "url": ""
    419. }
    420. }
    421. ]
    422. }
    423. ],
    424. "max_tokens": 100,
    425. "stream": false
    426. }
    427. */
    428. public class JsonRequestStruct
    429. {
    430. public int max_tokens;
    431. public bool stream;
    432. public float temperature;
    433. public List messages;
    434. }
    435. public class Message
    436. {
    437. public string role;
    438. public object content; //这个是不规则的json 列表
    439. }
    440. #endregion
    441. #region JsonResponseStruct
    442. /* json 字符串
    443. {
    444. "id": "chatcmpl-8X0uY6Xbv4XpU4zo0KXhVk4iTldJf",
    445. "object": "chat.completion",
    446. "created": 1702879018,
    447. "model": "gpt-4v",
    448. "prompt_filter_results": [{
    449. "prompt_index": 0,
    450. "content_filter_results": {
    451. "hate": {
    452. "filtered": false,
    453. "severity": "safe"
    454. },
    455. "self_harm": {
    456. "filtered": false,
    457. "severity": "safe"
    458. },
    459. "sexual": {
    460. "filtered": false,
    461. "severity": "safe"
    462. },
    463. "violence": {
    464. "filtered": false,
    465. "severity": "safe"
    466. }
    467. }
    468. }],
    469. "choices": [{
    470. "finish_details": {
    471. "type": "stop",
    472. "stop": "<|fim_suffix|>"
    473. },
    474. "index": 0,
    475. "message": {
    476. "role": "assistant",
    477. "content": "这张图片展示了一辆银灰色的跑车,停靠在一个内饰精致的展厅里。车身呈流线型,前脸上有显著的品牌标志和数字“10”。车身上的漆面光洁明亮,反射着展厅内柔和的灯光。背景中可以看到其他几辆停放整齐的高端车辆,以及墙上挂着的一些装饰性画作。整个场景显得高端大气,彰显了跑车的豪华品质。"
    478. },
    479. "content_filter_results": {
    480. "hate": {
    481. "filtered": false,
    482. "severity": "safe"
    483. },
    484. "self_harm": {
    485. "filtered": false,
    486. "severity": "safe"
    487. },
    488. "sexual": {
    489. "filtered": false,
    490. "severity": "safe"
    491. },
    492. "violence": {
    493. "filtered": false,
    494. "severity": "safe"
    495. }
    496. }
    497. }],
    498. "usage": {
    499. "prompt_tokens": 826,
    500. "completion_tokens": 175,
    501. "total_tokens": 1001
    502. }
    503. }
    504. */
    505. public class JsonResponseStruct
    506. {
    507. public string id { get; set; }
    508. public string @object { get; set; }
    509. public long created { get; set; }
    510. public string model { get; set; }
    511. public Usage usage { get; set; }
    512. public List choices { get; set; }
    513. public List prompt_filter_results { get; set; }
    514. }
    515. public class Usage
    516. {
    517. public int prompt_tokens { get; set; }
    518. public int completion_tokens { get; set; }
    519. public int total_tokens { get; set; }
    520. }
    521. public class Choice
    522. {
    523. public RMessage message { get; set; }
    524. public FinishDetails finish_details { get; set; }
    525. public int index { get; set; }
    526. public ContentFilterResult content_filter_results { get; set; }
    527. }
    528. public class RMessage
    529. {
    530. public string role;
    531. public string content; //这个是不规则的json 列表
    532. }
    533. public class FinishDetails
    534. {
    535. public string type { get; set; }
    536. public string stop { get; set; }
    537. }
    538. public class PromptFilterResult
    539. {
    540. public int index { get; set; }
    541. public ContentFilterResult content_filter_results { get; set; }
    542. }
    543. public class ContentFilterResult
    544. {
    545. public FilterReuslt hate { get; set; }
    546. public FilterReuslt self_harm { get; set; }
    547. public FilterReuslt sexual { get; set; }
    548. public FilterReuslt violence { get; set; }
    549. }
    550. public class FilterReuslt
    551. {
    552. public bool filtered { get; set; }
    553. public string severity { get; set; }
    554. }
    555. #endregion
    556. }

    3、AzureGPT4o

    1. public class AzureGPT4o : BaseAzureGpt4o
    2. {
    3. ///
    4. /// TAG
    5. ///
    6. protected override string TAG { get; } = "[AzureGPT4o]";
    7. ///
    8. /// API_BASE
    9. ///
    10. protected override string API_BASE { get; } = "https://gpt4o-version.openai.azure.com/";
    11. ///
    12. /// DEPLOYMENT_NAME
    13. ///
    14. protected override string DEPLOYMENT_NAME { get; } = "Your_Deployment_Name";
    15. ///
    16. /// API_KEY
    17. ///
    18. protected override string API_KEY { get; } = "Your_API_Key";
    19. ///
    20. /// 对应模型接口的发行版本
    21. ///
    22. protected override string MODEL_VERSION { get; } = "2024-05-01-preview";
    23. ///
    24. /// 最大的 Tokens
    25. ///
    26. protected override int MAX_TOKENS { get; } = 300;
    27. }

    4、TestAzureGPT4o

    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class TestAzureGPT4o : MonoBehaviour
    5. {
    6. string TAG = "[TestAzureGPT4o] ";
    7. IAzureGpt4o m_AzureGpt4o;
    8. // Start is called before the first frame update
    9. void Start()
    10. {
    11. //TestGPT4o_Text();
    12. TestGPT4o_Image();
    13. }
    14. // Update is called once per frame
    15. void Update()
    16. {
    17. if (Input.GetKeyDown(KeyCode.Space)) {
    18. m_AzureGpt4o?.CancelRequest();
    19. }
    20. }
    21. async void TestGPT4o_Text()
    22. {
    23. m_AzureGpt4o = new AzureGPT4o();
    24. m_AzureGpt4o.OnSendRequestFailed = (err) => { Debug.Log(TAG + "TestGPT4o_Text(): OnSendRequestFailed err " + err); };
    25. m_AzureGpt4o.OnResponseFinished = (str) => { Debug.Log(TAG + "TestGPT4o_Text(): OnResponseFinished str " + str); };
    26. m_AzureGpt4o.OnResponsingData = (str) => { Debug.Log(TAG + "TestGPT4o_Text(): OnResponsingData str " + str); };
    27. string rlt = await m_AzureGpt4o.SendRequestAsync(
    28. "你好呀,你是谁?",
    29. null);
    30. Debug.Log(TAG + "TestGPT4o_Text(): rlt " + rlt);
    31. }
    32. async void TestGPT4o_Image()
    33. {
    34. m_AzureGpt4o = new AzureGPT4o();
    35. m_AzureGpt4o.OnSendRequestFailed = (err) => { Debug.Log(TAG + "TestGPT4o_Image(): OnSendRequestFailed err " + err); };
    36. m_AzureGpt4o.OnResponseFinished = (str) => { Debug.Log(TAG + "TestGPT4o_Image(): OnResponseFinished str " + str); };
    37. m_AzureGpt4o.OnResponsingData = (str) => { Debug.Log(TAG + "TestGPT4o_Image(): OnResponsingData str " + str); };
    38. string rlt = await m_AzureGpt4o.SendRequestStreamResponseAsync(
    39. "描述一下",
    40. "https://d1.faiusr.com/4/AAEIABAEGAAggOra9AUooNDeiAEwoAY45gM.png");
    41. Debug.Log(TAG + "TestGPT4o_Image(): rlt " + rlt);
    42. }
    43. }

  • 相关阅读:
    GE千兆以太网光口模式协商原理
    0x61c88647斐波那契数列
    UOS服务器操作系统部署EFK
    LeetCode 2342. 数位和相等数对的最大和
    源表应用之四探针法测量半导体电阻率
    转换流,序列化和反序列化,transient关键字笔记
    【大型电商项目开发】性能压测-压力测试基本概念&JMeter-38
    爬虫(五)
    【物联网开发】机智云App远程电机PWM调速
    尚硅谷Git学习笔记
  • 原文地址:https://blog.csdn.net/u014361280/article/details/139826894