processResponse.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { Screenplay, textsToScreenplay } from "@/features/chat/messages";
  2. export type ProcessResponseRetVal = {
  3. sentences: string[];
  4. aiTextLog: string;
  5. receivedMessage: string;
  6. tag: string;
  7. isThinking: boolean;
  8. rolePlay: string;
  9. shouldBreak: boolean;
  10. }
  11. // this function is used to process the response from the AI
  12. // it will call callback once it has a full "sentence" to speak
  13. // it returns updated variables for the next iteration
  14. // this is intended to be used in a loop
  15. export function processResponse({
  16. sentences,
  17. aiTextLog,
  18. receivedMessage,
  19. tag,
  20. isThinking,
  21. rolePlay,
  22. callback,
  23. }: {
  24. sentences: string[],
  25. aiTextLog: string,
  26. receivedMessage: string,
  27. tag: string,
  28. isThinking: boolean,
  29. rolePlay: string,
  30. callback: (aiTalks: Screenplay[]) => boolean,
  31. }): ProcessResponseRetVal {
  32. let shouldBreak = false;
  33. const thinkTagMatch = receivedMessage.match(/<\/?think>/);
  34. if (thinkTagMatch && thinkTagMatch[0]) {
  35. if (thinkTagMatch[0] === "</think>") {
  36. isThinking = false;
  37. } else {
  38. isThinking = true;
  39. }
  40. receivedMessage = receivedMessage.slice(thinkTagMatch[0].length);
  41. }
  42. // Detection of tag part of reply content
  43. const tagMatch = receivedMessage.match(/^\[(.*?)\]/);
  44. if (tagMatch && tagMatch[0]) {
  45. tag = tagMatch[0];
  46. receivedMessage = receivedMessage.slice(tag.length);
  47. }
  48. // Detection of role play part of reply content e.g. *smiling nervously*
  49. const rolePlayMatch = receivedMessage.match(/\*(.*?)\*/);
  50. if (rolePlayMatch && rolePlayMatch[0]) {
  51. rolePlay = rolePlayMatch[0];
  52. receivedMessage = receivedMessage.replace(rolePlay, '');
  53. }
  54. // Cut out and process the response sentence by sentence
  55. const sentenceMatch = receivedMessage.match(
  56. /^(.+[\.\。\!\!\?\?\,\n]|.{10,}[,])/,
  57. );
  58. if (sentenceMatch && sentenceMatch[0]) {
  59. const sentence = sentenceMatch[0];
  60. sentences.push(sentence);
  61. receivedMessage = receivedMessage
  62. .slice(sentence.length)
  63. .trimStart();
  64. // Skip if the string is unnecessary/impossible to utter.
  65. if (
  66. !sentence.replace(
  67. /^[\s\[\(\{「[(【『〈《〔{«‹〘〚〛〙›»〕》〉』】)]」\}\)\]]+$/g,
  68. "",
  69. )
  70. ) {
  71. // continue
  72. return {
  73. sentences,
  74. aiTextLog,
  75. receivedMessage,
  76. tag,
  77. isThinking,
  78. rolePlay,
  79. shouldBreak,
  80. }
  81. }
  82. const aiText = `${tag} ${sentence}`;
  83. const aiTalks = textsToScreenplay([aiText]);
  84. aiTextLog += aiText;
  85. shouldBreak = callback(aiTalks);
  86. }
  87. return {
  88. sentences,
  89. aiTextLog,
  90. receivedMessage,
  91. tag,
  92. isThinking,
  93. rolePlay,
  94. shouldBreak,
  95. }
  96. }