feat: OpenAI compatibility improvements & build fixes

- Fix hydration mismatches and initialization errors
- Add /v1/models endpoint for OpenAI clients
- Add Codex response translator (Responses → OpenAI)
- Fix circular dependencies and PropTypes
- Add Material Symbols font and CSS fixes
- Update README with deployment guide

Co-merged from PR #18 (14/15 commits, skipped debug)
This commit is contained in:
decolua
2026-01-20 13:16:34 +07:00
parent 0848dd5d13
commit d9b8e48725
15 changed files with 762 additions and 171 deletions
@@ -1,6 +1,6 @@
"use client";
import { useState, useEffect, useMemo } from "react";
import { useState, useEffect, useMemo, useCallback } from "react";
import { useParams } from "next/navigation";
import Link from "next/link";
import Image from "next/image";
@@ -27,11 +27,7 @@ export default function ProviderDetailPage() {
const models = getModelsByProviderId(providerId);
const providerAlias = getProviderAlias(providerId);
useEffect(() => {
fetchConnections();
fetchAliases();
}, [fetchConnections, fetchAliases]);
// Define callbacks BEFORE the useEffect that uses them
const fetchAliases = useCallback(async () => {
try {
const res = await fetch("/api/models/alias");
@@ -44,6 +40,26 @@ export default function ProviderDetailPage() {
}
}, []);
const fetchConnections = useCallback(async () => {
try {
const res = await fetch("/api/providers");
const data = await res.json();
if (res.ok) {
const filtered = (data.connections || []).filter(c => c.provider === providerId);
setConnections(filtered);
}
} catch (error) {
console.log("Error fetching connections:", error);
} finally {
setLoading(false);
}
}, [providerId]);
useEffect(() => {
fetchConnections();
fetchAliases();
}, [fetchConnections, fetchAliases]);
const handleSetAlias = async (modelId, alias) => {
const fullModel = `${providerAlias}/${modelId}`;
try {
@@ -76,21 +92,6 @@ export default function ProviderDetailPage() {
}
};
const fetchConnections = useCallback(async () => {
try {
const res = await fetch("/api/providers");
const data = await res.json();
if (res.ok) {
const filtered = (data.connections || []).filter(c => c.provider === providerId);
setConnections(filtered);
}
} catch (error) {
console.log("Error fetching connections:", error);
} finally {
setLoading(false);
}
}, [providerId]);
const handleDelete = async (id) => {
if (!confirm("Delete this connection?")) return;
try {