Skip to content

Commit

Permalink
Default to limit trades in mani (#3420)
Browse files Browse the repository at this point in the history
* Limit orders by default on mani

* Use o3-mini for clarifications & replace gpt4-o

* Dedupe getLimitBetReturns input logic

* mani: Listen to user balances and unfilled bets

* remove log

* Remove unused
  • Loading branch information
IanPhilips authored Feb 1, 2025
1 parent 7cb516c commit 932790f
Show file tree
Hide file tree
Showing 32 changed files with 701 additions and 497 deletions.
6 changes: 3 additions & 3 deletions backend/api/src/get-best-comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { convertContractComment } from 'common/supabase/comments'
import { parseJsonContentToText } from 'common/util/parse'
import { getContractsDirect } from 'shared/supabase/contracts'
import { uniq } from 'lodash'
import { promptGPT4 } from 'shared/helpers/openai-utils'
import { promptOpenAI } from 'shared/helpers/openai-utils'
import { ContractComment } from 'common/comment'
import { log } from 'shared/utils'
import { rateLimitByUser } from './helpers/rate-limit'
Expand Down Expand Up @@ -186,7 +186,7 @@ export const getBestComments: APIHandler<'get-best-comments'> = rateLimitByUser(
Only return to me the comment ID, (ie don't say here is my top comment, just give me the ID)
`

const batchMsgContent = await promptGPT4(batchContent)
const batchMsgContent = await promptOpenAI(batchContent, 'o3-mini')
const batchCommentIds = batchMsgContent
? batchMsgContent
.split(',')
Expand Down Expand Up @@ -230,7 +230,7 @@ export const getBestComments: APIHandler<'get-best-comments'> = rateLimitByUser(
of descending quality? (ie don't say here are my top comments, just give me the IDs)
`

const gpt4Response = await promptGPT4(gpt4Prompt)
const gpt4Response = await promptOpenAI(gpt4Prompt, 'o3-mini')
commentIds = gpt4Response
? gpt4Response
.split(',')
Expand Down
7 changes: 5 additions & 2 deletions backend/api/src/get-market-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { convertContractComment } from 'common/supabase/comments'
import { ContractMetric } from 'common/contract-metric'
import { ContractComment } from 'common/comment'
import { type APIHandler } from './helpers/endpoint'
import { MarketContract } from 'common/contract'

export const getMarketProps: APIHandler<'get-market-props'> = async (
props: { id?: string; slug?: string },
Expand Down Expand Up @@ -126,7 +127,7 @@ export const getMarketProps: APIHandler<'get-market-props'> = async (
`,
[contractId]
)
const contract = first(results[0]?.map(convertContract))
const contract = first(results[0]?.map(convertContract<MarketContract>))
if (!contract) throw new APIError(404, 'Contract not found')
const chartAnnotations = results[1]
const topics = results[2].map(convertGroup)
Expand All @@ -138,7 +139,9 @@ export const getMarketProps: APIHandler<'get-market-props'> = async (
const topContractMetrics = results[7].map((r) => r.data as ContractMetric)
const totalPositions = results[8]?.[0]?.count ?? 0
const dashboards = results[9]
const siblingContract = first(results[10]?.map(convertContract))
const siblingContract = first(
results[10]?.map(convertContract<MarketContract>)
)
if (!siblingContract) throw new APIError(404, 'Sibiling contract not found')
const manaContract = contract.token === 'MANA' ? contract : siblingContract
const cashContract = contract.token === 'CASH' ? contract : siblingContract
Expand Down
13 changes: 13 additions & 0 deletions backend/api/src/get-users-by-ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,16 @@ export const getUsersByIds: APIHandler<'users/by-id'> = async (props) => {
)
return users.map((user) => removeNullOrUndefinedProps(user))
}

export const getUserBalancesByIds: APIHandler<'users/by-id/balance'> = async (
props
) => {
const pg = createSupabaseDirectClient()
const users = await pg.manyOrNone(
`select id, balance
from users
where id = any($1)`,
[props.ids]
)
return users.map((user) => removeNullOrUndefinedProps(user))
}
2 changes: 1 addition & 1 deletion backend/api/src/on-create-comment-on-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ NOTE: If the creator explicitly states that their comment is not a clarification
Only return the raw JSON object without any markdown code blocks, backticks, additional formatting, or anything else.`

try {
const response = await promptOpenAI(prompt, 'o1-mini')
const response = await promptOpenAI(prompt, 'o3-mini')
log('Clarification response:', {
question: contract.question,
contractId: contract.id,
Expand Down
3 changes: 2 additions & 1 deletion backend/api/src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { getComments } from './get-comments'
import { getBets } from './get-bets'
import { getLiteUser, getUser } from './get-user'
import { getUsers } from './get-users'
import { getUsersByIds } from './get-users-by-ids'
import { getUserBalancesByIds, getUsersByIds } from './get-users-by-ids'
import { getMarket } from './get-market'
import { getMarketProb } from './get-market-prob'
import { getMarketProbs } from './get-market-probs'
Expand Down Expand Up @@ -240,6 +240,7 @@ export const handlers: { [k in APIPath]: APIHandler<k> } = {
'user/by-id/:id/unblock': unblockUser,
users: getUsers,
'users/by-id': getUsersByIds,
'users/by-id/balance': getUserBalancesByIds,
'search-users': searchUsers,
react: addOrRemoveReaction,
'save-twitch': saveTwitchCredentials,
Expand Down
2 changes: 2 additions & 0 deletions backend/api/url-map-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pathMatchers:
- pathTemplateMatch: /v0/user/by-id/*/lite
- pathTemplateMatch: /v0/user/*
- pathTemplateMatch: /v0/user/*/lite
- pathTemplateMatch: /v0/users/by-id
- pathTemplateMatch: /users/by-id/balance
- pathTemplateMatch: /v0/user/*/bets
- pathTemplateMatch: /get-balance-changes
- pathTemplateMatch: /get-user-limit-orders-with-contracts
Expand Down
4 changes: 2 additions & 2 deletions backend/scheduler/src/jobs/auto-award-bounty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BountiedQuestionContract } from 'common/contract'
import { getAutoBountyPayoutPerHour } from 'common/bounty'
import { createSupabaseDirectClient } from 'shared/supabase/init'
import { awardBounty } from 'shared/bounty'
import { promptGPT4 } from 'shared/helpers/openai-utils'
import { promptOpenAI } from 'shared/helpers/openai-utils'
import { log, revalidateContractStaticProps } from 'shared/utils'
import { updateContract } from 'shared/supabase/contracts'

Expand Down Expand Up @@ -79,7 +79,7 @@ Description: ${JSON.stringify(contract.description)}
The following comments have been submitted:
` + sortedComments.map((c) => `${c.likes} likes:\n${c.content}`).join('\n\n')
const resultMessage = await promptGPT4(prompt)
const resultMessage = await promptOpenAI(prompt, 'o3-mini')
if (resultMessage) {
await updateContract(pg, contract.id, {
gptCommentSummary: resultMessage,
Expand Down
29 changes: 5 additions & 24 deletions backend/shared/src/helpers/openai-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import OpenAI from 'openai'
import * as dayjs from 'dayjs'
import { log } from 'shared/utils'
import * as utc from 'dayjs/plugin/utc'
import { APIError } from 'common/api/utils'
dayjs.extend(utc)
export type MODELS = 'gpt-4o' | 'o1-mini' | 'o1-preview'
export type MODELS = 'o3-mini'

export const generateEmbeddings = async (question: string) => {
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
Expand Down Expand Up @@ -84,40 +85,20 @@ export const generateImage = async (q: string) => {
.catch((err) => (console.log(err), undefined))
}

export const promptGPT4 = async (prompt: string) => {
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })

const result = await openai.chat.completions
.create({
model: 'gpt-4o',
messages: [{ role: 'system', content: prompt }],
max_tokens: 4096,
})
.catch((err) => (console.log(err), undefined))

if (!result) return undefined

const message = result.choices[0].message.content
log('GPT4 returned message:', message)
return message
}

export const promptOpenAI = async (prompt: string, model: MODELS) => {
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })

const result = await openai.chat.completions
.create({
model,
messages: [
// o1-* models don't support system messages
{ role: model === 'gpt-4o' ? 'system' : 'user', content: prompt },
],
messages: [{ role: 'system', content: prompt }],
})
.catch((err) => (console.log(err), undefined))

if (!result) return undefined
if (!result) throw new APIError(500, 'No result from OpenAI')

const message = result.choices[0].message.content
log('GPT4 returned message:', message)
if (!message) throw new APIError(500, 'No result from OpenAI')
return message
}
117 changes: 113 additions & 4 deletions client-common/src/hooks/use-bets.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { APIParams, APIPath, APIResponse } from 'common/api/schema'
import { APIParams, APIResponse } from 'common/api/schema'
import { usePersistentInMemoryState } from './use-persistent-in-memory-state'
import { Bet } from 'common/bet'
import { Bet, LimitBet } from 'common/bet'
import { Dispatch, SetStateAction, useEffect } from 'react'
import { useApiSubscription } from './use-api-subscription'
import { sortBy, uniqBy } from 'lodash'
import { LimitBet } from 'common/bet'
import { sortBy, uniq, uniqBy } from 'lodash'
import { User } from 'common/user'

export const useContractBets = (
contractId: string,
Expand Down Expand Up @@ -121,3 +121,112 @@ export const useSubscribeGlobalBets = (options?: APIParams<'bets'>) => {

return newBets
}

export const useUnfilledBets = (
contractId: string,
api: (params: APIParams<'bets'>) => Promise<APIResponse<'bets'>>,
useIsPageVisible: () => boolean,
options?: {
enabled?: boolean
}
) => {
const { enabled = true } = options ?? {}

const [bets, setBets] = usePersistentInMemoryState<LimitBet[] | undefined>(
undefined,
`unfilled-bets-${contractId}`
)

const addBets = (newBets: LimitBet[]) => {
setBets((bets) => {
return sortBy(
uniqBy([...newBets, ...(bets ?? [])], 'id'),
'createdTime'
).filter(
(bet) =>
!bet.isFilled &&
!bet.isCancelled &&
(!bet.expiresAt || bet.expiresAt > Date.now())
)
})
}

const isPageVisible = useIsPageVisible()

useEffect(() => {
if (enabled)
api({ contractId, kinds: 'open-limit', order: 'asc' }).then(
// Reset bets instead of adding to existing, since we want to exclude those recently filled/cancelled.
(bets) => setBets(bets as LimitBet[])
)
}, [enabled, contractId, isPageVisible])

useApiSubscription({
enabled,
topics: [`contract/${contractId}/orders`],
onBroadcast: ({ data }) => {
addBets(data.bets as LimitBet[])
},
})

return bets
}

export const useUnfilledBetsAndBalanceByUserId = (
contractId: string,
api: (params: APIParams<'bets'>) => Promise<APIResponse<'bets'>>,
usersApi: (
params: APIParams<'users/by-id/balance'>
) => Promise<APIResponse<'users/by-id/balance'>>,
useIsPageVisible: () => boolean
) => {
const unfilledBets =
useUnfilledBets(contractId, api, useIsPageVisible, { enabled: true }) ?? []
const userIds = uniq(unfilledBets.map((b) => b.userId))
const balances = useUserBalances(userIds, usersApi, useIsPageVisible) ?? []

const balanceByUserId = Object.fromEntries(
balances.map(({ id, balance }) => [id, balance])
)
return { unfilledBets, balanceByUserId }
}

const useUserBalances = (
userIds: string[],
api: (
params: APIParams<'users/by-id/balance'>
) => Promise<APIResponse<'users/by-id/balance'>>,
useIsPageVisible: () => boolean
) => {
const [users, setUsers] = usePersistentInMemoryState<
{ id: string; balance: number }[]
>([], `user-balances-${userIds.join('-')}`)
const isPageVisible = useIsPageVisible()

// Load initial data
useEffect(() => {
if (!userIds.length || !isPageVisible) return
api({ ids: userIds }).then((users) => {
setUsers(users)
})
}, [userIds.join(','), isPageVisible])

// Subscribe to updates
useApiSubscription({
topics: userIds.map((id) => `user/${id}`),
onBroadcast: ({ data }) => {
const { user } = data as { user: Partial<User> }
if (!user) return
const prevUser = users.find((u) => u.id === user.id)
if (!prevUser) return
setUsers((prevUsers) => {
return prevUsers.map((prevU) =>
prevU.id === user.id ? { ...prevU, ...user } : prevU
)
})
},
enabled: userIds.length > 0 && isPageVisible,
})

return users
}
Loading

0 comments on commit 932790f

Please sign in to comment.