@caoguo/maplibre-ai 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1478,6 +1478,168 @@ function createDeepSeekClient(config) {
1478
1478
  return new DeepSeekClient(config);
1479
1479
  }
1480
1480
 
1481
+ // src/llm/openaiCompatible.ts
1482
+ function normalizeError2(body, provider) {
1483
+ const err = new Error(body || `${provider} API \u8BF7\u6C42\u5931\u8D25`);
1484
+ err.name = `${provider}Error`;
1485
+ return err;
1486
+ }
1487
+ var OpenAICompatibleClient = class {
1488
+ apiKey;
1489
+ baseUrl;
1490
+ model;
1491
+ temperature;
1492
+ maxTokens;
1493
+ timeoutMs;
1494
+ retries;
1495
+ fetchImpl;
1496
+ authScheme;
1497
+ extraHeaders;
1498
+ providerLabel;
1499
+ constructor(config) {
1500
+ if (!config.apiKey) throw new Error("OpenAICompatibleClient: apiKey \u4E0D\u80FD\u4E3A\u7A7A");
1501
+ if (!config.baseUrl) throw new Error("OpenAICompatibleClient: baseUrl \u4E0D\u80FD\u4E3A\u7A7A");
1502
+ if (!config.model) throw new Error("OpenAICompatibleClient: model \u4E0D\u80FD\u4E3A\u7A7A");
1503
+ this.apiKey = config.apiKey;
1504
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
1505
+ this.model = config.model;
1506
+ this.temperature = config.temperature ?? 0.3;
1507
+ this.maxTokens = config.maxTokens ?? 2048;
1508
+ this.timeoutMs = config.timeoutMs ?? 3e4;
1509
+ this.retries = config.retries ?? 2;
1510
+ this.fetchImpl = config.fetchImpl ?? (globalThis.fetch ?? fetch);
1511
+ this.authScheme = config.authScheme ?? "Bearer";
1512
+ this.extraHeaders = config.extraHeaders ?? {};
1513
+ this.providerLabel = (() => {
1514
+ try {
1515
+ return new URL(this.baseUrl).hostname || "LLM";
1516
+ } catch {
1517
+ return "LLM";
1518
+ }
1519
+ })();
1520
+ }
1521
+ async chat(messages, opts = {}) {
1522
+ return this.requestWithRetry(messages, opts);
1523
+ }
1524
+ async chatJson(messages) {
1525
+ const result = await this.chat(messages, { json: true });
1526
+ const raw = result.content.trim();
1527
+ const cleaned = raw.replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "");
1528
+ let data;
1529
+ try {
1530
+ data = JSON.parse(cleaned);
1531
+ } catch {
1532
+ const match = cleaned.match(/\{[\s\S]*\}|\[[\s\S]*\]/);
1533
+ if (match) {
1534
+ data = JSON.parse(match[0]);
1535
+ } else {
1536
+ throw new Error(`${this.providerLabel} \u8FD4\u56DE\u4E86\u975E JSON \u5185\u5BB9: ${raw.slice(0, 200)}`);
1537
+ }
1538
+ }
1539
+ return { data, raw, model: result.model };
1540
+ }
1541
+ async requestWithRetry(messages, opts) {
1542
+ let lastError = null;
1543
+ for (let attempt = 0; attempt <= this.retries; attempt++) {
1544
+ try {
1545
+ return await this.requestOnce(messages, opts);
1546
+ } catch (e) {
1547
+ lastError = e;
1548
+ if (attempt < this.retries) {
1549
+ await this.sleep(Math.min(1e3 * 2 ** attempt, 8e3));
1550
+ }
1551
+ }
1552
+ }
1553
+ throw lastError ?? new Error(`${this.providerLabel} \u8BF7\u6C42\u5931\u8D25`);
1554
+ }
1555
+ async requestOnce(messages, opts) {
1556
+ const controller = new AbortController();
1557
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
1558
+ const body = {
1559
+ model: this.model,
1560
+ messages,
1561
+ temperature: this.temperature,
1562
+ max_tokens: this.maxTokens,
1563
+ stream: Boolean(opts.onChunk)
1564
+ };
1565
+ if (opts.json) {
1566
+ body.response_format = { type: "json_object" };
1567
+ }
1568
+ const headers = {
1569
+ "Content-Type": "application/json",
1570
+ ...this.extraHeaders
1571
+ };
1572
+ if (this.authScheme === "Bearer") {
1573
+ headers.Authorization = `Bearer ${this.apiKey}`;
1574
+ } else {
1575
+ headers["X-Api-Key"] = this.apiKey;
1576
+ }
1577
+ try {
1578
+ const res = await this.fetchImpl(`${this.baseUrl}/chat/completions`, {
1579
+ method: "POST",
1580
+ headers,
1581
+ body: JSON.stringify(body),
1582
+ signal: controller.signal
1583
+ });
1584
+ if (!res.ok) {
1585
+ const text = await res.text().catch(() => "");
1586
+ throw normalizeError2(`${this.providerLabel} HTTP ${res.status}: ${text}`, this.providerLabel);
1587
+ }
1588
+ if (opts.onChunk && res.body) {
1589
+ return this.parseStream(res.body, opts.onChunk);
1590
+ }
1591
+ const json = await res.json();
1592
+ const content = json.choices?.[0]?.message?.content ?? "";
1593
+ return {
1594
+ content,
1595
+ model: json.model ?? this.model,
1596
+ usage: json.usage ? {
1597
+ promptTokens: json.usage.prompt_tokens,
1598
+ completionTokens: json.usage.completion_tokens,
1599
+ totalTokens: json.usage.prompt_tokens + json.usage.completion_tokens
1600
+ } : void 0
1601
+ };
1602
+ } finally {
1603
+ clearTimeout(timer);
1604
+ }
1605
+ }
1606
+ async parseStream(body, onChunk) {
1607
+ const reader = body.getReader();
1608
+ const decoder = new TextDecoder();
1609
+ let content = "";
1610
+ let buffer = "";
1611
+ while (true) {
1612
+ const { done, value } = await reader.read();
1613
+ if (done) break;
1614
+ buffer += decoder.decode(value, { stream: true });
1615
+ const lines = buffer.split("\n");
1616
+ buffer = lines.pop() ?? "";
1617
+ for (const line of lines) {
1618
+ const trimmed = line.trim();
1619
+ if (!trimmed.startsWith("data:")) continue;
1620
+ const data = trimmed.slice(5).trim();
1621
+ if (data === "[DONE]") continue;
1622
+ try {
1623
+ const json = JSON.parse(data);
1624
+ const delta = json.choices?.[0]?.delta?.content ?? "";
1625
+ if (delta) {
1626
+ content += delta;
1627
+ onChunk(delta);
1628
+ }
1629
+ } catch {
1630
+ }
1631
+ }
1632
+ }
1633
+ return { content, model: this.model };
1634
+ }
1635
+ sleep(ms) {
1636
+ return new Promise((r) => setTimeout(r, ms));
1637
+ }
1638
+ };
1639
+ function createOpenAICompatibleClient(config) {
1640
+ return new OpenAICompatibleClient(config);
1641
+ }
1642
+
1481
1643
  exports.CARRIER_STYLES = CARRIER_STYLES;
1482
1644
  exports.CHINA_BOUNDS = CHINA_BOUNDS;
1483
1645
  exports.COLOR_NAMES = COLOR_NAMES;
@@ -1489,6 +1651,7 @@ exports.LOCAL_GEO_DB = LOCAL_GEO_DB;
1489
1651
  exports.LlmMapCopilot = LlmMapCopilot;
1490
1652
  exports.LlmNlpg = LlmNlpg;
1491
1653
  exports.MapCopilot = MapCopilot;
1654
+ exports.OpenAICompatibleClient = OpenAICompatibleClient;
1492
1655
  exports.PLACE_COORDINATES = PLACE_COORDINATES;
1493
1656
  exports.adjustBrightness = adjustBrightness;
1494
1657
  exports.analyzePerformance = analyzePerformance;
@@ -1496,6 +1659,7 @@ exports.analyzeTiles = analyzeTiles;
1496
1659
  exports.batchGeocode = batchGeocode;
1497
1660
  exports.classifyIntent = classifyIntent;
1498
1661
  exports.createDeepSeekClient = createDeepSeekClient;
1662
+ exports.createOpenAICompatibleClient = createOpenAICompatibleClient;
1499
1663
  exports.detectCRS = detectCRS;
1500
1664
  exports.detectField = detectField;
1501
1665
  exports.detectHeaders = detectHeaders;