sbkl
sbkl
CCConvex Community
Created by sbkl on 12/27/2024 in #support-community
http actions with abort signal
I am using the ai package from vercel and stream some llm output. I want to handle client disconnection with the abortSignal property when the user reloads the browser manually but it seems that convex http actions don't support it at the moment? I am using http actions with hono. Getting this error: "Not implemented: get signal for Request. Consider calling an action defined in Node.js instead (https://docs.convex.dev/functions/actions)."
import { streamText } from "ai";

app.post(
"/api/stream",
async (ctx) => {

const signal = ctx.req.raw.signal;

signal.addEventListener("abort", async (data) => {
console.log("Stream aborted by client", sectionId, data);
});

const result = streamText({
model: model,
system,
prompt,
abortSignal: signal,
onFinish: async ({ usage, text, ...rest }) => {
// Handle end of streaming
},
});

return result.toDataStreamResponse();
},
);
import { streamText } from "ai";

app.post(
"/api/stream",
async (ctx) => {

const signal = ctx.req.raw.signal;

signal.addEventListener("abort", async (data) => {
console.log("Stream aborted by client", sectionId, data);
});

const result = streamText({
model: model,
system,
prompt,
abortSignal: signal,
onFinish: async ({ usage, text, ...rest }) => {
// Handle end of streaming
},
});

return result.toDataStreamResponse();
},
);
2 replies
CCConvex Community
Created by sbkl on 11/20/2024 in #support-community
Using gemini with openai library working in action but not http action
I followed this guide to integrate ai streaming in my convex app. But instead of using openai, I want to use gemini because of their larger context window (1M tokens for gemini-1.5-flash). I get a bad request answer just using the basic example from google docs here. However, the exact same code works in actions which I assume it is due to the fact that http action cannot run node packages? What I don't get is why it is supposed to work with openAI (cannot try as I am not located in a country where opeanai is available) but it doesn't work for gemini. But still works in actions. Any idea if there is a way to make it work? Here is the code as an example (gemini api key created via google ai studio):
const openai = new OpenAI({
apiKey: env.GEMINI_API_KEY,
baseURL: "https://generativelanguage.googleapis.com/v1beta/openai/",
});
const response = await openai.chat.completions.create({
model: "gemini-1.5-flash",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{
role: "user",
content: "Explain to me how AI works",
},
],
});
const openai = new OpenAI({
apiKey: env.GEMINI_API_KEY,
baseURL: "https://generativelanguage.googleapis.com/v1beta/openai/",
});
const response = await openai.chat.completions.create({
model: "gemini-1.5-flash",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{
role: "user",
content: "Explain to me how AI works",
},
],
});
7 replies
CCConvex Community
Created by sbkl on 10/28/2024 in #support-community
Uncaught Error: The arguments to a Convex function must be an object. Received: skip
Using convex-react-query, I noticed there is a new skip arguments that can be used to disable a query when the arguments is not available yet. But I get this error: Uncaught Error: The arguments to a Convex function must be an object. Received: skip. Which means the convex client complaining about the args. Looked at the code and normally the query shouldn't run at all. Any idea? Maybe I understand it wrong. My code:
export function useGetDocument() {
const params = useParams();
const documentId = params.documentId as Id<"documents"> | undefined;
const query = useQuery(
convexQuery(
api.documents.query.find,
documentId
? {
documentId: documentId as Id<"documents">,
}
: "skip",
),
);

return { documentId, ...query };
}
export function useGetDocument() {
const params = useParams();
const documentId = params.documentId as Id<"documents"> | undefined;
const query = useQuery(
convexQuery(
api.documents.query.find,
documentId
? {
documentId: documentId as Id<"documents">,
}
: "skip",
),
);

return { documentId, ...query };
}
5 replies
CCConvex Community
Created by sbkl on 10/11/2024 in #support-community
File serving in a nextjs app via http action authenticated with clerk
After looking at the docs, this is the implementation I came with for serving my files securely via http action. Any feedback appreciated. /convex/http.ts
import { HonoWithConvex, HttpRouterWithHono } from "convex-helpers/server/hono";
import { Hono } from "hono";

import { ActionCtx } from "./_generated/server";

const app: HonoWithConvex<ActionCtx> = new Hono();

app.get("/storage", async (ctx) => {
const identity = await ctx.env.auth.getUserIdentity();
if (!identity?.subject) {
return new Response("User is not signed in.", { status: 401 });
}
const storageId = ctx.req.query("storageId");
const fileType = ctx.req.query("fileType");

if (!storageId) {
return new Response("Storage ID is required.", { status: 400 });
}

if (!fileType) {
return new Response("File type is required.", { status: 400 });
}

switch (fileType) {
case "document":
case "documentThumbnail":
await ctx.env.runQuery(internal.documents.query.verify, {
fileType,
storageId: storageId as Id<"_storage">,
userExternalId: identity.subject.toString(),
});
break;
default:
return new Response("Invalid file type.", { status: 400 });
}

const blob = await ctx.env.storage.get(storageId as Id<"_storage">);
if (blob === null) {
return new Response("File not found", {
status: 404,
});
}
return new Response(blob);
});

export default new HttpRouterWithHono(app);
import { HonoWithConvex, HttpRouterWithHono } from "convex-helpers/server/hono";
import { Hono } from "hono";

import { ActionCtx } from "./_generated/server";

const app: HonoWithConvex<ActionCtx> = new Hono();

app.get("/storage", async (ctx) => {
const identity = await ctx.env.auth.getUserIdentity();
if (!identity?.subject) {
return new Response("User is not signed in.", { status: 401 });
}
const storageId = ctx.req.query("storageId");
const fileType = ctx.req.query("fileType");

if (!storageId) {
return new Response("Storage ID is required.", { status: 400 });
}

if (!fileType) {
return new Response("File type is required.", { status: 400 });
}

switch (fileType) {
case "document":
case "documentThumbnail":
await ctx.env.runQuery(internal.documents.query.verify, {
fileType,
storageId: storageId as Id<"_storage">,
userExternalId: identity.subject.toString(),
});
break;
default:
return new Response("Invalid file type.", { status: 400 });
}

const blob = await ctx.env.storage.get(storageId as Id<"_storage">);
if (blob === null) {
return new Response("File not found", {
status: 404,
});
}
return new Response(blob);
});

export default new HttpRouterWithHono(app);
4 replies
CCConvex Community
Created by sbkl on 9/26/2024 in #support-community
LLamaindex package: External packages in convex.json doesn't work
I want to use the llamaindex package to parse documents with their parser model. However, this model also includes a VectorStoreIndex that is used in conjuction with openAI to create embeddings and store it in the llamacloud database. As I don't have access to openAI (based in Hong Kong) and I want to keep using convex for vector search, I don't use this functionality. But I believe there are the reason for the error below. I put "use node" at the top of the file and inserted the packages that errored my build to the node.externalPackages convex.json file. But I still get the same errors. Any clue on what that could be? The pg packages must be used for their vector database which I don't use.
{
"node": {
"externalPackages": [
"llamaindex",
"pg",
"pgvector/pg",
"@xenova/transformers"
]
}
}
{
"node": {
"externalPackages": [
"llamaindex",
"pg",
"pgvector/pg",
"@xenova/transformers"
]
}
}
3 replies
CCConvex Community
Created by sbkl on 9/25/2024 in #support-community
Object contains extra field that is not in the validator.
I get this error. ArgumentValidationError: Object contains extra field example that is not in the validator. How to allow pass args that have unknown args and make the validator just ignore them but make sure what is requested is in there? Looked at the docs and couldn't find an example.
4 replies
CCConvex Community
Created by sbkl on 5/13/2024 in #support-community
Convex Ents, many to many pivot table with additional fields
Cannot find it in the documentation. Is it possible to add custom fields to a many-to-many relationships pivot table with convex Ents and the edges method? Like a collection could belong to many regions and a region can have many collections. If the case you would want to add an archive feature to archive a specific collection for a given region, the pivot table would have a "archivedAt" field to record this, on top of the collectionId and regionId fields. If you see what I mean. Otherwise, I guess the only is to make it manually with the vanilla convex syntax which would be the same for query and mutation?
2 replies
CCConvex Community
Created by sbkl on 5/12/2024 in #support-community
preloadQuery client cache
Using the preloadQuery with nextjs app router, it is server rendering the page as expected. However, when I create a new element in a list that navigates to that page and I hit the back button, the list display is the initial page rendered missing the new item. Then the convex real time server kicks in and the new item appears. Recorded my screen for demo. Is there a way to trigger a refetch/invalidate of the preload query after a mutation similar to react-query?
4 replies
CCConvex Community
Created by sbkl on 5/11/2024 in #support-community
preloadQuery for server side rendering getting the client component error
I want to preload my query with a server component and get this error
Error: createContext only works in Client Components. Add the "use client" directive at the top of the file to use it.
I followed the documentation here: https://docs.convex.dev/client/react/nextjs/server-rendering When commenting out the preloadQuery, the page renders properly, so I assume the error can only come from this. Also, the token is properly retrieved from clerck. Below the code:
app/collections/page.tsx
import { preloadQuery } from "convex/nextjs";
import { api } from "@capacity/api";
import { getAuthToken } from "@/lib/auth";

export default async function Page() {
const token = await getAuthToken();
const preloadedCollections = await preloadQuery(
api.collections.list,
{},
{
token,
},
);
return <main>{token}</main>;
}

lib/auth.ts
import { auth } from "@clerk/nextjs/server";

export async function getAuthToken() {
return (await auth().getToken({ template: "convex" })) ?? undefined;
}
app/collections/page.tsx
import { preloadQuery } from "convex/nextjs";
import { api } from "@capacity/api";
import { getAuthToken } from "@/lib/auth";

export default async function Page() {
const token = await getAuthToken();
const preloadedCollections = await preloadQuery(
api.collections.list,
{},
{
token,
},
);
return <main>{token}</main>;
}

lib/auth.ts
import { auth } from "@clerk/nextjs/server";

export async function getAuthToken() {
return (await auth().getToken({ template: "convex" })) ?? undefined;
}
4 replies