← Documentation

Interviews

An interview is a conversation with a witness. The case keeps what it established, and may keep the transcript.

An investigator rarely stops at a witness's first account. They go back to the witness: to fix a figure, to ask what was not said, to check what does not add up. That conversation is an interview, and a case can hold it next to the accounts it is about.

An interview is a conversation held with one or several witnesses of the case, by one or several people (an investigator, an association), at a given time and through some medium: face to face, by phone, in a video call, by chat, by email or by letter. What the case keeps of it is what it established (a short description, in as many languages as you like) and, when there is one, its transcript: who said what, and when. The transcript is what a reader can check the description against.

Several interviewers, several witnesses#

An interview may have any number of speakers. by lists every interviewer and interviewOf every observation held with; in the file the first interviewer is interviewer, the next interviewer2, and likewise witness, witness2… The editor keeps them in step with the event.

Its place in the case#

A case holds events. An interview is one of them, and it refers to the observation of the witness it was held with (to the observations, when several witnesses were interviewed together). The reference goes both ways: a passage of the transcript can say which moment of the observation it tells of, and the observation then lists, at that moment, the passages that tell of it. Nothing of an interview is replayed: the observation is what is replayed, the interview is what explains its figures.

A turn can say which moment of the observation it tells of: "refs": [{ "at": 0.5 }], in seconds from the beginning of the observation. sighting names the observation when the interview was held with several, and range ([from, to] in characters of text) the part of the turn concerned. In the editor a turn with a reference has a button that shows the observation at that moment, and the observation lists, under it, the passages that tell of it (“Reported in …”), each a link back to the turn.

Taking passages out#

A published transcript may hold less than what was recorded: a private life, a name, an exact place. What is taken out keeps its place (speaker and times) and says why in reason, so that a reader sees a gap and its reason rather than a silent cut. When only a detail goes, use parts: the answer to “are there lights in the park?” stays, the streets that would identify the place go.

Who approved it#

A transcript is proofread when every speaker has approved it. proofreading gives each speaker a status: pending (not asked, or no answer), approved, or covered. covered is for a file that holds less than one the speaker already approved (passages removed, nothing added): the earlier approval of the whole is enough, and coveredBy names that fuller version. A speaker who is not listed has not approved.

In the interview editor#

Summary: the witnesses, the medium, the date, the interviewers and what the interview established.
Summary: the witnesses, the medium, the date, the interviewers and what the interview established.
Exchanges: the interview as a dialogue, a turn that tells of a moment of the observation with its link.
Exchanges: the interview as a dialogue, a turn that tells of a moment of the observation with its link.
File: the transcript as text, completed from its schema, to load from a file and to save.
File: the transcript as text, completed from its schema, to load from a file and to save.

<rr0-interview-editor> has three groups: the Summary (title, witnesses, medium, date, interviewers, description), the Exchanges (the interview read as a dialogue: who said what, the time of each turn as a tooltip, passages taken out blacked out with their reason, who has not approved yet) and the File (the transcript as text, completed from its schema, to load and to save). It is a chunk of its own, fetched only when a case has an interview.

Importing a transcript that is not in our format#

Most transcripts come from somewhere else. In the File group, “Load a file” reads, besides JSON:

  • WebVTT and SRT, as a recording tool or a subtitle editor writes them: the times are kept, the speaker is the <v Name> tag or a Name: before the text;
  • text or Markdown with a name before each turn: Name: …, [00:12:34] Name: …, Name (00:12:34): …, Q: / R: or Q. / A.; a line with no name goes on the turn before;
  • plain paragraphs: one turn each, with no speaker and no time.

The names found are matched to the interview's: one that is among those who held it is an interviewer, one that is a witness of the case is that witness. Otherwise the first to speak is the interviewer and the others are witnesses; Q always asks and R or A always answers. All are pending approval, and the note says what file it came from.

It guesses, and says so: what it gets wrong is corrected in the File group. Word processor and PDF files are not read: save them as text first. A colon in a sentence is not taken for a speaker unless a name comes back often enough.

Technical part: the files#

What follows is for whoever writes these files by hand, generates them, or reads them in code. In the editor none of it has to be known.

The event in the case#

In case.json, an interview is an event whose eventType is "interview".

FieldMeaning
idWhat other things refer to it by
timeWhen it was held, as the case writes a time
titleWhat it is called, said in as many languages as you like
summaryWhat it established, in the same way
mediumin-person, phone, video, chat, email, letter or other
byWho held it: one agent, or several ({ "people": "…" } or { "org": "…" })
interviewOfThe id of the observation the interview was held with, or a list of them when there were several witnesses
urlThe transcript file, when there is one, relative to the case

The transcript file#

A plain JSON file, interview.schema.json being its schema. It holds everything the event says of the interview (the summary and the file are kept the same, whichever is edited) AND what was said.

FieldMeaning
version, id, language1; the interview's id; the language it was held in
title, time, medium, by, interviewOf, summaryThe same as the event's
speakersWho speaks, by an id of your choice: { role, by?, title?, of? }. role is interviewer or witness; by an agent for the interviewer; title what a witness is called (initials where unnamed) and of the observation they gave
transcriptionHow the text was obtained: method (automatic or manual), engine, and a free note
proofreadingWho approved it, by speaker (see below)
anonymizationWhat was replaced (replaced) and what stands in its place (marker)
segmentsThe turns of speech, in order

A turn of speech

Each entry of segments is one turn.

FieldMeaning
speakerA key of speakers
start, endSeconds from the beginning of the recording, both optional: a transcript typed by hand has none, and a turn without a time is not in the subtitles
textWhat was said, as plain text or HTML (a link, a title in italics, a foreign word in its language: what a page publishing it would write), escaped as any JSON string. The format says who speaks and when; the rest is HTML's
redacted{ reason }: the whole turn was taken out of the published file. It then has no text
partsInstead of text, when only a stretch was taken out: a list of { text } and { redacted }, in order
refsThe moments of the observation this turn tells of (see “Links with the observation”)

Every excerpt below is read-only, and each knows the format: put the caret inside an object and press Ctrl+Space (⌥+I on a Mac) to list every key that could go there, with what the model says of each.

An example

{
  "version": 1,
  "id": "interview-qb-1",
  "language": "fr",
  "title": { "fr": "Entretien avec Q. B." },
  "time": "2026-10-13 21:27",
  "medium": "video",
  "by": [{ "people": "BeauJerome" }],
  "interviewOf": "qb",
  "speakers": {
    "interviewer": { "role": "interviewer", "by": { "people": "BeauJerome" } },
    "witness": { "role": "witness", "title": "Q. B.", "of": "qb" }
  },
  "transcription": { "method": "automatic", "engine": "whisper.cpp large-v3-turbo" },
  "proofreading": { "interviewer": { "status": "approved" }, "witness": { "status": "pending" } },
  "segments": [
    { "speaker": "interviewer", "start": 0, "end": 4.2, "text": "Où étiez-vous ?" },
    { "speaker": "witness", "start": 5, "end": 9, "text": "Dans le parc.", "refs": [{ "at": 0.5 }] },
    { "speaker": "witness", "start": 10, "end": 18, "parts": [
      { "text": "Il n'y en a pas." },
      { "redacted": { "reason": { "fr": "Lieu précis" } } }
    ] },
    { "speaker": "interviewer", "start": 20, "end": 40, "redacted": { "reason": { "fr": "Vie privée" } } }
  ]
}

In code#

@rr0/data reads and writes the same files: RR0Interview.fromEventJson / toEventJson for the event, fromFileJson / toFileJson for the file, and proofread says whether everyone approved. In UFO@home, InterviewFile.toVtt makes subtitles from a transcript, InterviewFile.passagesAbout lists the turns that tell of an observation, and InterviewImport.parse reads a foreign file.

<rr0-interview>

An interview read as a dialogue: who said what, as the HTML it may be, the passages taken out as bars that say why, the time of each turn when it is pointed at, and the passages that tell of a moment of the observation as buttons that go there. It draws in the page itself, not in a shadow root, so the page's styles reach the text and its links.

<script src="https://ufoathome.org/lib/rr0-interview.mjs" type="module"></script>
<rr0-sighting id="player" src="case.json"></rr0-sighting>
<rr0-interview src="interview.json" player="player"></rr0-interview>

A module of its own, light: it holds the dialogue and nothing of the scene or of the editors.

MemberKindWhat it does
srcattributeThe interview's file, relative to the page. Its links are relative to it.
playerattributeThe id of an <rr0-sighting> of the page: a passage followed to its moment shows the observation there, at that moment.
interviewpropertyThe interview shown, set directly instead of fetched.
documentUrlpropertyWhat the links of an interview set directly are relative to.
revealSegment(index)methodShows that turn and where it is.
interviewseekeventSent, and bubbling, when a reader follows a turn to the moment of the observation it tells of: detail is { sighting, at }.

<rr0-interview-editor>

The editor of one interview of a case: its summary, its exchanges and its transcript file. The case editor shows it in place of the recording's editor when an interview is chosen.

const interview = document.createElement("rr0-interview-editor")
interview.documentUrl = "https://example.org/cases/saint-lo/case.json"
interview.witnesses = [{ id: "qb", label: "Q. B." }]
interview.event = { type: "event", eventType: "interview", interviewOf: "qb" }
interview.addEventListener("interviewchange", event => console.log(event.detail.field))

Not a bundle of its own: the case editor's module fetches it, and defines it, the first time an interview is shown, since most cases have none.

MemberKindWhat it does
eventpropertyThe interview's event of the case, edited in place.
witnessespropertyThe observers it may have been held with, [{ id, label }]: one box each, at least one checked.
documentUrlpropertyWhat the transcript's url is relative to: the address of the case.
transcriptTextpropertyThe transcript as text, once edited or loaded; undefined until then, when it is fetched from the event's url.
readonlyattributeOnly shows the interview.
revealSegment(index)methodOpens the Exchanges group at that turn and shows where it is.
interviewchangeeventSent, and bubbling, at each edit: detail is { field, event, text? }, the transcript's text being in text.
interviewseekeventSent, and bubbling, when a reader follows a turn to the moment of the observation it tells of: detail is { sighting, at }, at in seconds since the start of the observation.