from otree.api import * from openai import OpenAI import random import itertools import time import os from random import choice doc = """ """ class C(BaseConstants): NAME_IN_URL = 'AI' PLAYERS_PER_GROUP = None NUM_ROUNDS = 15 TIME_LIMIT_SECONDS = 120 MAX_CHARS = 500 OPENAI_MODEL = "gpt-5.4-nano-2026-03-17" PRACTICE_TEXT_TITLE = "Practice round Text. The Water Cycle" PRACTICE_TEXT = """ The water cycle describes the continuous movement of water through the environment in different physical forms. Water evaporates from oceans, lakes, rivers, and soil when heat from the sun causes liquid water to become water vapour. Plants also release water vapour through a process called transpiration. As this vapour rises into the atmosphere, it cools and condenses into tiny droplets, forming clouds. When the droplets combine and grow large enough, they fall as precipitation, which may take the form of rain, snow, sleet, or hail depending on temperature conditions. Some of this water flows across the land as surface runoff and enters streams and rivers, while some soaks into the ground and becomes groundwater. Groundwater can move slowly through soil and rock and may later return to the surface through springs or human wells. Ice and snow can store water for long periods in glaciers and mountain regions before melting and rejoining the cycle. This circulation helps distribute freshwater around the planet, influences weather patterns, shapes landscapes through erosion, and supports agriculture, ecosystems, and daily human activities. """ TASKS = [ { "title": "Text #1. Public Libraries", "text": """ Public libraries are community institutions that provide access to information, reading materials, and educational services. Traditionally, libraries have been known for lending books, but most now offer a wider range of resources, including newspapers, magazines, maps, audiobooks, films, and digital databases. Many libraries provide internet access, computers, and quiet study spaces for students, job seekers, and other users. Librarians help visitors locate materials, use catalogues, and evaluate sources, which supports information literacy. Public libraries often organise events such as reading groups, language classes, children’s story sessions, and workshops on practical skills. In many places, they also preserve local history through archives, photographs, and records. Library collections are usually organised using classification systems that group materials by subject, making it easier for users to find related items. Funding typically comes from local or national government, though some libraries also receive support from charities or community groups. By offering free or low-cost access to knowledge and services, public libraries play a role in education, lifelong learning, and social inclusion for people of different ages and backgrounds. """, }, { "title": "Text #2. Volcanoes", "text": """ Volcanoes are openings in the Earth’s crust through which molten rock, gases, and ash can reach the surface. Most volcanoes form near the boundaries of tectonic plates, where sections of the Earth’s outer layer move relative to one another. At some boundaries, one plate sinks beneath another, causing rock to melt and produce magma. At others, plates pull apart, allowing magma to rise from below. There are also volcanoes formed above hotspots, where heat from deep within the Earth creates volcanic activity away from plate edges. When pressure builds, a volcano may erupt and release lava, ash clouds, rock fragments, and gases such as water vapour and carbon dioxide. Some eruptions are gentle and produce slow-moving lava flows, while others are explosive and can send material high into the atmosphere. Volcanoes can create new landforms, enrich soils with minerals, and alter local climates for short periods if ash blocks sunlight. At the same time, eruptions may damage settlements, disrupt transport, and affect air quality. Scientists monitor volcanoes by measuring earthquakes, ground movement, gas emissions, and temperature changes in order to better understand activity and reduce risk. """, }, { "title": "Text #3. The Postal System", "text": """ The postal system is a service network designed to collect, sort, transport, and deliver letters and parcels. Its basic function is to connect senders and recipients across short and long distances through a standardised process. A postal item usually begins its journey when it is deposited at a post office, collection box, or service counter. It is then gathered with other items and taken to a sorting centre, where addresses, barcodes, and postage information are checked. Automated machines and human workers direct items to the correct transport routes, which may involve road, rail, air, or sea. Delivery offices receive the sorted mail and prepare it for final distribution to homes, businesses, or collection points. Postal systems often provide additional services such as registered mail, tracking, insurance, money orders, and passport or government document support. In many countries, postal networks have also played an important role in administration, commerce, and communication, especially before the spread of telephones and the internet. Although digital communication has reduced personal letter writing, parcel delivery has grown because of online shopping. As a result, modern postal services continue to adapt their operations, technology, and infrastructure to changing patterns of demand. """, }, { "title": "Text #4. Bees and Pollination", "text": """ Bees are insects that play an important role in pollination, the transfer of pollen from one flower to another. This process allows many plants to produce seeds and fruits. When a bee visits a flower to collect nectar or pollen for food, grains of pollen can attach to its body. As the bee moves to another flower of the same species, some of this pollen is transferred, enabling fertilisation. Many wild plants depend on this process, and a large number of food crops also benefit from bee pollination, including apples, strawberries, tomatoes, and almonds. Bees vary widely in their behaviour and living arrangements. Some species, such as honeybees, live in large colonies with a queen, workers, and drones, while many others are solitary and build individual nests in soil, wood, or plant stems. Bees use sensory cues such as colour, shape, and scent to locate flowers, and some species can communicate information about food sources. Their activity is influenced by temperature, weather, and seasonal changes. Scientists and farmers study bees because pollination affects biodiversity and agricultural production. Changes in land use, pesticide exposure, disease, and habitat loss can influence bee populations and therefore affect plant reproduction and crop yields. """, }, { "title": "Text #5. Time Zones", "text": """ Time zones are regions of the world that use the same standard time. They exist because the Earth rotates, causing different places to experience daylight and darkness at different moments. Since the planet turns once every twenty-four hours, the world is divided into roughly twenty-four main time zones, each representing about fifteen degrees of longitude. The reference point for this system is the Prime Meridian, which passes through Greenwich in London, and standard time is often measured as an offset from Coordinated Universal Time. Countries select official time zones for practical reasons, but these do not always follow exact lines of longitude. Political borders, economic ties, and administrative convenience often shape time zone boundaries. Some countries use a single time zone across a large territory, while others use several. In addition, some places shift their clocks seasonally through daylight saving time, although this practice is not universal and may change over time. Time zones are important for transport, international trade, broadcasting, digital systems, and communication between regions. They help coordinate schedules and reduce confusion, but they can also create challenges for global organisations, travellers, and online meetings, especially when seasonal clock changes differ between countries. """, }, { "title": "Text #6. The Formation of Fossils", "text": """ Fossils are preserved remains, impressions, or traces of organisms from the past. They provide evidence about ancient life and environmental conditions over long periods of Earth’s history. Fossil formation usually begins when a plant or animal dies and is quickly buried by sediment such as mud, sand, or volcanic ash. Rapid burial protects the remains from scavengers, weather, and decay. Over time, additional layers of sediment accumulate and harden into rock under pressure. In some cases, the original material dissolves and is replaced by minerals carried by groundwater, preserving the structure of bones, shells, or wood. In other cases, impressions or footprints remain as trace fossils, showing how an organism moved or behaved. Fossils are more common for organisms with hard parts, such as teeth or shells, because soft tissues usually decay before preservation occurs. Paleontologists study fossils to classify extinct species, estimate their age, and reconstruct past ecosystems. They use rock layers and dating methods to place fossils in chronological order. Fossils have helped scientists understand major changes in life on Earth, including extinction events, evolutionary transitions, and long-term climate shifts that affected habitats and species distribution. """, }, { "title": "Text #7. Bridges", "text": """ Bridges are structures built to carry people, vehicles, railways, pipes, or cables across obstacles such as rivers, roads, valleys, or rail lines. Their design depends on the distance to be crossed, the weight they must support, local ground conditions, available materials, and cost. Common bridge types include beam bridges, arch bridges, suspension bridges, and cable-stayed bridges. A beam bridge carries loads directly across horizontal supports, while an arch bridge transfers weight outward and downward into its supports. Suspension bridges use cables hanging from towers to carry the deck, which makes them suitable for very long spans. Cable-stayed bridges also use towers and cables, but the cables connect directly to the deck in a different arrangement. Engineers must consider forces such as tension, compression, wind, vibration, and thermal expansion when planning a bridge. Construction may involve concrete, steel, stone, timber, or combinations of these materials. In addition to transport functions, bridges can influence trade, urban growth, and regional connectivity by reducing travel time and linking communities. Regular inspection and maintenance are necessary because weather, corrosion, heavy traffic, and aging materials can weaken structural performance over time if not managed properly. """, }, { "title": "Text #8. Soil", "text": """ Soil is the upper layer of the Earth’s land surface where plants grow and many organisms live. It forms gradually through the breakdown of rock and the accumulation of organic matter from decayed plants and animals. This process can take hundreds or thousands of years, depending on climate, parent material, water, and biological activity. Soil is made up of mineral particles, organic material, water, air, and living organisms such as bacteria, fungi, worms, and insects. These components interact to create a system that stores nutrients, holds water, and supports root growth. Different soils have different textures depending on the proportions of sand, silt, and clay they contain. Texture influences drainage, fertility, and ease of cultivation. Soil is usually arranged in layers called horizons, which differ in colour, composition, and structure. Healthy soil contributes to agriculture, water filtration, carbon storage, and ecosystem stability. However, soil can be degraded by erosion, compaction, pollution, salinisation, and loss of organic matter. Human activities such as intensive farming, construction, and deforestation can accelerate this damage. Because soil forms slowly but can be lost quickly, its management is important for food production, environmental quality, and long-term land use. """, }, { "title": "Text #9. Museums", "text": """ Museums are institutions that collect, preserve, study, and display objects of cultural, historical, artistic, or scientific significance. Their collections may include paintings, tools, fossils, clothing, manuscripts, machinery, and everyday items from different periods and regions. One purpose of museums is preservation, which involves protecting objects from light, humidity, insects, and physical damage so they remain available for future research and public access. Another purpose is interpretation, as museums provide labels, exhibitions, catalogues, and educational programmes to explain the meaning and context of the items on display. Museums vary in size and focus. Some are national institutions with large permanent collections, while others are local museums centred on a town, industry, or specific theme. Many also hold temporary exhibitions that bring together selected objects for a limited period. Behind the public galleries, museum staff conduct tasks such as documentation, conservation, loan management, and scholarly research. Increasingly, museums use digital tools to create online collections, virtual tours, and interactive displays. They may also work with communities, schools, and researchers to widen access and improve interpretation. Through these activities, museums support learning, record material evidence from the past, and encourage public understanding of different fields of knowledge. """, }, { "title": "Text #10. Weather Forecasting", "text": """ Weather forecasting is the process of estimating future atmospheric conditions for a particular place and time. Forecasts are based on observations of temperature, air pressure, humidity, wind, cloud cover, and precipitation. These data are collected from weather stations, ocean buoys, aircraft, satellites, and balloons that carry instruments high into the atmosphere. Meteorologists use this information to understand current weather patterns and enter it into computer models. These models apply physical laws to simulate how the atmosphere is likely to change over the next hours or days. Forecasts can range from short-term local predictions, such as whether rain is likely in the afternoon, to larger-scale outlooks about storms, heatwaves, or seasonal trends. Accuracy depends on data quality, model performance, and the complexity of atmospheric processes. Forecasts are generally more reliable over shorter periods because small uncertainties grow over time. Weather forecasting supports many sectors, including agriculture, aviation, shipping, energy supply, and emergency planning. It also helps the public make everyday decisions about travel, clothing, and outdoor activities. Because severe weather can create risks to life and infrastructure, forecasting systems are closely linked to warning services and communication networks that help authorities respond more effectively. """, }, { "title": "Text #11. The Printing Press", "text": """ The printing press is a technology that allowed written material to be reproduced in much larger quantities than hand copying. While printing methods existed in parts of Asia earlier, the development of movable type printing in Europe during the fifteenth century greatly increased the speed and scale of book production. A printing press worked by arranging individual letters or characters into lines and pages, applying ink to the raised surfaces, and pressing paper onto them to create a printed sheet. This method made it possible to produce many identical copies of a text more efficiently than manuscript production by scribes. As printing expanded, books, pamphlets, official documents, and educational materials became more widely available. This contributed to the spread of literacy, religious debate, scientific exchange, and administrative standardisation. Printers also helped establish more consistent spelling and punctuation in written languages over time. The growth of print culture supported the circulation of news and ideas across regions, linking scholars, merchants, and political authorities. Later improvements in machinery, paper production, and typesetting further increased output. Although digital publishing has changed how information is distributed today, the printing press remains a major historical development in communication and the transmission of knowledge. """, }, { "title": "Text #12. Coral Reefs", "text": """ Coral reefs are marine ecosystems formed mainly by colonies of tiny animals called coral polyps. These organisms secrete hard calcium carbonate skeletons, which gradually build reef structures over long periods. Most reef-building corals live in warm, shallow, sunlit waters, where they form a close relationship with microscopic algae that live inside their tissues. The algae use sunlight to produce energy, and in return they provide nutrients that help the corals grow. Coral reefs support a high variety of marine life by offering food, shelter, and breeding areas for fish, crustaceans, molluscs, and other species. Reefs can also reduce wave energy and help protect coastlines from erosion. There are several main types of reefs, including fringing reefs near shorelines, barrier reefs farther offshore, and atolls that form ring-shaped structures around lagoons. Although reefs occupy a relatively small part of the ocean floor, they are important for fisheries, tourism, and biodiversity. Scientists study coral reefs to understand ecological relationships and environmental change. Reef systems can be affected by rising sea temperatures, ocean acidification, pollution, sedimentation, and destructive fishing practices. Because coral growth is slow, damage may take a long time to reverse even when conditions improve. """, }, { "title": "Text #13. Railways", "text": """ Railways are transport systems in which trains run on tracks to move passengers or goods. A railway network usually includes rails, sleepers, signalling systems, stations, depots, and power or fuel infrastructure. Trains may be powered by diesel engines, electricity, or, in earlier periods, steam. Rail transport developed rapidly during the nineteenth century and became important for industry, trade, and urban growth because it allowed large quantities of goods and people to be moved more efficiently than many earlier methods. Freight railways can carry materials such as coal, grain, containers, and manufactured products, while passenger railways connect cities, suburbs, and rural areas. Railway safety depends on track maintenance, signalling, communication systems, and operating rules that control train movement and reduce collision risk. In urban areas, rail-based systems such as trams, metros, and suburban lines help manage large daily flows of commuters. High-speed rail, where available, reduces travel time between major cities and can compete with air travel on some routes. Railways also influence land use, station development, and regional accessibility. Because trains can move many people or large loads at once, rail transport is often discussed in relation to efficiency, long-distance travel, and infrastructure planning. """, }, { "title": "Text #14. Maps", "text": """ Maps are visual representations of places, spaces, or geographic relationships. They are used to show the location of features such as roads, rivers, borders, mountains, and settlements, but they can also display information about climate, population, land use, or transport networks. Because the Earth is curved and maps are usually flat, mapmakers must use projections to represent the surface. Every projection changes some combination of shape, area, distance, or direction, so different map types are suited to different purposes. Maps also rely on scale, which indicates the relationship between distances on the map and actual distances on the ground. Large-scale maps show smaller areas in more detail, while small-scale maps show larger areas with less detail. Symbols, colours, labels, and legends help users interpret the information. Historically, maps were drawn by hand and often reflected the knowledge and priorities of their time. Modern cartography uses satellite data, aerial imagery, surveying, and geographic information systems to create more precise and frequently updated maps. Digital maps can provide real-time navigation, route planning, and layered information. Despite changes in technology, maps remain important tools for travel, planning, education, emergency response, and the communication of spatial data. """, }, { "title": "Text #15. Recycling", "text": """ Recycling is the process of collecting, sorting, and reprocessing materials so they can be used again rather than discarded as waste. Common recyclable materials include paper, cardboard, glass, metals, and certain plastics. The process usually begins when households, businesses, or institutions separate items into designated containers. These materials are then transported to facilities where they are sorted by type, cleaned, and prepared for manufacturing. Paper may be pulped and turned into new paper products, glass can be crushed and melted, and metals such as aluminium can be reprocessed into new containers or components. Recycling can reduce the amount of waste sent to landfill or incineration and may lower demand for some raw materials. However, recycling systems depend on factors such as collection infrastructure, market demand, contamination levels, and the technical properties of different materials. Not all products are easy to recycle, especially when they contain mixed materials or harmful substances. Public guidance is therefore important, since incorrect sorting can reduce the quality of recyclable material. Recycling is one part of broader waste management, which also includes reducing consumption, reusing items, and designing products that generate less waste over their full life cycle. """, }, ] class Subsession(BaseSubsession): pass def creating_session(subsession): # treatments for p in subsession.get_players(): p.Prolific_ID = p.participant.label if p.id_in_subsession: pressures = itertools.cycle([1, 1, 2, 2, 3, 3]) for player in subsession.get_players(): player.code_treatment = next(pressures) if p.code_treatment == 1: p.treatment = "NoAI" elif p.code_treatment == 2: p.treatment = "AINoinfo" elif p.code_treatment == 3: p.treatment = "AIinfo" for p in subsession.get_players(): if p.id_in_subsession: pressures2 = itertools.cycle([1, 2]) for player in subsession.get_players(): player.codetext = next(pressures2) if player.codetext == 1: player.type = 'worker' elif player.codetext == 2: player.type = 'evaluator' class Group(BaseGroup): pass class Player(BasePlayer): code_treatment = models.IntegerField() treatment = models.StringField() codetext = models.IntegerField() type = models.StringField() code = models.StringField(label='') practice_summary = models.LongStringField(blank=True) summary = models.LongStringField(blank=True) practice_timeout = models.BooleanField(initial=False) task_timeout = models.BooleanField(initial=False) practice_time_spent = models.FloatField(initial=0) task_time_spent = models.FloatField(initial=0) practice_chat_history = models.LongStringField(blank=True) task_chat_history = models.LongStringField(blank=True) Q1 = models.StringField( choices=[ ['1', '5'], ['2', '10'], ['3', '15'], ], label="Q1: How many rounds are there for the actual experiment (excluding the practice round)?", widget=widgets.RadioSelect ) Q2 = models.StringField( choices=[ ['1', '5'], ['2', '10'], ['3', '15'], ], label="Q2: How many rounds are selected for the final payment?", widget=widgets.RadioSelect ) Q3 = models.StringField( choices=[ ['1', 'True'], ['2', 'False'], ], label="Q3: The rounds are selected for final payment at random. Is this statement True or False?", widget=widgets.RadioSelect ) Q4 = models.StringField( choices=[ ['1', '£0.00'], ['2', '£1.50'], ['3', '£3.00'], ], label="", widget=widgets.RadioSelect ) gender = models.StringField( choices=[ ['1', 'Male'], ['2', 'Female'], ['3', 'Other'], ], label="1. What is your gender?", widget=widgets.RadioSelect ) age = models.IntegerField( label="2. What is your age?", min=0, max=120 ) language = models.StringField( choices=[ ['1', 'Yes'], ['2', 'No'], ], label="3. Is English your first language?", widget=widgets.RadioSelect ) max_income = models.StringField( choices=[ ['1', 'Very important'], ['2', 'Important'], ['3', 'Indifferent'], ['4', 'Not important'], ['5', 'Not important at all'], ], label="4. How important was it for you to maximise your own income during the experiment?", widget=widgets.RadioSelect ) trust = models.StringField( choices=[ ['1', 'Most people can be trusted'], ['2', 'You need to be very careful in dealing with people'], ], label="5. Generally speaking, would you say that most people can be trusted or that you need to be very careful in dealing with people?", widget=widgets.RadioSelect ) risk = models.StringField( choices=[ ['1', ''], ['2', ''], ['3', ''], ['4', ''], ['5', ''], ['6', ''], ['7', ''], ['8', ''], ['9', ''], ['10', ''], ], label="", widget=widgets.RadioSelectHorizontal ) instructions = models.StringField( choices=[ ['1', 'Very difficult'], ['2', 'Difficult'], ['3', 'Neutral'], ['4', 'Easy'], ['5', 'Very easy'], ], label="7. How did you find the instructions?", widget=widgets.RadioSelect ) econ_exp = models.IntegerField( label="8. How many economics experiments have you participated in before this one? ", ) feedback = models.StringField( blank=True, label="9. Do you have any other comments or feedback regarding this experiment?", ) class ChatLog(ExtraModel): player = models.Link(Player) round_number = models.IntegerField() role = models.StringField() # "user" or "assistant" content = models.LongStringField() created_at = models.FloatField() turn_index = models.IntegerField() def Q1_error_message(player, value): correct_answer = '3' if value != correct_answer: error_message = "The selected answer is incorrect. Please try again." return error_message def Q2_error_message(player, value): correct_answer = '1' if value != correct_answer: error_message = "The selected answer is incorrect. Please try again." return error_message def Q3_error_message(player, value): correct_answer = '1' if value != correct_answer: error_message = "The selected answer is incorrect. Please try again." return error_message def Q4_error_message(player, value): correct_answer = '2' if value != correct_answer: error_message = "The selected answer is incorrect. Please try again." return error_message def current_task(player: "Player"): return C.TASKS[player.round_number - 1] class Code(Page): form_model = 'player' form_fields = ['code'] def is_displayed(player): return player.round_number == 1 class Welcome(Page): form_model = 'player' def is_displayed(player): return player.round_number == 1 class General_Instructions(Page): def is_displayed(player): return player.round_number == 1 class Instructions(Page): def is_displayed(player): return player.round_number == 1 class Check(Page): form_model = 'player' form_fields = ['Q1', 'Q2', 'Q3', 'Q4'] def is_displayed(player): return player.round_number == 1 class Wait1(WaitPage): def is_displayed(player): return player.round_number == 1 client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY")) def append_chat(existing_text, speaker, message): existing_text = existing_text or "" return existing_text + f"{speaker}: {message}\n\n" class Practice(Page): form_model = 'player' form_fields = ['practice_summary', 'practice_time_spent'] timeout_seconds = C.TIME_LIMIT_SECONDS @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def before_next_page(player: Player, timeout_happened): player.practice_timeout = timeout_happened @staticmethod def error_message(player: Player, values): text = (values.get('practice_summary') or '').strip() if len(text) > C.MAX_CHARS: return f"Your summary must not exceed {C.MAX_CHARS} characters." @staticmethod def vars_for_template(player: Player): show_ai = player.treatment in ['AINoinfo', 'AIinfo'] return dict( text_title=C.PRACTICE_TEXT_TITLE, original_text=C.PRACTICE_TEXT, max_chars=C.MAX_CHARS, show_ai=show_ai, ) @staticmethod def live_method(player: Player, data): if data.get("type") != "chat": return if player.treatment not in ['AINoinfo', 'AIinfo']: return { player.id_in_group: { "type": "error", "message": "AI help is not available in this condition." } } user_msg = (data.get("message") or "").strip() if not user_msg: return { player.id_in_group: { "type": "error", "message": "Please enter a question." } } if len(user_msg) > 5000: return { player.id_in_group: { "type": "error", "message": "Your question is too long." } } prior_logs = ChatLog.filter(player=player, round_number=0) turn_index = len(prior_logs) + 1 ChatLog.create( player=player, round_number=0, role="user", content=user_msg, created_at=time.time(), turn_index=turn_index, ) player.practice_chat_history = append_chat( player.field_maybe_none("practice_chat_history"), "User", user_msg ) recent_logs = ChatLog.filter(player=player, round_number=0)[-6:] input_items = [ { "role": "system", "content": ( "You are an AI assistant helping a participant summarise a text. " "Be concise and helpful. Answer questions about the text, identify key points, " "and offer brief guidance. Do not produce unnecessarily long answers. " "Do not invent facts not contained in the text. " "Assume the participant may refer to 'the text on the left'; you already have access to that text." ), }, { "role": "user", "content": f"Here is the text the participant is working on:\n\n{C.PRACTICE_TEXT}" } ] for log in recent_logs: input_items.append( {"role": log.role, "content": log.content} ) try: response = client.responses.create( model=C.OPENAI_MODEL, input=input_items, store=False, ) assistant_text = response.output_text.strip() except Exception as e: assistant_text = "Sorry, the AI assistant is temporarily unavailable. Please try again." print("OpenAI API error (practice):", e) ChatLog.create( player=player, round_number=0, role="assistant", content=assistant_text, created_at=time.time(), turn_index=turn_index + 1, ) player.practice_chat_history = append_chat( player.field_maybe_none("practice_chat_history"), "ChatGPT", assistant_text ) return { player.id_in_group: { "type": "chat_reply", "user_message": user_msg, "assistant_message": assistant_text, } } class Wait(WaitPage): body_text = "Please wait while all participants finish the practice round." def is_displayed(player): return player.round_number == 1 class Task(Page): form_model = 'player' form_fields = ['summary', 'task_time_spent'] timeout_seconds = C.TIME_LIMIT_SECONDS @staticmethod def error_message(player: Player, values): text = (values.get('summary') or '').strip() if len(text) > C.MAX_CHARS: return f"Your summary must not exceed {C.MAX_CHARS} characters." @staticmethod def before_next_page(player: Player, timeout_happened): player.task_timeout = timeout_happened @staticmethod def vars_for_template(player: Player): task = current_task(player) show_ai = player.treatment in ['AINoinfo', 'AIinfo'] return dict( round_number=player.round_number, num_rounds=C.NUM_ROUNDS, text_title=task['title'], original_text=task['text'], show_ai=show_ai, max_chars=C.MAX_CHARS, ) @staticmethod def live_method(player: Player, data): if data.get("type") != "chat": return if player.treatment not in ['AINoinfo', 'AIinfo']: return { player.id_in_group: { "type": "error", "message": "AI help is not available in this condition." } } user_msg = (data.get("message") or "").strip() if not user_msg: return { player.id_in_group: { "type": "error", "message": "Please enter a question." } } if len(user_msg) > 5000: return { player.id_in_group: { "type": "error", "message": "Your question is too long." } } prior_logs = ChatLog.filter(player=player, round_number=player.round_number) turn_index = len(prior_logs) + 1 ChatLog.create( player=player, round_number=player.round_number, role="user", content=user_msg, created_at=time.time(), turn_index=turn_index, ) player.task_chat_history = append_chat( player.field_maybe_none("task_chat_history"), "User", user_msg ) task = current_task(player) recent_logs = ChatLog.filter(player=player, round_number=player.round_number)[-6:] input_items = [ { "role": "system", "content": ( "You are an AI assistant helping a participant summarise a text. " "Be concise and helpful. Answer questions about the text, identify key points, " "and offer brief guidance. Do not produce unnecessarily long answers. " "Do not invent facts not contained in the text. " "Assume the participant may refer to 'the text on the left'; you already have access to that text." ), }, { "role": "user", "content": f"Here is the text the participant is working on:\n\n{task['text']}" } ] for log in recent_logs: input_items.append( {"role": log.role, "content": log.content} ) try: response = client.responses.create( model=C.OPENAI_MODEL, input=input_items, store=False, ) assistant_text = response.output_text.strip() except Exception as e: assistant_text = "Sorry, the AI assistant is temporarily unavailable. Please try again." print("OpenAI API error:", e) ChatLog.create( player=player, round_number=player.round_number, role="assistant", content=assistant_text, created_at=time.time(), turn_index=turn_index + 1, ) player.task_chat_history = append_chat( player.field_maybe_none("task_chat_history"), "ChatGPT", assistant_text ) return { player.id_in_group: { "type": "chat_reply", "user_message": user_msg, "assistant_message": assistant_text, } } class Questionnaire(Page): form_model = 'player' form_fields = [ 'gender', 'age', 'language', 'max_income', 'trust', 'risk', 'instructions', 'econ_exp', 'feedback' ] def is_displayed(player): return player.round_number == C.NUM_ROUNDS class Thanks(Page): def is_displayed(player): return player.round_number == C.NUM_ROUNDS page_sequence = [Code, Welcome, General_Instructions, Instructions, Check, Practice, Wait,Task, Questionnaire, Thanks]