1717import random
1818import re
1919import datetime
20-
20+ import requests
2121
2222# Third Party
2323# -----------
@@ -848,28 +848,27 @@ def get_async_llm_reflection():
848848 "you are a student talking to another student during peer instruction.\n "
849849 "you are both looking at the same multiple choice question with code and answers.\n "
850850 "you remember the code and choices.\n "
851- "most messages should be short (1 to 3 sentences, often very short).\n "
851+ "most messages should be short (1 to 3 sentences often very short).\n "
852852 "use casual informal language and common typos.\n "
853- "sometimes use words.\n "
854853 "never use commas.\n "
855854 "never use gendered language.\n "
856855 "do not use new lines.\n "
857856 "do not sound like a teacher.\n "
858857 "do not explain step by step.\n "
859858 "do not mention libraries formally.\n "
860859 "never say something is right or wrong.\n "
861- "never mention a choice letter as the correct answer (like 'c is right' or 'probably b') .\n "
860+ "never mention a choice letter as the correct answer.\n "
862861 "never clearly describe the final result of the code.\n "
863862 "never fully state what the program prints.\n "
864863 "keep reasoning partial or uncertain.\n "
865- "if the other student clearly states confidence or repeats the same answer twice, stop debating and directly tell them to vote again.\n "
866- "do not continue reasoning after telling them to vote again.\n "
867864 "use common misconceptions and focus on only one part of the code.\n "
868- "refer to code loosely ( like 'that line', 'the loop', 'the head', 'the print') .\n "
865+ "refer to code loosely like 'that line' or 'the loop' or 'the head' or 'the print'.\n "
869866 "often hedge with uncertainty.\n "
870867 "never agree with the other student's interpretation even if it sounds correct.\n "
868+ "use content from the other multiple choice options in your reponses when needed\n "
871869 "maintain a mistaken or incomplete mental model throughout the conversation.\n "
872- "if the other student sounds confident or if they are not changing their perspective, tell them to vote again.\n "
870+ "if the other student clearly sounds confident or repeats the same answer twice stop debating and tell them to vote again or submit it.\n "
871+ "do not continue reasoning after telling them to vote again.\n "
873872 "focus on reasoning not teaching.\n \n "
874873 )
875874
@@ -1011,22 +1010,6 @@ def send_lti_scores():
10111010
10121011
10131012
1014-
1015-
1016- import os , json
1017- import requests
1018-
1019- # --- helper to sanitize long, messy text we include in prompts ---
1020- def clean_text (s ):
1021- try :
1022- s = s or ""
1023- s = str (s )
1024- # collapse whitespace per-line, avoid huge payloads
1025- s = "\n " .join (line .strip () for line in s .splitlines ())
1026- return s [:2000 ]
1027- except Exception :
1028- return ""
1029-
10301013def _get_umgpt_settings ():
10311014 api_key = os .environ .get ("UMGPT_API_KEY" , "" ).strip ()
10321015 base_url = os .environ .get ("UMGPT_BASE_URL" , "" ).strip ()
@@ -1066,76 +1049,4 @@ def _call_openai(messages):
10661049 )
10671050 resp .raise_for_status ()
10681051 data = resp .json ()
1069- return data ["choices" ][0 ]["message" ]["content" ].strip ()
1070-
1071- def get_gpt_response ():
1072- """
1073-
1074- GET ?message=... -> echo mode
1075- POST JSON {"messages":[...]} -> calls UMGPT if UMGPT_* config is set, else stub
1076- """
1077- if request .env .request_method == "GET" :
1078- msg = request .vars .message or ""
1079- return response .json (dict (ok = True , echo = msg , reply = "(echo) " + msg , tokens_used = 0 ))
1080-
1081- try :
1082- raw = request .body .read ().decode ("utf-8" )
1083- except Exception :
1084- raw = "{}"
1085-
1086- try :
1087- payload = json .loads (raw or "{}" )
1088- except Exception :
1089- payload = {}
1090-
1091- messages = payload .get ("messages" , [])
1092- context = payload .get ("context" ) or {}
1093-
1094- messages_with_context = messages
1095- try :
1096- if isinstance (context , dict ) and context .get ("ok" ) is True :
1097- course = context .get ("course" )
1098- basecourse = context .get ("basecourse" )
1099- username = context .get ("username" )
1100- comp_id = context .get ("id" )
1101- comp_type = context .get ("type" )
1102- prompt_txt = clean_text (context .get ("prompt" ))
1103- code_txt = clean_text (context .get ("code" ))
1104- choices = context .get ("choices" ) or []
1105- selected = context .get ("selected" )
1106- out_txt = clean_text (context .get ("output" ))
1107- err_txt = clean_text (context .get ("error" ))
1108- coach_txt = clean_text (context .get ("coach" ))
1109-
1110- sys_ctx = (
1111- "You are a friendly peer in a Runestone ebook helping with the CURRENT exercise. "
1112- "Be concise, guide reasoning, and avoid giving full solutions. If the user asks 'what is this asking me to do', "
1113- "summarize the task in plain language, then suggest first steps.\n \n "
1114- f"Course: { course } | Basecourse: { basecourse } | User: { username } \n "
1115- f"Component: { comp_type } | ID: { comp_id } \n "
1116- f"Prompt:\n { prompt_txt } \n \n "
1117- + (f"Starter/Current Code:\n { code_txt } \n \n " if code_txt else "" )
1118- + ("Choices:\n - " + "\n - " .join (map (str , choices )) + (f"\n \n Selected: { selected } " if selected else "" ) + "\n \n " if choices else "" )
1119- + (f"Last Run Output:\n { out_txt } \n \n " if out_txt else "" )
1120- + (f"Last Run Error:\n { err_txt } \n \n " if err_txt else "" )
1121- + (f"Coach/Guidance:\n { coach_txt } \n \n " if coach_txt else "" )
1122- + "Rules: Never reveal solutions verbatim. Encourage peer-instruction style hints."
1123- )
1124-
1125- messages_with_context = [{"role" : "system" , "content" : sys_ctx }] + messages
1126- except Exception :
1127- messages_with_context = messages
1128- if not isinstance (messages , list ) or not messages :
1129- return response .json (dict (ok = False , error = "messages[] required" ))
1130-
1131- try :
1132- reply = _call_openai (messages_with_context )
1133- if reply is None :
1134- user_last = next ((m .get ("content" ,"" ) for m in reversed (messages ) if m .get ("role" )== "user" ), "" )
1135- reply = f"(stub) Here is how to think about it: { user_last } "
1136- return response .json (dict (ok = True , reply = reply , tokens_used = 0 ))
1137- except requests .HTTPError as e :
1138- return response .json (dict (ok = False , error = f"HTTP { e .response .status_code } : { e .response .text [:200 ]} " ))
1139- except Exception as e :
1140- return response .json (dict (ok = False , error = str (e )[:200 ]))
1141-
1052+ return data ["choices" ][0 ]["message" ]["content" ].strip ()
0 commit comments