nodebb-plugin-openai 1.3.1 → 1.4.0

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.
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ import serverConfig from 'eslint-config-nodebb';
4
+ import publicConfig from 'eslint-config-nodebb/public';
5
+
6
+ export default [
7
+ ...publicConfig,
8
+ ...serverConfig,
9
+ ];
10
+
package/lib/summary.js CHANGED
@@ -8,7 +8,7 @@ const user = require.main.require('./src/user');
8
8
 
9
9
  function formatPosts(posts) {
10
10
  return posts
11
- .map((post) => `User ${post.username}:\n${post.content}`)
11
+ .map(post => `User ${post.username}:\n${post.content}`)
12
12
  .join('\n---\n');
13
13
  }
14
14
 
@@ -17,7 +17,6 @@ function chunkPosts(posts, maxTokensPerChunk = 3000) {
17
17
  let currentChunk = [];
18
18
  let currentTokens = 0;
19
19
 
20
- // eslint-disable-next-line no-restricted-syntax
21
20
  for (const post of posts) {
22
21
  const estimatedTokens = Math.ceil(post.content.length / 4) + 10;
23
22
  if (currentTokens + estimatedTokens > maxTokensPerChunk) {
@@ -59,7 +58,7 @@ async function summarizeChunk(chunk, openai, settings) {
59
58
  return response.choices[0].message.content.trim();
60
59
  }
61
60
 
62
- exports.summarizeTopic = async function(tid, openai, settings) {
61
+ exports.summarizeTopic = async function (tid, openai, settings) {
63
62
  const allPids = await topics.getPids(tid);
64
63
 
65
64
  const userMap = {};
@@ -68,11 +67,11 @@ exports.summarizeTopic = async function(tid, openai, settings) {
68
67
 
69
68
  await batch.processArray(allPids, async function (pids) {
70
69
  let postData = await posts.getPostsFields(pids, ['uid', 'content', 'deleted']);
71
- postData = postData.filter((p) => !p.deleted);
70
+ postData = postData.filter(p => !p.deleted);
72
71
  const missingUids = [];
73
72
  postData.forEach((p) => {
74
73
  if (!userMap.hasOwnProperty(p.uid)) {
75
- missingUids.push(p.uid)
74
+ missingUids.push(p.uid);
76
75
  }
77
76
  });
78
77
  const userData = await user.getUsersFields(missingUids, ['username']);
@@ -86,7 +85,7 @@ exports.summarizeTopic = async function(tid, openai, settings) {
86
85
  const chunks = chunkPosts(postData);
87
86
 
88
87
  chunkSummaries.push(...await Promise.all(chunks.map(async (chunk) => {
89
- return summarizeChunk(chunk, openai, settings)
88
+ return summarizeChunk(chunk, openai, settings);
90
89
  })));
91
90
  }, {
92
91
  batch: 500,
@@ -96,7 +95,7 @@ exports.summarizeTopic = async function(tid, openai, settings) {
96
95
  return chunkSummaries[0];
97
96
  }
98
97
  // Final summary from all summaries
99
- const finalInput = chunkSummaries.join("\n\n");
98
+ const finalInput = chunkSummaries.join('\n\n');
100
99
  if (!finalInput) {
101
100
  return '';
102
101
  }
@@ -118,6 +117,6 @@ exports.summarizeTopic = async function(tid, openai, settings) {
118
117
  return finalResponse.choices[0].message.content.trim();
119
118
  };
120
119
 
121
- exports.clearTopicSummary = async function(tids) {
122
- await db.deleteObjectFields(tids.map((tid) => `topic:${tid}`), ['openai:summary']);
120
+ exports.clearTopicSummary = async function (tids) {
121
+ await db.deleteObjectFields(tids.map(tid => `topic:${tid}`), ['openai:summary']);
123
122
  };
package/library.js CHANGED
@@ -34,18 +34,27 @@ const defaults = {
34
34
 
35
35
  plugin.init = async (params) => {
36
36
  const { router /* , middleware , controllers */ } = params;
37
- const settings = await meta.settings.get('openai')
37
+ const settings = await meta.settings.get('openai');
38
38
  if (settings && settings.apikey) {
39
39
  openai = new OpenAI({
40
40
  apiKey: settings.apikey,
41
+ baseURL: settings.apiBaseUrl || 'https://api.openai.com/v1',
41
42
  });
43
+
44
+ // Uncomment the following lines to list available models
45
+ // const list = await openai.models.list();
46
+ // for await (const model of list) {
47
+ // console.log(model.id);
48
+ // }
49
+
50
+ plugin.openai = openai;
42
51
  }
43
52
 
44
53
  routeHelpers.setupAdminPageRoute(router, '/admin/plugins/openai', controllers.renderAdminPage);
45
54
  };
46
55
 
47
56
  async function getSettings() {
48
- const settings = await meta.settings.get('openai')
57
+ const settings = await meta.settings.get('openai');
49
58
  return {...defaults, ...settings };
50
59
  }
51
60
 
@@ -150,7 +159,7 @@ plugin.actionMessagingSave = async function (hookData) {
150
159
  let messages = await messaging.getMessagesFields(mids, ['fromuid', 'content', 'system']);
151
160
  messages = messages.filter(m => m && !m.system);
152
161
  conversation = messages.map(
153
- (msg) => ({ role: msg.fromuid === chatgptUid ? 'assistant' : 'user', content: msg.content })
162
+ msg => ({ role: msg.fromuid === chatgptUid ? 'assistant' : 'user', content: msg.content })
154
163
  );
155
164
  }
156
165
 
@@ -180,7 +189,8 @@ async function canUseOpenAI(uid, settings, silent = false) {
180
189
 
181
190
  async function checkReputation(uid, settings, silent) {
182
191
  const reputation = await user.getUserField(uid, 'reputation');
183
- const hasEnoughRep = parseInt(settings.minimumReputation, 10) === 0 || parseInt(reputation, 10) >= parseInt(settings.minimumReputation, 10);
192
+ const hasEnoughRep = parseInt(settings.minimumReputation, 10) === 0 ||
193
+ parseInt(reputation, 10) >= parseInt(settings.minimumReputation, 10);
184
194
 
185
195
  if (!hasEnoughRep && !silent) {
186
196
  sockets.server.in(`uid_${uid}`).emit('event:alert', {
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "nodebb-plugin-openai",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "A NodeBB OpenAI plugin",
5
5
  "main": "library.js",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/nodebb/nodebb-plugin-openai"
9
9
  },
10
+ "scripts": {
11
+ "lint": "eslint ."
12
+ },
10
13
  "keywords": [
11
14
  "nodebb",
12
15
  "plugin",
@@ -30,17 +33,16 @@
30
33
  },
31
34
  "readmeFilename": "README.md",
32
35
  "nbbpm": {
33
- "compatibility": "^3.2.0"
36
+ "compatibility": "^3.2.0 || ^4.0.0"
34
37
  },
35
38
  "dependencies": {
36
- "openai": "4.53.2"
39
+ "openai": "4.103.0"
37
40
  },
38
41
  "devDependencies": {
39
42
  "@commitlint/cli": "19.3.0",
40
43
  "@commitlint/config-angular": "19.3.0",
41
- "eslint": "8.57.0",
42
- "eslint-config-nodebb": "0.2.1",
43
- "eslint-plugin-import": "2.29.1",
44
+ "eslint": "9.26.0",
45
+ "eslint-config-nodebb": "^1.1.4",
44
46
  "husky": "9.0.11",
45
47
  "lint-staged": "15.2.7"
46
48
  }
@@ -11,9 +11,18 @@
11
11
  <label class="form-label" for="apikey">API Key</label>
12
12
  <input type="text" id="apikey" name="apikey" title="API Key" class="form-control">
13
13
  <p class="form-text">
14
- Get your <a href="https://platform.openai.com/api-keys">API Key</a> and enter it above. Requires a restart.
14
+ Get your <a href="https://platform.openai.com/api-keys">API Key</a> and enter it above. You can enter a Google Gemini API key if you want to use Google Gemini. Don't forget to change the model used to a gemini variant. Requires a restart.
15
15
  </p>
16
16
  </div>
17
+
18
+ <div class="mb-3">
19
+ <label class="form-label" for="apiBaseUrl">API Base Url</label>
20
+ <input type="text" id="apiBaseUrl" name="apiBaseUrl" title="API Base Url" class="form-control">
21
+ <p class="form-text">
22
+ If you want to use Google's Gemini API, enter the base URL here (https://generativelanguage.googleapis.com/v1beta/openai/). Otherwise, leave it blank to use OpenAI's API. Requires a restart.
23
+ </p>
24
+ </div>
25
+
17
26
  <div class="mb-3">
18
27
  <label class="form-label" for="chatgpt-username">ChatGPT Username</label>
19
28
  <input type="text" id="chatgpt-username" name="chatgpt-username" title="ChatGPT Username" class="form-control">
@@ -38,6 +47,9 @@
38
47
  <option value="gpt-4o">gpt-4o</option>
39
48
  <option value="gpt-4-turbo">gpt-4-turbo</option>
40
49
  <option value="gpt-4">gpt-4</option>
50
+ <option value="gpt-4.1-mini">gpt-4.1-mini</option>
51
+ <option value="gpt-4.1">gpt-4.1</option>
52
+ <option value="gemini-2.0-flash">gemini-2.0-flash</option>
41
53
  </select>
42
54
  </div>
43
55
  <div class="">
package/.eslintrc DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "extends": "nodebb/public"
3
- }
@@ -1,3 +0,0 @@
1
- {
2
- "extends": "nodebb/public"
3
- }