← back to drhiramrodriguez__medscribe-ai

Function bodies 223 total

All specs Real LLM only Function bodies
TranscribeShell function · typescript · L10-L52 (43 LOC)
frontend/src/app/transcribe/layout.tsx
function TranscribeShell({ children }: { children: React.ReactNode }) {
  const { isAuthenticated, isLoading } = useAuth();
  const router = useRouter();

  useEffect(() => {
    if (!isLoading && !isAuthenticated) {
      router.push("/login");
    }
  }, [isAuthenticated, isLoading, router]);

  if (isLoading) {
    return (
      <div className="flex min-h-screen items-center justify-center bg-medical-surface">
        <div className="flex flex-col items-center gap-3">
          <Loader2 className="h-8 w-8 animate-spin text-brand-600" />
          <p className="text-sm text-medical-muted">Loading...</p>
        </div>
      </div>
    );
  }

  if (!isAuthenticated) {
    return null;
  }

  return (
    <div className="flex min-h-screen flex-col">
      <Navbar />
      <div className="flex flex-1">
        <div className="hidden lg:block">
          <div className="sticky top-14 h-[calc(100vh-3.5rem)]">
            <Sidebar />
          </div>
        </div>
        <main classNam
TranscribeLayout function · typescript · L54-L64 (11 LOC)
frontend/src/app/transcribe/layout.tsx
export default function TranscribeLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <AuthProvider>
      <TranscribeShell>{children}</TranscribeShell>
    </AuthProvider>
  );
}
TranscribePage function · typescript · L27-L323 (297 LOC)
frontend/src/app/transcribe/page.tsx
export default function TranscribePage() {
  const router = useRouter();
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
  const [language, setLanguage] = useState<"en" | "es">("en");
  const [uploading, setUploading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [result, setResult] = useState<TranscriptionResult | null>(null);
  const [dragActive, setDragActive] = useState(false);

  const validateFile = (file: File): string | null => {
    const ext = "." + file.name.split(".").pop()?.toLowerCase();

    if (!ALLOWED_FORMATS.includes(ext)) {
      return `Invalid file format. Allowed formats: ${ALLOWED_FORMATS.join(", ")}`;
    }

    if (file.size > MAX_FILE_SIZE_BYTES) {
      return `File is too large. Maximum size is ${MAX_FILE_SIZE_MB}MB, but your file is ${(file.size / 1024 / 1024).toFixed(1)}MB`;
    }

    return null;
  };

  const handleFileSelect = (file: F
ErrorBoundary class · typescript · L15-L71 (57 LOC)
frontend/src/components/ErrorBoundary.tsx
export default class ErrorBoundary extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error("Error caught by ErrorBoundary:", error, errorInfo);
  }

  handleReset = () => {
    this.setState({ hasError: false, error: undefined });
  };

  render() {
    if (this.state.hasError) {
      return (
        <div className="flex min-h-screen flex-col items-center justify-center bg-medical-surface px-4">
          <div className="flex max-w-md flex-col items-center gap-4 text-center">
            <div className="flex h-12 w-12 items-center justify-center rounded-full bg-red-50">
              <AlertCircle className="h-6 w-6 text-red-500" />
            </div>
            <h1 className="text-lg font-semibold text-medical-dark">
             
constructor method · typescript · L16-L19 (4 LOC)
frontend/src/components/ErrorBoundary.tsx
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false };
  }
getDerivedStateFromError method · typescript · L21-L23 (3 LOC)
frontend/src/components/ErrorBoundary.tsx
  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }
componentDidCatch method · typescript · L25-L27 (3 LOC)
frontend/src/components/ErrorBoundary.tsx
  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error("Error caught by ErrorBoundary:", error, errorInfo);
  }
Repobility analyzer · published findings · https://repobility.com
render method · typescript · L33-L70 (38 LOC)
frontend/src/components/ErrorBoundary.tsx
  render() {
    if (this.state.hasError) {
      return (
        <div className="flex min-h-screen flex-col items-center justify-center bg-medical-surface px-4">
          <div className="flex max-w-md flex-col items-center gap-4 text-center">
            <div className="flex h-12 w-12 items-center justify-center rounded-full bg-red-50">
              <AlertCircle className="h-6 w-6 text-red-500" />
            </div>
            <h1 className="text-lg font-semibold text-medical-dark">
              Something went wrong
            </h1>
            <p className="text-sm text-medical-muted">
              We encountered an unexpected error. Please try again or contact support if the issue persists.
            </p>
            {this.state.error && (
              <details className="w-full text-left">
                <summary className="cursor-pointer text-xs text-medical-muted hover:text-medical-dark">
                  Error details
                </summary>
                <pre c
ExportButtons function · typescript · L14-L154 (141 LOC)
frontend/src/components/ExportButtons.tsx
export default function ExportButtons({
  sessionId,
  draftId,
  noteText,
  noteType,
}: ExportButtonsProps) {
  const [exportingPdf, setExportingPdf] = useState(false);
  const [exportingMeditext, setExportingMeditext] = useState(false);
  const [exportError, setExportError] = useState<string | null>(null);

  const handleExportText = () => {
    const blob = new Blob(
      [
        `MedScribe AI - Clinical Note Draft\n`,
        `Note Type: ${noteType}\n`,
        `Session: ${sessionId}\n`,
        `Exported: ${new Date().toISOString()}\n`,
        `\n${"=".repeat(60)}\n`,
        `DRAFT - Requires physician review before clinical use\n`,
        `${"=".repeat(60)}\n\n`,
        noteText,
        `\n\n${"=".repeat(60)}\n`,
        `This note was generated by MedScribe AI, a documentation copilot.\n`,
        `All content is a draft and requires physician attestation.\n`,
      ],
      { type: "text/plain;charset=utf-8" },
    );
    const url = URL.createObjectURL(blob);
    con
Navbar function · typescript · L8-L94 (87 LOC)
frontend/src/components/Navbar.tsx
export default function Navbar() {
  const { user, logout } = useAuth();
  const [menuOpen, setMenuOpen] = useState(false);
  const [mobileOpen, setMobileOpen] = useState(false);
  const menuRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    function handleClickOutside(e: MouseEvent) {
      if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
        setMenuOpen(false);
      }
    }
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  return (
    <header className="sticky top-0 z-30 border-b border-medical-border bg-white">
      <div className="flex h-14 items-center justify-between px-4 lg:px-6">
        {/* Left: logo + mobile toggle */}
        <div className="flex items-center gap-3">
          <button
            className="lg:hidden btn-ghost p-1.5"
            onClick={() => setMobileOpen(!mobileOpen)}
            aria-label="Toggle sidebar"
    
handleClickOutside function · typescript · L15-L19 (5 LOC)
frontend/src/components/Navbar.tsx
    function handleClickOutside(e: MouseEvent) {
      if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
        setMenuOpen(false);
      }
    }
NoteEditor function · typescript · L13-L110 (98 LOC)
frontend/src/components/NoteEditor.tsx
export default function NoteEditor({
  value,
  onChange,
  readOnly = false,
  showDraftWatermark = true,
}: NoteEditorProps) {
  const [copied, setCopied] = useState(false);
  const textareaRef = useRef<HTMLTextAreaElement>(null);

  useEffect(() => {
    if (textareaRef.current) {
      textareaRef.current.style.height = "auto";
      textareaRef.current.style.height = `${Math.max(
        400,
        textareaRef.current.scrollHeight,
      )}px`;
    }
  }, [value]);

  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(value);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch {
      const textarea = document.createElement("textarea");
      textarea.value = value;
      document.body.appendChild(textarea);
      textarea.select();
      document.execCommand("copy");
      document.body.removeChild(textarea);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    }
  };

  return (
    <div cla
getQuotaLimits function · typescript · L11-L13 (3 LOC)
frontend/src/components/QuotaWidget.tsx
function getQuotaLimits(tier: SubscriptionTier) {
  return tier === "pro" ? { limit: 50, plan: "Pro" } : { limit: 10, plan: "Free" };
}
countSessionsToday function · typescript · L15-L25 (11 LOC)
frontend/src/components/QuotaWidget.tsx
function countSessionsToday(sessions: NoteSession[]): number {
  const today = new Date();
  today.setHours(0, 0, 0, 0);

  return sessions.filter((session) => {
    if (!session.created_at) return false;
    const sessionDate = new Date(session.created_at);
    sessionDate.setHours(0, 0, 0, 0);
    return sessionDate.getTime() === today.getTime();
  }).length;
}
QuotaWidget function · typescript · L27-L83 (57 LOC)
frontend/src/components/QuotaWidget.tsx
export default function QuotaWidget({ sessions, tier }: QuotaWidgetProps) {
  const { limit, plan } = getQuotaLimits(tier);
  const used = countSessionsToday(sessions);
  const percentage = (used / limit) * 100;
  const remaining = limit - used;

  return (
    <div className="card p-6 mb-6">
      <div className="flex items-start justify-between mb-4">
        <div className="flex items-center gap-3">
          <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-brand-50">
            <BarChart3 className="h-5 w-5 text-brand-600" />
          </div>
          <div>
            <h3 className="text-sm font-medium text-medical-dark">Daily Quota</h3>
            <p className="mt-0.5 text-xs text-medical-muted">{plan} Plan</p>
          </div>
        </div>
        <div className="text-right">
          <p className="text-sm font-semibold text-medical-dark">
            {used} of {limit}
          </p>
          <p className="mt-0.5 text-xs text-medical-muted">
      
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
formatDate function · typescript · L15-L24 (10 LOC)
frontend/src/components/SessionCard.tsx
function formatDate(dateString: string): string {
  const date = new Date(dateString);
  return date.toLocaleDateString("en-US", {
    month: "short",
    day: "numeric",
    year: "numeric",
    hour: "numeric",
    minute: "2-digit",
  });
}
SessionCard function · typescript · L26-L144 (119 LOC)
frontend/src/components/SessionCard.tsx
export default function SessionCard({ session, onDelete }: SessionCardProps) {
  const [deleting, setDeleting] = useState(false);
  const isDraft = session.status === "draft";
  const latestDraft =
    session.drafts && session.drafts.length > 0
      ? session.drafts[session.drafts.length - 1]
      : null;

  const handleDelete = async (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();

    const confirmed = window.confirm(
      "Delete this session and all its drafts? This cannot be undone."
    );
    if (!confirmed) return;

    setDeleting(true);
    try {
      await api.delete(`/notes/sessions/${session.id}`);
      onDelete?.();
    } catch (err) {
      console.error("Failed to delete session:", err);
      alert("Failed to delete session. Please try again.");
    } finally {
      setDeleting(false);
    }
  };

  return (
    <Link href={`/notes/${session.id}`} className="block">
      <div className="card p-4 transition-shadow hover:shadow-elevate
Sidebar function · typescript · L52-L106 (55 LOC)
frontend/src/components/Sidebar.tsx
export default function Sidebar() {
  const pathname = usePathname();

  return (
    <aside className="flex h-full w-60 flex-col border-r border-medical-border bg-white">
      <nav className="flex-1 space-y-1 px-3 py-4">
        <p className="mb-2 px-3 text-xs font-medium uppercase tracking-wider text-medical-muted">
          Clinical
        </p>
        {NAV_ITEMS.map((item) => {
          const isActive =
            pathname === item.href ||
            (item.href !== "/dashboard" && pathname.startsWith(item.href));
          return (
            <Link
              key={item.href}
              href={item.href}
              className={`flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors ${
                isActive
                  ? "bg-brand-50 text-brand-700"
                  : "text-medical-muted hover:bg-gray-50 hover:text-medical-dark"
              }`}
            >
              <item.icon className="h-4 w-4" />
              {item.label
sleep function · typescript · L22-L24 (3 LOC)
frontend/src/lib/api.ts
function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
AuthProvider function · typescript · L30-L138 (109 LOC)
frontend/src/lib/auth.ts
export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [token, setToken] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const router = useRouter();

  useEffect(() => {
    const storedToken = localStorage.getItem("medscribe_token");
    const storedUser = localStorage.getItem("medscribe_user");
    if (storedToken && storedUser) {
      setToken(storedToken);
      try {
        setUser(JSON.parse(storedUser));
      } catch {
        localStorage.removeItem("medscribe_user");
      }
    }
    setIsLoading(false);
  }, []);

  const clearError = useCallback(() => setError(null), []);

  const login = useCallback(
    async (credentials: UserLogin) => {
      setIsLoading(true);
      setError(null);
      try {
        const formData = new URLSearchParams();
        formData.append("username", credentials.user
useAuth function · typescript · L140-L146 (7 LOC)
frontend/src/lib/auth.ts
export function useAuth(): AuthContextValue {
  const ctx = useContext(AuthContext);
  if (!ctx) {
    throw new Error("useAuth must be used inside AuthProvider");
  }
  return ctx;
}
test_one_note_type function · python · L93-L155 (63 LOC)
scripts/smoke_test_openai.py
async def test_one_note_type(
    note_type: str,
    language: str = "en",
    model: str = "gpt-4o",
) -> dict:
    """Generate one structured note and validate it. Returns result dict."""
    from app.services.structured_generation import (
        generate_structured_note,
        StructuredGenerationError,
    )

    dictation = SAMPLE_DICTATION.get(note_type)
    if not dictation:
        return {"note_type": note_type, "status": "SKIP", "reason": "No sample dictation"}

    start = time.monotonic()
    try:
        structured_note, meta = await generate_structured_note(
            input_text=dictation,
            note_type=note_type,
            language=language,
        )
        elapsed = time.monotonic() - start

        # Render to text
        rendered = render_note_text(structured_note)

        # Validate plan has items
        plan_count = len(structured_note.plan)
        billing_count = len(structured_note.billing_keywords)

        return {
            "note_type":
main function · python · L158-L224 (67 LOC)
scripts/smoke_test_openai.py
async def main():
    import argparse

    parser = argparse.ArgumentParser(description="MedScribe AI OpenAI Smoke Test")
    parser.add_argument("note_types", nargs="*", help="Note types to test (default: all)")
    parser.add_argument("--language", default="en", choices=["en", "es"])
    parser.add_argument("--runs", type=int, default=1, help="Number of runs per type")
    args = parser.parse_args()

    # Verify API key
    api_key = os.environ.get("OPENAI_API_KEY", "")
    if not api_key or api_key.startswith("sk-..."):
        print("ERROR: Set OPENAI_API_KEY environment variable")
        sys.exit(1)

    types_to_test = args.note_types or list(SAMPLE_DICTATION.keys())

    print(f"MedScribe AI — OpenAI Structured Output Smoke Test")
    print(f"Schema version: {SCHEMA_VERSION}")
    print(f"Language: {args.language}")
    print(f"Note types: {', '.join(types_to_test)}")
    print(f"Runs per type: {args.runs}")
    print(f"{'=' * 60}")

    results = []
    for note_type in types
‹ prevpage 5 / 5