File size: 5,572 Bytes
bc82223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import React from "react";
import { TbExternalLink } from "react-icons/tb";
import { motion } from "framer-motion";

const projects = [
  {
    id: 1,
    title: "Multi-Platform Document Intelligence App",
    status: "In progress",
    description: (
      <>
        Cross-platform client that uploads documents and returns{" "}
        <span className="font-semibold">entity extraction</span>,{" "}
        <span className="font-semibold">concise summaries</span>, and{" "}
        <span className="font-semibold">semantic search</span> using an LLM-backed
        extraction & embedding service. Design includes client-side indexing,
        secure uploads, vector search, and cloud sync for offline-first usage.
      </>
    ),
    tech: [
      "Kotlin Multiplatform",
      "Compose Multiplatform",
      "Ktor",
      "Supabase",
      "Docker",
      "Embeddings / LLM",
    ],
    image: "/assets/project-doc.png",
    link: "#"
  },
  {
    id: 2,
    title: "End-to-End Media Processing Pipeline",
    status: "Prototype",
    description: (
      <>
        Asynchronous processing pipeline for uploaded media: resilient{" "}
        <span className="font-semibold">transcoding</span>,{" "}
        <span className="font-semibold">speech-to-text</span> (Whisper / ASR),
        AI-powered <span className="font-semibold">moderation & summarization</span>,
        and webhook/push notifications. Built for horizontal scale and fault
        tolerance with signed artifact URLs for clients.
      </>
    ),
    tech: [
      "Ktor",
      "FFmpeg",
      "Whisper / ASR",
      "Redis / RabbitMQ",
      "S3 / Supabase",
      "Docker workers",
    ],
    image: "/assets/project-media.png",
    link: "#"
  },
  {
    id: 3,
    title: "Hermetic Reproducible ML Pipelines (MLOps PoC)",
    status: "Prototype",
    description: (
      <>
        Hermetic, reproducible training + serving setup: Dockerized training
        environments, deterministic seeds, dataset versioning, experiment
        tracking with <span className="font-semibold">MLflow</span>, and REST
        inference endpoints for stable model deployment and CI-driven retraining.
      </>
    ),
    tech: [
      "Docker",
      "Python",
      "PyTorch / scikit-learn",
      "MLflow",
      "GitHub Actions",
      "Ktor (inference)",
    ],
    image: "/assets/project-mlops.png",
    link: "#"
  }
];

export default function Projects() {
  return (
    <section
      id="projects"
      className="bg-black px-5 lg:px-28 py-10 lg:py-16 text-white"
      aria-label="Projects"
    >
      <h2 className="text-2xl lg:text-4xl text-center">
        My <span className="font-extrabold">Projects</span>
      </h2>

      <div className="mt-10 lg:mt-16 space-y-12">
        {projects.map((project, index) => (
          <motion.article
            key={project.id}
            className={`flex flex-col items-center gap-8 lg:gap-12 ${
              index % 2 === 0 ? "lg:flex-row" : "lg:flex-row-reverse"
            }`}
            initial={{ opacity: 0, y: 40 }}
            whileInView={{ opacity: 1, y: 0 }}
            transition={{ type: "spring", stiffness: 80, damping: 12, delay: index * 0.15 }}
            viewport={{ once: true }}
          >
            {/* Image */}
            <div className="lg:w-1/2 w-full rounded-2xl overflow-hidden shadow-lg">
              <img
                src={project.image}
                alt={`${project.title} screenshot`}
                className="w-full h-64 lg:h-80 object-cover transform hover:scale-105 transition-transform duration-500"
                loading="lazy"
              />
            </div>

            {/* Content */}
            <div className="lg:w-1/2 w-full">
              <div className="flex items-start justify-between">
                <div>
                  <h3 className="text-3xl lg:text-4xl font-extrabold">
                    {String(project.id).padStart(2, "0")}
                  </h3>
                  <p className="mt-1 text-xl lg:text-2xl font-bold">{project.title}</p>
                </div>

                <div className="text-sm lg:text-base">
                  <span className="inline-block bg-white/10 px-3 py-1 rounded-full text-white/90 text-xs lg:text-sm">
                    {project.status}
                  </span>
                </div>
              </div>

              <p className="mt-4 text-sm lg:text-base text-gray-300 leading-relaxed">
                {project.description}
              </p>

              {/* Tech badges */}
              <div className="mt-4 flex flex-wrap gap-2">
                {project.tech.map((t) => (
                  <span
                    key={t}
                    className="text-xs lg:text-sm bg-white/6 border border-white/8 px-2 py-1 rounded-md text-gray-200"
                  >
                    {t}
                  </span>
                ))}
              </div>

              {/* Links */}
              <div className="mt-4 flex items-center gap-4">
                <a
                  href={project.link}
                  className="inline-flex items-center gap-2 text-white hover:underline"
                  target="_blank"
                  rel="noopener noreferrer"
                  aria-label={`Open ${project.title} link`}
                >
                  <TbExternalLink size={20} />
                  <span className="text-sm lg:text-base">View Repo / Demo</span>
                </a>
              </div>
            </div>
          </motion.article>
        ))}
      </div>
    </section>
  );
}