File size: 3,393 Bytes
d958e80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
 * M5 JavaScript SDK
 */

class M5Client {
  constructor(apiKey, baseUrl = 'https://m5.hf.space') {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl.replace(/\/$/, '');
    this.headers = {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    };
  }

  async chatCompletion(options) {
    const {
      model,
      messages,
      temperature = 0.7,
      maxTokens = null,
      stream = false,
      ollamaUrl = null
    } = options;

    const payload = {
      model,
      messages,
      temperature,
      stream
    };

    if (maxTokens) payload.max_tokens = maxTokens;
    if (ollamaUrl) payload.ollama_url = ollamaUrl;

    const response = await fetch(`${this.baseUrl}/v1/chat/completions`, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify(payload)
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    return await response.json();
  }

  async *chatCompletionStream(options) {
    const {
      model,
      messages,
      temperature = 0.7,
      maxTokens = null,
      ollamaUrl = null
    } = options;

    const payload = {
      model,
      messages,
      temperature,
      stream: true
    };

    if (maxTokens) payload.max_tokens = maxTokens;
    if (ollamaUrl) payload.ollama_url = ollamaUrl;

    const response = await fetch(`${this.baseUrl}/v1/chat/completions`, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify(payload)
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = decoder.decode(value, { stream: true });
      const lines = chunk.split('\n');

      for (const line of lines) {
        if (!line.startsWith('data: ')) continue;
        const data = line.slice(6).trim();
        if (data === '[DONE]') break;

        try {
          const parsed = JSON.parse(data);
          if (parsed.choices && parsed.choices[0]) {
            const delta = parsed.choices[0].delta;
            if (delta && delta.content) {
              yield delta.content;
            }
          }
        } catch (e) {
          // Skip invalid JSON
        }
      }
    }
  }

  async listModels() {
    const response = await fetch(`${this.baseUrl}/v1/models`, {
      headers: this.headers
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    return data.data || [];
  }
}

// Convenience classes
class Chat {
  constructor(client) {
    this.client = client;
  }

  async create(options) {
    return await this.client.chatCompletion(options);
  }

  async *createStream(options) {
    yield* this.client.chatCompletionStream(options);
  }
}

class M5 {
  constructor(apiKey, baseUrl = 'https://m5.hf.space') {
    this.client = new M5Client(apiKey, baseUrl);
    this.chat = new Chat(this.client);
  }
}

// Export for Node.js
if (typeof module !== 'undefined' && module.exports) {
  module.exports = { M5, M5Client, Chat };
}

// Export for browser
if (typeof window !== 'undefined') {
  window.M5 = M5;
  window.M5Client = M5Client;
  window.Chat = Chat;
}