custom-transformer.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. <script setup lang="ts">
  2. import { TagsOutlined } from '@ant-design/icons-vue';
  3. import { Button, Flex } from 'ant-design-vue';
  4. import { ThoughtChain, type ThoughtChainItem, XRequest } from 'ant-design-x-vue';
  5. import { ref, h } from 'vue';
  6. defineOptions({ name: 'AXXRequestCustomTransformerSetup' });
  7. const BASE_URL = 'https://api.example.host';
  8. const PATH = '/chat';
  9. const MODEL = 'gpt-4o';
  10. const ND_JSON_SEPARATOR = '\n';
  11. async function mockFetch() {
  12. const ndJsonData = `{data:{"id":"0","choices":[{"index":0,"delta":{"content":"Hello","role":"assistant"}}],"created":1733129200,"model":"gpt-4o"}}
  13. {data:{"id":"1","choices":[{"index":1,"delta":{"content":"world!","role":"assistant"}}],"created":1733129300,"model":"gpt-4o"}}
  14. {data:{"id":"2","choices":[{"index":2,"delta":{"content":"I","role":"assistant"}}],"created":1733129400,"model":"gpt-4o"}}
  15. {data:{"id":"3","choices":[{"index":3,"delta":{"content":"am","role":"assistant"}}],"created":1733129500,"model":"gpt-4o"}}
  16. {data:{"id":"4","choices":[{"index":4,"delta":{"content":"Ant Design X!","role":"assistant"}}],"created":1733129600,"model":"gpt-4o"}}`;
  17. const chunks = ndJsonData.split(ND_JSON_SEPARATOR);
  18. const response = new Response(
  19. new ReadableStream({
  20. async start(controller) {
  21. for (const chunk of chunks) {
  22. await new Promise((resolve) => setTimeout(resolve, 100));
  23. controller.enqueue(new TextEncoder().encode(chunk));
  24. }
  25. controller.close();
  26. },
  27. }),
  28. {
  29. headers: {
  30. 'Content-Type': 'application/x-ndjson',
  31. },
  32. },
  33. );
  34. return response;
  35. }
  36. const exampleRequest = XRequest({
  37. baseURL: BASE_URL + PATH,
  38. model: MODEL,
  39. fetch: mockFetch,
  40. });
  41. const status = ref<ThoughtChainItem['status']>();
  42. const lines = ref<string[]>([]);
  43. async function request() {
  44. status.value = 'pending';
  45. await exampleRequest.create(
  46. {
  47. messages: [{ role: 'user', content: 'hello, who are u?' }],
  48. stream: true,
  49. },
  50. {
  51. onSuccess: (messages) => {
  52. status.value = 'success';
  53. console.log('onSuccess', messages);
  54. },
  55. onError: (error) => {
  56. status.value = 'error';
  57. console.error('onError', error);
  58. },
  59. onUpdate: (msg) => {
  60. lines.value = [...lines.value, msg];
  61. console.log('onUpdate', msg);
  62. },
  63. },
  64. new TransformStream < string, string > ({
  65. transform(chunk, controller) {
  66. controller.enqueue(chunk);
  67. },
  68. }),
  69. );
  70. }
  71. </script>
  72. <template>
  73. <Flex
  74. align="start"
  75. gap="16"
  76. :style="{ overflow: 'auto' }"
  77. >
  78. <Button
  79. type="primary"
  80. :disabled="status === 'pending'"
  81. @click="request"
  82. >
  83. {{ `Request - ${BASE_URL + PATH}` }}
  84. </Button>
  85. <ThoughtChain
  86. :items="[
  87. {
  88. title: 'Mock Custom Protocol - Log',
  89. status: status,
  90. icon: h(TagsOutlined),
  91. content: h('pre', { style: { overflow: 'scroll' } }, [
  92. h('code', lines.join(ND_JSON_SEPARATOR))
  93. ]),
  94. },
  95. ]"
  96. />
  97. </Flex>
  98. </template>