sopel-ai 1.0.14__py3-none-any.whl → 1.3.4__py3-none-any.whl
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.
- sopel_ai/__init__.py +4 -1
- sopel_ai/config.py +2 -0
- sopel_ai/core.py +63 -24
- sopel_ai/errors.py +1 -1
- sopel_ai/plugin.py +26 -15
- {sopel_ai-1.0.14.dist-info → sopel_ai-1.3.4.dist-info}/METADATA +72 -10
- sopel_ai-1.3.4.dist-info/RECORD +11 -0
- sopel_ai-1.0.14.dist-info/RECORD +0 -11
- {sopel_ai-1.0.14.dist-info → sopel_ai-1.3.4.dist-info}/LICENSE.txt +0 -0
- {sopel_ai-1.0.14.dist-info → sopel_ai-1.3.4.dist-info}/WHEEL +0 -0
- {sopel_ai-1.0.14.dist-info → sopel_ai-1.3.4.dist-info}/entry_points.txt +0 -0
- {sopel_ai-1.0.14.dist-info → sopel_ai-1.3.4.dist-info}/top_level.txt +0 -0
sopel_ai/__init__.py
CHANGED
sopel_ai/config.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# See: https://raw.githubcontent.com/pr3d4t0r/sopel_ai/master/LICENSE.txt
|
2
2
|
|
3
3
|
from sopel import config
|
4
|
+
from sopel_ai.core import DEFAULT_API_KEY
|
4
5
|
from sopel_ai.core import DEFAULT_LLM
|
5
6
|
from sopel_ai.core import DEFAULT_LLM_PROVIDER
|
6
7
|
from sopel_ai.core import DEFAULT_LLM_SERVICE
|
@@ -9,6 +10,7 @@ from sopel_ai.core import DEFAULT_LOG_LEVEL
|
|
9
10
|
|
10
11
|
class SopelAISection(config.types.StaticSection):
|
11
12
|
llm_engine = config.types.ValidatedAttribute('llm_engine', str, default = DEFAULT_LLM)
|
13
|
+
llm_key = config.types.ValidatedAttribute('llm_key', str, default = DEFAULT_API_KEY, is_secret = True)
|
12
14
|
llm_provider = config.types.ValidatedAttribute('llm_provider', str, default = DEFAULT_LLM_PROVIDER)
|
13
15
|
llm_service = config.types.ValidatedAttribute('llm_service', str, default = DEFAULT_LLM_SERVICE)
|
14
16
|
logLevel = config.types.ValidatedAttribute('logLevel', str, default = DEFAULT_LOG_LEVEL)
|
sopel_ai/core.py
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# See: https://raw.githubcontent.com/pr3d4t0r/sopel_ai/master/LICENSE.txt
|
2
2
|
|
3
|
-
from perplexipy import PERPLEXITY_API_KEY
|
4
3
|
from perplexipy import PERPLEXITY_API_URL
|
5
4
|
from perplexipy import PERPLEXITY_DEFAULT_MODEL
|
6
5
|
from perplexipy import PerplexityClient
|
7
6
|
from sopel_ai import __VERSION__
|
8
|
-
from sopel_ai.errors import
|
7
|
+
from sopel_ai.errors import SopelAIError
|
9
8
|
from tinydb import Query
|
10
9
|
from tinydb import TinyDB
|
11
10
|
|
@@ -14,6 +13,7 @@ from tinydb import TinyDB
|
|
14
13
|
|
15
14
|
# +++ constants +++
|
16
15
|
|
16
|
+
DEFAULT_API_KEY = 'pplx-3a45enterthekeyhere'
|
17
17
|
DEFAULT_LLM = PERPLEXITY_DEFAULT_MODEL
|
18
18
|
DEFAULT_LLM_PROVIDER = 'PerplexityAI'
|
19
19
|
DEFAULT_LLM_SERVICE = PERPLEXITY_API_URL
|
@@ -54,19 +54,20 @@ def _checkDB(fileName: str) -> TinyDB:
|
|
54
54
|
|
55
55
|
if not _database:
|
56
56
|
_database = TinyDB(fileName)
|
57
|
+
_database.table('_default', cache_size = 0)
|
57
58
|
|
58
59
|
return _database
|
59
60
|
|
60
61
|
|
61
|
-
def _checkClientInstance() -> None:
|
62
|
+
def _checkClientInstance(key: str) -> None:
|
62
63
|
global _client
|
63
64
|
|
64
65
|
if not _client:
|
65
|
-
_client = PerplexityClient(key =
|
66
|
+
_client = PerplexityClient(key = key, endpoint = PERPLEXITY_API_URL)
|
66
67
|
_client.model = PERPLEXITY_DEFAULT_MODEL
|
67
68
|
|
68
69
|
|
69
|
-
def runQuery(query: str, nick: str = None, fileNameDB: str = None, responseLength: int = MAX_RESPONSE_LENGTH) -> str:
|
70
|
+
def runQuery(query: str, nick: str = None, fileNameDB: str = None, responseLength: int = MAX_RESPONSE_LENGTH, key: str = None) -> str:
|
70
71
|
"""
|
71
72
|
Run a query against the LLM engine using the PerplexipyClient, and return the
|
72
73
|
query result in a string.
|
@@ -87,25 +88,36 @@ def runQuery(query: str, nick: str = None, fileNameDB: str = None, responseLengt
|
|
87
88
|
responseLength
|
88
89
|
The maximum response length requested from the AI provider. See `MAX_RESPONSE_LENGTH`.
|
89
90
|
|
91
|
+
key
|
92
|
+
The LLM service provider API key.
|
93
|
+
|
90
94
|
Returns
|
91
95
|
-------
|
92
96
|
A string with the response if the service found a reasonable and convenient
|
93
97
|
one, or the text of an Error and the possible cause, as reported by the
|
94
98
|
Python run-time.
|
95
99
|
|
100
|
+
Raises
|
101
|
+
------
|
102
|
+
`SopelAIError` if the `key` is empty or if the query is invalid. The string
|
103
|
+
message in the error reflects the cause.
|
104
|
+
|
96
105
|
---
|
97
106
|
"""
|
107
|
+
if not key:
|
108
|
+
raise SopelAIError('key argument cannot be empty - set the LLM service API key')
|
109
|
+
|
98
110
|
_checkDB(fileNameDB)
|
99
|
-
model = getModelForUser(nick, fileNameDB)
|
111
|
+
model = getModelForUser(nick, fileNameDB, key)
|
100
112
|
if not nick or model == DEFAULT_LLM:
|
101
|
-
_checkClientInstance()
|
113
|
+
_checkClientInstance(key)
|
102
114
|
client = _client
|
103
115
|
else:
|
104
116
|
client = _clientCache[nick]
|
105
117
|
|
106
118
|
try:
|
107
119
|
if not query:
|
108
|
-
raise
|
120
|
+
raise SopelAIError('query parameter cannot be empty')
|
109
121
|
query = 'Brief answer in %s characters or less to: "%s". Include one URL in the response and strip off all Markdown and hashtags.' % (responseLength, query)
|
110
122
|
result = client.query(query).replace('\n', '')
|
111
123
|
except Exception as e:
|
@@ -114,7 +126,7 @@ def runQuery(query: str, nick: str = None, fileNameDB: str = None, responseLengt
|
|
114
126
|
return result
|
115
127
|
|
116
128
|
|
117
|
-
def modelsList() -> list:
|
129
|
+
def modelsList(key: str = None) -> list:
|
118
130
|
"""
|
119
131
|
Returns a list of all available models so that they can be used for
|
120
132
|
requesting a specific one in another command.
|
@@ -125,26 +137,37 @@ def modelsList() -> list:
|
|
125
137
|
order depends on what the underlying API reports, and it's unlikely to
|
126
138
|
change between calls.
|
127
139
|
|
128
|
-
Other
|
140
|
+
Other SopelAI functions will use the index to refer to a model in the
|
129
141
|
collection.
|
130
142
|
|
143
|
+
Raises
|
144
|
+
------
|
145
|
+
`SopelAIError` if the `key` is empty or if the query is invalid. The string
|
146
|
+
message in the error reflects the cause.
|
147
|
+
|
131
148
|
---
|
132
149
|
"""
|
133
|
-
|
150
|
+
if not key:
|
151
|
+
raise SopelAIError('key argument cannot be empty - set the LLM service API key')
|
152
|
+
|
153
|
+
_checkClientInstance(key)
|
134
154
|
|
135
155
|
return sorted(list(_client.models.keys()))
|
136
156
|
|
137
157
|
|
138
|
-
def versionInfo() -> str:
|
139
|
-
|
158
|
+
def versionInfo(key: str = None) -> str:
|
159
|
+
if not key:
|
160
|
+
raise SopelAIError('key argument cannot be empty - set the LLM service API key')
|
161
|
+
|
162
|
+
_checkClientInstance(key)
|
140
163
|
return 'sopel_ai v%s using %s' % (__VERSION__, '.'.join([_client.__class__.__module__, _client.__class__.__name__]))
|
141
164
|
|
142
165
|
|
143
|
-
def setModelForUser(modelID: int, nick: str, fileNameDB: str) -> str:
|
166
|
+
def setModelForUser(modelID: int, nick: str, fileNameDB: str, key = None) -> str:
|
144
167
|
"""
|
145
168
|
Set the model associated with `modelID` for processing requests from `nick`.
|
146
169
|
The `modelID` is the index into the `models` object returned by
|
147
|
-
`
|
170
|
+
`sopel_ai.modelsList()`, from zero.
|
148
171
|
|
149
172
|
Arguments
|
150
173
|
---------
|
@@ -158,6 +181,9 @@ def setModelForUser(modelID: int, nick: str, fileNameDB: str) -> str:
|
|
158
181
|
fileNameDB
|
159
182
|
The path to the database in the file system. Can be absolute or relative.
|
160
183
|
|
184
|
+
key
|
185
|
+
The LLM service provider API key.
|
186
|
+
|
161
187
|
The function assumes that `nick` represents a valid user /nick because Sopel
|
162
188
|
enforces that the exists and is registered in the server.
|
163
189
|
|
@@ -167,26 +193,26 @@ def setModelForUser(modelID: int, nick: str, fileNameDB: str) -> str:
|
|
167
193
|
|
168
194
|
Raises
|
169
195
|
------
|
170
|
-
`
|
196
|
+
`sopel_ai.errors.SopelAIError` if the arguments are invalid or out of range.
|
171
197
|
|
172
198
|
---
|
173
199
|
"""
|
174
200
|
_checkDB(fileNameDB)
|
175
|
-
models= modelsList()
|
201
|
+
models= modelsList(key)
|
176
202
|
if modelID not in range(len(models)):
|
177
|
-
raise
|
203
|
+
raise SopelAIError('modelID outside of available models index range')
|
178
204
|
|
179
|
-
|
205
|
+
query = Query()
|
180
206
|
|
181
|
-
if _database.search(
|
182
|
-
_database.update({ 'model': models[modelID], },
|
207
|
+
if _database.search(query.nick == nick):
|
208
|
+
_database.update({ 'model': models[modelID], }, query.nick == nick)
|
183
209
|
else:
|
184
210
|
_database.insert({ 'nick': nick, 'model': models[modelID], })
|
185
211
|
|
186
212
|
return models[modelID]
|
187
213
|
|
188
214
|
|
189
|
-
def getModelForUser(nick: str, fileNameDB: str) -> str:
|
215
|
+
def getModelForUser(nick: str, fileNameDB: str, key = None) -> str:
|
190
216
|
"""
|
191
217
|
Get the model name for the user with `nick`.
|
192
218
|
|
@@ -198,19 +224,32 @@ def getModelForUser(nick: str, fileNameDB: str) -> str:
|
|
198
224
|
fileNameDB
|
199
225
|
The path to the database in the file system. Can be absolute or relative.
|
200
226
|
|
227
|
+
key
|
228
|
+
The LLM service provider API key.
|
229
|
+
|
201
230
|
Returns
|
202
231
|
-------
|
203
232
|
A string representing the model name, if one exists in the database
|
204
|
-
associated with the user, `
|
233
|
+
associated with the user, `sopel_ai.DEFAULT_LLM` otherwise.
|
234
|
+
|
235
|
+
Raises
|
236
|
+
------
|
237
|
+
`sopel_ai.errors.SopelAIError` if the arguments are invalid or out of range.
|
205
238
|
|
206
239
|
---
|
207
240
|
"""
|
241
|
+
if not key:
|
242
|
+
raise SopelAIError('key argument cannot be empty - set the LLM service API key')
|
243
|
+
|
208
244
|
_checkDB(fileNameDB)
|
209
245
|
Preference = Query()
|
210
246
|
preference = _database.search(Preference.nick == nick)
|
211
247
|
if preference:
|
248
|
+
client = PerplexityClient(key = key, endpoint = PERPLEXITY_API_URL)
|
212
249
|
model = preference[0]['model']
|
213
|
-
|
250
|
+
# TODO: Implement unit test for this case.
|
251
|
+
if model not in client.models.keys():
|
252
|
+
model = tuple(client.models.keys())[0]
|
214
253
|
client.model = model
|
215
254
|
_clientCache[nick] = client
|
216
255
|
return model
|
sopel_ai/errors.py
CHANGED
sopel_ai/plugin.py
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
# See: https://raw.githubcontent.com/pr3d4t0r/sopel_ai/master/LICENSE.txt
|
2
2
|
"""
|
3
|
-
|
4
|
-
user-callable objects, functions defined in it. If in doubt, user the Force and
|
5
|
-
read the Source.
|
3
|
+
Sopel AI interactive models service
|
6
4
|
"""
|
7
5
|
|
6
|
+
from sopel import formatting
|
7
|
+
from sopel import plugin
|
8
8
|
from sopel.bot import Sopel
|
9
9
|
from sopel.bot import SopelWrapper
|
10
10
|
from sopel.config import Config
|
11
|
-
from sopel import formatting
|
12
|
-
from sopel import plugin
|
13
11
|
from sopel.trigger import Trigger
|
14
12
|
from sopel_ai.config import SopelAISection
|
13
|
+
from sopel_ai.core import DEFAULT_API_KEY
|
15
14
|
from sopel_ai.core import DEFAULT_LLM
|
16
15
|
from sopel_ai.core import DEFAULT_LLM_PROVIDER
|
17
16
|
from sopel_ai.core import DEFAULT_LLM_SERVICE
|
@@ -26,6 +25,12 @@ from sopel_ai.core import versionInfo
|
|
26
25
|
|
27
26
|
import os
|
28
27
|
|
28
|
+
"""
|
29
|
+
This module is intended for interfacing with Sopel and there are no
|
30
|
+
user-callable objects, functions defined in it. If in doubt, user the Force and
|
31
|
+
read the Source.
|
32
|
+
"""
|
33
|
+
|
29
34
|
|
30
35
|
# +++ constants +++
|
31
36
|
|
@@ -49,6 +54,7 @@ def configure(config: Config) -> None:
|
|
49
54
|
"""
|
50
55
|
config.define_section('sopel_ai', SopelAISection)
|
51
56
|
config.sopel_ai.configure_setting('llm_engine', 'Set the LLM engine', default = DEFAULT_LLM)
|
57
|
+
config.sopel_ai.configure_setting('llm_key', 'Set the API key', default = DEFAULT_API_KEY)
|
52
58
|
config.sopel_ai.configure_setting('llm_provider', 'Set the LLM provider name', default = DEFAULT_LLM_PROVIDER)
|
53
59
|
config.sopel_ai.configure_setting('llm_service', 'Set the LLM service URL', default = DEFAULT_LLM_SERVICE)
|
54
60
|
config.sopel_ai.configure_setting('logLevel', 'Set the log level', default = DEFAULT_LOG_LEVEL)
|
@@ -66,7 +72,7 @@ def _queryCommand(bot: SopelWrapper, trigger: Trigger) -> None:
|
|
66
72
|
return
|
67
73
|
|
68
74
|
# TODO: Log this
|
69
|
-
bot.reply(runQuery(trigger.group(2), trigger.nick, fileNameDB = _USER_DB_FILE))
|
75
|
+
bot.reply(runQuery(trigger.group(2), trigger.nick, fileNameDB = _USER_DB_FILE, key = bot.config.sopel_ai.llm_key))
|
70
76
|
|
71
77
|
|
72
78
|
@plugin.commands('qpm', 'llmqpm')
|
@@ -80,7 +86,12 @@ def _queryCommandPrivateMessage(bot: SopelWrapper, trigger: Trigger) -> None:
|
|
80
86
|
bot.reply('No search term. Usage: {}qpm Some question about anything'.format(bot.config.core.help_prefix))
|
81
87
|
return
|
82
88
|
|
83
|
-
bot.say(runQuery(
|
89
|
+
bot.say(runQuery(
|
90
|
+
trigger.group(2),
|
91
|
+
trigger.nick,
|
92
|
+
fileNameDB = _USER_DB_FILE,
|
93
|
+
responseLength = _PRIVATE_MESSAGE_RESPONSE_LENGTH,
|
94
|
+
key = bot.config.sopel_ai.llm_key), trigger.nick)
|
84
95
|
|
85
96
|
|
86
97
|
@plugin.commands('mver')
|
@@ -89,7 +100,7 @@ def _queryCommandPrivateMessage(bot: SopelWrapper, trigger: Trigger) -> None:
|
|
89
100
|
@plugin.require_account(message = 'You must be a registered to use this command.', reply = True)
|
90
101
|
@plugin.thread(True)
|
91
102
|
def _versionCommand(bot: SopelWrapper, trigger: Trigger) -> None:
|
92
|
-
bot.reply(versionInfo())
|
103
|
+
bot.reply(versionInfo(key = bot.config.sopel_ai.llm_key))
|
93
104
|
|
94
105
|
|
95
106
|
@plugin.commands('models')
|
@@ -98,7 +109,7 @@ def _versionCommand(bot: SopelWrapper, trigger: Trigger) -> None:
|
|
98
109
|
@plugin.require_account(message = 'You must be a registered to use this command.', reply = True)
|
99
110
|
@plugin.thread(True)
|
100
111
|
def _modelsCommand(bot: SopelWrapper, trigger: Trigger) -> None:
|
101
|
-
models = sorted(modelsList())
|
112
|
+
models = sorted(modelsList(key = bot.config.sopel_ai.llm_key))
|
102
113
|
s = ''
|
103
114
|
for index in range(len(models)):
|
104
115
|
s += '[%d] %s; ' % (index+1, models[index])
|
@@ -115,13 +126,13 @@ def _setModelCommand(bot: SopelWrapper, trigger: Trigger) -> None:
|
|
115
126
|
modelID = int(trigger.group(2))
|
116
127
|
except:
|
117
128
|
modelID = -1
|
118
|
-
models = modelsList()
|
129
|
+
models = modelsList(bot.config.sopel_ai.llm_key)
|
119
130
|
if modelID not in range(1, len(models)+1):
|
120
131
|
message = 'Invalid model ID; must be in range %s. Usage: {}setmodel n, where n ::= integer' % ('1 - %d' % len(models))
|
121
132
|
bot.reply(message.format(bot.config.core.help_prefix))
|
122
133
|
else:
|
123
134
|
effectiveModelID = modelID-1
|
124
|
-
effectiveModel = setModelForUser(effectiveModelID, trigger.nick, _USER_DB_FILE)
|
135
|
+
effectiveModel = setModelForUser(effectiveModelID, trigger.nick, _USER_DB_FILE, key = bot.config.sopel_ai.llm_key)
|
125
136
|
bot.reply('All your future interactions will use the %s model.' % effectiveModel)
|
126
137
|
|
127
138
|
|
@@ -131,7 +142,7 @@ def _setModelCommand(bot: SopelWrapper, trigger: Trigger) -> None:
|
|
131
142
|
@plugin.require_account(message = 'You must be a registered to use this command.', reply = True)
|
132
143
|
@plugin.thread(True)
|
133
144
|
def _getModelCommand(bot: SopelWrapper, trigger: Trigger) -> None:
|
134
|
-
bot.reply(getModelForUser(trigger.nick, _USER_DB_FILE))
|
145
|
+
bot.reply(getModelForUser(trigger.nick, _USER_DB_FILE, key = bot.config.sopel_ai.llm_key))
|
135
146
|
|
136
147
|
|
137
148
|
@plugin.commands('mymodel')
|
@@ -146,12 +157,12 @@ def _myModelCommand(bot: SopelWrapper, trigger: Trigger) -> None:
|
|
146
157
|
_setModelCommand(bot, trigger)
|
147
158
|
|
148
159
|
|
149
|
-
@plugin.commands('
|
150
|
-
@plugin.example('.
|
160
|
+
@plugin.commands('reqai')
|
161
|
+
@plugin.example('.reqai Displays the URL for opening a GitHub features/bug/issues request for sopel_ai')
|
151
162
|
@plugin.output_prefix(_PLUGIN_OUTPUT_PREFIX)
|
152
163
|
@plugin.require_account(message = 'You must be a registered to use this command.', reply = True)
|
153
164
|
@plugin.thread(True)
|
154
165
|
def _reqCommand(bot: SopelWrapper, trigger: Trigger) -> None:
|
155
166
|
locator = formatting.bold(GITHUB_NEW_ISSUE_URL)
|
156
|
-
bot.reply('SopelAI version %s. Enter your
|
167
|
+
bot.reply('SopelAI version %s. Enter your feature request or bug report at this URL: %s' % (__VERSION__, locator))
|
157
168
|
|
@@ -1,8 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sopel-ai
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.4
|
4
4
|
Summary: Sopel AI - an LLM enhanced chat bot plug-in
|
5
5
|
Author-email: The SopelAI team <sopel_ai@cime.net>
|
6
|
+
License: BSD-3-Clause
|
6
7
|
Project-URL: Homepage, https://github.com/pr3d4t0r/sopel_ai
|
7
8
|
Project-URL: Bug Tracker, https://github.com/pr3d4t0r/sopel_ai/issues
|
8
9
|
Keywords: ai,bot,irc,llm,plugin,sopel
|
@@ -19,11 +20,11 @@ Classifier: Topic :: Utilities
|
|
19
20
|
Requires-Python: >=3.9
|
20
21
|
Description-Content-Type: text/markdown
|
21
22
|
License-File: LICENSE.txt
|
22
|
-
Requires-Dist: perplexipy
|
23
|
+
Requires-Dist: perplexipy (==1.1.4)
|
23
24
|
Requires-Dist: sopel (>=7.1)
|
24
25
|
Requires-Dist: tinydb
|
25
26
|
|
26
|
-
% sopel_ai(1) Version 1.
|
27
|
+
% sopel_ai(1) Version 1.3.4 chatbot plugin
|
27
28
|
|
28
29
|
Name
|
29
30
|
====
|
@@ -105,8 +106,8 @@ The bot produces a numbered list of supported models by issuing:
|
|
105
106
|
`.models`
|
106
107
|
|
107
108
|
Users are welcome to change the default model to one of those listed by issuing
|
108
|
-
the `.mymodel` command followed by the item number for the desired model from
|
109
|
-
list:
|
109
|
+
the `.mymodel` command followed by the item number for the desired model from
|
110
|
+
the list:
|
110
111
|
|
111
112
|
`.mymodel 1`
|
112
113
|
|
@@ -114,6 +115,15 @@ Users may request private instead of in-channel responses:
|
|
114
115
|
|
115
116
|
`.qpm Quote the Three Laws of Robotics and give me examples.`
|
116
117
|
|
118
|
+
Responses generated by making `.q` queries are expected to be short or are
|
119
|
+
trunked at 480 characters. They are intended to appear in-channel and to be as
|
120
|
+
brief as possible.
|
121
|
+
|
122
|
+
Responses generated from a `.qpm` query are expected to be long and detailed,
|
123
|
+
with a 16 KB length limit, span multpile messages (due to ircv3 limitations),
|
124
|
+
and `sopel_ai` presents them to the user in private message, regardless of
|
125
|
+
whether they were issued from a channel or a direct message.
|
126
|
+
|
117
127
|
Users can query the bot plugin and AI provider using:
|
118
128
|
|
119
129
|
`.mver`
|
@@ -127,13 +137,65 @@ support other providers.
|
|
127
137
|
|
128
138
|
API Key
|
129
139
|
=======
|
130
|
-
All AI services providers require an API key for access.
|
131
|
-
|
140
|
+
All AI services providers require an API key for access. The API key is
|
141
|
+
configured via:
|
142
|
+
|
143
|
+
`sopel config`
|
144
|
+
|
145
|
+
Or edit this section in the Sopel configuration file:
|
146
|
+
|
147
|
+
```ini
|
148
|
+
[sopel_ai]
|
149
|
+
.
|
150
|
+
.
|
151
|
+
llm_key = pplx-3a45enteryourkeykere
|
152
|
+
```
|
153
|
+
|
154
|
+
|
155
|
+
Docker
|
156
|
+
======
|
157
|
+
Sopel AI is dockerized and available from Docker Hub as pr3d4t0r/sopel_ai. The
|
158
|
+
version tag is the same as the latest version number for Sopel AI.
|
159
|
+
|
160
|
+
The examples in this section assume execution from the local file system. Adapt
|
161
|
+
as needed to run in a Kubernets cluster or other deployment method.
|
162
|
+
|
163
|
+
|
164
|
+
### First time
|
132
165
|
|
133
|
-
|
166
|
+
The Sopel + AI configuration file must be created:
|
167
|
+
|
168
|
+
```bash
|
169
|
+
docker run -ti -v ${HOME}/sopel_ai_data:/home/sopel_ai \
|
170
|
+
pr3d4t0r/sopel_ai:latest \
|
171
|
+
sopel configure
|
172
|
+
```
|
173
|
+
|
174
|
+
The API key and other relevant configuration data must be provided at this time.
|
175
|
+
`$HOME/sopel_ai_data` is volume mapped to the container's `/home/sopel_ai/.sopel
|
176
|
+
directory. Ensure that your host has write permissions in the shared volume.
|
177
|
+
|
178
|
+
The `pr3d4t0r/sopel_ai:latest` image is used if no version is specified. The
|
179
|
+
image update policy is left to the sysops and is not automatic.
|
180
|
+
|
181
|
+
Once `$HOME/sopel_ai_data` exists it's possible to copy the contents of a
|
182
|
+
different `~/.sopel` directory to it and use is as the configuration and Sopel
|
183
|
+
AI database store.
|
184
|
+
|
185
|
+
|
186
|
+
### Starting Sopel AI
|
187
|
+
|
188
|
+
A Docker Compose file is provided as an example of how to start the service,
|
189
|
+
<a href='./dockerized/docker-compose.yaml' target='_blank'>docker-file.yaml</a>. With this Docker Compose
|
190
|
+
file in the current directory, start the service with:
|
191
|
+
|
192
|
+
```bash
|
193
|
+
docker-compose up [-d] sopel_ai
|
194
|
+
|
195
|
+
```
|
134
196
|
|
135
|
-
|
136
|
-
|
197
|
+
The `-d` parameter daemonizes the service. Without it, the service will start
|
198
|
+
and display its output in the current console.
|
137
199
|
|
138
200
|
|
139
201
|
License
|
@@ -0,0 +1,11 @@
|
|
1
|
+
sopel_ai/__init__.py,sha256=UXSuXZj_p860rLAiewSe5nbKg-qbIEcXq6jkqYmaMnI,2531
|
2
|
+
sopel_ai/config.py,sha256=y0vbvfeDjjfLUOvTJ3W56mAGVpJxeizrXJbCaFW4ZXk,867
|
3
|
+
sopel_ai/core.py,sha256=m5XutY1Rm7z-nh1_qPOAcrnfP20BekMH6jveXoSX3NQ,7425
|
4
|
+
sopel_ai/errors.py,sha256=XMVgFk4Rw64Z0UO3ZInp-N6LP0GRG8NFIuXKnhu5rLo,192
|
5
|
+
sopel_ai/plugin.py,sha256=51mYp6B_mUtgS6mL-IMhK8Qiz_Rw_qAwmTLdML-qQ2o,6800
|
6
|
+
sopel_ai-1.3.4.dist-info/LICENSE.txt,sha256=I8aHapysmbM9F3y-rUfp011GQoosNO5L8pzl7IKgPnE,1531
|
7
|
+
sopel_ai-1.3.4.dist-info/METADATA,sha256=yUU8251bdLtOwpudjsUOZLdjAZ9DeSrsdmXVVXLVx98,6210
|
8
|
+
sopel_ai-1.3.4.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
9
|
+
sopel_ai-1.3.4.dist-info/entry_points.txt,sha256=7Juxcn6L4j6F83TjkviiTwiyXLM4gZxAAXFQDR2G_m4,43
|
10
|
+
sopel_ai-1.3.4.dist-info/top_level.txt,sha256=kpNMzNEGbhCXkyn7oc3uQPmrX1J6qLxn59IcZBpwSYg,9
|
11
|
+
sopel_ai-1.3.4.dist-info/RECORD,,
|
sopel_ai-1.0.14.dist-info/RECORD
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
sopel_ai/__init__.py,sha256=qH1q1GP7whFC-A28pYlcg2YIb9WGv7TFnUykJqXp6Lc,2473
|
2
|
-
sopel_ai/config.py,sha256=Kj8yacVbjjC4FRz7ser16Hf4fS9_XwvXK3f5dPSpZ0I,718
|
3
|
-
sopel_ai/core.py,sha256=Jy7zyzc_mbvs_9nUeetH-hlAAus087zfXW9_h3Vsv4Q,6181
|
4
|
-
sopel_ai/errors.py,sha256=fgc9mjYJMnq1AxFXOwiknFwnJBJTWRNkZIHzRKS9m5g,191
|
5
|
-
sopel_ai/plugin.py,sha256=tCsTsqQsuBC4orcEZCQu2d2iS09NvVPBpook0fV7w5k,6306
|
6
|
-
sopel_ai-1.0.14.dist-info/LICENSE.txt,sha256=I8aHapysmbM9F3y-rUfp011GQoosNO5L8pzl7IKgPnE,1531
|
7
|
-
sopel_ai-1.0.14.dist-info/METADATA,sha256=_OcL-mDwQVViDahpFK7gcI7fZMnaKuiTWUYg-f62ENo,4324
|
8
|
-
sopel_ai-1.0.14.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
9
|
-
sopel_ai-1.0.14.dist-info/entry_points.txt,sha256=7Juxcn6L4j6F83TjkviiTwiyXLM4gZxAAXFQDR2G_m4,43
|
10
|
-
sopel_ai-1.0.14.dist-info/top_level.txt,sha256=kpNMzNEGbhCXkyn7oc3uQPmrX1J6qLxn59IcZBpwSYg,9
|
11
|
-
sopel_ai-1.0.14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|