Skip to content

Commit

Permalink
Add gpt-4o-mini, 'deactivate' gpt-3.5-turbo.
Browse files Browse the repository at this point in the history
  • Loading branch information
liffiton committed Aug 1, 2024
1 parent 7a61bc3 commit 32ff645
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/codehelp/docs/manual_class_creation.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ If you don't have an API key yet, you can leave it blank for now, but it will be
You can create an API key using an account at <a href="https://openai.com/">openai.com</a>.
OpenAI will charge you directly for your students' usage, so you will need to purchase usage credits using a credit card.
The cost is low.
One query from CodeHelp costs roughly US$0.01 if using GPT-4 (the recommended model) or $0.001 using GPT-3.5 (which is less accurate).
One query from CodeHelp costs roughly US$0.01 if using GPT-4o (the recommended model) or $0.0004 using GPT-4o-mini (which is less accurate).

## Configuration

Expand Down
3 changes: 2 additions & 1 deletion src/codehelp/templates/landing.html
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ <h1 class="title mb-0 mr-6">
<div class="box content">
<h2 id="costs">Costs</h2>
<p>CodeHelp itself does not take payment, but the OpenAI large language models it uses are not free. We will ask you to provide an OpenAI API key to be used for your students' queries.</p>
<p>Costs are low: OpenAI will charge you roughly US$0.01 for each query made with the GPT-4 model (GPT-3.5 is roughly 1/10 the cost, though less accurate). If your students use CodeHelp regularly and average 50 queries each over a semester (higher than the average we've observed), your total costs would be roughly $0.50 per student (or $0.05 per student if using GPT-3.5).</p>
<p>Costs are low: OpenAI will charge you roughly US$0.01 for each query made with the default GPT-4o model. If your students use CodeHelp regularly and average 50 queries each over a semester (higher than the average we've observed), your total costs would be roughly $0.50 per student.</p>
<p>(The GPT-4o-mini model is also available, and it is much less expensive though also less accurate and helpful. The same scenario above would cost about $0.02 per student if using GPT-4o-mini.)</p>
</div>

<div class="box content">
Expand Down
4 changes: 4 additions & 0 deletions src/gened/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ def create_app_base(import_name: str, app_config: dict[str, Any], instance_path:
SEND_FILE_MAX_AGE_DEFAULT=3*60*60, # 3 hours
# Free query tokens given to new users
DEFAULT_TOKENS=10,
# Model IDs for various circumstances (see also: models table in DB schema)
DEFAULT_MODEL_ID=2, # Default for new users: GPT-4o
SYSTEM_MODEL_ID=2, # Default for 'system' use: GPT-4o

PYLTI_CONFIG={
# will be loaded from the consumers table in the database
"consumers": { }
Expand Down
4 changes: 2 additions & 2 deletions src/gened/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ class name from the user
class_id = cur.lastrowid
assert class_id is not None
db.execute(
"INSERT INTO classes_user (class_id, creator_user_id, link_ident, openai_key, link_reg_expires) VALUES (?, ?, ?, ?, ?)",
[class_id, user_id, link_ident, openai_key, dt.date.min]
"INSERT INTO classes_user (class_id, creator_user_id, link_ident, openai_key, link_reg_expires, model_id) VALUES (?, ?, ?, ?, ?, ?)",
[class_id, user_id, link_ident, openai_key, dt.date.min, current_app.config['DEFAULT_MODEL_ID']]
)
db.execute(
"INSERT INTO roles (user_id, class_id, role) VALUES (?, ?, ?)",
Expand Down
31 changes: 31 additions & 0 deletions src/gened/migrations/20240731--expand-models.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-- SPDX-FileCopyrightText: 2024 Mark Liffiton <liffiton@gmail.com>
--
-- SPDX-License-Identifier: AGPL-3.0-only

PRAGMA foreign_keys = OFF;

BEGIN;

-- Note: Not removing DEFAULT values on model_id in consumer and classes_user.
-- With the default removed in the schema, no code going forward should
-- ever use that default (else it would crash in testing).

DROP TABLE models;

CREATE TABLE models (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
shortname TEXT NOT NULL UNIQUE,
model TEXT NOT NULL,
active BOOLEAN NOT NULL CHECK (active IN (0,1))
);
-- See also: DEFAULT_MODEL_ID in app.config (src/gened/base.py)
INSERT INTO models(name, shortname, model, active) VALUES
('OpenAI GPT-3.5 Turbo', 'GPT-3.5', 'gpt-3.5-turbo-0125', false),
('OpenAI GPT-4o', 'GPT-4o', 'gpt-4o', true),
('OpenAI GPT-4o-mini', 'GPT-4o-mini', 'gpt-4o-mini', true)
;

COMMIT;

PRAGMA foreign_keys = ON;
7 changes: 3 additions & 4 deletions src/gened/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def _get_llm(*, use_system_key: bool, spend_token: bool) -> LLMConfig:
a) LTI class config is in the linked LTI consumer.
b) User class config is in the user class.
c) If there is a current class but it is disabled or has no key, raise an error.
3) If the user is a local-auth user, the system API key and GPT-3.5 is used.
3) If the user is a local-auth user, the system API key and model is used.
4) Otherwise, we use tokens and the system API key / model.
If spend_token is True, the user must have 1 or more tokens remaining.
If they have 0 tokens, raise an error.
Expand All @@ -63,8 +63,7 @@ def make_system_client(tokens_remaining: int | None = None) -> LLMConfig:
""" Factory function to initialize a default client (using the system key)
only if/when needed.
"""
# Get the systemwide default model (TODO: better control than just id=2)
model_row = db.execute("SELECT models.model FROM models WHERE models.id=2").fetchone()
model_row = db.execute("SELECT models.model FROM models WHERE models.id=?", [current_app.config['SYSTEM_MODEL_ID']]).fetchone()
system_model = model_row['model']
system_key = current_app.config["OPENAI_API_KEY"]
return LLMConfig(
Expand Down Expand Up @@ -183,7 +182,7 @@ def decorated_function(*args: P.args, **kwargs: P.kwargs) -> str | R:
def get_models() -> list[Row]:
"""Enumerate the models available in the database."""
db = get_db()
models = db.execute("SELECT * FROM models ORDER BY id ASC").fetchall()
models = db.execute("SELECT * FROM models WHERE active ORDER BY id ASC").fetchall()
return models


Expand Down
15 changes: 9 additions & 6 deletions src/gened/schema_common.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ CREATE TABLE consumers (
lti_consumer TEXT NOT NULL UNIQUE,
lti_secret TEXT,
openai_key TEXT,
model_id INTEGER NOT NULL DEFAULT 1, -- gpt-3.5
model_id INTEGER NOT NULL,
created DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY(model_id) REFERENCES models(id)
);
Expand Down Expand Up @@ -111,7 +111,7 @@ CREATE UNIQUE INDEX classes_lti_by_consumer_context ON classes_lti(lti_consumer
CREATE TABLE classes_user (
class_id INTEGER PRIMARY KEY, -- references classes.id
openai_key TEXT,
model_id INTEGER NOT NULL DEFAULT 1, -- gpt-3.5
model_id INTEGER NOT NULL,
link_ident TEXT NOT NULL UNIQUE, -- random (unguessable) identifier used in access/registration link for this class
link_reg_expires DATE NOT NULL, -- registration active for the class link if this date is in the future (anywhere on Earth)
creator_user_id INTEGER NOT NULL, -- references users.id
Expand Down Expand Up @@ -158,11 +158,14 @@ CREATE TABLE models (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
shortname TEXT NOT NULL UNIQUE,
model TEXT NOT NULL
model TEXT NOT NULL,
active BOOLEAN NOT NULL CHECK (active IN (0,1))
);
INSERT INTO models(name, shortname, model) VALUES
('OpenAI GPT-3.5 Turbo', 'GPT-3.5', 'gpt-3.5-turbo-0125'),
('OpenAI GPT-4o', 'GPT-4', 'gpt-4o')
-- See also: DEFAULT_MODEL_ID in app.config (src/gened/base.py)
INSERT INTO models(name, shortname, model, active) VALUES
('OpenAI GPT-3.5 Turbo', 'GPT-3.5', 'gpt-3.5-turbo-0125', false),
('OpenAI GPT-4o', 'GPT-4o', 'gpt-4o', true),
('OpenAI GPT-4o-mini', 'GPT-4o-mini', 'gpt-4o-mini', false)
;


Expand Down
1 change: 0 additions & 1 deletion src/gened/templates/instructor_class_config.html
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ <h2 class="title is-size-4 mt-5">Language Model</h2>
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label" for="model_id">Model:</label>
<p class="help-text">Note that GPT-4 produces more accurate results than 3.5 but is also roughly 10 times the cost.</p>
</div>
<div class="field-body">
<div class="field">
Expand Down
14 changes: 7 additions & 7 deletions tests/test_data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
--
-- SPDX-License-Identifier: AGPL-3.0-only

INSERT INTO consumers (id, lti_consumer, lti_secret, openai_key)
INSERT INTO consumers (id, lti_consumer, lti_secret, openai_key, model_id)
VALUES
(1, 'consumer.domain', 'seecrits1', 'keeeez1'),
(2, 'consumer.otherdomain', 'seecrits2', 'keeeez2');
(1, 'consumer.domain', 'seecrits1', 'keeeez1', 1),
(2, 'consumer.otherdomain', 'seecrits2', 'keeeez2', 2);

INSERT INTO classes (id, name, enabled)
VALUES
Expand Down Expand Up @@ -41,11 +41,11 @@ VALUES
(22, 2, null, 'ltiuser2@domain.edu', null, false, false, 0),
(23, 2, null, 'ltiuser3@domain.edu', null, false, false, 0);

INSERT INTO classes_user (class_id, openai_key, link_ident, link_reg_expires, creator_user_id)
INSERT INTO classes_user (class_id, openai_key, link_ident, link_reg_expires, creator_user_id, model_id)
VALUES
(2, 'nope', 'reg_disabled', '0001-01-01', 11),
(3, 'nope', 'reg_expired', '2023-01-01', 11),
(4, 'nope', 'reg_enabled', '9999-12-31', 11);
(2, 'nope', 'reg_disabled', '0001-01-01', 11, 1),
(3, 'nope', 'reg_expired', '2023-01-01', 11, 2),
(4, 'nope', 'reg_enabled', '9999-12-31', 11, 2);

INSERT INTO auth_local (user_id, username, password)
VALUES
Expand Down

0 comments on commit 32ff645

Please sign in to comment.