Skip to content

Commit

Permalink
[large update] Merge contexts branch into main
Browse files Browse the repository at this point in the history
Adds "contexts" feature, subsuming older language and avoid set configurations with a more flexible approach for tailoring responses to a class and its assignments or modules.
  • Loading branch information
liffiton authored Jul 18, 2024
2 parents 2eeb856 + e6f5f01 commit b0587de
Show file tree
Hide file tree
Showing 37 changed files with 1,407 additions and 529 deletions.
7 changes: 4 additions & 3 deletions src/codehelp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from flask.wrappers import Response
from gened import base

from . import admin, class_config, helper, tutor
from . import admin, context, helper, tutor


def create_app(test_config: dict[str, Any] | None = None, instance_path: Path | None = None) -> Flask:
Expand Down Expand Up @@ -49,8 +49,9 @@ def create_app(test_config: dict[str, Any] | None = None, instance_path: Path |
app.register_blueprint(helper.bp)
app.register_blueprint(tutor.bp)

# register our custom class configuration with Gen-Ed
class_config.register_with_gened()
# register our custom context configuration with Gen-Ed
# and grab a reference to the app's markdown filter
context.init_app(app)

# register app-specific charts in the admin interface
admin.register_with_gened()
Expand Down
40 changes: 0 additions & 40 deletions src/codehelp/class_config.py

This file was deleted.

92 changes: 92 additions & 0 deletions src/codehelp/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# SPDX-FileCopyrightText: 2023 Mark Liffiton <[email protected]>
#
# SPDX-License-Identifier: AGPL-3.0-only

from dataclasses import dataclass

from flask import Flask, current_app
from gened.contexts import ContextConfig, register_context
from jinja2 import Environment
from typing_extensions import Self
from werkzeug.datastructures import ImmutableMultiDict


def _default_langs() -> list[str]:
langs: list[str] = current_app.config['DEFAULT_LANGUAGES'] # declaration keeps mypy happy
return langs

jinja_env_prompt = Environment(
trim_blocks=True,
lstrip_blocks=True,
autoescape=False, # noqa: S701 - no need to escape for the LLM
)
jinja_env_html = Environment(
trim_blocks=True,
lstrip_blocks=True,
autoescape=True,
)


@dataclass(frozen=True)
class CodeHelpContext(ContextConfig):
name: str
tools: str = ''
details: str = ''
avoid: str = ''
template: str = "codehelp_context_form.html"

@classmethod
def from_request_form(cls, form: ImmutableMultiDict[str, str]) -> Self:
return cls(
name=form['name'],
tools=form.get('tools', ''),
details=form.get('details', ''),
avoid=form.get('avoid', ''),
)

@staticmethod
def _list_fmt(s: str) -> str:
if s:
return '; '.join(s.splitlines())
else:
return ''

def prompt_str(self) -> str:
""" Convert this context into a string to be used in an LLM prompt. """
template = jinja_env_prompt.from_string("""\
<name>{{ name }}</name>
{% if tools %}
Environment and tools: <tools>{{ tools }}</tools>
{% endif %}
{% if details %}
Details: <details>{{ details }}</details>
{% endif %}
{% if avoid %}
Keywords and concepts to avoid (do not mention these in your response at all): <avoid>{{ avoid }}</avoid>
{% endif %}
""")
return template.render(name=self.name, tools=self._list_fmt(self.tools), details=self.details, avoid=self._list_fmt(self.avoid))

def desc_html(self) -> str:
""" Convert this context into a description for users in HTML.
Does not include the avoid set (not necessary to show students).
"""
template = jinja_env_html.from_string("""\
{% if tools %}
<p><b>Environment & tools:</b> {{ tools }}</p>
{% endif %}
{% if details %}
<p><b>Details:</b></p>
{{ details | markdown }}
{% endif %}
""")
return template.render(tools=self._list_fmt(self.tools), details=self.details, avoid=self._list_fmt(self.avoid))


def init_app(app: Flask) -> None:
""" Register the custom context class with Gen-Ed,
and grab a copy of the app's markdown filter for use here.
"""
register_context(CodeHelpContext)
jinja_env_html.filters['markdown'] = app.jinja_env.filters['markdown']
2 changes: 0 additions & 2 deletions src/codehelp/docs/manual_class_creation.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ Anyone using the link will register as a student in the class if "Registration v
You can control whether registration is allowed by manually enabling and disabling it or by setting a date up through which registration will be enabled.
Once students have registered, they can use the same link to access CodeHelp and make queries connected to your class.

Before your students can use CodeHelp, you will need to provide a configuration under "Queries &amp; Responses," at least selecting a default language.

In the configuration screen, you can also archive the class (so students can see their past queries but not make new ones) and change or delete the OpenAI API key you have connected to it.

## Adding Instructors
Expand Down
Loading

0 comments on commit b0587de

Please sign in to comment.