1
0

chatbotDiagnosis.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import { ChatbotBackend } from "@/types/backend";
  2. import { EvaluationResult } from "./diagnosisScript";
  3. import { getOpenAiChatResponseStream } from "../chat/openAiChat";
  4. const additionalUrls = {
  5. openai: "/v1/chat/completions",
  6. ollama: "/api/chat",
  7. llamacpp: "/completions",
  8. koboldai: "/api/v1/generate",
  9. kobolda_extra: "/api/extra/generate/stream",
  10. openrouter: "/chat/completions",
  11. };
  12. const prompt = [{ role: "user", content: "Hello" }];
  13. const promptBuild = "User: Hello\n";
  14. const TIME_OUT = 20000; // time out 10 secs
  15. const MIN_DURATION = 5000; // latest time to add the score
  16. // Utility to safely call fetch with a timeout
  17. async function safeFetch(
  18. fullUrl: string,
  19. options: RequestInit,
  20. timeoutMs = TIME_OUT,
  21. ): Promise<EvaluationResult> {
  22. const controller = new AbortController();
  23. const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
  24. const start = performance.now();
  25. try {
  26. const res = await fetch(fullUrl, {
  27. ...options,
  28. signal: controller.signal,
  29. });
  30. clearTimeout(timeoutId);
  31. const duration = performance.now() - start;
  32. const status = res.status >= 200 && res.status < 300 ? "pass" : "fail";
  33. const score = calculateScore({ status, duration });
  34. return {
  35. status,
  36. score,
  37. };
  38. } catch (err: any) {
  39. clearTimeout(timeoutId);
  40. const duration = performance.now() - start;
  41. const isTimeout = err.name === "AbortError";
  42. const status = "fail";
  43. return {
  44. status,
  45. score: calculateScore({ status, duration, timeout: isTimeout }),
  46. };
  47. }
  48. }
  49. // Score calculation logic
  50. function calculateScore({
  51. status,
  52. duration,
  53. timeout = false,
  54. }: {
  55. status: "pass" | "fail";
  56. duration: number;
  57. timeout?: boolean;
  58. }): number {
  59. if (timeout) return 0;
  60. let score = 0;
  61. if (status === "pass") score += 50;
  62. if (duration < MIN_DURATION)
  63. score += 50 * ((MIN_DURATION - duration) / MIN_DURATION);
  64. return Math.round(score);
  65. }
  66. // Individual backend handlers
  67. const backendHandlers: Record<
  68. string,
  69. (params: ChatbotBackend) => Promise<EvaluationResult>
  70. > = {
  71. openai: async (params) => {
  72. const { openai_apikey, openai_model, openai_url } = params.openai || {};
  73. if (!openai_apikey || !openai_url || !openai_model)
  74. return { status: "fail", score: 0 };
  75. return await safeFetch(`${openai_url}${additionalUrls.openai}`, {
  76. headers: {
  77. "Content-Type": "application/json",
  78. Authorization: `Bearer ${openai_apikey}`,
  79. "HTTP-Referer": "https://amica.arbius.ai",
  80. "X-Title": "Amica",
  81. },
  82. method: "POST",
  83. body: JSON.stringify({
  84. model: openai_model,
  85. messages: prompt,
  86. stream: false,
  87. max_tokens: 200,
  88. }),
  89. });
  90. },
  91. llamacpp: async (params) => {
  92. const { llamacpp_url } = params.llamacpp || {};
  93. if (!llamacpp_url) return { status: "fail", score: 0 };
  94. return await safeFetch(`${llamacpp_url}${additionalUrls.llamacpp}`, {
  95. method: "POST",
  96. headers: {
  97. "Content-Type": "application/json",
  98. Connection: "keep-alive",
  99. Accept: "text/event-stream",
  100. },
  101. body: JSON.stringify({
  102. stream: true,
  103. n_predict: 400,
  104. temperature: 0.7,
  105. cache_prompt: true,
  106. prompt: promptBuild,
  107. }),
  108. });
  109. },
  110. ollama: async (params) => {
  111. const { ollama_url, ollama_model } = params.ollama || {};
  112. if (!ollama_url) return { status: "fail", score: 0 };
  113. return await safeFetch(`${ollama_url}${additionalUrls.ollama}`, {
  114. method: "POST",
  115. headers: { "Content-Type": "application/json" },
  116. body: JSON.stringify({ model: ollama_model, messages: prompt }),
  117. });
  118. },
  119. koboldai: async (params) => {
  120. const { koboldai_url, koboldai_use_extra } = params.koboldai || {};
  121. if (!koboldai_url) return { status: "fail", score: 0 };
  122. const path =
  123. koboldai_use_extra === "true"
  124. ? additionalUrls.kobolda_extra
  125. : additionalUrls.koboldai;
  126. return await safeFetch(`${koboldai_url}${path}`, {
  127. method: "POST",
  128. headers: { "Content-Type": "application/json" },
  129. body: JSON.stringify({ prompt }),
  130. });
  131. },
  132. openrouter: async (params) => {
  133. const { openrouter_apikey, openrouter_model, openrouter_url } =
  134. params.openrouter || {};
  135. if (!openrouter_apikey || !openrouter_model || !openrouter_url)
  136. return { status: "fail", score: 0 };
  137. return await safeFetch(`${openrouter_url}${additionalUrls.openrouter}`, {
  138. method: "POST",
  139. headers: {
  140. "Content-Type": "application/json",
  141. Authorization: `Bearer ${openrouter_apikey}`,
  142. "HTTP-Referer": "https://amica.arbius.ai",
  143. "X-Title": "Amica Chat",
  144. },
  145. body: JSON.stringify({
  146. model: openrouter_model,
  147. messages: prompt,
  148. stream: true,
  149. }),
  150. });
  151. },
  152. windowai: async () => {
  153. return { status: "pass", score: 100 };
  154. },
  155. };
  156. // Dispatcher function
  157. export async function chatbotDiagnosis(
  158. backend: string,
  159. params: ChatbotBackend,
  160. ): Promise<EvaluationResult> {
  161. const handler = backendHandlers[backend];
  162. if (!handler) return { status: "fail", score: 0 };
  163. return await handler(params);
  164. }