sensorium-mcp 2.16.28 → 2.16.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/config.d.ts +1 -11
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +3 -49
  4. package/dist/config.js.map +1 -1
  5. package/dist/dashboard/presets.d.ts +18 -0
  6. package/dist/dashboard/presets.d.ts.map +1 -0
  7. package/dist/dashboard/presets.js +78 -0
  8. package/dist/dashboard/presets.js.map +1 -0
  9. package/dist/dashboard/routes.d.ts +33 -0
  10. package/dist/dashboard/routes.d.ts.map +1 -0
  11. package/dist/dashboard/routes.js +283 -0
  12. package/dist/dashboard/routes.js.map +1 -0
  13. package/dist/dashboard.d.ts +6 -29
  14. package/dist/dashboard.d.ts.map +1 -1
  15. package/dist/dashboard.js +6 -1158
  16. package/dist/dashboard.js.map +1 -1
  17. package/dist/data/file-storage.d.ts +19 -0
  18. package/dist/data/file-storage.d.ts.map +1 -0
  19. package/dist/data/file-storage.js +58 -0
  20. package/dist/data/file-storage.js.map +1 -0
  21. package/dist/data/memory/bootstrap.d.ts +40 -0
  22. package/dist/data/memory/bootstrap.d.ts.map +1 -0
  23. package/dist/data/memory/bootstrap.js +240 -0
  24. package/dist/data/memory/bootstrap.js.map +1 -0
  25. package/dist/data/memory/consolidation.d.ts +12 -0
  26. package/dist/data/memory/consolidation.d.ts.map +1 -0
  27. package/dist/data/memory/consolidation.js +248 -0
  28. package/dist/data/memory/consolidation.js.map +1 -0
  29. package/dist/data/memory/episodes.d.ts +34 -0
  30. package/dist/data/memory/episodes.d.ts.map +1 -0
  31. package/dist/data/memory/episodes.js +89 -0
  32. package/dist/data/memory/episodes.js.map +1 -0
  33. package/dist/data/memory/index.d.ts +14 -0
  34. package/dist/data/memory/index.d.ts.map +1 -0
  35. package/dist/data/memory/index.js +14 -0
  36. package/dist/data/memory/index.js.map +1 -0
  37. package/dist/data/memory/procedures.d.ts +42 -0
  38. package/dist/data/memory/procedures.d.ts.map +1 -0
  39. package/dist/data/memory/procedures.js +122 -0
  40. package/dist/data/memory/procedures.js.map +1 -0
  41. package/dist/data/memory/schema.d.ts +11 -0
  42. package/dist/data/memory/schema.d.ts.map +1 -0
  43. package/dist/data/memory/schema.js +327 -0
  44. package/dist/data/memory/schema.js.map +1 -0
  45. package/dist/data/memory/semantic.d.ts +94 -0
  46. package/dist/data/memory/semantic.d.ts.map +1 -0
  47. package/dist/data/memory/semantic.js +385 -0
  48. package/dist/data/memory/semantic.js.map +1 -0
  49. package/dist/data/memory/voice-sig.d.ts +33 -0
  50. package/dist/data/memory/voice-sig.d.ts.map +1 -0
  51. package/dist/data/memory/voice-sig.js +48 -0
  52. package/dist/data/memory/voice-sig.js.map +1 -0
  53. package/dist/data/templates.d.ts +19 -0
  54. package/dist/data/templates.d.ts.map +1 -0
  55. package/dist/data/templates.js +46 -0
  56. package/dist/data/templates.js.map +1 -0
  57. package/dist/dispatcher.d.ts +5 -97
  58. package/dist/dispatcher.d.ts.map +1 -1
  59. package/dist/dispatcher.js +5 -525
  60. package/dist/dispatcher.js.map +1 -1
  61. package/dist/drive.d.ts.map +1 -1
  62. package/dist/drive.js +3 -1
  63. package/dist/drive.js.map +1 -1
  64. package/dist/index.d.ts +4 -23
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +11 -289
  67. package/dist/index.js.map +1 -1
  68. package/dist/integrations/openai/chat.d.ts +29 -0
  69. package/dist/integrations/openai/chat.d.ts.map +1 -0
  70. package/dist/integrations/openai/chat.js +84 -0
  71. package/dist/integrations/openai/chat.js.map +1 -0
  72. package/dist/integrations/openai/index.d.ts +6 -0
  73. package/dist/integrations/openai/index.d.ts.map +1 -0
  74. package/dist/integrations/openai/index.js +6 -0
  75. package/dist/integrations/openai/index.js.map +1 -0
  76. package/dist/integrations/openai/speech.d.ts +21 -0
  77. package/dist/integrations/openai/speech.d.ts.map +1 -0
  78. package/dist/integrations/openai/speech.js +75 -0
  79. package/dist/integrations/openai/speech.js.map +1 -0
  80. package/dist/integrations/openai/video.d.ts +15 -0
  81. package/dist/integrations/openai/video.d.ts.map +1 -0
  82. package/dist/integrations/openai/video.js +131 -0
  83. package/dist/integrations/openai/video.js.map +1 -0
  84. package/dist/integrations/openai/vision.d.ts +23 -0
  85. package/dist/integrations/openai/vision.d.ts.map +1 -0
  86. package/dist/integrations/openai/vision.js +116 -0
  87. package/dist/integrations/openai/vision.js.map +1 -0
  88. package/dist/integrations/openai/voice-emotion.d.ts +41 -0
  89. package/dist/integrations/openai/voice-emotion.d.ts.map +1 -0
  90. package/dist/integrations/openai/voice-emotion.js +50 -0
  91. package/dist/integrations/openai/voice-emotion.js.map +1 -0
  92. package/dist/integrations/telegram/types.d.ts +112 -0
  93. package/dist/integrations/telegram/types.d.ts.map +1 -0
  94. package/dist/integrations/telegram/types.js +6 -0
  95. package/dist/integrations/telegram/types.js.map +1 -0
  96. package/dist/memory.d.ts +6 -205
  97. package/dist/memory.d.ts.map +1 -1
  98. package/dist/memory.js +6 -1357
  99. package/dist/memory.js.map +1 -1
  100. package/dist/openai.d.ts +11 -102
  101. package/dist/openai.d.ts.map +1 -1
  102. package/dist/openai.js +14 -421
  103. package/dist/openai.js.map +1 -1
  104. package/dist/response-builders.d.ts +1 -11
  105. package/dist/response-builders.d.ts.map +1 -1
  106. package/dist/response-builders.js +2 -38
  107. package/dist/response-builders.js.map +1 -1
  108. package/dist/server/factory.d.ts +17 -0
  109. package/dist/server/factory.d.ts.map +1 -0
  110. package/dist/server/factory.js +279 -0
  111. package/dist/server/factory.js.map +1 -0
  112. package/dist/services/dispatcher/broker.d.ts +83 -0
  113. package/dist/services/dispatcher/broker.d.ts.map +1 -0
  114. package/dist/services/dispatcher/broker.js +175 -0
  115. package/dist/services/dispatcher/broker.js.map +1 -0
  116. package/dist/services/dispatcher/index.d.ts +7 -0
  117. package/dist/services/dispatcher/index.d.ts.map +1 -0
  118. package/dist/services/dispatcher/index.js +7 -0
  119. package/dist/services/dispatcher/index.js.map +1 -0
  120. package/dist/services/dispatcher/lock.d.ts +25 -0
  121. package/dist/services/dispatcher/lock.d.ts.map +1 -0
  122. package/dist/services/dispatcher/lock.js +111 -0
  123. package/dist/services/dispatcher/lock.js.map +1 -0
  124. package/dist/services/dispatcher/poller.d.ts +19 -0
  125. package/dist/services/dispatcher/poller.d.ts.map +1 -0
  126. package/dist/services/dispatcher/poller.js +269 -0
  127. package/dist/services/dispatcher/poller.js.map +1 -0
  128. package/dist/telegram.d.ts +2 -88
  129. package/dist/telegram.d.ts.map +1 -1
  130. package/dist/telegram.js +2 -0
  131. package/dist/telegram.js.map +1 -1
  132. package/dist/tool-definitions.d.ts +1 -14
  133. package/dist/tool-definitions.d.ts.map +1 -1
  134. package/dist/tool-definitions.js +1 -403
  135. package/dist/tool-definitions.js.map +1 -1
  136. package/dist/tools/definitions.d.ts +15 -0
  137. package/dist/tools/definitions.d.ts.map +1 -0
  138. package/dist/tools/definitions.js +404 -0
  139. package/dist/tools/definitions.js.map +1 -0
  140. package/dist/tools/start-session-tool.d.ts.map +1 -1
  141. package/dist/tools/start-session-tool.js +2 -0
  142. package/dist/tools/start-session-tool.js.map +1 -1
  143. package/dist/tools/wait/drive-handler.d.ts +61 -0
  144. package/dist/tools/wait/drive-handler.d.ts.map +1 -0
  145. package/dist/tools/wait/drive-handler.js +138 -0
  146. package/dist/tools/wait/drive-handler.js.map +1 -0
  147. package/dist/tools/wait/index.d.ts +8 -0
  148. package/dist/tools/wait/index.d.ts.map +1 -0
  149. package/dist/tools/wait/index.js +8 -0
  150. package/dist/tools/wait/index.js.map +1 -0
  151. package/dist/tools/wait/media-processor.d.ts +52 -0
  152. package/dist/tools/wait/media-processor.d.ts.map +1 -0
  153. package/dist/tools/wait/media-processor.js +261 -0
  154. package/dist/tools/wait/media-processor.js.map +1 -0
  155. package/dist/tools/wait/message-delivery.d.ts +63 -0
  156. package/dist/tools/wait/message-delivery.d.ts.map +1 -0
  157. package/dist/tools/wait/message-delivery.js +281 -0
  158. package/dist/tools/wait/message-delivery.js.map +1 -0
  159. package/dist/tools/wait/poll-loop.d.ts +72 -0
  160. package/dist/tools/wait/poll-loop.d.ts.map +1 -0
  161. package/dist/tools/wait/poll-loop.js +280 -0
  162. package/dist/tools/wait/poll-loop.js.map +1 -0
  163. package/dist/tools/wait/reaction-handler.d.ts +49 -0
  164. package/dist/tools/wait/reaction-handler.d.ts.map +1 -0
  165. package/dist/tools/wait/reaction-handler.js +126 -0
  166. package/dist/tools/wait/reaction-handler.js.map +1 -0
  167. package/dist/tools/wait/task-handler.d.ts +40 -0
  168. package/dist/tools/wait/task-handler.d.ts.map +1 -0
  169. package/dist/tools/wait/task-handler.js +41 -0
  170. package/dist/tools/wait/task-handler.js.map +1 -0
  171. package/dist/tools/wait-tool.d.ts +3 -69
  172. package/dist/tools/wait-tool.d.ts.map +1 -1
  173. package/dist/tools/wait-tool.js +3 -876
  174. package/dist/tools/wait-tool.js.map +1 -1
  175. package/package.json +1 -1
  176. package/templates/daily-review.default.md +26 -0
  177. package/templates/drive-dispatcher.default.md +2 -0
@@ -0,0 +1,75 @@
1
+ /**
2
+ * OpenAI speech services: TTS (text-to-speech) and Whisper transcription.
3
+ *
4
+ * Extracted from openai.ts for modular decomposition (Phase 3B).
5
+ */
6
+ // ─── TTS ──────────────────────────────────────────────────────────────────
7
+ /** Valid TTS voice names. */
8
+ export const TTS_VOICES = [
9
+ "alloy", "echo", "fable", "onyx", "nova", "shimmer",
10
+ ];
11
+ /**
12
+ * Convert text to speech using OpenAI TTS API.
13
+ * Returns OGG Opus audio suitable for Telegram's sendVoice.
14
+ */
15
+ export async function textToSpeech(text, apiKey, voice = "nova") {
16
+ const controller = new AbortController();
17
+ const timer = setTimeout(() => controller.abort(), 60_000);
18
+ try {
19
+ const response = await fetch("https://api.openai.com/v1/audio/speech", {
20
+ method: "POST",
21
+ headers: {
22
+ "Content-Type": "application/json",
23
+ Authorization: `Bearer ${apiKey}`,
24
+ },
25
+ body: JSON.stringify({
26
+ model: "tts-1",
27
+ input: text,
28
+ voice,
29
+ response_format: "opus",
30
+ }),
31
+ signal: controller.signal,
32
+ });
33
+ if (!response.ok) {
34
+ const errText = await response.text().catch(() => response.statusText);
35
+ throw new Error(`OpenAI TTS failed: ${response.status} ${errText}`);
36
+ }
37
+ return Buffer.from(await response.arrayBuffer());
38
+ }
39
+ finally {
40
+ clearTimeout(timer);
41
+ }
42
+ }
43
+ /**
44
+ * Transcribe an audio buffer using OpenAI Whisper API.
45
+ * @param audioBuffer Raw audio content (OGG Opus from Telegram voice messages).
46
+ * @param apiKey OpenAI API key.
47
+ * @returns The transcribed text (empty string if no speech detected).
48
+ */
49
+ export async function transcribeAudio(audioBuffer, apiKey, filename = "voice.ogg") {
50
+ // Telegram stores voice as .oga (OGG Opus). Whisper accepts .ogg but
51
+ // not .oga, so we hardcode the extension.
52
+ const controller = new AbortController();
53
+ const timer = setTimeout(() => controller.abort(), 60_000);
54
+ try {
55
+ const formData = new FormData();
56
+ formData.append("file", new Blob([new Uint8Array(audioBuffer)]), filename);
57
+ formData.append("model", "whisper-1");
58
+ const response = await fetch("https://api.openai.com/v1/audio/transcriptions", {
59
+ method: "POST",
60
+ headers: { Authorization: `Bearer ${apiKey}` },
61
+ body: formData,
62
+ signal: controller.signal,
63
+ });
64
+ if (!response.ok) {
65
+ const errText = await response.text().catch(() => response.statusText);
66
+ throw new Error(`OpenAI Whisper transcription failed: ${response.status} ${errText}`);
67
+ }
68
+ const result = (await response.json());
69
+ return result.text ?? "";
70
+ }
71
+ finally {
72
+ clearTimeout(timer);
73
+ }
74
+ }
75
+ //# sourceMappingURL=speech.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"speech.js","sourceRoot":"","sources":["../../../src/integrations/openai/speech.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Video frame extraction (ffmpeg) and GPT-4o-mini vision analysis.
3
+ * Extracted from openai.ts for modular decomposition (Phase 3).
4
+ */
5
+ /** Maximum number of frames to extract from a video. */
6
+ export declare const MAX_FRAMES = 6;
7
+ /**
8
+ * Extract key frames from a video buffer using ffmpeg.
9
+ * Writes video to a temp file and reads JPEG frames from stdout.
10
+ * @param videoBuffer Raw video file content (MP4).
11
+ * @param durationSec Video duration in seconds (used to calculate interval).
12
+ * @returns Array of JPEG-encoded frame buffers.
13
+ */
14
+ export declare function extractVideoFrames(videoBuffer: Buffer, durationSec: number): Promise<Buffer[]>;
15
+ //# sourceMappingURL=video.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../src/integrations/openai/video.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA2DH,wDAAwD;AACxD,eAAO,MAAM,UAAU,IAAI,CAAC;AAkB5B;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAC9B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAsDnB"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Video frame extraction (ffmpeg) and GPT-4o-mini vision analysis.
3
+ * Extracted from openai.ts for modular decomposition (Phase 3).
4
+ */
5
+ import { spawn } from "node:child_process";
6
+ import { randomUUID } from "node:crypto";
7
+ import { mkdirSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
8
+ import { homedir } from "node:os";
9
+ import { join } from "node:path";
10
+ // ---------------------------------------------------------------------------
11
+ // Temp-file management
12
+ // ---------------------------------------------------------------------------
13
+ // Dedicated temp directory so crash-leftover files are cleaned on next startup.
14
+ const TEMP_DIR = join(homedir(), ".remote-copilot-mcp", "tmp");
15
+ /** Remove stale files from TEMP_DIR; create the dir if absent. */
16
+ function cleanupTempDir() {
17
+ mkdirSync(TEMP_DIR, { recursive: true });
18
+ const STALE_AGE = 5 * 60 * 1000; // 5 minutes — any temp file this old is a crash leftover
19
+ const now = Date.now();
20
+ for (const name of readdirSync(TEMP_DIR)) {
21
+ try {
22
+ const fullPath = join(TEMP_DIR, name);
23
+ const mtime = statSync(fullPath).mtimeMs;
24
+ if (now - mtime > STALE_AGE) {
25
+ unlinkSync(fullPath);
26
+ }
27
+ }
28
+ catch { /* ignore per-file errors */ }
29
+ }
30
+ }
31
+ // Track in-flight temp files for cleanup on unexpected exit.
32
+ const activeTempFiles = new Set();
33
+ function registerTempFile(path) {
34
+ activeTempFiles.add(path);
35
+ }
36
+ function unregisterTempFile(path) {
37
+ activeTempFiles.delete(path);
38
+ try {
39
+ unlinkSync(path);
40
+ }
41
+ catch { /* ignore */ }
42
+ }
43
+ // Clean up in-flight temp files on graceful/forced shutdown.
44
+ for (const sig of ["exit", "SIGINT", "SIGTERM"]) {
45
+ process.on(sig, () => {
46
+ for (const f of activeTempFiles) {
47
+ try {
48
+ unlinkSync(f);
49
+ }
50
+ catch { /* ignore */ }
51
+ }
52
+ });
53
+ }
54
+ // Run once when the module loads.
55
+ cleanupTempDir();
56
+ // ---------------------------------------------------------------------------
57
+ // Frame extraction
58
+ // ---------------------------------------------------------------------------
59
+ /** Maximum number of frames to extract from a video. */
60
+ export const MAX_FRAMES = 6;
61
+ /**
62
+ * Split a buffer of concatenated JPEG images by SOI marker (0xFFD8).
63
+ */
64
+ function splitJpegs(buf) {
65
+ const frames = [];
66
+ let start = 0;
67
+ for (let i = 2; i < buf.length - 1; i++) {
68
+ if (buf[i] === 0xFF && buf[i + 1] === 0xD8) {
69
+ frames.push(buf.subarray(start, i));
70
+ start = i;
71
+ }
72
+ }
73
+ if (start < buf.length)
74
+ frames.push(buf.subarray(start));
75
+ return frames.filter(f => f.length > 100); // drop tiny garbage
76
+ }
77
+ /**
78
+ * Extract key frames from a video buffer using ffmpeg.
79
+ * Writes video to a temp file and reads JPEG frames from stdout.
80
+ * @param videoBuffer Raw video file content (MP4).
81
+ * @param durationSec Video duration in seconds (used to calculate interval).
82
+ * @returns Array of JPEG-encoded frame buffers.
83
+ */
84
+ export function extractVideoFrames(videoBuffer, durationSec) {
85
+ const tempPath = join(TEMP_DIR, `video-${randomUUID()}.mp4`);
86
+ writeFileSync(tempPath, videoBuffer);
87
+ registerTempFile(tempPath);
88
+ return new Promise((resolve, reject) => {
89
+ // Calculate frame interval: aim for ~1 frame every 5s, capped at MAX_FRAMES.
90
+ const interval = Math.max(1, Math.ceil(durationSec / MAX_FRAMES));
91
+ const args = [
92
+ "-i", tempPath,
93
+ "-vf", `fps=1/${interval}`,
94
+ "-c:v", "mjpeg",
95
+ "-f", "image2pipe",
96
+ "-q:v", "3",
97
+ "pipe:1",
98
+ ];
99
+ const proc = spawn("ffmpeg", args, {
100
+ stdio: ["ignore", "pipe", "pipe"],
101
+ });
102
+ const chunks = [];
103
+ const errChunks = [];
104
+ proc.stdout.on("data", (chunk) => chunks.push(chunk));
105
+ proc.stderr.on("data", (chunk) => errChunks.push(chunk));
106
+ // Kill ffmpeg if it hangs for more than 30 seconds.
107
+ const killTimer = setTimeout(() => proc.kill("SIGKILL"), 30_000);
108
+ proc.on("error", (err) => {
109
+ clearTimeout(killTimer);
110
+ reject(new Error(`ffmpeg not found or failed to start: ${err.message}`));
111
+ });
112
+ proc.on("close", (code) => {
113
+ clearTimeout(killTimer);
114
+ if (code !== 0) {
115
+ const stderr = Buffer.concat(errChunks).toString("utf8").slice(-500);
116
+ reject(new Error(`ffmpeg exited with code ${code}: ${stderr}`));
117
+ return;
118
+ }
119
+ const combined = Buffer.concat(chunks);
120
+ if (combined.length === 0) {
121
+ resolve([]);
122
+ return;
123
+ }
124
+ const frames = splitJpegs(combined).slice(0, MAX_FRAMES);
125
+ resolve(frames);
126
+ });
127
+ }).finally(() => {
128
+ unregisterTempFile(tempPath);
129
+ });
130
+ }
131
+ //# sourceMappingURL=video.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.js","sourceRoot":"","sources":["../../../src/integrations/openai/video.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,gFAAgF;AAChF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,qBAAqB,EAAE,KAAK,CAAC,CAAC;AAE/D,kEAAkE;AAClE,SAAS,cAAc;IACnB,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,yDAAyD;IAC1F,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC;YACzC,IAAI,GAAG,GAAG,KAAK,GAAG,SAAS,EAAE,CAAC;gBAC1B,UAAU,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;QACL,CAAC;QAAC,MAAM,CAAC,CAAC,4BAA4B,CAAC,CAAC;IAC5C,CAAC;AACL,CAAC;AAED,6DAA6D;AAC7D,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;AAE1C,SAAS,gBAAgB,CAAC,IAAY;IAClC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACpC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC;QAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;AACpD,CAAC;AAED,6DAA6D;AAC7D,KAAK,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;IACvD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE;QACjB,KAAK,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC;YAC9B,IAAI,CAAC;gBAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QACjD,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAED,kCAAkC;AAClC,cAAc,EAAE,CAAC;AAEjB,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,wDAAwD;AACxD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAE5B;;GAEG;AACH,SAAS,UAAU,CAAC,GAAW;IAC3B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;YACpC,KAAK,GAAG,CAAC,CAAC;QACd,CAAC;IACL,CAAC;IACD,IAAI,KAAK,GAAG,GAAG,CAAC,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACzD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,oBAAoB;AACnE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAC9B,WAAmB,EACnB,WAAmB;IAEnB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,MAAM,CAAC,CAAC;IAC7D,aAAa,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACrC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAE3B,OAAO,IAAI,OAAO,CAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,6EAA6E;QAC7E,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC;QAElE,MAAM,IAAI,GAAG;YACT,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,SAAS,QAAQ,EAAE;YAC1B,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,GAAG;YACX,QAAQ;SACX,CAAC;QAEF,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE;YAC/B,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SACpC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAa,EAAE,CAAC;QAE/B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAEjE,oDAAoD;QACpD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;QAEjE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACrB,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,MAAM,CAAC,IAAI,KAAK,CAAC,wCAAwC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC7E,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACtB,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACb,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;gBACrE,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC;gBAChE,OAAO;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACvC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,EAAE,CAAC,CAAC;gBACZ,OAAO;YACX,CAAC;YACD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;YACzD,OAAO,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;QACZ,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * OpenAI vision services: image analysis (GPT-4o) and video frame analysis (GPT-4o-mini).
3
+ *
4
+ * Extracted from openai.ts for modular decomposition (Phase 3C).
5
+ */
6
+ /**
7
+ * Analyze an image using GPT-4o vision capability.
8
+ * Sends the image as base64 with a text prompt and returns the analysis.
9
+ * @param imageBuffer Raw image content (JPEG, PNG, etc.).
10
+ * @param prompt The analysis prompt to send alongside the image.
11
+ * @param apiKey OpenAI API key.
12
+ * @returns The vision model's text response.
13
+ */
14
+ export declare function analyzeImage(imageBuffer: Buffer, prompt: string, apiKey: string): Promise<string>;
15
+ /**
16
+ * Analyze video frames using OpenAI GPT-4o-mini vision.
17
+ * @param frames Array of JPEG frame buffers.
18
+ * @param durationSec Video duration for timestamp context.
19
+ * @param apiKey OpenAI API key.
20
+ * @returns Human-readable description of the video content.
21
+ */
22
+ export declare function analyzeVideoFrames(frames: Buffer[], durationSec: number, apiKey: string): Promise<string>;
23
+ //# sourceMappingURL=vision.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vision.d.ts","sourceRoot":"","sources":["../../../src/integrations/openai/vision.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAC9B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CA4CjB;AAID;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACpC,MAAM,EAAE,MAAM,EAAE,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CA0DjB"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * OpenAI vision services: image analysis (GPT-4o) and video frame analysis (GPT-4o-mini).
3
+ *
4
+ * Extracted from openai.ts for modular decomposition (Phase 3C).
5
+ */
6
+ import { MAX_FRAMES } from "./video.js";
7
+ // ─── Image / Vision Analysis ──────────────────────────────────────────────
8
+ /**
9
+ * Analyze an image using GPT-4o vision capability.
10
+ * Sends the image as base64 with a text prompt and returns the analysis.
11
+ * @param imageBuffer Raw image content (JPEG, PNG, etc.).
12
+ * @param prompt The analysis prompt to send alongside the image.
13
+ * @param apiKey OpenAI API key.
14
+ * @returns The vision model's text response.
15
+ */
16
+ export async function analyzeImage(imageBuffer, prompt, apiKey) {
17
+ const base64 = imageBuffer.toString("base64");
18
+ const controller = new AbortController();
19
+ const timer = setTimeout(() => controller.abort(), 30_000);
20
+ try {
21
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
22
+ method: "POST",
23
+ headers: {
24
+ "Content-Type": "application/json",
25
+ Authorization: `Bearer ${apiKey}`,
26
+ },
27
+ body: JSON.stringify({
28
+ model: "gpt-4o",
29
+ messages: [
30
+ {
31
+ role: "user",
32
+ content: [
33
+ { type: "text", text: prompt },
34
+ {
35
+ type: "image_url",
36
+ image_url: {
37
+ url: `data:image/jpeg;base64,${base64}`,
38
+ detail: "low",
39
+ },
40
+ },
41
+ ],
42
+ },
43
+ ],
44
+ max_completion_tokens: 150,
45
+ temperature: 0,
46
+ }),
47
+ signal: controller.signal,
48
+ });
49
+ if (!response.ok) {
50
+ const errText = await response.text().catch(() => response.statusText);
51
+ throw new Error(`OpenAI vision analysis failed: ${response.status} ${errText}`);
52
+ }
53
+ const json = await response.json();
54
+ return json.choices?.[0]?.message?.content?.trim() ?? "";
55
+ }
56
+ finally {
57
+ clearTimeout(timer);
58
+ }
59
+ }
60
+ // ─── Video Frame Vision Analysis ──────────────────────────────────────────
61
+ /**
62
+ * Analyze video frames using OpenAI GPT-4o-mini vision.
63
+ * @param frames Array of JPEG frame buffers.
64
+ * @param durationSec Video duration for timestamp context.
65
+ * @param apiKey OpenAI API key.
66
+ * @returns Human-readable description of the video content.
67
+ */
68
+ export async function analyzeVideoFrames(frames, durationSec, apiKey) {
69
+ if (frames.length === 0) {
70
+ return "(no frames could be extracted from the video)";
71
+ }
72
+ const interval = Math.max(1, Math.ceil(durationSec / MAX_FRAMES));
73
+ const timestamps = frames.map((_, i) => `${i * interval}s`).join(", ");
74
+ const content = [
75
+ {
76
+ type: "text",
77
+ text: `These are ${frames.length} sequential frames extracted from a ${durationSec}s video message at timestamps: [${timestamps}]. ` +
78
+ `Describe what is happening in the video concisely (2-3 sentences). ` +
79
+ `Note any people, actions, objects, movement, text, or scene changes.`,
80
+ },
81
+ ...frames.map((frame) => ({
82
+ type: "image_url",
83
+ image_url: {
84
+ url: `data:image/jpeg;base64,${frame.toString("base64")}`,
85
+ detail: "low", // circle videos are small (240-384px)
86
+ },
87
+ })),
88
+ ];
89
+ const controller = new AbortController();
90
+ const timer = setTimeout(() => controller.abort(), 60_000);
91
+ try {
92
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
93
+ method: "POST",
94
+ headers: {
95
+ "Content-Type": "application/json",
96
+ Authorization: `Bearer ${apiKey}`,
97
+ },
98
+ body: JSON.stringify({
99
+ model: "gpt-4o-mini",
100
+ messages: [{ role: "user", content }],
101
+ max_completion_tokens: 300,
102
+ }),
103
+ signal: controller.signal,
104
+ });
105
+ if (!response.ok) {
106
+ const errText = await response.text().catch(() => response.statusText);
107
+ throw new Error(`OpenAI vision analysis failed: ${response.status} ${errText}`);
108
+ }
109
+ const result = (await response.json());
110
+ return result.choices?.[0]?.message?.content?.trim() ?? "(no description generated)";
111
+ }
112
+ finally {
113
+ clearTimeout(timer);
114
+ }
115
+ }
116
+ //# sourceMappingURL=vision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vision.js","sourceRoot":"","sources":["../../../src/integrations/openai/vision.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Voice emotion analysis via an external microservice.
3
+ * Extracted from openai.ts for modular decomposition (Phase 3).
4
+ */
5
+ export interface AudioEvent {
6
+ label: string;
7
+ score: number;
8
+ }
9
+ export interface Paralinguistics {
10
+ speech_rate?: number;
11
+ mean_pitch_hz?: number;
12
+ pitch_std_hz?: number;
13
+ jitter?: number;
14
+ shimmer?: number;
15
+ hnr_db?: number;
16
+ }
17
+ export interface VoiceAnalysisResult {
18
+ emotion: string | null;
19
+ emotion_scores?: Record<string, number>;
20
+ arousal: number | null;
21
+ dominance: number | null;
22
+ valence: number | null;
23
+ gender: string | null;
24
+ age_estimate: number | null;
25
+ duration_seconds: number;
26
+ audio_events?: AudioEvent[];
27
+ paralinguistics?: Paralinguistics;
28
+ }
29
+ /**
30
+ * Analyze a voice message for emotion using an external microservice.
31
+ * @param audioBuffer Raw audio content (OGG).
32
+ * @param serviceUrl Base URL of the voice analysis service (e.g. https://voice-analysis.example.com).
33
+ * @param timeoutMs Request timeout in milliseconds (default: 15000).
34
+ * @returns Analysis result, or null if the service is unavailable or errors.
35
+ */
36
+ export declare function analyzeVoiceEmotion(audioBuffer: Buffer, serviceUrl: string, options?: {
37
+ mimeType?: string;
38
+ filename?: string;
39
+ timeoutMs?: number;
40
+ }): Promise<VoiceAnalysisResult | null>;
41
+ //# sourceMappingURL=voice-emotion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-emotion.d.ts","sourceRoot":"","sources":["../../../src/integrations/openai/voice-emotion.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;CACrC;AAMD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACrC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAuCrC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Voice emotion analysis via an external microservice.
3
+ * Extracted from openai.ts for modular decomposition (Phase 3).
4
+ */
5
+ import { log } from "../../logger.js";
6
+ // ---------------------------------------------------------------------------
7
+ // Service client
8
+ // ---------------------------------------------------------------------------
9
+ /**
10
+ * Analyze a voice message for emotion using an external microservice.
11
+ * @param audioBuffer Raw audio content (OGG).
12
+ * @param serviceUrl Base URL of the voice analysis service (e.g. https://voice-analysis.example.com).
13
+ * @param timeoutMs Request timeout in milliseconds (default: 15000).
14
+ * @returns Analysis result, or null if the service is unavailable or errors.
15
+ */
16
+ export async function analyzeVoiceEmotion(audioBuffer, serviceUrl, options) {
17
+ const { mimeType = "audio/ogg", filename = "voice.ogg", timeoutMs = 120_000 } = options ?? {};
18
+ const start = Date.now();
19
+ const baseUrl = serviceUrl.replace(/\/+$/, "");
20
+ log.verbose("voice-analysis", `Starting analysis (timeout: ${timeoutMs}ms, format: ${mimeType})...`);
21
+ const controller = new AbortController();
22
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
23
+ try {
24
+ const formData = new FormData();
25
+ formData.append("file", new Blob([new Uint8Array(audioBuffer)], { type: mimeType }), filename);
26
+ const response = await fetch(`${baseUrl}/analyze`, {
27
+ method: "POST",
28
+ body: formData,
29
+ signal: controller.signal,
30
+ });
31
+ const elapsed = Date.now() - start;
32
+ if (!response.ok) {
33
+ log.warn(`[voice-analysis] HTTP ${response.status} after ${elapsed}ms`);
34
+ return null;
35
+ }
36
+ const result = (await response.json());
37
+ log.verbose("voice-analysis", `Success in ${elapsed}ms`);
38
+ return result;
39
+ }
40
+ catch (err) {
41
+ const elapsed = Date.now() - start;
42
+ const msg = err instanceof Error ? err.message : String(err);
43
+ log.error(`[voice-analysis] Failed after ${elapsed}ms: ${msg}`);
44
+ return null;
45
+ }
46
+ finally {
47
+ clearTimeout(timer);
48
+ }
49
+ }
50
+ //# sourceMappingURL=voice-emotion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-emotion.js","sourceRoot":"","sources":["../../../src/integrations/openai/voice-emotion.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAiCtC,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACrC,WAAmB,EACnB,UAAkB,EAClB,OAAsE;IAEtE,MAAM,EAAE,QAAQ,GAAG,WAAW,EAAE,QAAQ,GAAG,WAAW,EAAE,SAAS,GAAG,OAAO,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAC9F,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/C,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,+BAA+B,SAAS,eAAe,QAAQ,MAAM,CAAC,CAAC;IAErG,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAChC,QAAQ,CAAC,MAAM,CACX,MAAM,EACN,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAC3D,QAAQ,CACX,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,UAAU,EAAE;YAC/C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,UAAU,CAAC,MAAM;SAC5B,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACf,GAAG,CAAC,IAAI,CAAC,yBAAyB,QAAQ,CAAC,MAAM,UAAU,OAAO,IAAI,CAAC,CAAC;YACxE,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;QAC9D,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,cAAc,OAAO,IAAI,CAAC,CAAC;QACzD,OAAO,MAAM,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACnC,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,GAAG,CAAC,KAAK,CAAC,iCAAiC,OAAO,OAAO,GAAG,EAAE,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IAChB,CAAC;YAAS,CAAC;QACP,YAAY,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;AACL,CAAC"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Telegram Bot API type definitions.
3
+ * Extracted from telegram.ts for modularity.
4
+ */
5
+ export interface TelegramSticker {
6
+ file_id: string;
7
+ file_unique_id: string;
8
+ emoji?: string;
9
+ set_name?: string;
10
+ }
11
+ export interface TelegramAnimation {
12
+ file_id: string;
13
+ file_unique_id: string;
14
+ width?: number;
15
+ height?: number;
16
+ duration?: number;
17
+ mime_type?: string;
18
+ file_name?: string;
19
+ file_size?: number;
20
+ thumbnail?: PhotoSize;
21
+ thumb?: PhotoSize;
22
+ }
23
+ export interface TelegramMessage {
24
+ message_id: number;
25
+ chat: {
26
+ id: number;
27
+ };
28
+ text?: string;
29
+ caption?: string;
30
+ date: number;
31
+ message_thread_id?: number;
32
+ photo?: PhotoSize[];
33
+ document?: TelegramDocument;
34
+ voice?: TelegramVoice;
35
+ video_note?: TelegramVideoNote;
36
+ sticker?: TelegramSticker;
37
+ animation?: TelegramAnimation;
38
+ }
39
+ export interface PhotoSize {
40
+ file_id: string;
41
+ file_unique_id: string;
42
+ width: number;
43
+ height: number;
44
+ file_size?: number;
45
+ }
46
+ export interface TelegramDocument {
47
+ file_id: string;
48
+ file_unique_id: string;
49
+ file_name?: string;
50
+ mime_type?: string;
51
+ file_size?: number;
52
+ }
53
+ export interface TelegramVoice {
54
+ file_id: string;
55
+ file_unique_id: string;
56
+ duration: number;
57
+ mime_type?: string;
58
+ file_size?: number;
59
+ }
60
+ export interface TelegramVideoNote {
61
+ file_id: string;
62
+ file_unique_id: string;
63
+ length: number;
64
+ duration: number;
65
+ thumbnail?: PhotoSize;
66
+ file_size?: number;
67
+ }
68
+ export interface TelegramMessageReaction {
69
+ chat: {
70
+ id: number;
71
+ };
72
+ message_id: number;
73
+ date: number;
74
+ new_reaction: Array<{
75
+ type: string;
76
+ emoji?: string;
77
+ }>;
78
+ }
79
+ export interface TelegramUpdate {
80
+ update_id: number;
81
+ message?: TelegramMessage;
82
+ message_reaction?: TelegramMessageReaction;
83
+ }
84
+ export interface GetUpdatesResult {
85
+ ok: boolean;
86
+ result: TelegramUpdate[];
87
+ description?: string;
88
+ }
89
+ export interface SendMessageResult {
90
+ ok: boolean;
91
+ result?: TelegramMessage;
92
+ description?: string;
93
+ }
94
+ export interface ForumTopic {
95
+ message_thread_id: number;
96
+ name: string;
97
+ }
98
+ export interface CreateForumTopicResult {
99
+ ok: boolean;
100
+ result?: ForumTopic;
101
+ description?: string;
102
+ }
103
+ export interface TelegramFile {
104
+ file_id: string;
105
+ file_path: string;
106
+ }
107
+ export interface GetFileResult {
108
+ ok: boolean;
109
+ result?: TelegramFile;
110
+ description?: string;
111
+ }
112
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/integrations/telegram/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Telegram Bot API type definitions.
3
+ * Extracted from telegram.ts for modularity.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/integrations/telegram/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}