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
2 changes: 1 addition & 1 deletion the-operation/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const ollama = new Ollama({
})

export const ODDY_INITIAL_PROMPT =
'You are Odd Reitan, CEO of Reitan Retail, one of the biggest retail companies in the nordics. Don\'t mention other nordic retail stores. You only own Rema 1000. You answer to, and call yourself (should it be necessary) "Oddy" and "Odd" as well. Don\'t sign off every message with Oddy, but use it if necessary. You are acting as an assistant, and want to help the user to the best of your ability. The rest of this request will be in Norwegian. Please respond in Norwegian. Use plain text(no markdown) and respond briefly (ca. 150 characters max).'
"You are Oddy, an AI chatbot and digital shopping assistant. You are based off of Odd Reitan, CEO of Reitan Retail, one of the biggest retail companies in the nordics. Don't mention other nordic retail stores. You only own Rema 1000. You are acting as an assistant, and want to help the user to the best of your ability. The rest of this request will be in Norwegian. Please respond in Norwegian. Use plain text(no markdown) and respond fairly briefly"
export const FROGGY_INITIAL_PROMPT =
"You are Froggy, a frog in a round pan. You do not speak any english, don't ever respond in english, only frog and a tiny bit of Norwegian, but mostly frog. Do not break character, act like froggy. You have a big mouth. You really don't like REMA 1000 or Odd Reitan, when any of these are mentioned you get really mad in frog language"
export const PRIDE_EXTENSION =
Expand Down
6 changes: 4 additions & 2 deletions whitewash/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/material": "^7.3.4",
"material-ui-popup-state": "^5.3.6",
"@tanstack/react-query": "^5.90.5",
"material-ui-popup-state": "^5.3.6",
"next": "15.5.6",
"react": "19.1.0",
"react-dom": "19.1.0"
"react-dom": "19.1.0",
"react-markdown": "^10.1.0",
"remark-gfm": "^4.0.1"
},
"devDependencies": {
"@biomejs/biome": "2.2.0",
Expand Down
885 changes: 882 additions & 3 deletions whitewash/pnpm-lock.yaml

Large diffs are not rendered by default.

32 changes: 28 additions & 4 deletions whitewash/src/app/components/chat/OddyChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import prideFrog from "@/assets/images/pride-froggy.png"
import styles from "../oddy/Oddy.module.css"
import { useEffect, useRef, useState } from "react"
import { useStateArray } from "@/hooks/useStateArray"
import Markdown from "react-markdown"
import remarkGfm from "remark-gfm"

type ChatMsg = {
id: string
Expand Down Expand Up @@ -94,7 +96,7 @@ export const OddyChat = ({
}

return () => ws.current?.close()
}, [isFrog, isPride, addMessage, previousMessages.map, ])
}, [isFrog, isPride, addMessage, previousMessages.map])

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
Expand All @@ -111,6 +113,18 @@ export const OddyChat = ({
setInput("")
}

const tableStyles = `
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: left;
}
`

return (
<div className="fixed bottom-6 right-6 z-50 flex flex-col items-end gap-4 bg-rema-secondary-lightblue rounded-3xl p-5 backdrop-blur">
<Image
Expand All @@ -135,16 +149,26 @@ export const OddyChat = ({
{messages
.filter((v) => v.id !== "0")
.map((m) => (
<p
<div
key={m.id}
className={`max-w-[85%] rounded px-3 py-2 ${
m.role === "assistant"
? "bg-gray-100 text-gray-900 self-start"
: "bg-blue-600 text-white self-end ml-auto"
}`}
>
{m.content}
</p>
<style>{tableStyles}</style>
<Markdown
remarkPlugins={[remarkGfm]}
components={{
table: ({ node, ...props }) => (
<table style={{ border: "1px solid black" }} {...props} />
),
}}
>
{m.content}
</Markdown>
</div>
))}
<div ref={messagesEndRef} />
</div>
Expand Down
8 changes: 6 additions & 2 deletions whitewash/src/app/components/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ import { HeaderItem } from "./HeaderItem"
import Link from "next/link"
import { type FormEvent, useState } from "react"
import { ShoppingCartPreview } from "./ShoppingCartPreview"
import { useSearchParams } from "next/navigation"

export function Header() {
const [searchInput, setSearchInput] = useState("")
const searchParams = useSearchParams()
const [searchInput, setSearchInput] = useState(
searchParams.get("search") ?? "",
)

const handleSearch = (e: FormEvent) => {
e.preventDefault()
if (searchInput.length > 0) {
window.location.href = `/search?a=${searchInput}`
window.location.href = `/search?search=${searchInput}`
}
}

Expand Down
4 changes: 2 additions & 2 deletions whitewash/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ export default function Home() {
src={oddyImg}
alt="Oddy our supreme leader"
className="rounded-lg"
/>
/>
<div className="bg-white rounded-lg flex items-center justify-center p-20">
<p className="mt-4 text-center text-lg italic">
"Rema‑1000 er som... som... wow! Billige priser, så... så god smak,
så... så glad hjertet ditt hopper som en... som en dans!" – Oddy
</p>
</div>
</div>
{oddyView}
{oddyView}
</div>
)
}
40 changes: 30 additions & 10 deletions whitewash/src/app/search/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client"

import { OddyChat } from "@/components/chat/OddyChat"
import { Header } from "@/components/header/header"
import { Header } from "@/components/header/Header"
import { Oddy } from "@/components/oddy/Oddy"
import { Product } from "@/components/shopping-cart/Product"
import { useQuery } from "@tanstack/react-query"
Expand All @@ -24,7 +24,7 @@ export type ProductItem = {
export default function SearchPage() {
const [chattingWithOddy, setChattingWithOddy] = useState(false)
const searchParams = useSearchParams()
const search = searchParams.get("a")
const search = searchParams.get("search")
const url = `http://localhost:4000/api/findProducts?search=`

const { data, isLoading, error } = useQuery({
Expand All @@ -36,19 +36,17 @@ export default function SearchPage() {
},
})

const oddyMessage = `Jeg har søkt på ${search} på nettsiden din, og fått opp disse resultatene (i json format): ${JSON.stringify(data)}. Gi meg en anbefaling på hva jeg burde kjøpe basert på CO2 fotavtrykket til varene, pris og sunnhet. Til senere svar, vennligst bare referer til disse varene og baser svar på resultatene`
const { data: oddyResponse } = useQuery({
const oddyMessage = `Jeg har søkt på ${search} på nettsiden din, og fått opp disse resultatene (i json format): ${JSON.stringify(data)}. Gi meg en anbefaling på hva jeg burde kjøpe basert på CO2 fotavtrykket til varene, pris og sunnhet. Til senere svar, vennligst bare referer til disse varene og baser svar på resultatene. Du har ikke tilgang til å finne mer informasjon om varer på egen hånd. Om du trenger mer informasjon, be meg om å starte ett nytt søk etter det du leter etter. Vennligst svar kort på denne første melding, ca 100 bokstaver på det meste. Til senere meldinger kan du gi lengre svar.`
const { data: oddyResponse, isLoading: oddyLoading } = useQuery({
queryKey: ["Oddy", "oddySearch", JSON.stringify(data)],
queryFn: async () => {
const url = "http://localhost:4000/api/oddy?inMessage="

// console.log(oddyMessage)

const res = await fetch(url + oddyMessage)

return (await res.json()) as { message: string }
},
enabled: !!data,
enabled: !!data && data.length > 0,
})

const handleToggleChat = () => setChattingWithOddy((v) => !v)
Expand All @@ -69,12 +67,34 @@ export default function SearchPage() {
content: oddyResponse.message,
},
]
: []
: [
{
id: "0",
role: "user",
content:
oddyMessage +
"Om det ikke er noen resultater, spør om det er noe annet du kan hjelpe med.",
},
{
id: crypto.randomUUID(),
role: "assistant",
content:
"Set ut som vi ikke fant noen resultater for søket ditt. Er det noe annet jeg kan hjelpe med?",
Comment thread
henrygraesberg marked this conversation as resolved.
},
]
}
/>
) : (
oddyResponse && (
<Oddy message={oddyResponse.message} onClick={handleToggleChat} />
!oddyLoading &&
!!data && (
<Oddy
message={
data.length > 0 && oddyResponse
? oddyResponse.message
: "Set ut som vi ikke fant noen resultater for søket ditt. Er det noe annet jeg kan hjelpe med?"
}
onClick={handleToggleChat}
/>
)
)

Expand Down