mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-11 17:26:45 +02:00
fix(openrouter): respect the requesting user's saved model config
generatePostText ignored the userId it received and always read an arbitrary row via getAnyOpenrouterConfig() (LIMIT 1, no ORDER BY), so a model chosen and saved in Settings could be shadowed by another stale config row. Now it prefers the requesting user's own config, falling back to the most recently updated shared one. Also swap the retired anthropic/claude-3.5-sonnet default for a live OpenRouter slug.
This commit is contained in:
7 files changed
+11
-10
No files matched your search
@@ -32,7 +32,7 @@ export default function AiChat() {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const [input, setInput] = useState("");
|
const [input, setInput] = useState("");
|
||||||
const [selectedModel, setSelectedModel] = useState("anthropic/claude-3.5-sonnet");
|
const [selectedModel, setSelectedModel] = useState("anthropic/claude-sonnet-4.5");
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
// Fetch available models from OpenRouter
|
// Fetch available models from OpenRouter
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export default function SettingsMobile() {
|
|||||||
const [endpointUrl, setEndpointUrl] = useState("");
|
const [endpointUrl, setEndpointUrl] = useState("");
|
||||||
const [publicUrl, setPublicUrl] = useState("");
|
const [publicUrl, setPublicUrl] = useState("");
|
||||||
const [openrouterApiKey, setOpenrouterApiKey] = useState("");
|
const [openrouterApiKey, setOpenrouterApiKey] = useState("");
|
||||||
const [openrouterModel, setOpenrouterModel] = useState("anthropic/claude-3.5-sonnet");
|
const [openrouterModel, setOpenrouterModel] = useState("anthropic/claude-sonnet-4.5");
|
||||||
const [openrouterSystemPrompt, setOpenrouterSystemPrompt] = useState("Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
const [openrouterSystemPrompt, setOpenrouterSystemPrompt] = useState("Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
||||||
const [logoFile, setLogoFile] = useState<File | null>(null);
|
const [logoFile, setLogoFile] = useState<File | null>(null);
|
||||||
const [logoPreview, setLogoPreview] = useState<string | null>(null);
|
const [logoPreview, setLogoPreview] = useState<string | null>(null);
|
||||||
@@ -64,7 +64,7 @@ export default function SettingsMobile() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (openrouterConfig) {
|
if (openrouterConfig) {
|
||||||
setOpenrouterModel((openrouterConfig as any).model || "anthropic/claude-3.5-sonnet");
|
setOpenrouterModel((openrouterConfig as any).model || "anthropic/claude-sonnet-4.5");
|
||||||
setOpenrouterSystemPrompt((openrouterConfig as any).systemPrompt || "Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
setOpenrouterSystemPrompt((openrouterConfig as any).systemPrompt || "Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
||||||
}
|
}
|
||||||
}, [openrouterConfig]);
|
}, [openrouterConfig]);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export default function Settings() {
|
|||||||
const [endpointUrl, setEndpointUrl] = useState("");
|
const [endpointUrl, setEndpointUrl] = useState("");
|
||||||
const [publicUrl, setPublicUrl] = useState("");
|
const [publicUrl, setPublicUrl] = useState("");
|
||||||
const [openrouterApiKey, setOpenrouterApiKey] = useState("");
|
const [openrouterApiKey, setOpenrouterApiKey] = useState("");
|
||||||
const [openrouterModel, setOpenrouterModel] = useState("anthropic/claude-3.5-sonnet");
|
const [openrouterModel, setOpenrouterModel] = useState("anthropic/claude-sonnet-4.5");
|
||||||
const [openrouterSystemPrompt, setOpenrouterSystemPrompt] = useState("Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
const [openrouterSystemPrompt, setOpenrouterSystemPrompt] = useState("Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
||||||
const [logoFile, setLogoFile] = useState<File | null>(null);
|
const [logoFile, setLogoFile] = useState<File | null>(null);
|
||||||
const [logoPreview, setLogoPreview] = useState<string | null>(null);
|
const [logoPreview, setLogoPreview] = useState<string | null>(null);
|
||||||
@@ -81,7 +81,7 @@ export default function Settings() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (openrouterConfig) {
|
if (openrouterConfig) {
|
||||||
setOpenrouterModel((openrouterConfig as any).model || "anthropic/claude-3.5-sonnet");
|
setOpenrouterModel((openrouterConfig as any).model || "anthropic/claude-sonnet-4.5");
|
||||||
setOpenrouterSystemPrompt((openrouterConfig as any).systemPrompt || "Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
setOpenrouterSystemPrompt((openrouterConfig as any).systemPrompt || "Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
||||||
}
|
}
|
||||||
}, [openrouterConfig]);
|
}, [openrouterConfig]);
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ CREATE TABLE IF NOT EXISTS openrouter_config (
|
|||||||
id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(),
|
id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
user_id VARCHAR NOT NULL UNIQUE REFERENCES users(id) ON DELETE CASCADE,
|
user_id VARCHAR NOT NULL UNIQUE REFERENCES users(id) ON DELETE CASCADE,
|
||||||
api_key TEXT NOT NULL,
|
api_key TEXT NOT NULL,
|
||||||
model TEXT NOT NULL DEFAULT 'anthropic/claude-3.5-sonnet',
|
model TEXT NOT NULL DEFAULT 'anthropic/claude-sonnet-4.5',
|
||||||
system_prompt TEXT NOT NULL DEFAULT 'Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l''engagement.',
|
system_prompt TEXT NOT NULL DEFAULT 'Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l''engagement.',
|
||||||
created_at TIMESTAMP DEFAULT NOW(),
|
created_at TIMESTAMP DEFAULT NOW(),
|
||||||
updated_at TIMESTAMP DEFAULT NOW()
|
updated_at TIMESTAMP DEFAULT NOW()
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ export class OpenRouterService {
|
|||||||
private baseUrl = "https://openrouter.ai/api/v1/chat/completions";
|
private baseUrl = "https://openrouter.ai/api/v1/chat/completions";
|
||||||
|
|
||||||
async generatePostText(productInfo: ProductInfo, userId: string, modelOverride?: string): Promise<GeneratedText[]> {
|
async generatePostText(productInfo: ProductInfo, userId: string, modelOverride?: string): Promise<GeneratedText[]> {
|
||||||
// Get any available OpenRouter configuration (shared across all users)
|
// Prefer the requesting user's own configuration; fall back to the most
|
||||||
const config = await storage.getAnyOpenrouterConfig();
|
// recently saved shared configuration if this user hasn't set one up.
|
||||||
|
const config = (await storage.getOpenrouterConfig(userId)) || (await storage.getAnyOpenrouterConfig());
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error('Configuration OpenRouter non trouvée. Veuillez demander à un administrateur de configurer OpenRouter dans les Paramètres.');
|
throw new Error('Configuration OpenRouter non trouvée. Veuillez demander à un administrateur de configurer OpenRouter dans les Paramètres.');
|
||||||
|
|||||||
+1
-1
@@ -461,7 +461,7 @@ export class DatabaseStorage implements IStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getAnyOpenrouterConfig(): Promise<OpenrouterConfig | undefined> {
|
async getAnyOpenrouterConfig(): Promise<OpenrouterConfig | undefined> {
|
||||||
const [config] = await db.select().from(openrouterConfig).limit(1);
|
const [config] = await db.select().from(openrouterConfig).orderBy(desc(openrouterConfig.updatedAt)).limit(1);
|
||||||
return config || undefined;
|
return config || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -127,7 +127,7 @@ export const openrouterConfig = pgTable("openrouter_config", {
|
|||||||
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
|
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
|
||||||
userId: varchar("user_id").notNull().unique().references(() => users.id, { onDelete: "cascade" }),
|
userId: varchar("user_id").notNull().unique().references(() => users.id, { onDelete: "cascade" }),
|
||||||
apiKey: text("api_key").notNull(),
|
apiKey: text("api_key").notNull(),
|
||||||
model: text("model").notNull().default("anthropic/claude-3.5-sonnet"),
|
model: text("model").notNull().default("anthropic/claude-sonnet-4.5"),
|
||||||
systemPrompt: text("system_prompt").notNull().default("Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement."),
|
systemPrompt: text("system_prompt").notNull().default("Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement."),
|
||||||
createdAt: timestamp("created_at").defaultNow(),
|
createdAt: timestamp("created_at").defaultNow(),
|
||||||
updatedAt: timestamp("updated_at").defaultNow(),
|
updatedAt: timestamp("updated_at").defaultNow(),
|
||||||
|
|||||||
Reference in new issue
Block a user