suggestions.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <script setup lang="ts">
  2. import { SmileOutlined, UserOutlined } from '@ant-design/icons-vue';
  3. import { Flex } from 'ant-design-vue';
  4. import { Bubble, Prompts, Sender, useXAgent, useXChat, type BubbleListProps } from 'ant-design-x-vue';
  5. import { ref, h } from 'vue';
  6. defineOptions({ name: 'AXUseXChatSuggestionsSetup' });
  7. const sleep = () => new Promise((resolve) => setTimeout(resolve, 1000));
  8. const roles: BubbleListProps['roles'] = {
  9. user: {
  10. placement: 'end',
  11. avatar: { icon: UserOutlined, style: { background: '#87d068' } },
  12. },
  13. text: {
  14. placement: 'start',
  15. avatar: { icon: UserOutlined, style: { background: '#fde3cf' } },
  16. typing: true,
  17. },
  18. suggestion: {
  19. placement: 'start',
  20. avatar: { icon: UserOutlined, style: { visibility: 'hidden' } },
  21. variant: 'borderless',
  22. messageRender: (content) => h(Prompts, {
  23. vertical: true,
  24. items: (content as any as string[]).map((text) => ({
  25. key: text,
  26. icon: h(SmileOutlined, { style: { color: '#FAAD14' } }),
  27. description: text,
  28. }))
  29. }),
  30. },
  31. };
  32. type AgentUserMessage = {
  33. type: 'user';
  34. content: string;
  35. };
  36. type AgentAIMessage = {
  37. type: 'ai';
  38. content?: string;
  39. list?: (
  40. | {
  41. type: 'text';
  42. content: string;
  43. }
  44. | {
  45. type: 'suggestion';
  46. content: string[];
  47. }
  48. )[];
  49. };
  50. type AgentMessage = AgentUserMessage | AgentAIMessage;
  51. type BubbleMessage = {
  52. role: string;
  53. };
  54. const content = ref('');
  55. const senderLoading = ref(false);
  56. // Agent for request
  57. const [ agent ] = useXAgent<AgentMessage>({
  58. request: async ({ message }, { onSuccess }) => {
  59. senderLoading.value = true;
  60. await sleep();
  61. const { content } = message || {};
  62. senderLoading.value = false;
  63. onSuccess({
  64. type: 'ai',
  65. list: [
  66. {
  67. type: 'text',
  68. content: `Do you want?`,
  69. },
  70. {
  71. type: 'suggestion',
  72. content: [`Look at: ${content}`, `Search: ${content}`, `Try: ${content}`],
  73. },
  74. ],
  75. });
  76. },
  77. });
  78. // Chat messages
  79. const { onRequest, parsedMessages } = useXChat<AgentMessage, BubbleMessage>({
  80. agent: agent.value,
  81. defaultMessages: [
  82. {
  83. id: 'init',
  84. message: {
  85. type: 'ai',
  86. content: 'Hello, what can I do for you?',
  87. },
  88. status: 'success',
  89. },
  90. ],
  91. requestPlaceholder: {
  92. type: 'ai',
  93. content: 'Waiting...',
  94. },
  95. // Convert AgentMessage to BubbleMessage
  96. parser: (agentMessages) => {
  97. const list = agentMessages.content ? [agentMessages] : (agentMessages as AgentAIMessage).list;
  98. return (list || []).map((msg) => ({
  99. role: msg.type,
  100. content: msg.content,
  101. }));
  102. },
  103. });
  104. </script>
  105. <template>
  106. <Flex
  107. vertical
  108. gap="middle"
  109. >
  110. <Bubble.List
  111. :roles="roles"
  112. :style="{ maxHeight: 300 }"
  113. :items="parsedMessages.map(({ id, message, status }) => ({
  114. key: id,
  115. loading: status === 'loading',
  116. ...message,
  117. }))"
  118. />
  119. <Sender
  120. :loading="senderLoading"
  121. :value="content"
  122. :on-change="(v) => content = v"
  123. :on-submit="(nextContent) => {
  124. onRequest({
  125. type: 'user',
  126. content: nextContent,
  127. });
  128. content = '';
  129. }"
  130. />
  131. </Flex>
  132. </template>