🍊 Clementime Survey

86 photo-verified clementine ratings, colored by bag.

📄 Capture Graph Code

Clementime.py

"""
Clementime Survey
=================

A photo-verified survey: each session photographs a clementine and rates it
across several taste axes. Demonstrates user input woven together with a
verification photo and a per-session thumbnail.
"""

import capturegraph as cg
from server import authoring as cgserver

REFERENCE_URL = (
    "https://upload.wikimedia.org/wikipedia/commons/5/5d/"
    "Clementines_whole%2C_peeled%2C_half_and_sectioned.jpg"
)


class ClementineSession(cg.Struct):
    user_id: cg.UserID
    bag: cg.String
    store_name: cg.String
    fruit_type: cg.String
    photo: cg.Image
    tastiness_rating: cg.Number
    sweet_rating: cg.Number
    tartness_rating: cg.Number
    firmness_rating: cg.Number
    comments: cg.String
    _metadata: cg.Metadata


class Clementime(cg.Struct):
    instructions: cg.Image
    reference: cg.Image
    clementine: cg.Map[cg.Date, ClementineSession]
    _metadata: cg.Metadata


@cgserver.target
@cg.procedure(Clementime)
def clementime(root):
    # Reference imagery + a root thumbnail, captured once.
    root.reference |= cg.DownloadImage(url=REFERENCE_URL)
    root._metadata._thumbnail |= cg.ConvertImageToThumbnail(image=root.reference)

    cg.do(
        cg.ShowInstructions(
            text=(
                "Photograph the clementine BEFORE eating it. Use a plate for "
                "consistency, align with the reference image, then rate its taste."
            ),
            image=root.reference,
        )
    )

    session = root.clementine[cg.CaptureTime()]
    session.user_id &= cg.GetUserID()

    session.bag &= cg.UserInputSelectString(
        label="Which bag is this from?",
        options=["A", "B", "C"],
    )
    session.store_name &= cg.UserInputString(label="Where was it bought?")
    session.fruit_type &= cg.UserInputString(label="Fruit type")

    session.photo &= cg.CaptureAlignedImage(
        label="Photograph the clementine",
        reference_image=root.reference,
        alignment=cg.ReferenceAlignment.OPTIONAL,
    )
    session._metadata._thumbnail &= cg.ConvertImageToThumbnail(image=session.photo)

    session.tastiness_rating &= cg.UserInputRating(
        label="How tasty?",
        max_stars=5,
        bad_text="Not Tasty",
        good_text="Tasty",
    )
    session.sweet_rating &= cg.UserInputRating(
        label="How sweet?",
        max_stars=5,
        bad_text="Not Sweet",
        good_text="Sweet",
    )
    session.tartness_rating &= cg.UserInputRating(
        label="How tart?",
        max_stars=5,
        bad_text="Not Tart",
        good_text="Tart",
    )
    session.firmness_rating &= cg.UserInputRating(
        label="How firm?",
        max_stars=5,
        bad_text="Soft",
        good_text="Firm",
    )

    with cg.optional():
        session.comments &= cg.UserInputString(label="Comments? (Optional)")