Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions care_scribe/migrations/0012_scribe_transcript_only.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from django.db import migrations, models


def rename_processing_meta_keys_forward(apps, schema_editor):
"""Rename old processing meta keys to the new keys.

Old -> New:
provider -> chat_provider
audio_model -> transcribe_model

Also adds `transcribe_provider` mirroring `chat_provider` so historical
entries match the new shape.
"""
Scribe = apps.get_model("care_scribe", "Scribe")
to_update = []
for scribe in Scribe.objects.exclude(meta={}).iterator():
meta = scribe.meta or {}
processings = meta.get("processings")
if not processings:
continue
changed = False
for processing in processings:
if not isinstance(processing, dict):
continue
if "provider" in processing and "chat_provider" not in processing:
processing["chat_provider"] = processing.pop("provider")
changed = True
if "audio_model" in processing and "transcribe_model" not in processing:
processing["transcribe_model"] = processing.pop("audio_model")
changed = True
if (
"chat_provider" in processing
and "transcribe_provider" not in processing
):
processing["transcribe_provider"] = processing["chat_provider"]
changed = True
if changed:
scribe.meta = meta
to_update.append(scribe)
if len(to_update) >= 500:
Scribe.objects.bulk_update(to_update, ["meta"])
to_update = []
if to_update:
Scribe.objects.bulk_update(to_update, ["meta"])


def rename_processing_meta_keys_reverse(apps, schema_editor):
"""Revert the rename: new keys -> old keys."""
Scribe = apps.get_model("care_scribe", "Scribe")
to_update = []
for scribe in Scribe.objects.exclude(meta={}).iterator():
meta = scribe.meta or {}
processings = meta.get("processings")
if not processings:
continue
changed = False
for processing in processings:
if not isinstance(processing, dict):
continue
if "chat_provider" in processing and "provider" not in processing:
processing["provider"] = processing.pop("chat_provider")
changed = True
if "transcribe_model" in processing and "audio_model" not in processing:
processing["audio_model"] = processing.pop("transcribe_model")
changed = True
if "transcribe_provider" in processing:
processing.pop("transcribe_provider")
changed = True
if changed:
scribe.meta = meta
to_update.append(scribe)
if len(to_update) >= 500:
Scribe.objects.bulk_update(to_update, ["meta"])
to_update = []
if to_update:
Scribe.objects.bulk_update(to_update, ["meta"])


class Migration(migrations.Migration):

dependencies = [
('care_scribe', '0011_scribefile_mime_type'),
]

operations = [
migrations.AddField(
model_name='scribe',
name='transcript_only',
field=models.BooleanField(
default=False,
help_text='If True, only transcribe the audio without running any AI form-fill processing.',
),
),
migrations.RunPython(
rename_processing_meta_keys_forward,
rename_processing_meta_keys_reverse,
),
]
4 changes: 4 additions & 0 deletions care_scribe/models/scribe.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ class Status(models.TextChoices):
chat_model = models.CharField(max_length=100, null=True, blank=True)
audio_model = models.CharField(max_length=100, null=True, blank=True)
chat_model_temperature = models.FloatField(null=True, blank=True)
transcript_only = models.BooleanField(
default=False,
help_text="If True, only transcribe the audio without running any AI form-fill processing.",
)

is_feedback_positive = models.BooleanField(null=True, blank=True, help_text="Whether the user has given positive feedback on the AI response")
feedback_comments = models.TextField(null=True, blank=True, help_text="Details of the feedback provided by the user")
Expand Down
1 change: 1 addition & 0 deletions care_scribe/serializers/scribe.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class Meta:
"chat_model",
"audio_model",
"chat_model_temperature",
"transcript_only",
"is_feedback_positive",
"feedback_comments",
]
Expand Down
45 changes: 28 additions & 17 deletions care_scribe/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,29 +86,40 @@ def validate(self) -> None:
f'Please set the "{setting}" in the environment or the {PLUGIN_NAME} plugin config.'
)

if getattr(self, "SCRIBE_API_PROVIDER") not in ("openai", "azure", "google"):
valid_providers = ("openai", "azure", "google")
providers_in_use = set()

for setting_name in ("SCRIBE_CHAT_MODEL_NAME", "SCRIBE_TRANSCRIBE_MODEL_NAME"):
value = getattr(self, setting_name)
if "/" not in value:
raise ImproperlyConfigured(
f'Invalid value for "{setting_name}". '
f'Expected format "provider/model-name" '
f'(provider must be one of {valid_providers}).'
)
provider = value.split("/", 1)[0]
if provider not in valid_providers:
raise ImproperlyConfigured(
f'Invalid provider "{provider}" in "{setting_name}". '
f'Provider must be one of {valid_providers}.'
)
providers_in_use.add(provider)

if "openai" in providers_in_use and not getattr(self, "SCRIBE_OPENAI_API_KEY"):
raise ImproperlyConfigured(
'Invalid value for "SCRIBE_API_PROVIDER". '
'Please set the "SCRIBE_API_PROVIDER" to "openai", "google" or "azure".'
'The "SCRIBE_OPENAI_API_KEY" setting is required when using OpenAI API. '
f'Please set it in the environment or the {PLUGIN_NAME} plugin config.'
)

if getattr(self, "SCRIBE_API_PROVIDER") == "openai":
for setting in ("SCRIBE_OPENAI_API_KEY",):
if not getattr(self, setting):
raise ImproperlyConfigured(
f'The "{setting}" setting is required when using OpenAI API. '
f'Please set the "{setting}" in the environment or the {PLUGIN_NAME} plugin config.'
)

if getattr(self, "SCRIBE_API_PROVIDER") == "azure":
if "azure" in providers_in_use:
for setting in ("SCRIBE_AZURE_API_VERSION", "SCRIBE_AZURE_ENDPOINT", "SCRIBE_AZURE_API_KEY"):
if not getattr(self, setting):
raise ImproperlyConfigured(
f'The "{setting}" setting is required when using Azure API. '
f'Please set the "{setting}" in the environment or the {PLUGIN_NAME} plugin config.'
)

if getattr(self, "SCRIBE_API_PROVIDER") == "google":
if "google" in providers_in_use:
for setting in ("SCRIBE_GOOGLE_PROJECT_ID", "SCRIBE_GOOGLE_LOCATION"):
if not getattr(self, setting):
raise ImproperlyConfigured(
Expand All @@ -129,19 +140,19 @@ def reload(self) -> None:

REQUIRED_SETTINGS = {
"SCRIBE_CHAT_MODEL_NAME",
"SCRIBE_API_PROVIDER",
"SCRIBE_TRANSCRIBE_MODEL_NAME",
}

DEFAULTS = {
"SCRIBE_OPENAI_API_KEY": "",
"SCRIBE_AZURE_API_KEY": "",
"SCRIBE_AUDIO_MODEL_NAME": "whisper-1",
"SCRIBE_CHAT_MODEL_NAME": "gpt-4o",
"SCRIBE_API_PROVIDER": "openai",
"SCRIBE_TRANSCRIBE_MODEL_NAME": "openai/whisper-1",
"SCRIBE_CHAT_MODEL_NAME": "openai/gpt-4o",
"SCRIBE_AZURE_API_VERSION": "",
"SCRIBE_AZURE_ENDPOINT": "",
"SCRIBE_GOOGLE_PROJECT_ID" : "",
"SCRIBE_GOOGLE_LOCATION" : "",
"SCRIBE_TRANSCRIBE_LANGUAGE": "", # only works for google. OpenAI can return source language or only translate to English.
"SCRIBE_TNC": "<Please add your terms and conditions here>",
}

Expand Down
Loading