Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ hypr-calendar-outlook = { path = "crates/calendar-outlook", package = "calendar-
hypr-data = { path = "crates/data", package = "data" }
hypr-db-admin = { path = "crates/db-admin", package = "db-admin" }
hypr-db-core = { path = "crates/db-core", package = "db-core" }
hypr-db-script = { path = "crates/db-script", package = "db-script" }
hypr-db-user = { path = "crates/db-user", package = "db-user" }
hypr-detect = { path = "crates/detect", package = "detect" }
hypr-download-interface = { path = "crates/download-interface", package = "download-interface" }
Expand Down
4 changes: 2 additions & 2 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,5 @@ tasks:

stt:
cmds:
- chmod +x ./apps/desktop/src-tauri/resources/stt-aarch64-apple-darwin
- chmod +x ./apps/desktop/src-tauri/resources/passthrough-aarch64-apple-darwin
- chmod +x ./apps/desktop2/src-tauri/resources/stt-aarch64-apple-darwin
- chmod +x ./apps/desktop2/src-tauri/resources/passthrough-aarch64-apple-darwin
1 change: 1 addition & 0 deletions apps/desktop2/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ tauri-plugin-opener = { workspace = true }
tauri-plugin-os = { workspace = true }
tauri-plugin-process = { workspace = true }
tauri-plugin-sentry = { workspace = true }
tauri-plugin-shell = { workspace = true }
tauri-plugin-single-instance = { workspace = true }
tauri-plugin-store = { workspace = true }
tauri-plugin-store2 = { workspace = true }
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop2/src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"local-stt:default",
"dialog:default",
"listener:default",
"template:default"
"template:default",
"shell:default"
]
}
4 changes: 4 additions & 0 deletions apps/desktop2/src-tauri/resources/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
stt-aarch64-apple-darwin
passthrough-aarch64-apple-darwin
stt
ttt
1 change: 1 addition & 0 deletions apps/desktop2/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub async fn main() {
.plugin(tauri_plugin_tracing::init())
.plugin(tauri_plugin_analytics::init())
.plugin(tauri_plugin_listener::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_local_stt::init())
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_deep_link::init())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Icon } from "@iconify-icon/react";
import { openUrl } from "@tauri-apps/plugin-opener";
import useMediaQuery from "beautiful-react-hooks/useMediaQuery";
import { useCallback, useState } from "react";

import { SoundIndicator } from "@hypr/ui/components/block/sound-indicator";
import { Spinner } from "@hypr/ui/components/ui/spinner";
import { useListener } from "../../../../../contexts/listener";
import { useSTTConnection } from "../../../../../hooks/useSTTConnection";
import * as persisted from "../../../../../store/tinybase/persisted";
import { type Tab } from "../../../../../store/zustand/tabs";
import { FloatingButton, formatTime } from "./shared";
Expand Down Expand Up @@ -44,14 +44,7 @@ function BeforeMeeingButton({ tab }: { tab: Extract<Tab, { type: "sessions" }> }
const remote = useRemoteMeeting(tab.id);
const isNarrow = useMediaQuery("(max-width: 870px)");

const start = useListener((state) => state.start);

const handleClick = useCallback(() => {
start();
if (remote?.url) {
openUrl(remote.url);
}
}, [start, remote]);
const handleClick = useStartSession(tab.id);

if (remote?.type === "zoom") {
return (
Expand Down Expand Up @@ -135,3 +128,30 @@ function useRemoteMeeting(sessionId: string): RemoteMeeting | null {

return remote;
}

function useStartSession(sessionId: string) {
const start = useListener((state) => state.start);
const conn = useSTTConnection();

const handleClick = () => {
// TODO: We should be notified
if (!conn) {
console.log("no connection");
return;
}

start({
session_id: sessionId,
languages: ["en"],
onboarding: false,
record_enabled: false,
model: conn.model,
base_url: conn.baseUrl,
api_key: conn.apiKey,
}, (response) => {
console.log(response);
});
};

return handleClick;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useRef } from "react";

import type { TiptapEditor } from "@hypr/tiptap/editor";
import { cn } from "@hypr/ui/lib/utils";
import { useRef } from "react";
import { useListener } from "../../../../../contexts/listener";
import * as persisted from "../../../../../store/tinybase/persisted";
import { type Tab, useTabs } from "../../../../../store/zustand/tabs";
import { type EditorView } from "../../../../../store/zustand/tabs/schema";
import { EnhancedEditor } from "./enhanced";
import { RawEditor } from "./raw";
import { TranscriptEditorWrapper } from "./transcript";
import { TranscriptView } from "./transcript";

export function NoteInput({ tab }: { tab: Extract<Tab, { type: "sessions" }> }) {
const editorTabs = useEditorTabs({ sessionId: tab.id });
Expand All @@ -31,7 +32,7 @@ export function NoteInput({ tab }: { tab: Extract<Tab, { type: "sessions" }> })
<div className="flex-1 overflow-auto mt-3" onClick={handleContainerClick}>
{currentTab === "enhanced" && <EnhancedEditor ref={editorRef} sessionId={sessionId} />}
{currentTab === "raw" && <RawEditor ref={editorRef} sessionId={sessionId} />}
{currentTab === "transcript" && <TranscriptEditorWrapper sessionId={sessionId} />}
{currentTab === "transcript" && <TranscriptView sessionId={sessionId} />}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { ChevronDownIcon } from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react";
import * as persisted from "../../../../../store/tinybase/persisted";

import { Button } from "@hypr/ui/components/ui/button";
import { useSegments } from "../../../../../hooks/useSegments";

export function TranscriptEditorWrapper({
sessionId,
}: {
Expand All @@ -9,3 +14,84 @@ export function TranscriptEditorWrapper({

return <pre>{JSON.stringify(value, null, 2)}</pre>;
}

export function TranscriptView({ sessionId }: { sessionId: string }) {
const segments = useSegments(sessionId);

const [isAtBottom, setIsAtBottom] = useState(true);
const scrollContainerRef = useRef<HTMLDivElement | null>(null);

useEffect(() => {
if (isAtBottom && scrollContainerRef.current) {
scrollContainerRef.current.scrollTo({
top: scrollContainerRef.current.scrollHeight,
behavior: "smooth",
});
}
}, [segments, isAtBottom]);

const handleScroll = useCallback(() => {
const container = scrollContainerRef.current;
if (!container) {
return;
}

const { scrollTop, scrollHeight, clientHeight } = container;
const threshold = 100;
const atBottom = scrollHeight - scrollTop - clientHeight <= threshold;
setIsAtBottom(atBottom);
}, []);

const scrollToBottom = useCallback(() => {
const container = scrollContainerRef.current;
if (!container) {
return;
}

container.scrollTo({
top: container.scrollHeight,
behavior: "smooth",
});
}, []);

const hasContent = segments.length > 0;

if (!hasContent) {
return <div className="h-full" />;
}

return (
<div className="relative h-full flex flex-col">
<div
ref={scrollContainerRef}
className="flex-1 min-h-0 overflow-y-auto overflow-x-hidden pt-8 pb-6"
onScroll={handleScroll}
>
<div className="px-8 text-[15px] leading-relaxed space-y-4">
{segments.map((segment, idx) => (
<div key={idx} className="space-y-1">
<div className="text-xs font-medium text-gray-500">
Speaker {segment.speaker ?? "Unknown"}
</div>
<div className="text-gray-800">
{segment.words.map(word => word.punctuated_word || word.word).join(" ")}
</div>
</div>
))}
</div>
</div>

{!isAtBottom && (
<Button
onClick={scrollToBottom}
size="sm"
className="absolute bottom-4 left-1/2 transform -translate-x-1/2 rounded-full shadow-lg bg-white hover:bg-gray-50 text-gray-700 border border-gray-200 z-10 flex items-center gap-1"
variant="outline"
>
<ChevronDownIcon size={14} />
<span className="text-xs">Go to bottom</span>
</Button>
)}
</div>
);
}
120 changes: 0 additions & 120 deletions apps/desktop2/src/components/main/body/sessions/transcript.tsx

This file was deleted.

Loading
Loading