Get transcript summaries of Web videos.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 

123 lignes
2.9 KiB

  1. import fetchPonyfill from 'fetch-ponyfill';
  2. import Handlebars from 'handlebars';
  3. import { resolve } from 'path';
  4. import { readFile } from 'fs/promises';
  5. import * as config from './config';
  6. import { OpenAiParams } from './common';
  7. export interface MakeAiCallParams {
  8. prompts: string[];
  9. openAiParams: OpenAiParams;
  10. }
  11. export class AiCallError extends Error {
  12. constructor(message: string, public readonly response: Response) {
  13. super(message);
  14. this.name = 'AiCallError';
  15. }
  16. }
  17. const makeAiCall = async (params: MakeAiCallParams): Promise<string> => {
  18. const {
  19. prompts,
  20. openAiParams: {
  21. apiKey,
  22. organizationId,
  23. model = 'gpt-3.5-turbo',
  24. temperature = 0.6,
  25. },
  26. } = params;
  27. const headers: Record<string, string> = {
  28. 'Content-Type': 'application/json',
  29. Accept: 'application/json',
  30. Authorization: `Bearer ${apiKey}`,
  31. };
  32. if (organizationId) {
  33. headers['OpenAI-Organization'] = organizationId;
  34. }
  35. const { fetch } = fetchPonyfill();
  36. const response = await fetch(
  37. new URL('/v1/chat/completions', 'https://api.openai.com'),
  38. {
  39. method: 'POST',
  40. headers,
  41. body: JSON.stringify({
  42. model,
  43. temperature,
  44. messages: [
  45. {
  46. role: 'user',
  47. content: prompts[Math.floor(Math.random() * prompts.length)].trim(),
  48. },
  49. ],
  50. }),
  51. },
  52. );
  53. if (!response.ok) {
  54. const { error } = await response.json();
  55. throw new AiCallError(`OpenAI API call failed with status ${response.status}: ${error.message}`, response);
  56. }
  57. const { choices } = await response.json();
  58. // should we use all the response choices?
  59. return choices[0].message.content;
  60. };
  61. const compilePrompts = async (filename: string, params: Record<string, unknown>): Promise<string[]> => {
  62. const rawPromptText = await readFile(resolve(config.openAi.promptsDir, filename), 'utf-8');
  63. const fill = Handlebars.compile(rawPromptText, { noEscape: true });
  64. const filledText = fill(params);
  65. return filledText.split('---').map((s) => s.trim());
  66. };
  67. export interface NormalizeTranscriptTextParams {
  68. rawTranscriptText: string,
  69. openAiParams: OpenAiParams,
  70. }
  71. export const normalizeTranscriptText = async (params: NormalizeTranscriptTextParams) => {
  72. const {
  73. rawTranscriptText,
  74. openAiParams,
  75. } = params;
  76. const prompts = await compilePrompts(
  77. 'normalize-transcript-text.hbs',
  78. {
  79. transcript: rawTranscriptText,
  80. },
  81. );
  82. return makeAiCall({
  83. prompts,
  84. openAiParams,
  85. });
  86. };
  87. export interface SummarizeTranscriptParams {
  88. normalizedTranscript: string,
  89. openAiParams: OpenAiParams,
  90. }
  91. export const summarizeTranscript = async (params: SummarizeTranscriptParams) => {
  92. const {
  93. normalizedTranscript,
  94. openAiParams,
  95. } = params;
  96. const prompts = await compilePrompts(
  97. 'summarize-transcript.hbs',
  98. {
  99. transcript: normalizedTranscript,
  100. },
  101. );
  102. return makeAiCall({
  103. prompts,
  104. openAiParams,
  105. });
  106. };