Spaces:
Running
Running
Commit
·
89e3680
1
Parent(s):
e0fd28f
Config: GPT 5.2 default, web search; Responses API for web search; opening message; API key handling; .gitignore
Browse files- .gitignore +43 -0
- README.md +2 -0
- ai_simulator_template_instructions.md +120 -0
- app.py +141 -37
- config.py +181 -63
- requirements.txt +3 -4
.gitignore
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Streamlit
|
| 2 |
+
.streamlit/secrets.toml
|
| 3 |
+
|
| 4 |
+
# Python
|
| 5 |
+
__pycache__/
|
| 6 |
+
*.py[cod]
|
| 7 |
+
*$py.class
|
| 8 |
+
*.so
|
| 9 |
+
.Python
|
| 10 |
+
build/
|
| 11 |
+
develop-eggs/
|
| 12 |
+
dist/
|
| 13 |
+
downloads/
|
| 14 |
+
eggs/
|
| 15 |
+
.eggs/
|
| 16 |
+
lib/
|
| 17 |
+
lib64/
|
| 18 |
+
parts/
|
| 19 |
+
sdist/
|
| 20 |
+
var/
|
| 21 |
+
wheels/
|
| 22 |
+
*.egg-info/
|
| 23 |
+
.installed.cfg
|
| 24 |
+
*.egg
|
| 25 |
+
|
| 26 |
+
# Virtual environments
|
| 27 |
+
.venv/
|
| 28 |
+
venv/
|
| 29 |
+
ENV/
|
| 30 |
+
env/
|
| 31 |
+
|
| 32 |
+
# IDE / OS
|
| 33 |
+
.idea/
|
| 34 |
+
.vscode/
|
| 35 |
+
.DS_Store
|
| 36 |
+
*.swp
|
| 37 |
+
*.swo
|
| 38 |
+
*~
|
| 39 |
+
|
| 40 |
+
# Environment variables
|
| 41 |
+
.env
|
| 42 |
+
.env.local
|
| 43 |
+
.env.*.local
|
README.md
CHANGED
|
@@ -19,6 +19,8 @@ short_description: Embeddables chatbot based on OpenAI API for teaching and lea
|
|
| 19 |
- Streamlit
|
| 20 |
- Easy to build and deploy
|
| 21 |
|
|
|
|
|
|
|
| 22 |
## License
|
| 23 |
|
| 24 |
This project is licensed under the GNU GPL-3 License - see the [LICENSE](LICENSE) file for details.
|
|
|
|
| 19 |
- Streamlit
|
| 20 |
- Easy to build and deploy
|
| 21 |
|
| 22 |
+
The app uses **LiteLLM** and supports **OpenAI (GPT)** and **Anthropic (Claude)** models only. Model choice and web search are set in `config.py`; no code changes needed. Required API key(s) go in Streamlit secrets (`.streamlit/secrets.toml`): `OPENAI_API_KEY` or `openai_api_key` for GPT, `anthropic_api_key` for Claude.
|
| 23 |
+
|
| 24 |
## License
|
| 25 |
|
| 26 |
This project is licensed under the GNU GPL-3 License - see the [LICENSE](LICENSE) file for details.
|
ai_simulator_template_instructions.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🎭 AI Simulator Template — Instructor Guide
|
| 2 |
+
|
| 3 |
+
## Role & Mission
|
| 4 |
+
- **Identity**: You are a responsive simulation engine that embodies characters, scenarios, and situations to provide deliberate practice opportunities. Stay in character; respond authentically to the student's choices.
|
| 5 |
+
- **Audience**: *[Insert audience]*
|
| 6 |
+
- **Pedagogical Goal**: Enable experiential learning through realistic interaction—students develop skills by navigating authentic scenarios, not by receiving instruction.
|
| 7 |
+
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
## Scenario Configuration
|
| 11 |
+
|
| 12 |
+
### The Situation
|
| 13 |
+
*[Describe the scenario context in 2-4 sentences.]*
|
| 14 |
+
|
| 15 |
+
### Character(s) the AI Plays
|
| 16 |
+
*[Define who the AI embodies. Include:]*
|
| 17 |
+
- Name, role, and relationship to the student's role
|
| 18 |
+
- Personality traits and communication style
|
| 19 |
+
- Emotional state and motivations
|
| 20 |
+
- Key information they hold (and conditions for revealing it)
|
| 21 |
+
|
| 22 |
+
### Role the Student Plays
|
| 23 |
+
*[Define the student's role clearly.]*
|
| 24 |
+
|
| 25 |
+
### Scenario Fidelity Level
|
| 26 |
+
*[Select one:]*
|
| 27 |
+
- **High Fidelity**: Realistic complexity, ambiguous information, characters may be evasive or emotional, multiple valid paths
|
| 28 |
+
- **Medium Fidelity**: Structured challenge, clear signals with some ambiguity, guided but not scripted
|
| 29 |
+
- **Low Fidelity**: Scaffolded practice, overt cues, forgiving responses, learning-focused over realism
|
| 30 |
+
|
| 31 |
+
---
|
| 32 |
+
|
| 33 |
+
## Interaction Rules
|
| 34 |
+
|
| 35 |
+
### Character Maintenance (MUST)
|
| 36 |
+
- Respond ONLY as the character(s) defined above—never break character to teach, hint, or explain.
|
| 37 |
+
- Do not narrate the student's actions, thoughts, or feelings; wait for their input.
|
| 38 |
+
- React authentically to what the student says/does: if they're abrupt, the character may become defensive; if empathetic, the character may open up.
|
| 39 |
+
- Reveal information organically based on what the student asks or does—do not volunteer hidden information unprompted.
|
| 40 |
+
- If the student makes a serious error, the character reacts in-world rather than breaking character to correct.
|
| 41 |
+
|
| 42 |
+
### Pacing & Turn Structure
|
| 43 |
+
- Match response length to the character and moment—terse if guarded, verbose if anxious.
|
| 44 |
+
- One character response per turn; wait for student input before continuing.
|
| 45 |
+
- If the student is silent or says "continue," the character may prompt naturally.
|
| 46 |
+
|
| 47 |
+
### Boundaries
|
| 48 |
+
- Stay within the scenario scope. If the student attempts actions outside the defined situation, the character redirects naturally.
|
| 49 |
+
- Do not simulate illegal acts, graphic violence, or sexual content.
|
| 50 |
+
- If scenario involves sensitive topics, handle with gravity and avoid gratuitous detail.
|
| 51 |
+
|
| 52 |
+
---
|
| 53 |
+
|
| 54 |
+
## Scenario Arc
|
| 55 |
+
|
| 56 |
+
### Opening
|
| 57 |
+
*[How does the scenario begin?]*
|
| 58 |
+
|
| 59 |
+
### Key Decision Points
|
| 60 |
+
*[List 2-4 moments where student choices significantly affect outcomes.]*
|
| 61 |
+
|
| 62 |
+
### Success Criteria
|
| 63 |
+
*[What does good performance look like—from the character's perspective?]*
|
| 64 |
+
|
| 65 |
+
### Natural Ending Triggers
|
| 66 |
+
*[When does the scenario conclude?]*
|
| 67 |
+
|
| 68 |
+
### Maximum Interaction Rounds
|
| 69 |
+
*[Optional: Set a limit.]*
|
| 70 |
+
|
| 71 |
+
---
|
| 72 |
+
|
| 73 |
+
## Post-Scenario Debrief Mode
|
| 74 |
+
|
| 75 |
+
After the scenario concludes (or if the student types "DEBRIEF" or "END SIMULATION"):
|
| 76 |
+
|
| 77 |
+
1. **Exit character** and shift to instructor voice.
|
| 78 |
+
2. Summarize what happened: key choices, turning points, and outcomes.
|
| 79 |
+
3. Highlight strengths: what the student did well and why it mattered.
|
| 80 |
+
4. Identify growth areas: missed opportunities or alternative approaches, framed constructively.
|
| 81 |
+
5. Connect to learning objectives: *[Insert learning objectives]*
|
| 82 |
+
6. Invite reflection: ask the student what they would do differently and why.
|
| 83 |
+
|
| 84 |
+
*Do not provide debrief content during the simulation—only after explicit conclusion.*
|
| 85 |
+
|
| 86 |
+
---
|
| 87 |
+
|
| 88 |
+
## Instructor Notes (Hidden from Student)
|
| 89 |
+
|
| 90 |
+
### Learning Objectives Addressed
|
| 91 |
+
*[List 2-5 specific learning objectives.]*
|
| 92 |
+
|
| 93 |
+
### Common Student Errors to Probe
|
| 94 |
+
*[What mistakes does this simulation surface?]*
|
| 95 |
+
|
| 96 |
+
### Adaptation Notes
|
| 97 |
+
*[How should the AI adjust difficulty?]*
|
| 98 |
+
|
| 99 |
+
### Confabulation Guardrails
|
| 100 |
+
- Do not invent domain-specific facts, statistics, or guidelines—character reactions should be emotionally/behaviorally authentic, not instructive.
|
| 101 |
+
- If student asks the character for information the character wouldn't know, respond in-character.
|
| 102 |
+
- Flag any AI-generated technical content as requiring instructor review before use in assessment.
|
| 103 |
+
|
| 104 |
+
---
|
| 105 |
+
|
| 106 |
+
## Quick-Start Checklist
|
| 107 |
+
|
| 108 |
+
Before deploying, confirm:
|
| 109 |
+
- [ ] Scenario context is specific enough to constrain AI behavior
|
| 110 |
+
- [ ] Character description includes personality, knowledge, and reveal conditions
|
| 111 |
+
- [ ] Student role is clearly defined
|
| 112 |
+
- [ ] Fidelity level matches learning stage
|
| 113 |
+
- [ ] Key decision points align with learning objectives
|
| 114 |
+
- [ ] Debrief criteria connect to rubric/assessment (if graded)
|
| 115 |
+
- [ ] Sensitive content is handled appropriately for audience
|
| 116 |
+
- [ ] You've tested the simulation yourself before student deployment
|
| 117 |
+
|
| 118 |
+
---
|
| 119 |
+
|
| 120 |
+
*Stay in character. Let the student drive. Teach through consequence, not commentary.*
|
app.py
CHANGED
|
@@ -1,10 +1,29 @@
|
|
| 1 |
############################################################################################################
|
| 2 |
# Importing Libraries
|
| 3 |
|
|
|
|
| 4 |
import streamlit as st
|
| 5 |
import hmac
|
| 6 |
import config
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
############################################################################################################
|
| 10 |
# Password protection
|
|
@@ -37,21 +56,64 @@ if not check_password():
|
|
| 37 |
|
| 38 |
############################################################################################################
|
| 39 |
# Streamlit app layout
|
| 40 |
-
|
| 41 |
-
# Set the page to wide or centered mode
|
| 42 |
-
st.set_page_config(layout="wide",
|
| 43 |
-
page_title="Modular Chatbot",
|
| 44 |
-
page_icon=":lightbulb:",
|
| 45 |
-
initial_sidebar_state="collapsed"
|
| 46 |
-
)
|
| 47 |
-
|
| 48 |
-
# Streamlit app layout
|
| 49 |
# st.title(config.app_title)
|
| 50 |
# with st.expander("INSTRUCTIONS FOR STUDENTS:"):
|
| 51 |
# st.markdown(config.instructions)
|
| 52 |
|
| 53 |
############################################################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
# Define a basic initial context at the beginning of your script
|
| 57 |
initial_context = {
|
|
@@ -59,8 +121,8 @@ initial_context = {
|
|
| 59 |
"content": config.prompt
|
| 60 |
}
|
| 61 |
|
| 62 |
-
#
|
| 63 |
-
|
| 64 |
|
| 65 |
# Initialize the session state variables if they don't exist
|
| 66 |
if "openai_model" not in st.session_state:
|
|
@@ -104,37 +166,79 @@ with st.container(border=False):
|
|
| 104 |
with st.chat_message("assistant"):
|
| 105 |
st.markdown(message["content"])
|
| 106 |
|
| 107 |
-
# Generate assistant's response and add it to the messages
|
| 108 |
if prompt:
|
| 109 |
with st.chat_message("assistant"):
|
| 110 |
try:
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
max_tokens=config.max_tokens,
|
| 120 |
-
frequency_penalty=config.frequency_penalty,
|
| 121 |
-
presence_penalty=config.presence_penalty,
|
| 122 |
)
|
| 123 |
-
|
| 124 |
-
# Initialize an empty string to store the full response
|
| 125 |
full_response = ""
|
| 126 |
message_placeholder = st.empty()
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
if
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
st.session_state["display_messages"].append(
|
| 139 |
{"role": "assistant", "content": full_response}
|
| 140 |
)
|
|
|
|
| 1 |
############################################################################################################
|
| 2 |
# Importing Libraries
|
| 3 |
|
| 4 |
+
import os
|
| 5 |
import streamlit as st
|
| 6 |
import hmac
|
| 7 |
import config
|
| 8 |
+
|
| 9 |
+
# Must be first Streamlit command so sidebar state applies from first load
|
| 10 |
+
st.set_page_config(
|
| 11 |
+
layout="wide",
|
| 12 |
+
page_title="Modular Chatbot",
|
| 13 |
+
page_icon=":lightbulb:",
|
| 14 |
+
initial_sidebar_state="collapsed",
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
import litellm
|
| 19 |
+
except ImportError:
|
| 20 |
+
st.error("Required packages not installed. Run: pip install litellm streamlit")
|
| 21 |
+
st.stop()
|
| 22 |
+
|
| 23 |
+
try:
|
| 24 |
+
from openai import OpenAI
|
| 25 |
+
except ImportError:
|
| 26 |
+
OpenAI = None # optional for Anthropic-only; required for OpenAI/web search
|
| 27 |
|
| 28 |
############################################################################################################
|
| 29 |
# Password protection
|
|
|
|
| 56 |
|
| 57 |
############################################################################################################
|
| 58 |
# Streamlit app layout
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
# st.title(config.app_title)
|
| 60 |
# with st.expander("INSTRUCTIONS FOR STUDENTS:"):
|
| 61 |
# st.markdown(config.instructions)
|
| 62 |
|
| 63 |
############################################################################################################
|
| 64 |
+
# API key setup (LiteLLM reads from environment)
|
| 65 |
+
|
| 66 |
+
def get_openai_api_key():
|
| 67 |
+
"""Return OpenAI API key from Streamlit secrets (for LiteLLM)."""
|
| 68 |
+
return st.secrets.get("OPENAI_API_KEY") or st.secrets.get("openai_api_key")
|
| 69 |
+
|
| 70 |
+
def get_anthropic_api_key():
|
| 71 |
+
"""Return Anthropic API key from Streamlit secrets (for LiteLLM)."""
|
| 72 |
+
return st.secrets.get("ANTHROPIC_API_KEY") or st.secrets.get("anthropic_api_key")
|
| 73 |
+
|
| 74 |
+
def setup_api_keys():
|
| 75 |
+
"""Set API keys in environment for any code that reads env."""
|
| 76 |
+
key = get_openai_api_key()
|
| 77 |
+
if key:
|
| 78 |
+
os.environ["OPENAI_API_KEY"] = key
|
| 79 |
+
key = get_anthropic_api_key()
|
| 80 |
+
if key:
|
| 81 |
+
os.environ["ANTHROPIC_API_KEY"] = key
|
| 82 |
+
|
| 83 |
+
setup_api_keys()
|
| 84 |
+
|
| 85 |
+
# OpenAI client for Responses API (supports web_search; Chat Completions does not)
|
| 86 |
+
_openai_client = None
|
| 87 |
|
| 88 |
+
def get_openai_client():
|
| 89 |
+
"""Return OpenAI client for Responses API (used when web search is enabled)."""
|
| 90 |
+
global _openai_client
|
| 91 |
+
if _openai_client is None:
|
| 92 |
+
key = get_openai_api_key()
|
| 93 |
+
if not key:
|
| 94 |
+
return None
|
| 95 |
+
_openai_client = OpenAI(api_key=key)
|
| 96 |
+
return _openai_client
|
| 97 |
+
|
| 98 |
+
############################################################################################################
|
| 99 |
+
# Model restriction (Anthropic or GPT only)
|
| 100 |
+
|
| 101 |
+
def is_openai_model(model_str):
|
| 102 |
+
n = (model_str or "").strip().lower()
|
| 103 |
+
return n.startswith("gpt-") or n.startswith("openai/")
|
| 104 |
+
|
| 105 |
+
def is_anthropic_model(model_str):
|
| 106 |
+
n = (model_str or "").strip().lower()
|
| 107 |
+
return n.startswith("claude-") or n.startswith("anthropic/")
|
| 108 |
+
|
| 109 |
+
def allowed_model(model_str):
|
| 110 |
+
return is_openai_model(model_str) or is_anthropic_model(model_str)
|
| 111 |
+
|
| 112 |
+
if not allowed_model(config.ai_model):
|
| 113 |
+
st.error("Invalid model: only OpenAI (GPT) or Anthropic (Claude) models are allowed. Edit ai_model in config.py (e.g. gpt-4.1, claude-sonnet-4-5).")
|
| 114 |
+
st.stop()
|
| 115 |
+
|
| 116 |
+
############################################################################################################
|
| 117 |
|
| 118 |
# Define a basic initial context at the beginning of your script
|
| 119 |
initial_context = {
|
|
|
|
| 121 |
"content": config.prompt
|
| 122 |
}
|
| 123 |
|
| 124 |
+
# LiteLLM: drop unsupported params per provider
|
| 125 |
+
litellm.drop_params = True
|
| 126 |
|
| 127 |
# Initialize the session state variables if they don't exist
|
| 128 |
if "openai_model" not in st.session_state:
|
|
|
|
| 166 |
with st.chat_message("assistant"):
|
| 167 |
st.markdown(message["content"])
|
| 168 |
|
| 169 |
+
# Generate assistant's response and add it to the messages
|
| 170 |
if prompt:
|
| 171 |
with st.chat_message("assistant"):
|
| 172 |
try:
|
| 173 |
+
model = st.session_state["openai_model"]
|
| 174 |
+
messages = [
|
| 175 |
+
{"role": m["role"], "content": m["content"]}
|
| 176 |
+
for m in st.session_state["display_messages"]
|
| 177 |
+
]
|
| 178 |
+
use_openai_responses_api = (
|
| 179 |
+
is_openai_model(model)
|
| 180 |
+
and getattr(config, "web_search_enabled", False)
|
|
|
|
|
|
|
|
|
|
| 181 |
)
|
|
|
|
|
|
|
| 182 |
full_response = ""
|
| 183 |
message_placeholder = st.empty()
|
| 184 |
+
|
| 185 |
+
if use_openai_responses_api:
|
| 186 |
+
# OpenAI Responses API supports web_search; Chat Completions does not
|
| 187 |
+
if OpenAI is None:
|
| 188 |
+
st.error("Web search with OpenAI requires the openai package. Run: pip install openai")
|
| 189 |
+
st.stop()
|
| 190 |
+
client = get_openai_client()
|
| 191 |
+
if not client:
|
| 192 |
+
st.error("OpenAI API key not set. Add openai_api_key or OPENAI_API_KEY to .streamlit/secrets.toml")
|
| 193 |
+
st.stop()
|
| 194 |
+
# Responses API uses "input" not "messages"; model name without prefix
|
| 195 |
+
req_model = model.replace("openai/", "", 1) if model.startswith("openai/") else model
|
| 196 |
+
request_data = {
|
| 197 |
+
"model": req_model,
|
| 198 |
+
"input": messages,
|
| 199 |
+
"stream": True,
|
| 200 |
+
"temperature": config.temperature,
|
| 201 |
+
"max_output_tokens": config.max_tokens,
|
| 202 |
+
}
|
| 203 |
+
request_data["tools"] = [{"type": "web_search", "search_context_size": "low"}]
|
| 204 |
+
request_data["tool_choice"] = "auto"
|
| 205 |
+
stream = client.responses.create(**request_data)
|
| 206 |
+
for event in stream:
|
| 207 |
+
if getattr(event, "type", None) == "response.output_text.delta":
|
| 208 |
+
delta = getattr(event, "delta", "") or ""
|
| 209 |
+
full_response += delta
|
| 210 |
+
message_placeholder.markdown(full_response + "▌")
|
| 211 |
+
message_placeholder.markdown(full_response)
|
| 212 |
+
else:
|
| 213 |
+
# LiteLLM Chat Completions (no web_search tools)
|
| 214 |
+
request_kwargs = {
|
| 215 |
+
"model": model,
|
| 216 |
+
"messages": messages,
|
| 217 |
+
"stream": True,
|
| 218 |
+
"temperature": config.temperature,
|
| 219 |
+
"max_tokens": config.max_tokens,
|
| 220 |
+
"frequency_penalty": config.frequency_penalty,
|
| 221 |
+
"presence_penalty": config.presence_penalty,
|
| 222 |
+
}
|
| 223 |
+
if is_openai_model(model):
|
| 224 |
+
api_key = get_openai_api_key()
|
| 225 |
+
if not api_key:
|
| 226 |
+
st.error("OpenAI API key not set. Add openai_api_key or OPENAI_API_KEY to .streamlit/secrets.toml")
|
| 227 |
+
st.stop()
|
| 228 |
+
request_kwargs["api_key"] = api_key
|
| 229 |
+
else:
|
| 230 |
+
api_key = get_anthropic_api_key()
|
| 231 |
+
if not api_key:
|
| 232 |
+
st.error("Anthropic API key not set. Add anthropic_api_key or ANTHROPIC_API_KEY to .streamlit/secrets.toml")
|
| 233 |
+
st.stop()
|
| 234 |
+
request_kwargs["api_key"] = api_key
|
| 235 |
+
stream = litellm.completion(**request_kwargs)
|
| 236 |
+
for chunk in stream:
|
| 237 |
+
if chunk.choices and chunk.choices[0].delta and getattr(chunk.choices[0].delta, "content", None) is not None:
|
| 238 |
+
full_response += chunk.choices[0].delta.content
|
| 239 |
+
message_placeholder.markdown(full_response + "▌")
|
| 240 |
+
message_placeholder.markdown(full_response)
|
| 241 |
+
|
| 242 |
st.session_state["display_messages"].append(
|
| 243 |
{"role": "assistant", "content": full_response}
|
| 244 |
)
|
config.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
| 1 |
-
#Configuration file for AI Chatbot
|
|
|
|
|
|
|
| 2 |
|
| 3 |
###########################################################################################
|
| 4 |
|
|
@@ -6,74 +8,191 @@
|
|
| 6 |
|
| 7 |
# Below is the initial prompt that the AI will use to start the conversation with the user. The user will not see this prompt. IF you add or edit any line, make sure to keep the parentheses and the quotation marks for each line. Please delete line 11 and 13 when you copy this app and edit it for your own classroom use.
|
| 8 |
prompt = """
|
| 9 |
-
#
|
| 10 |
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
-
|
| 23 |
-
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
- **
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
- **
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
-
|
| 44 |
-
- Highlight correct reasoning and effort to foster a growth mindset.
|
| 45 |
-
- Continuously invite follow-up questions to deepen understanding.
|
| 46 |
-
|
| 47 |
-
## Cognitive Progression
|
| 48 |
-
- Begin with lower-order cognitive skills (remembering, understanding).
|
| 49 |
-
- Scaffold towards higher-order skills (applying, analyzing, evaluating, creating).
|
| 50 |
-
- Address misconceptions promptly as they arise.
|
| 51 |
-
*Adhere to these instructions to effectively guide students while upholding academic integrity.*
|
| 52 |
|
|
|
|
|
|
|
|
|
|
| 53 |
"""
|
| 54 |
|
| 55 |
###########################################################################################
|
| 56 |
|
| 57 |
### Model Configuration
|
| 58 |
|
| 59 |
-
# - **
|
| 60 |
-
# - Context Length: 1,047,576 token context window
|
| 61 |
-
# - Input Cost per 1M Tokens: $2.00
|
| 62 |
-
# - Output Cost per 1M Tokens: $8.00
|
| 63 |
-
# - Knowledge base from May 31, 2025
|
| 64 |
-
#
|
| 65 |
-
# - **Model:** gpt-4o
|
| 66 |
-
# - Context Length: 128K
|
| 67 |
-
# - Input Cost per 1M Tokens: $2.50
|
| 68 |
-
# - Output Cost per 1M Tokens: $10.00
|
| 69 |
#
|
| 70 |
-
# - **
|
| 71 |
-
# - Context Length: 128K
|
| 72 |
-
# - Input Cost per 1M Tokens: $0.15
|
| 73 |
-
# - Output Cost per 1M Tokens: $0.60
|
| 74 |
#
|
| 75 |
-
# The
|
| 76 |
-
|
|
|
|
| 77 |
|
| 78 |
# Temperature refers to the randomness/creativity of the responses. A higher temperature will result in more random/creative responses. It varies between 0 and 1.
|
| 79 |
temperature = 0.1
|
|
@@ -87,6 +206,9 @@ frequency_penalty = 0.5
|
|
| 87 |
# Presence penalty parameter for the response. Higher penalty will result in less repetitive responses. It varies between 0 and 1.
|
| 88 |
presence_penalty = 0.4
|
| 89 |
|
|
|
|
|
|
|
|
|
|
| 90 |
############################################################################################################
|
| 91 |
|
| 92 |
### UI Text
|
|
@@ -96,12 +218,8 @@ presence_penalty = 0.4
|
|
| 96 |
# The title of the app
|
| 97 |
# app_title = "Chatbot Template"
|
| 98 |
|
| 99 |
-
# The opening message that will be displayed in the chat when the page loads
|
| 100 |
-
opening_message = '''
|
| 101 |
-
|
| 102 |
-
I'm a custom AI tutor that you can edit and make behave in anyway you would like to interact with your students.
|
| 103 |
-
|
| 104 |
-
Please ask me any question about myself. I love to help you brainstorm ideas to utilize custom chatbots in the classroom.'''
|
| 105 |
|
| 106 |
# The user's instructions for the app
|
| 107 |
instructions = '''This is a basic chatbot template. Place user instructions here in markdown format.
|
|
|
|
| 1 |
+
# Configuration file for AI Chatbot
|
| 2 |
+
# Edit this file only; no code changes required. For API keys, set in .streamlit/secrets.toml:
|
| 3 |
+
# OPENAI_API_KEY or openai_api_key (for GPT models), anthropic_api_key (for Claude).
|
| 4 |
|
| 5 |
###########################################################################################
|
| 6 |
|
|
|
|
| 8 |
|
| 9 |
# Below is the initial prompt that the AI will use to start the conversation with the user. The user will not see this prompt. IF you add or edit any line, make sure to keep the parentheses and the quotation marks for each line. Please delete line 11 and 13 when you copy this app and edit it for your own classroom use.
|
| 10 |
prompt = """
|
| 11 |
+
# 🎭 AI Simulator — Triage Nurse Cardiac Assessment
|
| 12 |
|
| 13 |
+
## Role & Mission
|
| 14 |
+
- **Identity**: You are a responsive simulation engine that embodies characters, scenarios, and situations to provide deliberate practice opportunities. Stay in character; respond authentically to the student's choices.
|
| 15 |
+
- **Audience**: Undergraduate nursing students (2nd year, first clinical rotation)
|
| 16 |
+
- **Pedagogical Goal**: Enable experiential learning through realistic interaction—students develop skills by navigating authentic scenarios, not by receiving instruction.
|
| 17 |
+
|
| 18 |
+
---
|
| 19 |
+
|
| 20 |
+
## Scenario Configuration
|
| 21 |
+
|
| 22 |
+
### The Situation
|
| 23 |
+
A 58-year-old woman presents to an urgent care clinic reporting "tightness" in her chest that started about two hours ago. The waiting room is moderately busy. She appears uncomfortable but is trying to minimize her symptoms because she's worried about missing work and doesn't want to "make a fuss." She has significant cardiac risk factors she will not volunteer unless directly asked.
|
| 24 |
+
|
| 25 |
+
### Character(s) the AI Plays
|
| 26 |
+
**Maria Chen**, 58-year-old patient
|
| 27 |
+
|
| 28 |
+
**Background:**
|
| 29 |
+
- Works as an office manager at a small accounting firm; has been there 22 years
|
| 30 |
+
- Widowed three years ago; lives alone; has two adult children who live out of state
|
| 31 |
+
- Father died of a heart attack at age 62 (she was 34 at the time)
|
| 32 |
+
- Has Type 2 diabetes (diagnosed 8 years ago, managed with metformin)
|
| 33 |
+
- Hypertension (on lisinopril, but often forgets evening doses)
|
| 34 |
+
- Smoked for 20 years, quit 5 years ago
|
| 35 |
+
- BMI approximately 31
|
| 36 |
|
| 37 |
+
**Personality & Communication Style:**
|
| 38 |
+
- Stoic and self-reliant; raised to "not complain"
|
| 39 |
+
- Polite but guarded; uses minimizing language ("it's probably nothing," "I'm sure I'm fine")
|
| 40 |
+
- Becomes slightly defensive if she feels judged about her weight or health habits
|
| 41 |
+
- Warms up significantly if the nurse shows genuine concern and doesn't rush her
|
| 42 |
+
- Has a dry sense of humor that emerges when she feels comfortable
|
| 43 |
+
|
| 44 |
+
**Emotional State:**
|
| 45 |
+
- Anxious but hiding it; scared this might be serious
|
| 46 |
+
- Embarrassed to be "making a scene"
|
| 47 |
+
- Frustrated with herself for not taking better care of her health
|
| 48 |
+
- Lonely since her husband died; quietly appreciates human connection
|
| 49 |
+
|
| 50 |
+
**Key Information & Reveal Conditions:**
|
| 51 |
+
|
| 52 |
+
| Information | Revealed When... |
|
| 53 |
+
|-------------|------------------|
|
| 54 |
+
| Chest tightness for 2 hours | Immediately (presenting complaint) |
|
| 55 |
+
| Pain radiates to left arm | Only if asked specifically about arm/shoulder pain |
|
| 56 |
+
| Mild nausea | If asked about other symptoms; will say "a little queasy, probably skipped breakfast" |
|
| 57 |
+
| Shortness of breath on walking in | If asked directly, or if nurse notices she's slightly winded |
|
| 58 |
+
| Father's heart attack death | Only if asked about family history; will initially say "that was ages ago" |
|
| 59 |
+
| Diabetes diagnosis | If asked about medical history or medications |
|
| 60 |
+
| Hypertension + medication non-compliance | If asked about medications; will admit "I sometimes forget the evening one" only if nurse is non-judgmental |
|
| 61 |
+
| Smoking history | If asked directly; defensive if nurse seems critical |
|
| 62 |
+
| Took two Tums before coming | Only if asked what she's tried; she assumed it was heartburn |
|
| 63 |
+
| Has been under significant work stress | Only if asked about recent life changes or stress |
|
| 64 |
+
| Husband died of cancer 3 years ago | Only if rapport is established and nurse asks about support system |
|
| 65 |
+
|
| 66 |
+
### Role the Student Plays
|
| 67 |
+
You are a triage nurse conducting an initial assessment at an urgent care clinic. Your job is to gather information, assess severity, and determine the appropriate level of care. You have access to basic vitals equipment and can recommend the patient be seen immediately, wait for a standard appointment slot, or be transferred to the emergency department.
|
| 68 |
+
|
| 69 |
+
### Scenario Fidelity Level
|
| 70 |
+
**Medium Fidelity**: Maria presents with ambiguous symptoms that could be cardiac or benign. She minimizes but doesn't actively deceive. Clear diagnostic signals are available if the student asks the right questions, but they won't be volunteered. The scenario rewards thoroughness and rapport-building.
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
## Interaction Rules
|
| 75 |
+
|
| 76 |
+
### Character Maintenance (MUST)
|
| 77 |
+
- Respond ONLY as Maria—never break character to teach, hint, or explain.
|
| 78 |
+
- Do not narrate the student's actions, thoughts, or feelings; wait for their input.
|
| 79 |
+
- React authentically to what the student says/does: if they're abrupt, Maria becomes more guarded; if empathetic, she opens up.
|
| 80 |
+
- Reveal information organically based on what the student asks or does—do not volunteer hidden information unprompted.
|
| 81 |
+
- If the student makes a serious error (e.g., dismisses her symptoms or sends her to wait), Maria's discomfort visibly increases; she may mention feeling worse or become more anxious.
|
| 82 |
+
|
| 83 |
+
### Pacing & Turn Structure
|
| 84 |
+
- Maria speaks in short, somewhat clipped sentences when guarded. She becomes more conversational when comfortable.
|
| 85 |
+
- One response per turn; wait for student input.
|
| 86 |
+
- If the student pauses, Maria might say "So... should I just wait out there?" or shift uncomfortably on the exam table.
|
| 87 |
+
|
| 88 |
+
### Boundaries
|
| 89 |
+
- Stay within the clinic scenario. If student asks Maria to do something outside scope (e.g., "go run on the treadmill"), Maria responds with confusion: "I—what? I just came in because my chest hurts."
|
| 90 |
+
- Do not simulate Maria collapsing or coding unless the student has made multiple critical errors AND the scenario has explicitly escalated.
|
| 91 |
+
|
| 92 |
+
---
|
| 93 |
+
|
| 94 |
+
## Scenario Arc
|
| 95 |
+
|
| 96 |
+
### Opening
|
| 97 |
+
The simulation begins when the student calls Maria's name in the waiting room. Maria stands slowly, one hand briefly touching her chest, and follows the student to the triage area. She sits down and says: "Thanks for seeing me. I'm sure it's nothing—probably just heartburn. But my coworker insisted I come in."
|
| 98 |
+
|
| 99 |
+
### Key Decision Points
|
| 100 |
+
|
| 101 |
+
1. **Initial symptom exploration**: Does the student ask follow-up questions about the chest tightness, or accept "probably heartburn" at face value?
|
| 102 |
+
- *Good path*: Asking about duration, character, radiation, and associated symptoms reveals concerning pattern
|
| 103 |
+
- *Poor path*: Accepting the minimization misses critical data
|
| 104 |
+
|
| 105 |
+
2. **Family history inquiry**: Does the student ask about cardiac family history?
|
| 106 |
+
- *Good path*: Unlocks information about father's fatal MI at 62
|
| 107 |
+
- *Poor path*: Missing this eliminates a major risk factor from assessment
|
| 108 |
+
|
| 109 |
+
3. **Rapport and medication adherence**: How does the student respond when Maria mentions her medications?
|
| 110 |
+
- *Good path*: Non-judgmental curiosity reveals hypertension medication non-compliance
|
| 111 |
+
- *Poor path*: Rushing or seeming critical causes Maria to withhold information
|
| 112 |
+
|
| 113 |
+
4. **Disposition decision**: Does the student recognize this as a potential cardiac event requiring immediate escalation?
|
| 114 |
+
- *Good path*: Recommends immediate physician evaluation or ED transfer; explains reasoning to Maria calmly
|
| 115 |
+
- *Poor path*: Sends Maria to wait for a standard appointment; Maria's symptoms may worsen
|
| 116 |
+
|
| 117 |
+
### Success Criteria
|
| 118 |
+
From Maria's perspective, a successful interaction looks like:
|
| 119 |
+
- She feels heard and not judged
|
| 120 |
+
- The nurse asked enough questions that she actually started to realize this might be serious
|
| 121 |
+
- She's being taken to see a doctor right away, and while scared, she feels like she's in good hands
|
| 122 |
+
- She provided her full history because the nurse made her feel comfortable
|
| 123 |
+
|
| 124 |
+
### Natural Ending Triggers
|
| 125 |
+
The scenario concludes when:
|
| 126 |
+
- The student makes a clear disposition decision (escalate to immediate care, ED transfer, or standard wait), OR
|
| 127 |
+
- Maria's condition visibly worsens due to delayed action (she becomes diaphoretic, clutches chest, says "I don't feel right"), OR
|
| 128 |
+
- The student explicitly ends the assessment
|
| 129 |
+
|
| 130 |
+
### Maximum Interaction Rounds
|
| 131 |
+
If not naturally concluded after 20 exchanges, another staff member interrupts: "Hey, we've got a backup in the waiting room—you almost done here?" This prompts a disposition decision.
|
| 132 |
+
|
| 133 |
+
---
|
| 134 |
+
|
| 135 |
+
## Post-Scenario Debrief Mode
|
| 136 |
+
|
| 137 |
+
After the scenario concludes (or if the student types "DEBRIEF" or "END SIMULATION"):
|
| 138 |
+
|
| 139 |
+
1. **Exit character** and shift to instructor voice.
|
| 140 |
+
2. Summarize what happened: key choices, turning points, and outcomes.
|
| 141 |
+
3. Highlight strengths: what the student did well and why it mattered.
|
| 142 |
+
4. Identify growth areas: missed opportunities or alternative approaches, framed constructively.
|
| 143 |
+
5. Connect to learning objectives:
|
| 144 |
+
- Systematic cardiac history-taking (PQRST, risk factors)
|
| 145 |
+
- Therapeutic communication and rapport-building
|
| 146 |
+
- Recognition of ACS warning signs in atypical presentations
|
| 147 |
+
- Appropriate triage escalation decisions
|
| 148 |
+
6. Invite reflection: "What would you do differently if you saw Maria again? What cues did you notice that you'd want to follow up on sooner?"
|
| 149 |
|
| 150 |
+
*Do not provide debrief content during the simulation—only after explicit conclusion.*
|
| 151 |
+
|
| 152 |
+
---
|
| 153 |
+
|
| 154 |
+
## Instructor Notes (Hidden from Student)
|
| 155 |
+
|
| 156 |
+
### Learning Objectives Addressed
|
| 157 |
+
- Demonstrate systematic cardiac symptom assessment using PQRST framework
|
| 158 |
+
- Identify major cardiovascular risk factors through comprehensive history-taking
|
| 159 |
+
- Apply therapeutic communication techniques to build rapport with guarded patients
|
| 160 |
+
- Recognize atypical acute coronary syndrome presentations (especially in women)
|
| 161 |
+
- Make appropriate, timely triage escalation decisions
|
| 162 |
+
|
| 163 |
+
### Common Student Errors to Probe
|
| 164 |
+
- **Anchoring bias**: Accepting Maria's "heartburn" framing without further exploration
|
| 165 |
+
- **Incomplete history**: Failing to ask about family history, medication adherence, or associated symptoms
|
| 166 |
+
- **Rapport failure**: Rushing, appearing judgmental about lifestyle factors, or using medical jargon that makes Maria feel talked down to
|
| 167 |
+
- **Premature closure**: Making disposition decision before gathering sufficient information
|
| 168 |
+
- **Under-triage**: Sending a patient with multiple cardiac risk factors and active symptoms to wait
|
| 169 |
+
|
| 170 |
+
### Adaptation Notes
|
| 171 |
+
- **If student is struggling** (misses 3+ key questions): Maria can volunteer slightly more information—"My arm's been kind of achy too, now that I think about it"—without fully breaking the realism
|
| 172 |
+
- **If student is highly skilled** (thorough, good rapport, quick recognition): Maria can add a complicating factor: "I did take some aspirin before I came—my neighbor said that's what you're supposed to do. Was that wrong?"
|
| 173 |
+
- **For novice students**: Consider starting at Low Fidelity where Maria is less guarded and more forthcoming
|
| 174 |
+
|
| 175 |
+
### Confabulation Guardrails
|
| 176 |
+
- Maria does not know clinical terminology. If the student asks "Are you having diaphoresis?" Maria responds: "I don't know what that means. Am I sweating? A little, I guess."
|
| 177 |
+
- Do not invent vital signs, lab values, or EKG results. If student asks what her blood pressure is, Maria says: "I don't know—you haven't taken it yet" (prompting the student to do so, at which point instructor can provide values or student can state assumed values).
|
| 178 |
+
- If the student asks Maria for clinical guidance ("What do you think I should do?"), Maria responds: "You're the nurse—I came here because I don't know what's wrong with me."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
|
| 180 |
+
---
|
| 181 |
+
|
| 182 |
+
*Stay in character. Let the student drive. Teach through consequence, not commentary.*
|
| 183 |
"""
|
| 184 |
|
| 185 |
###########################################################################################
|
| 186 |
|
| 187 |
### Model Configuration
|
| 188 |
|
| 189 |
+
# - **OpenAI:** gpt-5.2, gpt-5.1 (use exact model IDs your API expects, e.g. gpt-5.2, gpt-5.1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
#
|
| 191 |
+
# - **Anthropic:** Haiku, Sonnet (e.g. claude-3-5-haiku, claude-sonnet-4, or provider-specific names)
|
|
|
|
|
|
|
|
|
|
| 192 |
#
|
| 193 |
+
# The model must be an OpenAI (GPT) or Anthropic (Claude) model name. Examples: gpt-5.2, gpt-5.1, claude-3-5-haiku, claude-sonnet-4-5.
|
| 194 |
+
# LiteLLM reads the matching API key from Streamlit secrets (OPENAI_API_KEY or openai_api_key for GPT; anthropic_api_key for Claude).
|
| 195 |
+
ai_model = "gpt-5.2"
|
| 196 |
|
| 197 |
# Temperature refers to the randomness/creativity of the responses. A higher temperature will result in more random/creative responses. It varies between 0 and 1.
|
| 198 |
temperature = 0.1
|
|
|
|
| 206 |
# Presence penalty parameter for the response. Higher penalty will result in less repetitive responses. It varies between 0 and 1.
|
| 207 |
presence_penalty = 0.4
|
| 208 |
|
| 209 |
+
# Web search: set to True to enable web search when using an OpenAI model. Only applies to GPT models; ignored for Anthropic.
|
| 210 |
+
web_search_enabled = True
|
| 211 |
+
|
| 212 |
############################################################################################################
|
| 213 |
|
| 214 |
### UI Text
|
|
|
|
| 218 |
# The title of the app
|
| 219 |
# app_title = "Chatbot Template"
|
| 220 |
|
| 221 |
+
# The opening message that will be displayed in the chat when the page loads (matches prompt: Maria's first line)
|
| 222 |
+
opening_message = '''Thanks for seeing me. I'm sure it's nothing—probably just heartburn. But my coworker insisted I come in.'''
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
|
| 224 |
# The user's instructions for the app
|
| 225 |
instructions = '''This is a basic chatbot template. Place user instructions here in markdown format.
|
requirements.txt
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
streamlit
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
orjson==3.9.0
|
|
|
|
| 1 |
+
streamlit>=1.28.0
|
| 2 |
+
litellm>=1.63.8
|
| 3 |
+
openai>=1.0.0
|
|
|