feat: switch from OpenAI API to native Ollama Python client

This commit refactors the LLM integration to use Ollama's native Python client instead of OpenAI-compatible API, while fixing critical template syntax errors and improving project structure.

Key changes:
- Replace openai package with ollama package in backend requirements
- Rewrite llm.py to use ollama.AsyncClient for direct Ollama API calls
- Update main.py to use non-streaming Ollama responses with thinking extraction
- Fix template syntax error in MilkdownEditor.vue (GhostTextOverlay component tags)
- Fix string截取错误 by using slice() instead of substring()
- Add src/utils/api.js and src/utils/config.js for shared configuration
- Add CORS middleware to FastAPI backend
- Update prompt.py with clearer instructions for continuation generation
- Add comprehensive README.md documentation

BREAKING CHANGE: Environment variables OLLAMA_BASE_URL changed to OLLAMA_HOST (remove /v1/ suffix)
This commit is contained in:
2026-02-07 08:53:37 +08:00
committed by “ydy0615”
parent 5f00e71ceb
commit 2abf276d10
17 changed files with 1564 additions and 404 deletions

52
src/utils/api.js Normal file
View File

@@ -0,0 +1,52 @@
import { DEBUG, API_URL } from './config.js'
export async function fetchSuggestion(prefix, suffix, apiUrl = API_URL) {
if (DEBUG) console.log('[Debug] fetchSuggestion called with prefix length:', prefix.length, 'suffix length:', suffix.length)
try {
const res = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prefix, suffix, languageId: 'markdown' }),
})
if (DEBUG) console.log('[Debug] fetchSuggestion response status:', res.status)
if (!res.ok) {
const errorText = await res.text()
throw new Error(`HTTP ${res.status}: ${errorText}`)
}
const reader = res.body?.getReader()
if (!reader) {
if (DEBUG) console.log('[Debug] No reader available')
throw new Error('No reader available')
}
let text = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
const chunk = new TextDecoder().decode(value)
if (DEBUG) console.log('[Debug] Received chunk:', chunk.substring(0, 100))
const lines = chunk.split('\n').filter(l => l.startsWith('data: '))
for (const line of lines) {
try {
const data = JSON.parse(line.slice(6))
if (data.content) {
text += data.content
if (DEBUG) console.log('[Debug] Added content:', data.content)
}
if (data.done || data.error) break
} catch (e) {
if (DEBUG) console.warn('[Debug] JSON parse error:', e)
}
}
}
if (DEBUG) console.log('[Debug] Final suggestion text:', text.substring(0, 100))
return text
} catch (e) {
if (DEBUG) console.error('[Debug] fetchSuggestion error:', e)
throw e
}
}