from otree.api import * from os import environ import openai import json import math from decimal import Decimal, ROUND_HALF_UP import re doc = """ Your app description """ class C(BaseConstants): NAME_IN_URL = 'Uncertainty_process_BC_FI_new' PLAYERS_PER_GROUP = 8 NUM_ROUNDS = 10 TEMP = 0 MODEL = "gpt-5.2" class Subsession(BaseSubsession): pass class Group(BaseGroup): clear = models.BooleanField() average_price = models.FloatField() optimization = models.BooleanField() class Player(BasePlayer): #general variables omega_current = models.IntegerField(default = 40) omega_pre = models.IntegerField(default = 40) omega_small = models.IntegerField(default = 20) omega_large = models.IntegerField(default = 60) omega_average = models.IntegerField(default = 40) cost_deduction = models.IntegerField(default = 10) price_aim_parameter_pre = models.IntegerField(default = 15) price_aim_parameter_post = models.IntegerField(default = 25) price_aim_parameter_current = models.IntegerField(default = 15) price_aim_parameter_small = models.IntegerField(default=5) maximum_price = models.IntegerField() shock = models.IntegerField(default=6) shock_announcement = models.BooleanField() display_shock = models.BooleanField() explanation = models.LongStringField(label="Begründung:",max_length=2000) optimization_instruction = models.BooleanField() optimization = models.BooleanField() clear = models.BooleanField() clear_instruction = models.BooleanField() cum_score = models.IntegerField() sitzplatznummer = models.IntegerField() # player variables price = models.IntegerField(label= "",min=10) output = models.IntegerField() unit_costs = models.IntegerField() total_costs = models.IntegerField() revenue = models.IntegerField() earnings = models.IntegerField(min=0) per_piece_earnings = models.IntegerField() price_aim = models.IntegerField() # variables for payoffs payoff_round = models.IntegerField() # if I don't round, then it needs to be a float payoff_acc = models.IntegerField() exchange_rate = models.IntegerField(default=100) show_up_fee = models.CurrencyField(default=5) payoff_mon = models.CurrencyField() payoff_mon_final = models.CurrencyField() explanation_bonus_taler = models.IntegerField() explanation_bonus = models.CurrencyField() payoff_mon_final_otree = models.CurrencyField() # Questionnaire Question_1 = models.IntegerField( choices=[[1, ("Die Produktion erfolgt automatisch in Höhe der Nachfrage.")], [2, ("Die Produktion wird zufällig bestimmt.")], [3, ("Die Produktion hängt vom Durchschnittspreis ab.")]], label="Frage 1: Wie wird die Höhe Ihrer Produktion bestimmt?", widget=widgets.RadioSelect) Question_2 = models.IntegerField( choices=[[1, "Je höher mein Preis p, desto höher die Nachfrage y."], [2, "Je höher mein Preis p, desto niedriger die Nachfrage y."], [3, "Je niedriger mein Preis p, desto niedriger die Nachfrage y."]], label="Frage 2: Welche Aussage über Ihre Nachfrage y und Ihren Preis p ist richtig?", widget=widgets.RadioSelect) Question_3 = models.IntegerField( choices=[[1, ("Je höher der exogene Faktor ω, desto höher die Nachfrage y.")], [2, ("Je höher der exogene Faktor ω, desto niedriger die Nachfrage y.")], [3, ("Je niedriger der exogene Faktor ω, desto höher die Nachfrage y.")]], label="Frage 3: Welche Aussage über Ihre Nachfrage und den exogenen Faktor ω ist korrekt?", widget=widgets.RadioSelect) Question_4 = models.IntegerField( choices=[[1, "Der Preis des eigenen Produkts."], [2, "Der Durchschnittspreis aller Produzenten über alle Runden hinweg."], [3, "Der Durchschnittspreis aller Produzenten in der jeweiligen Runde."]], label="Frage 4: Welche der folgenden Variablen hat einen Einfluss auf die Kosten pro Stück Ihres Produkts?", widget=widgets.RadioSelect) Question_5 = models.IntegerField( choices=[[1, "... werden durch die Preissetzung aller Produzenten bestimmt und sind daher am Anfang jeder Runde unbekannt."], [2, "... sind zu Beginn jeder Runde bekannt."], [3, "... resultieren aus dem von mir festgelegten Preis."]], label="Frage 5: Die Produktionskosten ...", widget=widgets.RadioSelect) Question_6 = models.IntegerField( choices=[[1, "Eine KI bestimmt zufällige Werte."], [2, "Eine KI bewertet die grammatikalische und stilistische Qualität."], [3, "Eine KI bewertet die Überzeugungskraft."]], label="Frage 6: Wie wird die Bonuszahlung für Ihre Begründung bestimmt?", widget=widgets.RadioSelect) attempts = models.IntegerField(blank=True) Q1_first_attempt = models.IntegerField(blank=True) Q2_first_attempt = models.IntegerField(blank=True) Q3_first_attempt = models.IntegerField(blank=True) Q4_first_attempt = models.IntegerField(blank=True) Q5_first_attempt = models.IntegerField(blank=True) Q6_first_attempt = models.IntegerField(blank=True) #BC questions Question_1_BC = models.IntegerField( choices=[[1, ("Je näher mein Preis p am Zielpreis z liegt, desto höher mein Gewinn.")], [2, ("Je näher mein Preis p am Zielpreis z liegt, desto niedriger mein Gewinn.")], [3, ("Es gibt nur einen Gewinn, wenn mein Preis p exakt dem Zielpreis z entspricht.")]], label=("Frage 1: Welche Aussage über Ihren Gewinn ist korrekt?"), widget=widgets.RadioSelect) Question_2_BC = models.IntegerField( choices=[[1, ("Je höher der Durchschnittspreis P, desto höher der Zielpreis z.")], [2, ("Je höher der Durchschnittspreis P, desto niedriger der Zielpreis z.")], [3, ("Der Zielpreis z ist unabhängig vom Durchschnittspreis P.")]], label=("Frage 2: Welche Aussage über das Verhältnis zwischen dem Zielpreis z und dem Durchschnittspreis P ist korrekt?"), widget=widgets.RadioSelect) Question_3_BC = models.IntegerField( choices=[ [1, ("Der Zielpreis z liegt 15 Taler unter der Hälfte des Durchschnittspreises P.")], [2, ("Der Zielpreis z liegt 15 Taler über der Hälfte des Durchschnittspreises P.")], [3, ("Der Zielpreis z liegt 15 Taler über dem Durchschnittspreis P.")]], label=("Frage 3: Wie berechnet sich Ihr Zielpreis z?"), widget=widgets.RadioSelect, allow_html = True ) Question_4_BC = models.IntegerField( choices=[[1, "… wird durch die Preissetzung aller Produzenten bestimmt und ist daher zu Beginn jeder Runde unbekannt."], [2, "… ist zu Beginn jeder Runde bekannt."], [3, "… entspricht immer dem Zielpreis."]], label="Frage 4: Der Durchschnittspreis P ...", widget=widgets.RadioSelect) Question_5_BC = models.IntegerField( choices=[[1, "Eine KI bestimmt zufällige Werte."], [2, "Eine KI bewertet die grammatikalische und stilistische Qualität."], [3, "Eine KI bewertet die Überzeugungskraft."]], label="Frage 5: Wie wird die Bonuszahlung für Ihre Begründung bestimmt?", widget=widgets.RadioSelect) Q1_BC_first_attempt = models.IntegerField(blank=True) Q2_BC_first_attempt = models.IntegerField(blank=True) Q3_BC_first_attempt = models.IntegerField(blank=True) Q4_BC_first_attempt = models.IntegerField(blank=True) Q5_BC_first_attempt = models.IntegerField(blank=True) bonus = models.IntegerField(blank=True) bonus_mon = models.CurrencyField(blank=True) bonus_eligible = models.BooleanField(blank=True) payoff_bonus = models.IntegerField(blank=True) #Demographics Gender = models.IntegerField( choices=[[1, "Weiblich"], [2, "Männlich"], [3, "Divers"], [4, "keine Angabe"]], label="Welchem Geschlecht fühlen Sie sich zugehörig?", widget=widgets.RadioSelect) Age = models.IntegerField(label="Wie alt sind Sie?", min=10, max=99) Faculty = models.IntegerField( choices=[[1, "Sozial- und Bildungswissenschaftliche Fakultät"], [2, "Geistes- und Kulturwissenschaftliche Fakultät"], [3, "Wirtschaftswissenschaftliche Fakultät"], [4, "Juristische Fakultät"], [5, "Fakultät für Informatik und Mathematik "], [6, "An mehreren Fakultäten"], [7, "Sonstiges"]], label="An welcher Fakultät studieren Sie?", widget=widgets.RadioSelect) Makro = models.IntegerField( choices=[[1, "Ja"], [2, "Nein"]], label="Haben Sie bereits die Veranstaltung Makroökonomik besucht?", widget=widgets.RadioSelect) tech_problems = models.LongStringField(label="Haben Sie sonstige Anmerkungen oder sind Ihnen technische Fehler ausgefallen?",max_length=2000, blank=True) # GPT stuff prompt1 = models.LongStringField(blank=True) prompt2 = models.LongStringField(blank=True) prompt3 = models.LongStringField(blank=True) prompt4 = models.LongStringField(blank=True) prompt5 = models.LongStringField(blank=True) prompt6 = models.LongStringField(blank=True) chatLog = models.LongStringField(blank=True) receive = models.LongStringField(blank=True) msg1 = models.LongStringField(blank=True) msg2 = models.LongStringField(blank=True) msg3 = models.LongStringField(blank=True) msg4 = models.LongStringField(blank=True) msg5 = models.LongStringField(blank=True) msg6 = models.LongStringField(blank=True) explanation_score1 = models.IntegerField(blank=True, default=0) explanation_score2 = models.IntegerField(blank=True, default=0) explanation_score3 = models.IntegerField(blank=True, default=0) explanation_score4 = models.IntegerField(blank=True, default=0) explanation_score5 = models.IntegerField(blank=True, default=0) explanation_score6 = models.IntegerField(blank=True, default=0) reasoning1 = models.LongStringField(blank=True) reasoning2 = models.LongStringField(blank=True) reasoning3 = models.LongStringField(blank=True) reasoning4 = models.LongStringField(blank=True) reasoning5 = models.LongStringField(blank=True) reasoning6 = models.LongStringField(blank=True) #decision data keystroke_data = models.LongStringField(blank=True) # Stores JSON keystroke data keystroke_price_data = models.LongStringField(blank=True) # same for price def price_max(player): return player.omega_current def price_min(player): return player.cost_deduction # assign treatments def creating_session(subsession): for group in subsession.get_groups(): if subsession.round_number == 1: import itertools clear_cycle = itertools.cycle([True, False, False, True]) for group in subsession.get_groups(): group.clear = next(clear_cycle) print(f"Group {group.id_in_subsession}: clear = {group.clear}") import itertools optimization_cycle = itertools.cycle([False, False, True, False]) for group in subsession.get_groups(): group.optimization = next(optimization_cycle) print(f"Group {group.id_in_subsession}: optimization = {group.optimization}") else: group.clear = group.in_round(1).clear group.optimization = group.in_round(1).optimization # currently this is only for a positive shock of omega --> group statt player for p in group.get_players(): if 6<= group.round_number <=10: p.omega_current = p.omega_large p.price_aim_parameter_current = p.price_aim_parameter_post for group in subsession.get_groups(): if group.round_number==Player.shock: group.display_shock=True else: group.display_shock=False for group in subsession.get_groups(): for p in group.get_players(): p.optimization_instruction = group.optimization #print(f"Player {p.id_in_group}: optimization_instruction = {p.optimization_instruction}") for group in subsession.get_groups(): for p in group.get_players(): p.clear_instruction = group.clear #print(f"Player {p.id_in_group}: clear_instruction = {p.clear_instruction}") for group in subsession.get_groups(): for p in group.get_players(): p.prompt1 = """ Du bist eine Person, die im Experiment die Preisbegründung eines Teilnehmers bewertet. Die folgenden Instruktionen erklären das Spiel, das der Teilnehmer gespielt hat: ****** Das Experiment besteht aus 10 Runden. In jeder Runde erzielen Sie Gewinne in Form von Talern, die über alle Runden aufsummiert werden. Am Ende erhalten Sie Ihre gesamten Gewinne sowie eventuelle Bonuszahlungen ausbezahlt. In jeder Runde interagieren Sie mit 7 anderen Personen in diesem Raum. Diese Personen bleiben in allen Runden dieselben. Jede Person übernimmt die Rolle eines Produzenten in einer Volkswirtschaft. In jeder Runde legen Sie den Preis p für Ihr Produkt fest. Dieser Preis muss zwischen 10 und 40 Talern liegen. Ihr Gewinn hängt davon ab, wie nah Ihr gewählter Preis p am Zielpreis z liegt. Dieser Zielpreis hängt von den Preisen aller Produzenten ab: Aus allen gewählten Preisen wird ein Durchschnittspreis P berechnet. Daraus ergibt sich der Zielpreis nach der Formel: z=15+1/2 P Das bedeutet: Ihr Zielpreis liegt 15 Taler über der Hälfte des Durchschnittspreises. Dieser Zielpreis ist für alle Produzenten identisch. Da alle Produzenten gleichzeitig ihren Preis festlegen, kennt zu Beginn einer Runde noch niemand den Durchschnittspreis P. Ihr Ziel ist es also, möglichst gut einzuschätzen, wie die anderen Produzenten Ihre Preise setzen werden, und Ihren Preis entsprechend so zu wählen, dass er möglichst nah am Zielpreis liegt. Je besser Ihnen das gelingt, desto höher fällt Ihr Gewinn aus. ***** Du erhältst einen Preis p und eine Begründung. Gib „1“, wenn die Begründung mindestens zwei dieser drei Elemente enthält (klar erkennbar, auch grob formuliert): (1) Bezug auf andere oder den Durchschnitt P, z.B. „die anderen werden…“, „viele gehen auf…“, „der Schnitt wird etwa…“. (2) Verknüpfung Durchschnitt → Zielpreis: es ist erkennbar, dass der Zielpreis vom Durchschnitt abhängt (Formel nicht nötig). (3) Verknüpfung Zielpreis → eigener Preis: es ist erkennbar, dass p gewählt wird, um nahe am Zielpreis zu liegen. Reine Aussagen wie „stagniert/eingependelt“, „ich nehme wieder den Zielpreis“ oder Qualitäts-/Marketingargumente zählen nur, wenn sie mit (1)–(3) verbunden werden. Antwort: „1“ wenn mindestens 2 von 3 erfüllt sind, sonst „0“. Bitte bewerte nun den folgenden Preis mit Begründung: """ p.msg1 = json.dumps([{"role": "system", "content": p.prompt1}]) # in the prompt its currently inportant that the final score is the last stroke as only then the function at the end retrieves the score and stores it p.prompt2 =""" Du bist eine Person, die im Experiment die Preisbegründung eines Teilnehmers bewertet. Die folgenden Instruktionen erklären das Spiel, das der Teilnehmer gespielt hat: ****** Das Experiment besteht aus 10 Runden. In jeder Runde erzielen Sie Gewinne in Form von Talern, die über alle Runden aufsummiert werden. Am Ende erhalten Sie Ihre gesamten Gewinne sowie eventuelle Bonuszahlungen ausbezahlt. In jeder Runde interagieren Sie mit 7 anderen Personen in diesem Raum. Diese Personen bleiben in allen Runden dieselben. Jede Person übernimmt die Rolle eines Produzenten in einer Volkswirtschaft. In jeder Runde legen Sie den Preis p für Ihr Produkt fest. Dieser Preis muss zwischen 10 und 40 Talern liegen. Ihr Gewinn hängt davon ab, wie nah Ihr gewählter Preis p am Zielpreis z liegt. Dieser Zielpreis hängt von den Preisen aller Produzenten ab: Aus allen gewählten Preisen wird ein Durchschnittspreis P berechnet. Daraus ergibt sich der Zielpreis nach der Formel: z=15+1/2 P Das bedeutet: Ihr Zielpreis liegt 15 Taler über der Hälfte des Durchschnittspreises. Dieser Zielpreis ist für alle Produzenten identisch. Da alle Produzenten gleichzeitig ihren Preis festlegen, kennt zu Beginn einer Runde noch niemand den Durchschnittspreis P. Ihr Ziel ist es also, möglichst gut einzuschätzen, wie die anderen Produzenten Ihre Preise setzen werden, und Ihren Preis entsprechend so zu wählen, dass er möglichst nah am Zielpreis liegt. Je besser Ihnen das gelingt, desto höher fällt Ihr Gewinn aus. ***** Du erhältst einen Preis p und eine Begründung. Gib „1“, wenn die Begründung mindestens zwei dieser drei Elemente enthält (klar erkennbar, auch grob formuliert): (1) Bezug auf andere oder den Durchschnitt P, z.B. „die anderen werden…“, „viele gehen auf…“, „der Schnitt wird etwa…“. (2) Verknüpfung Durchschnitt → Zielpreis: es ist erkennbar, dass der Zielpreis vom Durchschnitt abhängt (Formel nicht nötig). (3) Verknüpfung Zielpreis → eigener Preis: es ist erkennbar, dass p gewählt wird, um nahe am Zielpreis zu liegen. Reine Aussagen wie „stagniert/eingependelt“, „ich nehme wieder den Zielpreis“ oder Qualitäts-/Marketingargumente zählen nur, wenn sie mit (1)–(3) verbunden werden. Antwort: „1“ wenn mindestens 2 von 3 erfüllt sind, sonst „0“. Bitte bewerte nun den folgenden Preis mit Begründung: """ p.msg2 = json.dumps([{"role": "system", "content": p.prompt2}]) p.prompt3 = """ Du bist eine Person, die im Experiment die Preisbegründung eines Teilnehmers bewertet. Die folgenden Instruktionen erklären das Spiel, das der Teilnehmer gespielt hat: ****** Das Experiment besteht aus 10 Runden. In jeder Runde erzielen Sie Gewinne in Form von Talern, die über alle Runden aufsummiert werden. Am Ende erhalten Sie Ihre gesamten Gewinne sowie eventuelle Bonuszahlungen ausbezahlt. In jeder Runde interagieren Sie mit 7 anderen Personen in diesem Raum. Diese Personen bleiben in allen Runden dieselben. Jede Person übernimmt die Rolle eines Produzenten in einer Volkswirtschaft. In jeder Runde legen Sie den Preis p für Ihr Produkt fest. Dieser Preis muss zwischen 10 und 40 Talern liegen. Ihr Gewinn hängt davon ab, wie nah Ihr gewählter Preis p am Zielpreis z liegt. Dieser Zielpreis hängt von den Preisen aller Produzenten ab: Aus allen gewählten Preisen wird ein Durchschnittspreis P berechnet. Daraus ergibt sich der Zielpreis nach der Formel: z=15+1/2 P Das bedeutet: Ihr Zielpreis liegt 15 Taler über der Hälfte des Durchschnittspreises. Dieser Zielpreis ist für alle Produzenten identisch. Da alle Produzenten gleichzeitig ihren Preis festlegen, kennt zu Beginn einer Runde noch niemand den Durchschnittspreis P. Ihr Ziel ist es also, möglichst gut einzuschätzen, wie die anderen Produzenten Ihre Preise setzen werden, und Ihren Preis entsprechend so zu wählen, dass er möglichst nah am Zielpreis liegt. Je besser Ihnen das gelingt, desto höher fällt Ihr Gewinn aus. ***** Du erhältst einen Preis p und eine Begründung. Gib „1“, wenn die Begründung mindestens zwei dieser drei Elemente enthält (klar erkennbar, auch grob formuliert): (1) Bezug auf andere oder den Durchschnitt P, z.B. „die anderen werden…“, „viele gehen auf…“, „der Schnitt wird etwa…“. (2) Verknüpfung Durchschnitt → Zielpreis: es ist erkennbar, dass der Zielpreis vom Durchschnitt abhängt (Formel nicht nötig). (3) Verknüpfung Zielpreis → eigener Preis: es ist erkennbar, dass p gewählt wird, um nahe am Zielpreis zu liegen. Reine Aussagen wie „stagniert/eingependelt“, „ich nehme wieder den Zielpreis“ oder Qualitäts-/Marketingargumente zählen nur, wenn sie mit (1)–(3) verbunden werden. Antwort: „1“ wenn mindestens 2 von 3 erfüllt sind, sonst „0“. Bitte bewerte nun den folgenden Preis mit Begründung: """ p.msg3 = json.dumps([{"role": "system", "content": p.prompt3}]) p.prompt4 = """Du bist eine Person, die im Experiment die Preisbegründung eines Teilnehmers bewertet. Die folgenden Instruktionen erklären das Spiel, das der Teilnehmer gespielt hat: ****** Das Experiment besteht aus 10 Runden. In jeder Runde erzielen Sie Gewinne in Form von Talern, die über alle Runden aufsummiert werden. Am Ende erhalten Sie Ihre gesamten Gewinne sowie eventuelle Bonuszahlungen ausbezahlt. In jeder Runde interagieren Sie mit 7 anderen Personen in diesem Raum. Diese Personen bleiben in allen Runden dieselben. Jede Person übernimmt die Rolle eines Produzenten in einer Volkswirtschaft. In jeder Runde legen Sie den Preis p für Ihr Produkt fest. Dieser Preis muss zwischen 10 und 40 Talern liegen. Ihr Gewinn hängt davon ab, wie nah Ihr gewählter Preis p am Zielpreis z liegt. Dieser Zielpreis hängt von den Preisen aller Produzenten ab: Aus allen gewählten Preisen wird ein Durchschnittspreis P berechnet. Daraus ergibt sich der Zielpreis nach der Formel: z=15+1/2 P Das bedeutet: Ihr Zielpreis liegt 15 Taler über der Hälfte des Durchschnittspreises. Dieser Zielpreis ist für alle Produzenten identisch. Da alle Produzenten gleichzeitig ihren Preis festlegen, kennt zu Beginn einer Runde noch niemand den Durchschnittspreis P. Ihr Ziel ist es also, möglichst gut einzuschätzen, wie die anderen Produzenten Ihre Preise setzen werden, und Ihren Preis entsprechend so zu wählen, dass er möglichst nah am Zielpreis liegt. Je besser Ihnen das gelingt, desto höher fällt Ihr Gewinn aus. ***** Du erhältst einen Preis p und eine Begründung. Gib „1“, wenn die Begründung mindestens zwei dieser drei Elemente enthält (klar erkennbar, auch grob formuliert): (1) Bezug auf andere oder den Durchschnitt P, z.B. „die anderen werden…“, „viele gehen auf…“, „der Schnitt wird etwa…“. (2) Verknüpfung Durchschnitt → Zielpreis: es ist erkennbar, dass der Zielpreis vom Durchschnitt abhängt (Formel nicht nötig). (3) Verknüpfung Zielpreis → eigener Preis: es ist erkennbar, dass p gewählt wird, um nahe am Zielpreis zu liegen. Reine Aussagen wie „stagniert/eingependelt“, „ich nehme wieder den Zielpreis“ oder Qualitäts-/Marketingargumente zählen nur, wenn sie mit (1)–(3) verbunden werden. Antwort: „1“ wenn mindestens 2 von 3 erfüllt sind, sonst „0“. Bitte beachte, dass die folgenden Begründungen aus einer Runde stammen, in der alle wissen, dass sich die Formel für den Zielpreis für alle auf z=25+1/2 P erhöht hat, und der Preis jetzt zwischen 10 und 60 liegen kann. Bitte bewerte nun den folgenden Preis mit Begründung: """ p.msg4 = json.dumps([{"role": "system", "content": p.prompt4}]) p.prompt5 = """Du bist eine Person, die im Experiment die Preisbegründung eines Teilnehmers bewertet. Die folgenden Instruktionen erklären das Spiel, das der Teilnehmer gespielt hat: ****** Das Experiment besteht aus 10 Runden. In jeder Runde erzielen Sie Gewinne in Form von Talern, die über alle Runden aufsummiert werden. Am Ende erhalten Sie Ihre gesamten Gewinne sowie eventuelle Bonuszahlungen ausbezahlt. In jeder Runde interagieren Sie mit 7 anderen Personen in diesem Raum. Diese Personen bleiben in allen Runden dieselben. Jede Person übernimmt die Rolle eines Produzenten in einer Volkswirtschaft. In jeder Runde legen Sie den Preis p für Ihr Produkt fest. Dieser Preis muss zwischen 10 und 40 Talern liegen. Ihr Gewinn hängt davon ab, wie nah Ihr gewählter Preis p am Zielpreis z liegt. Dieser Zielpreis hängt von den Preisen aller Produzenten ab: Aus allen gewählten Preisen wird ein Durchschnittspreis P berechnet. Daraus ergibt sich der Zielpreis nach der Formel: z=15+1/2 P Das bedeutet: Ihr Zielpreis liegt 15 Taler über der Hälfte des Durchschnittspreises. Dieser Zielpreis ist für alle Produzenten identisch. Da alle Produzenten gleichzeitig ihren Preis festlegen, kennt zu Beginn einer Runde noch niemand den Durchschnittspreis P. Ihr Ziel ist es also, möglichst gut einzuschätzen, wie die anderen Produzenten Ihre Preise setzen werden, und Ihren Preis entsprechend so zu wählen, dass er möglichst nah am Zielpreis liegt. Je besser Ihnen das gelingt, desto höher fällt Ihr Gewinn aus. ***** Du erhältst einen Preis p und eine Begründung. Gib „1“, wenn die Begründung mindestens zwei dieser drei Elemente enthält (klar erkennbar, auch grob formuliert): (1) Bezug auf andere oder den Durchschnitt P, z.B. „die anderen werden…“, „viele gehen auf…“, „der Schnitt wird etwa…“. (2) Verknüpfung Durchschnitt → Zielpreis: es ist erkennbar, dass der Zielpreis vom Durchschnitt abhängt (Formel nicht nötig). (3) Verknüpfung Zielpreis → eigener Preis: es ist erkennbar, dass p gewählt wird, um nahe am Zielpreis zu liegen. Reine Aussagen wie „stagniert/eingependelt“, „ich nehme wieder den Zielpreis“ oder Qualitäts-/Marketingargumente zählen nur, wenn sie mit (1)–(3) verbunden werden. Antwort: „1“ wenn mindestens 2 von 3 erfüllt sind, sonst „0“. Bitte beachte, dass die folgenden Begründungen aus einer Runde stammen, in der alle wissen, dass sich die Formel für den Zielpreis für alle auf z=25+1/2 P erhöht hat, und der Preis jetzt zwischen 10 und 60 liegen kann. Bitte bewerte nun den folgenden Preis mit Begründung: """ p.msg5 = json.dumps([{"role": "system", "content": p.prompt5}]) p.prompt6 = """Du bist eine Person, die im Experiment die Preisbegründung eines Teilnehmers bewertet. Die folgenden Instruktionen erklären das Spiel, das der Teilnehmer gespielt hat: ****** Das Experiment besteht aus 10 Runden. In jeder Runde erzielen Sie Gewinne in Form von Talern, die über alle Runden aufsummiert werden. Am Ende erhalten Sie Ihre gesamten Gewinne sowie eventuelle Bonuszahlungen ausbezahlt. In jeder Runde interagieren Sie mit 7 anderen Personen in diesem Raum. Diese Personen bleiben in allen Runden dieselben. Jede Person übernimmt die Rolle eines Produzenten in einer Volkswirtschaft. In jeder Runde legen Sie den Preis p für Ihr Produkt fest. Dieser Preis muss zwischen 10 und 40 Talern liegen. Ihr Gewinn hängt davon ab, wie nah Ihr gewählter Preis p am Zielpreis z liegt. Dieser Zielpreis hängt von den Preisen aller Produzenten ab: Aus allen gewählten Preisen wird ein Durchschnittspreis P berechnet. Daraus ergibt sich der Zielpreis nach der Formel: z=15+1/2 P Das bedeutet: Ihr Zielpreis liegt 15 Taler über der Hälfte des Durchschnittspreises. Dieser Zielpreis ist für alle Produzenten identisch. Da alle Produzenten gleichzeitig ihren Preis festlegen, kennt zu Beginn einer Runde noch niemand den Durchschnittspreis P. Ihr Ziel ist es also, möglichst gut einzuschätzen, wie die anderen Produzenten Ihre Preise setzen werden, und Ihren Preis entsprechend so zu wählen, dass er möglichst nah am Zielpreis liegt. Je besser Ihnen das gelingt, desto höher fällt Ihr Gewinn aus. ***** Du erhältst einen Preis p und eine Begründung. Gib „1“, wenn die Begründung mindestens zwei dieser drei Elemente enthält (klar erkennbar, auch grob formuliert): (1) Bezug auf andere oder den Durchschnitt P, z.B. „die anderen werden…“, „viele gehen auf…“, „der Schnitt wird etwa…“. (2) Verknüpfung Durchschnitt → Zielpreis: es ist erkennbar, dass der Zielpreis vom Durchschnitt abhängt (Formel nicht nötig). (3) Verknüpfung Zielpreis → eigener Preis: es ist erkennbar, dass p gewählt wird, um nahe am Zielpreis zu liegen. Reine Aussagen wie „stagniert/eingependelt“, „ich nehme wieder den Zielpreis“ oder Qualitäts-/Marketingargumente zählen nur, wenn sie mit (1)–(3) verbunden werden. Antwort: „1“ wenn mindestens 2 von 3 erfüllt sind, sonst „0“. Bitte beachte, dass die folgenden Begründungen aus einer Runde stammen, in der alle wissen, dass sich die Formel für den Zielpreis für alle auf z=25+1/2 P erhöht hat, und der Preis jetzt zwischen 10 und 60 liegen kann. Bitte bewerte nun den folgenden Preis mit Begründung: """ p.msg6 = json.dumps([{"role": "system", "content": p.prompt6}]) def runGPT(inputMessage): completion = openai.ChatCompletion.create( model=C.MODEL, messages=inputMessage, temperature=C.TEMP ) return completion["choices"][0]["message"]["content"] def average_price(group): group.average_price = 0 for player in group.get_players(): group.average_price += player.price group.average_price /= C.PLAYERS_PER_GROUP def explanation(player): return player.explanation # calculating the earnings def round_results(group): players = group.get_players() for p in players: if p.price < 10: p.price = 10 players = group.get_players() group.average_price = 0 for player in group.get_players(): group.average_price += player.price group.average_price /= C.PLAYERS_PER_GROUP group.average_price = int(Decimal(group.average_price).to_integral_value(rounding=ROUND_HALF_UP)) for p in players: p.output = (p.omega_current - p.price) p.revenue = p.output * p.price p.unit_costs = group.average_price - p.cost_deduction p.total_costs = p.unit_costs * p.output p.earnings = (p.price - p.unit_costs) * p.output p.per_piece_earnings = p.price - p.unit_costs # if in BC p.price_aim = round((p.omega_current + group.average_price - p.cost_deduction) / 2) for p in players: if p.output < 0: p.output =0 if p.earnings < 0: p.earnings = 0 players = group.get_players() for p in players: p.payoff_round = p.earnings if group.round_number>1: player_in_all_rounds=p.in_all_rounds() p.payoff_acc = sum([p.payoff_round for p in player_in_all_rounds]) else: p.payoff_acc = p.payoff_round if p.in_round(1).attempts > 1: p.bonus_eligible = False p.bonus = 0 if p.in_round(1).attempts == 1: p.bonus_eligible = True p.bonus = 200 p.bonus_mon = cu(p.bonus).to_real_world_currency(p.session) / p.exchange_rate p.payoff_mon = math.ceil(cu(p.payoff_acc).to_real_world_currency(p.session) / p.exchange_rate) if p.payoff_mon < 0.1: #? p.payoff_mon = 3.5 if group.round_number == 10: p.explanation_bonus_taler = ( p.in_round(1).explanation_score1 + p.in_round(2).explanation_score2 + p.in_round(5).explanation_score3 + p.in_round(6).explanation_score4 + p.in_round(7).explanation_score5 + p.in_round(10).explanation_score6 )*(p.exchange_rate//2) p.explanation_bonus = cu(p.explanation_bonus_taler).to_real_world_currency(p.session) / p.exchange_rate p.cum_score= (p.in_round(1).explanation_score1+ p.in_round(2).explanation_score2 + p.in_round(5).explanation_score3 + p.in_round(6).explanation_score4 + p.in_round(7).explanation_score5 + p.in_round(10).explanation_score6) p.payoff_mon_final = math.ceil(p.payoff_mon + p.bonus_mon + p.show_up_fee + p.explanation_bonus) p.payoff_mon_final_otree = math.ceil(p.payoff_mon + p.bonus_mon + p.explanation_bonus) p.payoff = p.payoff_mon_final_otree # as currently defined, there cannot be negative value in the end. otherwise use if conditions <0 = =0 # further currently there is no test or anything alike included, thus payoff = payoff_total # currently no calibration of the payoffs # PAGES class Place(Page): form_model = 'player' form_fields = ['sitzplatznummer'] @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.label = str(player.sitzplatznummer) @staticmethod def is_displayed(player: Player): return (player.round_number == 1) class Start(Page): @staticmethod def is_displayed(player: Player): return (player.round_number == 1) class Pre_Comprehension(Page): #timeout_seconds = 240 @staticmethod def is_displayed(player: Player): return (player.round_number == 1) class Comprehension_OT(Page): #timeout_seconds = 720 @staticmethod def is_displayed(player: Player): return (player.round_number == 1) and player.group.optimization == True form_model = 'player' form_fields = ['Question_1', 'Question_2', 'Question_3', 'Question_4', 'Question_5', 'Question_6', 'attempts', 'Q1_first_attempt', 'Q2_first_attempt', 'Q3_first_attempt', 'Q4_first_attempt', 'Q5_first_attempt', 'Q6_first_attempt'] class Comprehension_BC(Page): #timeout_seconds = 720 @staticmethod def is_displayed(player: Player): return (player.round_number == 1) and player.group.optimization == False form_model = 'player' form_fields = ['Question_1_BC', 'Question_2_BC', 'Question_3_BC', 'Question_4_BC', 'Question_5_BC', 'attempts', 'Q1_BC_first_attempt', 'Q2_BC_first_attempt', 'Q3_BC_first_attempt', 'Q4_BC_first_attempt', 'Q5_BC_first_attempt' ] class StartWait(WaitPage): @staticmethod def is_displayed(player: Player): return (player.round_number == 1) # after_all_players_arrive = 'assigned_roles' title_text = "Bitte warten Sie einen Moment." body_text = "Bitte warten Sie, bis die anderen Spieler bereit sind, um mit dem Experiment zu beginnen. " \ "Das Experiment wird in Kürze beginnen." class Price_and_Explanation_R1(Page): @staticmethod def app_after_this_page(player, timeout_happened): if timeout_happened: return None # Stay on the same page if time runs out @staticmethod def is_displayed(player: Player): return (player.round_number == 1) @staticmethod def live_method(player: Player, data): # set chatgpt api key openai.api_key = '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' # load msg messages = json.loads(player.msg1) # functions for retrieving text from openAI if 'explanation' in data or 'price' in data: explanation_text = (data.get('explanation') or '').strip() price_raw = (data.get('price') or '').strip() # robust parsing of price (don’t crash if empty/non-numeric) try: price_val = int(price_raw) except Exception: price_val = None # Build what the AI should evaluate combined = ( f"Preisentscheidung: {price_val}\n" f"Begründung: {explanation_text}" ) inputMsg = {'role': 'user', 'content': combined} botMsg = {'role': 'assistant', 'content': combined} # append messages and run chat gpt function messages.append(inputMsg) output = runGPT(messages) # also append messages with bot message botMsg = {'role': 'assistant', 'content': output} messages.append(botMsg) numbers = re.findall(r'\d+', output) score1 = int(numbers[-1]) if numbers else 0 player.explanation_score1=score1 player.participant.vars['score1'] = score1 reasoning_AI1 = str(output.strip().split()) player.reasoning1 = reasoning_AI1 return {player.id_in_group: output} else: pass form_model = 'player' form_fields = ['price', 'keystroke_data', 'keystroke_price_data', 'chatLog', 'receive'] class Price_and_Explanation_R2(Page): @staticmethod def app_after_this_page(player, timeout_happened): if timeout_happened: return None # Stay on the same page if time runs out @staticmethod def is_displayed(player: Player): return (player.round_number == 2) @staticmethod def live_method(player: Player, data): # set chatgpt api key openai.api_key = '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' # load msg messages = json.loads(player.msg2) # functions for retrieving text from openAI if 'text' in data: # grab text that participant inputs and format for chatgpt text = data['text'] inputMsg = {'role': 'user', 'content': text} botMsg = {'role': 'assistant', 'content': text} # append messages and run chat gpt function messages.append(inputMsg) output = runGPT(messages) # also append messages with bot message botMsg = {'role': 'assistant', 'content': output} messages.append(botMsg) numbers = re.findall(r'\d+', output) score2 = int(numbers[-1]) if numbers else 0 player.explanation_score2=score2 player.participant.vars['score2'] = score2 reasoning_AI2 = str(output.strip().split()) player.reasoning2 = reasoning_AI2 return {player.id_in_group: output} else: pass form_model = 'player' form_fields = ['price', 'keystroke_data', 'keystroke_price_data', 'chatLog', 'receive'] class Price_and_Explanation_R3(Page): @staticmethod def app_after_this_page(player, timeout_happened): if timeout_happened: return None # Stay on the same page if time runs out @staticmethod def is_displayed(player: Player): return (player.round_number == 5) @staticmethod def live_method(player: Player, data): # set chatgpt api key openai.api_key = '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' # load msg messages = json.loads(player.msg3) # functions for retrieving text from openAI if 'text' in data: # grab text that participant inputs and format for chatgpt text = data['text'] inputMsg = {'role': 'user', 'content': text} botMsg = {'role': 'assistant', 'content': text} # append messages and run chat gpt function messages.append(inputMsg) output = runGPT(messages) # also append messages with bot message botMsg = {'role': 'assistant', 'content': output} messages.append(botMsg) numbers = re.findall(r'\d+', output) score3 = int(numbers[-1]) if numbers else 0 player.explanation_score3=score3 player.participant.vars['score3'] = score3 reasoning_AI3 = str(output.strip().split()) player.reasoning3 = reasoning_AI3 return {player.id_in_group: output} else: pass form_model = 'player' form_fields = ['price', 'keystroke_data', 'keystroke_price_data', 'chatLog', 'receive'] class Price_and_Explanation_R4(Page): @staticmethod def app_after_this_page(player, timeout_happened): if timeout_happened: return None # Stay on the same page if time runs out @staticmethod def is_displayed(player: Player): return (player.round_number == 6) @staticmethod def live_method(player: Player, data): # set chatgpt api key openai.api_key = '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' # load msg messages = json.loads(player.msg4) # functions for retrieving text from openAI if 'text' in data: # grab text that participant inputs and format for chatgpt text = data['text'] inputMsg = {'role': 'user', 'content': text} botMsg = {'role': 'assistant', 'content': text} # append messages and run chat gpt function messages.append(inputMsg) output = runGPT(messages) # also append messages with bot message botMsg = {'role': 'assistant', 'content': output} messages.append(botMsg) numbers = re.findall(r'\d+', output) score4 = int(numbers[-1]) if numbers else 0 player.explanation_score4=score4 player.participant.vars['score4'] = score4 reasoning_AI4 = str(output.strip().split()) player.reasoning4 = reasoning_AI4 return {player.id_in_group: output} else: pass form_model = 'player' form_fields = ['price', 'keystroke_data', 'keystroke_price_data', 'chatLog', 'receive'] class Price_and_Explanation_R5(Page): @staticmethod def app_after_this_page(player, timeout_happened): if timeout_happened: return None # Stay on the same page if time runs out @staticmethod def is_displayed(player: Player): return (player.round_number == 7) @staticmethod def live_method(player: Player, data): # set chatgpt api key openai.api_key = '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' # load msg messages = json.loads(player.msg5) # functions for retrieving text from openAI if 'text' in data: # grab text that participant inputs and format for chatgpt text = data['text'] inputMsg = {'role': 'user', 'content': text} botMsg = {'role': 'assistant', 'content': text} # append messages and run chat gpt function messages.append(inputMsg) output = runGPT(messages) # also append messages with bot message botMsg = {'role': 'assistant', 'content': output} messages.append(botMsg) numbers = re.findall(r'\d+', output) score5 = int(numbers[-1]) if numbers else 0 player.explanation_score5=score5 player.participant.vars['score5'] = score5 reasoning_AI5 = str(output.strip().split()) player.reasoning5 = reasoning_AI5 return {player.id_in_group: output} else: pass form_model = 'player' form_fields = ['price', 'keystroke_data', 'keystroke_price_data', 'chatLog', 'receive'] class Price_and_Explanation_R6(Page): @staticmethod def app_after_this_page(player, timeout_happened): if timeout_happened: return None # Stay on the same page if time runs out @staticmethod def is_displayed(player: Player): return (player.round_number == 10) @staticmethod def live_method(player: Player, data): # set chatgpt api key openai.api_key = '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' # load msg messages = json.loads(player.msg6) # functions for retrieving text from openAI if 'text' in data: # grab text that participant inputs and format for chatgpt text = data['text'] inputMsg = {'role': 'user', 'content': text} botMsg = {'role': 'assistant', 'content': text} # append messages and run chat gpt function messages.append(inputMsg) output = runGPT(messages) # also append messages with bot message botMsg = {'role': 'assistant', 'content': output} messages.append(botMsg) numbers = re.findall(r'\d+', output) score6 = int(numbers[-1]) if numbers else 0 player.explanation_score6=score6 player.participant.vars['score6'] = score6 reasoning_AI6 = str(output.strip().split()) player.reasoning6 = reasoning_AI6 return {player.id_in_group: output} else: pass form_model = 'player' form_fields = ['price', 'keystroke_data', 'keystroke_price_data', 'chatLog', 'receive'] class PriceSetting(Page): @staticmethod def is_displayed(player: Player): return player.round_number in [ 3, 4, 8, 9] form_model = 'player' form_fields = ['price'] class ResultsWait(WaitPage): after_all_players_arrive='round_results' title_text = "Bitte warten Sie einen Moment." body_text = "Bitte warten Sie kurz bis alle Teilnehmenden eine Entscheidung getroffen haben. " \ "Es geht in Kürze weiter." class ResultsFeedback(Page): pass class ShockAnnouncement(Page): @staticmethod def is_displayed(player: Player): return (player.round_number == player.shock) class FinalResults(Page): @staticmethod def is_displayed(player: Player): return (player.round_number == 10) class Demographics(Page): @staticmethod def is_displayed(player: Player): return (player.round_number == 10) form_model = 'player' form_fields = ['Gender', 'Age', 'Faculty', 'Makro', 'tech_problems'] class FinalPage(Page): @staticmethod def is_displayed(player: Player): return (player.round_number == 10) page_sequence = [ Place, Start, Pre_Comprehension, Comprehension_OT, Comprehension_BC, StartWait, ShockAnnouncement, Price_and_Explanation_R1, Price_and_Explanation_R2, Price_and_Explanation_R3, Price_and_Explanation_R4, Price_and_Explanation_R5, Price_and_Explanation_R6, PriceSetting, ResultsWait, ResultsFeedback, FinalResults, Demographics, FinalPage]