# Meeting Transcript Integrations

## Read.ai

**Source**: `prototype/src/talentverse/connectors/read_ai_connector.py`
**Base URL**: `https://api.read.ai/v1`
**Protocol**: Async HTTP (aiohttp)
**Auth**: Bearer token (API key)

### Fetch Meetings

```python
headers = {
    'Authorization': f'Bearer {self.api_key}',
    'Content-Type': 'application/json'
}
params = {
    'since': since.isoformat(),
    'participant': self.emma_email
}

async with aiohttp.ClientSession() as session:
    async with session.get(
        f"{self.base_url}/meetings",
        headers=headers,
        params=params,
        timeout=aiohttp.ClientTimeout(total=30)
    ) as response:
        data = await response.json()
        meetings = data.get('meetings', [])
```

### Get Transcript

```python
async with session.get(
    f"{self.base_url}/meetings/{meeting_id}/transcript",
    headers=headers,
    timeout=aiohttp.ClientTimeout(total=30)
) as response:
    transcript = await response.json()
```

### Transcript Processing (Reusable Patterns)

```python
# Extract OKR discussions
patterns = [
    (r'(?:objective|OKR|key result|KR)[\s:]*#?(\d+)[:\s]*([^.]+)', 'okr_reference'),
    (r'(?:progress|status)[\s:]*(\d+)%[:\s]*([^.]+)', 'progress_update'),
    (r'(?:behind|ahead|on track)[:\s]*([^.]+)', 'status_update')
]

# Extract assessment evidence by pillar (People/Process/Performance)
evidence_patterns = {
    'people': ['team', 'leadership', 'culture', 'collaboration', 'mentoring', ...],
    'process': ['process', 'workflow', 'system', 'efficiency', 'optimization', ...],
    'performance': ['result', 'achievement', 'metric', 'kpi', 'target', ...]
}

# Extract action items
patterns = [
    r'(?:action item|todo|will do|going to|need to)[:\s]+([^.]+)',
    r'(?:follow up|next step)[:\s]+([^.]+)',
    r'(?:by next week|by tomorrow|by end of)[:\s]+([^.]+)'
]
```

### Database Sync Service

```python
class TranscriptSyncService:
    async def sync_transcripts(self, since=None):
        meetings = await self.read_ai.fetch_transcripts(since=since)
        for meeting_meta in meetings:
            transcript = await self.read_ai.get_transcript(meeting_meta['meeting_id'])
            processed = await self.read_ai.process_transcript(transcript)
            await self._store_transcript(processed, transcript)
```

---

## Fireflies.ai

**Source**: `prototype/src/talentverse/one_on_one/connectors/fireflies_connector.py`
**Base URL**: `https://api.fireflies.ai/graphql`
**Protocol**: GraphQL (aiohttp)
**Auth**: Bearer token (API key)

### Data Models

```python
@dataclass
class Meeting:
    id: str
    title: str
    date: datetime
    duration_minutes: int
    participants: List[str]
    transcript_id: Optional[str] = None

@dataclass
class Transcript:
    meeting_id: str
    text: str
    sentences: List[Dict[str, Any]]
    speakers: List[str]
    duration_seconds: int
    word_count: int
    date: Optional[datetime] = None

@dataclass
class Participant:
    name: str
    email: str
    speaking_time_seconds: int
    word_count: int
```

### Search Meetings (GraphQL)

```python
query = """
query Transcripts($limit: Int, $skip: Int) {
    transcripts(limit: $limit, skip: $skip) {
        id
        title
        date
        duration
        participants
        audio_url
        video_url
    }
}
"""

async with aiohttp.ClientSession() as session:
    async with session.post(
        "https://api.fireflies.ai/graphql",
        headers={
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        },
        json={"query": query, "variables": {"limit": 50, "skip": 0}},
        timeout=aiohttp.ClientTimeout(total=30)
    ) as response:
        data = await response.json()
        transcripts = data.get("data", {}).get("transcripts", [])
```

### Get Transcript (GraphQL)

```python
query = """
query Transcript($transcriptId: String!) {
    transcript(id: $transcriptId) {
        id
        title
        date
        sentences {
            text
            speaker_name
            start_time
            end_time
        }
        duration
    }
}
"""
```

### Duration Handling

```python
# Fireflies may return duration in milliseconds or seconds
duration_raw = t.get("duration", 0)
if duration_raw > 100000:  # Likely milliseconds
    duration_seconds = duration_raw / 1000
else:
    duration_seconds = duration_raw
```

### Date Handling

```python
date_value = t.get("date")
if isinstance(date_value, int):
    # Unix timestamp in milliseconds
    meeting_date = datetime.fromtimestamp(date_value / 1000)
elif isinstance(date_value, str):
    meeting_date = datetime.fromisoformat(date_value.replace("Z", "+00:00"))
```

### Pagination Pattern

```python
all_transcripts = []
skip = 0
limit = 50

while True:
    variables = {"limit": limit, "skip": skip}
    # ... fetch page ...
    transcripts = data.get("data", {}).get("transcripts", [])
    if not transcripts:
        break
    all_transcripts.extend(transcripts)
    if len(transcripts) < limit:
        break
    skip += limit
```
